@arnilo/prism-tools 0.0.0-stage → 0.13.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.
Files changed (331) hide show
  1. package/CHANGELOG.md +418 -0
  2. package/LICENSE +21 -0
  3. package/README.md +44 -2
  4. package/browser/README.md +98 -0
  5. package/browser/skills/browser-automation/SKILL.md +14 -0
  6. package/browser/src/actions/cdp.ts +131 -0
  7. package/browser/src/actions/dialog.ts +25 -0
  8. package/browser/src/actions/download_release.ts +22 -0
  9. package/browser/src/actions/index.ts +37 -0
  10. package/browser/src/actions/locator.ts +70 -0
  11. package/browser/src/actions/navigate.ts +23 -0
  12. package/browser/src/actions/screenshot.ts +27 -0
  13. package/browser/src/actions/scroll.ts +24 -0
  14. package/browser/src/actions/select_page.ts +21 -0
  15. package/browser/src/actions/types.ts +114 -0
  16. package/browser/src/actions/upload.ts +44 -0
  17. package/browser/src/actions/wait.ts +45 -0
  18. package/browser/src/browser.ts +197 -0
  19. package/browser/src/cdp.ts +178 -0
  20. package/browser/src/checkpoint.ts +189 -0
  21. package/browser/src/config.ts +72 -0
  22. package/browser/src/downloads.ts +253 -0
  23. package/browser/src/errors.ts +31 -0
  24. package/browser/src/evaluate.ts +101 -0
  25. package/browser/src/index.ts +129 -0
  26. package/browser/src/limits.ts +271 -0
  27. package/browser/src/manager.ts +730 -0
  28. package/browser/src/network.ts +263 -0
  29. package/browser/src/observe.ts +178 -0
  30. package/browser/src/policy.ts +133 -0
  31. package/browser/src/screenshot.ts +107 -0
  32. package/browser/src/shared-sandbox.ts +53 -0
  33. package/browser/src/snapshot.ts +99 -0
  34. package/browser/src/targets.ts +165 -0
  35. package/browser/src/tools.ts +480 -0
  36. package/browser/src/types.ts +316 -0
  37. package/browser/src/uploads.ts +174 -0
  38. package/coding/README.md +337 -0
  39. package/coding/src/agent/acp-operations.ts +146 -0
  40. package/coding/src/agent/artifacts.ts +38 -0
  41. package/coding/src/agent/ask-user-decision.ts +623 -0
  42. package/coding/src/agent/atomic-write.ts +23 -0
  43. package/coding/src/agent/bounded-file.ts +21 -0
  44. package/coding/src/agent/checks.ts +301 -0
  45. package/coding/src/agent/coding-checkpoint.ts +828 -0
  46. package/coding/src/agent/delete.ts +237 -0
  47. package/coding/src/agent/diagnostics-tool.ts +163 -0
  48. package/coding/src/agent/diagnostics.ts +262 -0
  49. package/coding/src/agent/edit-diff.ts +382 -0
  50. package/coding/src/agent/edit.ts +322 -0
  51. package/coding/src/agent/effects.ts +102 -0
  52. package/coding/src/agent/env.ts +28 -0
  53. package/coding/src/agent/execution-policy.ts +89 -0
  54. package/coding/src/agent/file-mutation-queue.ts +72 -0
  55. package/coding/src/agent/forge/github.ts +603 -0
  56. package/coding/src/agent/forge/index.ts +16 -0
  57. package/coding/src/agent/forge/types.ts +185 -0
  58. package/coding/src/agent/git-aware-repository.ts +305 -0
  59. package/coding/src/agent/git-exec.ts +326 -0
  60. package/coding/src/agent/git-status.ts +177 -0
  61. package/coding/src/agent/git-tools.ts +360 -0
  62. package/coding/src/agent/git.ts +1074 -0
  63. package/coding/src/agent/glob-match.ts +146 -0
  64. package/coding/src/agent/glob.ts +182 -0
  65. package/coding/src/agent/goal-verify.ts +385 -0
  66. package/coding/src/agent/grep-worker.ts +74 -0
  67. package/coding/src/agent/grep.ts +459 -0
  68. package/coding/src/agent/identity.ts +48 -0
  69. package/coding/src/agent/index.ts +676 -0
  70. package/coding/src/agent/language/client.ts +429 -0
  71. package/coding/src/agent/language/framing.ts +190 -0
  72. package/coding/src/agent/language/index.ts +23 -0
  73. package/coding/src/agent/language/intelligence.ts +682 -0
  74. package/coding/src/agent/language/types.ts +187 -0
  75. package/coding/src/agent/lifecycle-events.ts +121 -0
  76. package/coding/src/agent/lifecycle.ts +166 -0
  77. package/coding/src/agent/limits.ts +214 -0
  78. package/coding/src/agent/move.ts +178 -0
  79. package/coding/src/agent/mutation-path.ts +52 -0
  80. package/coding/src/agent/output-accumulator.ts +304 -0
  81. package/coding/src/agent/path-utils.ts +120 -0
  82. package/coding/src/agent/process/index.ts +58 -0
  83. package/coding/src/agent/process/recovery.ts +508 -0
  84. package/coding/src/agent/process/sessions-host.ts +222 -0
  85. package/coding/src/agent/process/sessions-monitor.ts +141 -0
  86. package/coding/src/agent/process/sessions-recovery.ts +241 -0
  87. package/coding/src/agent/process/sessions-spawn.ts +613 -0
  88. package/coding/src/agent/process/sessions-teardown.ts +281 -0
  89. package/coding/src/agent/process/sessions.ts +30 -0
  90. package/coding/src/agent/process/types.ts +358 -0
  91. package/coding/src/agent/read-path-set.ts +126 -0
  92. package/coding/src/agent/read.ts +713 -0
  93. package/coding/src/agent/repository/glob.ts +147 -0
  94. package/coding/src/agent/repository/indexed-search.ts +480 -0
  95. package/coding/src/agent/repository/list.ts +131 -0
  96. package/coding/src/agent/repository/operations.ts +22 -0
  97. package/coding/src/agent/repository/path.ts +98 -0
  98. package/coding/src/agent/repository/search.ts +277 -0
  99. package/coding/src/agent/repository/types.ts +243 -0
  100. package/coding/src/agent/repository/walk.ts +126 -0
  101. package/coding/src/agent/repository.ts +12 -0
  102. package/coding/src/agent/shell-background.ts +264 -0
  103. package/coding/src/agent/shell-output.ts +75 -0
  104. package/coding/src/agent/shell.ts +526 -0
  105. package/coding/src/agent/todo.ts +399 -0
  106. package/coding/src/agent/truncate.ts +251 -0
  107. package/coding/src/agent/write.ts +170 -0
  108. package/coding/src/ask-user-host.ts +48 -0
  109. package/coding/src/config.ts +278 -0
  110. package/coding/src/hard-deny.ts +97 -0
  111. package/coding/src/index.ts +318 -0
  112. package/coding/src/principal-guard.ts +84 -0
  113. package/coding/src/sandbox.ts +92 -0
  114. package/coding/src/security/approval.ts +144 -0
  115. package/coding/src/security/command-rules.ts +57 -0
  116. package/coding/src/security/docker-cli.ts +222 -0
  117. package/coding/src/security/docker-sandbox.ts +1205 -0
  118. package/coding/src/security/e2b-sandbox.ts +853 -0
  119. package/coding/src/security/egress/dns-pin.ts +88 -0
  120. package/coding/src/security/egress/index.ts +32 -0
  121. package/coding/src/security/egress/limits.ts +57 -0
  122. package/coding/src/security/egress/policy.ts +137 -0
  123. package/coding/src/security/egress/proxy.ts +599 -0
  124. package/coding/src/security/egress/types.ts +30 -0
  125. package/coding/src/security/index.ts +199 -0
  126. package/coding/src/security/native-sandbox.ts +639 -0
  127. package/coding/src/security/path-containment.ts +55 -0
  128. package/coding/src/security/sandbox-coding-operations.ts +392 -0
  129. package/coding/src/security/sandbox-fs-operations.ts +644 -0
  130. package/coding/src/security/sandbox-limits.ts +147 -0
  131. package/coding/src/security/sandbox-tar.ts +308 -0
  132. package/coding/src/security/sandbox.ts +179 -0
  133. package/coding/src/security/semaphore.ts +55 -0
  134. package/coding/src/targets.ts +110 -0
  135. package/coding/src/workspace/diff.ts +78 -0
  136. package/coding/src/workspace/errors.ts +29 -0
  137. package/coding/src/workspace/index.ts +5 -0
  138. package/coding/src/workspace/merge.ts +151 -0
  139. package/coding/src/workspace/routing.ts +76 -0
  140. package/coding/src/workspace/service.ts +584 -0
  141. package/computer-use/README.md +105 -0
  142. package/computer-use/skills/computer-use-linux/SKILL.md +17 -0
  143. package/computer-use/src/classify.ts +53 -0
  144. package/computer-use/src/command.ts +29 -0
  145. package/computer-use/src/config.ts +69 -0
  146. package/computer-use/src/create.ts +170 -0
  147. package/computer-use/src/devices.ts +247 -0
  148. package/computer-use/src/env.ts +28 -0
  149. package/computer-use/src/index.ts +157 -0
  150. package/computer-use/src/skill.ts +21 -0
  151. package/openapi/README.md +97 -0
  152. package/openapi/src/compile.ts +386 -0
  153. package/openapi/src/config.ts +73 -0
  154. package/openapi/src/errors.ts +16 -0
  155. package/openapi/src/execute.ts +241 -0
  156. package/openapi/src/index.ts +124 -0
  157. package/openapi/src/limits.ts +63 -0
  158. package/openapi/src/specs.ts +86 -0
  159. package/openapi/src/tools.ts +60 -0
  160. package/openapi/src/types.ts +61 -0
  161. package/package.json +171 -4
  162. package/research/README.md +72 -0
  163. package/research/skills/research-report/SKILL.md +12 -0
  164. package/research/skills/research-scoping/SKILL.md +10 -0
  165. package/research/skills/research-synthesis/SKILL.md +10 -0
  166. package/research/skills/source-triage/SKILL.md +10 -0
  167. package/research/src/check.ts +71 -0
  168. package/research/src/config.ts +41 -0
  169. package/research/src/index.ts +147 -0
  170. package/research/src/ledger.ts +157 -0
  171. package/research/src/urls.ts +21 -0
  172. package/web/README.md +287 -0
  173. package/web/skills/web-research/SKILL.md +17 -0
  174. package/web/src/brave.ts +66 -0
  175. package/web/src/cache.ts +151 -0
  176. package/web/src/config.ts +210 -0
  177. package/web/src/controls.ts +128 -0
  178. package/web/src/domains.ts +114 -0
  179. package/web/src/exa.ts +60 -0
  180. package/web/src/firecrawl.ts +160 -0
  181. package/web/src/index.ts +387 -0
  182. package/web/src/kagi.ts +73 -0
  183. package/web/src/limits.ts +55 -0
  184. package/web/src/native/convert.ts +84 -0
  185. package/web/src/native/fetch.ts +226 -0
  186. package/web/src/normalize.ts +131 -0
  187. package/web/src/obscura/cdp.ts +201 -0
  188. package/web/src/obscura/classify.ts +35 -0
  189. package/web/src/obscura/cli.ts +254 -0
  190. package/web/src/obscura/errors.ts +8 -0
  191. package/web/src/obscura/index.ts +59 -0
  192. package/web/src/obscura/limits.ts +92 -0
  193. package/web/src/obscura/mcp.ts +104 -0
  194. package/web/src/obscura/playwright.ts +133 -0
  195. package/web/src/obscura/process.ts +235 -0
  196. package/web/src/obscura/search-profile.ts +73 -0
  197. package/web/src/obscura/types.ts +48 -0
  198. package/web/src/obscura/web.ts +419 -0
  199. package/web/src/prompt-fetch.ts +88 -0
  200. package/web/src/render.ts +75 -0
  201. package/web/src/searxng.ts +78 -0
  202. package/web/src/slice.ts +139 -0
  203. package/web/src/tavily.ts +77 -0
  204. package/web/src/tools.ts +182 -0
  205. package/web/src/transport.ts +310 -0
  206. package/web/src/types.ts +199 -0
  207. package/work/README.md +77 -0
  208. package/work/THIRD_PARTY_NOTICES +24 -0
  209. package/work/docling/ocr.py +150 -0
  210. package/work/sandbox/Dockerfile +36 -0
  211. package/work/sandbox/soffice.sh +12 -0
  212. package/work/src/command.ts +29 -0
  213. package/work/src/config.ts +138 -0
  214. package/work/src/connectors/cli.ts +343 -0
  215. package/work/src/connectors/drafts.ts +647 -0
  216. package/work/src/connectors/errors.ts +8 -0
  217. package/work/src/connectors/file-bytes.ts +149 -0
  218. package/work/src/connectors/google-workspace-http.ts +399 -0
  219. package/work/src/connectors/google-workspace.ts +465 -0
  220. package/work/src/connectors/gws-tools.ts +378 -0
  221. package/work/src/connectors/http.ts +123 -0
  222. package/work/src/connectors/idempotency.ts +235 -0
  223. package/work/src/connectors/identity.ts +34 -0
  224. package/work/src/connectors/index.ts +93 -0
  225. package/work/src/connectors/limits.ts +50 -0
  226. package/work/src/connectors/m365-tools.ts +308 -0
  227. package/work/src/connectors/microsoft365-http.ts +428 -0
  228. package/work/src/connectors/microsoft365.ts +402 -0
  229. package/work/src/connectors/normalize.ts +120 -0
  230. package/work/src/connectors/tool-helpers.ts +398 -0
  231. package/work/src/connectors/tools.ts +42 -0
  232. package/work/src/connectors/types.ts +399 -0
  233. package/work/src/diagrams/canonicalize.ts +166 -0
  234. package/work/src/diagrams/caps.ts +52 -0
  235. package/work/src/diagrams/embed.ts +340 -0
  236. package/work/src/diagrams/errors.ts +76 -0
  237. package/work/src/diagrams/index.ts +81 -0
  238. package/work/src/diagrams/messages.ts +150 -0
  239. package/work/src/diagrams/origin.ts +52 -0
  240. package/work/src/diagrams/telemetry.ts +34 -0
  241. package/work/src/diagrams/xml.ts +267 -0
  242. package/work/src/document-extraction/index.ts +563 -0
  243. package/work/src/document-reader/ambient.d.ts +2 -0
  244. package/work/src/document-reader/errors.ts +7 -0
  245. package/work/src/document-reader/index.ts +181 -0
  246. package/work/src/document-reader/mistral-ocr.ts +318 -0
  247. package/work/src/document-reader/parsers.ts +171 -0
  248. package/work/src/documents/caps.ts +135 -0
  249. package/work/src/documents/diff.ts +269 -0
  250. package/work/src/documents/errors.ts +44 -0
  251. package/work/src/documents/fidelity.ts +98 -0
  252. package/work/src/documents/generate.ts +96 -0
  253. package/work/src/documents/hash.ts +8 -0
  254. package/work/src/documents/index.ts +14 -0
  255. package/work/src/documents/model-schema.ts +639 -0
  256. package/work/src/documents/parse.ts +252 -0
  257. package/work/src/documents/patch-history.ts +81 -0
  258. package/work/src/documents/patch.ts +476 -0
  259. package/work/src/documents/preview-html.ts +245 -0
  260. package/work/src/documents/preview.ts +227 -0
  261. package/work/src/documents/telemetry.ts +36 -0
  262. package/work/src/documents/translate/docx.ts +292 -0
  263. package/work/src/documents/translate/pptx.ts +304 -0
  264. package/work/src/documents/translate/xlsx.ts +137 -0
  265. package/work/src/documents/types.ts +188 -0
  266. package/work/src/index.ts +311 -0
  267. package/work/src/runtime/worker-pool-entry.ts +102 -0
  268. package/work/src/runtime/worker-pool.ts +267 -0
  269. package/work/src/sandbox/composition.ts +212 -0
  270. package/work/src/sandbox/image.ts +6 -0
  271. package/work/src/sandbox/index.ts +14 -0
  272. package/work/src/sheets/caps.ts +68 -0
  273. package/work/src/sheets/csv.ts +351 -0
  274. package/work/src/sheets/decimal.ts +388 -0
  275. package/work/src/sheets/errors.ts +52 -0
  276. package/work/src/sheets/index.ts +62 -0
  277. package/work/src/sheets/inference.ts +378 -0
  278. package/work/src/sheets/telemetry.ts +34 -0
  279. package/work/src/sheets/types.ts +162 -0
  280. package/work/src/sheets/xlsx.ts +388 -0
  281. package/work/src/skills/index.ts +8 -0
  282. package/work/src/skills/load.ts +43 -0
  283. package/work/src/tools/filesystem.ts +21 -0
  284. package/work/src/tools/index.ts +1 -0
  285. package/work/src/tools/local-filesystem.ts +33 -0
  286. package/work/src/tools/office.ts +311 -0
  287. package/work/vendor/hermes-agent/LICENSE +21 -0
  288. package/work/vendor/hermes-agent/skills/productivity/docx/LICENSE +21 -0
  289. package/work/vendor/hermes-agent/skills/productivity/docx/SKILL.md +196 -0
  290. package/work/vendor/hermes-agent/skills/productivity/docx/scripts/docx_comments.py +289 -0
  291. package/work/vendor/hermes-agent/skills/productivity/docx/scripts/docx_common.py +94 -0
  292. package/work/vendor/hermes-agent/skills/productivity/docx/scripts/docx_create.py +177 -0
  293. package/work/vendor/hermes-agent/skills/productivity/docx/scripts/docx_edit.py +250 -0
  294. package/work/vendor/hermes-agent/skills/productivity/docx/scripts/docx_read.py +149 -0
  295. package/work/vendor/hermes-agent/skills/productivity/docx/scripts/docx_revisions.py +147 -0
  296. package/work/vendor/hermes-agent/skills/productivity/docx/scripts/docx_template.py +70 -0
  297. package/work/vendor/hermes-agent/skills/productivity/docx/scripts/docx_validate.py +156 -0
  298. package/work/vendor/hermes-agent/skills/productivity/pdf/LICENSE +21 -0
  299. package/work/vendor/hermes-agent/skills/productivity/pdf/SKILL.md +125 -0
  300. package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/_raster.py +76 -0
  301. package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/extract_marker.py +88 -0
  302. package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/extract_pymupdf.py +101 -0
  303. package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_create.py +130 -0
  304. package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_fill_form.py +97 -0
  305. package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_form_layout.py +168 -0
  306. package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_make_form.py +145 -0
  307. package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_merge.py +50 -0
  308. package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_meta.py +115 -0
  309. package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_page_image.py +99 -0
  310. package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_read.py +153 -0
  311. package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_secure.py +71 -0
  312. package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_split.py +84 -0
  313. package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_stamp.py +143 -0
  314. package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_watermark.py +51 -0
  315. package/work/vendor/hermes-agent/skills/productivity/powerpoint/LICENSE +21 -0
  316. package/work/vendor/hermes-agent/skills/productivity/powerpoint/SKILL.md +220 -0
  317. package/work/vendor/hermes-agent/skills/productivity/powerpoint/scripts/pptx_create.py +214 -0
  318. package/work/vendor/hermes-agent/skills/productivity/powerpoint/scripts/pptx_edit.py +436 -0
  319. package/work/vendor/hermes-agent/skills/productivity/powerpoint/scripts/pptx_from_template.py +88 -0
  320. package/work/vendor/hermes-agent/skills/productivity/powerpoint/scripts/pptx_read.py +131 -0
  321. package/work/vendor/hermes-agent/skills/productivity/powerpoint/scripts/pptx_render.py +93 -0
  322. package/work/vendor/hermes-agent/skills/productivity/xlsx/LICENSE +21 -0
  323. package/work/vendor/hermes-agent/skills/productivity/xlsx/SKILL.md +196 -0
  324. package/work/vendor/hermes-agent/skills/productivity/xlsx/scripts/csv_to_xlsx.py +104 -0
  325. package/work/vendor/hermes-agent/skills/productivity/xlsx/scripts/xlsx_create.py +259 -0
  326. package/work/vendor/hermes-agent/skills/productivity/xlsx/scripts/xlsx_edit.py +263 -0
  327. package/work/vendor/hermes-agent/skills/productivity/xlsx/scripts/xlsx_read.py +160 -0
  328. package/work/vendor/hermes-agent/skills/productivity/xlsx/scripts/xlsx_recalc.py +111 -0
  329. package/work/vendor/hermes-agent/skills/productivity/xlsx/scripts/xlsx_restructure.py +337 -0
  330. package/work/vendor/hermes-agent/skills/productivity/xlsx/scripts/xlsx_to_csv.py +69 -0
  331. package/work/vendor-lock.json +11 -0
@@ -0,0 +1,254 @@
1
+ /**
2
+ * Bounded, shell-free Obscura CLI runner for one-shot `fetch`/`scrape` operations.
3
+ * Child processes are killed on timeout/abort, output is capped and collected
4
+ * linearly, and diagnostics never echo the configured argv.
5
+ */
6
+ import { type ChildProcess, spawn } from "node:child_process";
7
+ import { isIP } from "node:net";
8
+ import { assertSsrfAllowedUrl, type MediaHostAddress, type MediaHostnameResolver } from "@arnilo/prism";
9
+ import { defaultResolver, normalizeHostname } from "@arnilo/prism/net";
10
+ import { ObscuraError } from "./errors.js";
11
+ import type { ObscuraProcessLimits } from "./limits.js";
12
+ import { resolveObscuraProcessLimits } from "./limits.js";
13
+ import { validateObscuraCommand } from "./process.js";
14
+
15
+ export interface ObscuraCliRunResult {
16
+ readonly stdout: string;
17
+ readonly stderr: string;
18
+ readonly truncated: boolean;
19
+ readonly exitCode: number | null;
20
+ }
21
+
22
+ export interface ObscuraCliRunOptions {
23
+ readonly command: string;
24
+ /** Subcommand and its arguments, e.g. `["fetch", "https://example.com", "--dump", "markdown"]`. */
25
+ readonly args?: readonly string[];
26
+ /**
27
+ * Fixed argv placed before the subcommand — e.g. a script path for wrapped
28
+ * executables or `["run", "--rm", "-i", "image"]` for Docker. Never host-controlled.
29
+ */
30
+ readonly argsBefore?: readonly string[];
31
+ readonly env?: Readonly<Record<string, string>>;
32
+ readonly cwd?: string;
33
+ readonly limits?: Partial<ObscuraProcessLimits>;
34
+ readonly signal?: AbortSignal;
35
+ /** Wall-clock kill deadline for the child; bounded by the resolved web timeout. */
36
+ readonly timeoutMs?: number;
37
+ /** Cap on retained stdout (2 MiB default, 8 MiB hard ceiling enforced by callers). */
38
+ readonly maxOutputBytes?: number;
39
+ }
40
+
41
+ function collect(child: ChildProcess, stream: "stdout" | "stderr", maxBytes: number): { text: () => string; truncated: () => boolean } {
42
+ let size = 0;
43
+ let truncated = false;
44
+ const chunks: Buffer[] = [];
45
+ child[stream]!.on("data", (chunk: Buffer) => {
46
+ if (size >= maxBytes) {
47
+ truncated = true;
48
+ return;
49
+ }
50
+ const take = chunk.subarray(0, maxBytes - size);
51
+ if (take.byteLength < chunk.byteLength) truncated = true;
52
+ size += take.byteLength;
53
+ chunks.push(take);
54
+ });
55
+ return { text: () => Buffer.concat(chunks, size).toString("utf8"), truncated: () => truncated };
56
+ }
57
+
58
+ function kill(child: ChildProcess): void {
59
+ try {
60
+ child.kill("SIGKILL");
61
+ } catch {
62
+ // already gone
63
+ }
64
+ }
65
+
66
+ /** Run one bounded Obscura CLI operation; rejects with redacted diagnostics on any failure. */
67
+ export async function runObscuraCli(options: ObscuraCliRunOptions): Promise<ObscuraCliRunResult> {
68
+ const limits = resolveObscuraProcessLimits(options.limits);
69
+ const args = [...(options.argsBefore ?? []), ...(options.args ?? [])];
70
+ validateObscuraCommand({ command: options.command, args }, limits);
71
+ if (options.signal?.aborted) throw new ObscuraError("ERR_OBSCURA_ABORTED", "obscura cli aborted before start");
72
+
73
+ const child = spawn(options.command, args, {
74
+ env: { PATH: process.env.PATH ?? "", ...(options.env ?? {}) },
75
+ ...(options.cwd === undefined ? {} : { cwd: options.cwd }),
76
+ stdio: ["ignore", "pipe", "pipe"],
77
+ windowsHide: true,
78
+ });
79
+
80
+ const maxOutput = options.maxOutputBytes ?? 2 * 1024 * 1024;
81
+ if (!Number.isFinite(maxOutput) || maxOutput <= 0 || maxOutput > 8 * 1024 * 1024) {
82
+ throw new ObscuraError("ERR_OBSCURA_LIMIT", "maxOutputBytes out of range");
83
+ }
84
+ const stdout = collect(child, "stdout", maxOutput);
85
+ const stderr = collect(child, "stderr", 64 * 1024);
86
+
87
+ return await new Promise<ObscuraCliRunResult>((resolve, reject) => {
88
+ let settled = false;
89
+ let timer: NodeJS.Timeout | undefined;
90
+ const onAbort = () => {
91
+ settled = true;
92
+ kill(child);
93
+ reject(new ObscuraError("ERR_OBSCURA_ABORTED", "obscura cli aborted"));
94
+ };
95
+ const deadline = options.timeoutMs ?? 30_000;
96
+ timer = setTimeout(() => {
97
+ settled = true;
98
+ kill(child);
99
+ reject(new ObscuraError("ERR_OBSCURA_TIMEOUT", `obscura cli timed out after ${deadline}ms`));
100
+ }, deadline);
101
+ timer.unref?.();
102
+ options.signal?.addEventListener("abort", onAbort, { once: true });
103
+
104
+ child.once("error", (error) => {
105
+ if (settled) return;
106
+ settled = true;
107
+ clearTimeout(timer);
108
+ reject(new ObscuraError("ERR_OBSCURA_SPAWN", `obscura cli spawn failed: ${error.message}`));
109
+ });
110
+ child.once("exit", (code) => {
111
+ if (settled) return;
112
+ settled = true;
113
+ clearTimeout(timer);
114
+ options.signal?.removeEventListener("abort", onAbort);
115
+ const stderrText = stderr.text();
116
+ if (code !== 0) {
117
+ reject(
118
+ new ObscuraError("ERR_OBSCURA_CLI", `obscura cli exited with code ${code}${stderrText ? `: ${stderrText.slice(0, 512)}` : ""}`),
119
+ );
120
+ return;
121
+ }
122
+ resolve({ stdout: stdout.text(), stderr: stderrText, truncated: stdout.truncated() || stderr.truncated(), exitCode: code });
123
+ });
124
+ });
125
+ }
126
+
127
+ /** First Obscura release whose HTTP client re-validates every redirect hop and resolves through `SsrfGuardResolver`. */
128
+ export const OBSCURA_GUARDED_VERSION = "0.1.8";
129
+
130
+ /**
131
+ * Leading semver of an `obscura --version` line, or `undefined` when it is missing or a source build
132
+ * (`0.1.0-dev+<sha>`), which cannot be assumed to carry the per-hop guard.
133
+ */
134
+ export function parseObscuraVersion(output: string): string | undefined {
135
+ const line = output
136
+ .split(/\r?\n/u)
137
+ .map((part) => part.trim())
138
+ .find((part) => /\b\d+\.\d+\.\d+\b/u.test(part));
139
+ if (line === undefined || /-dev(?![\w])/iu.test(line)) return undefined;
140
+ const match = line.match(/\b(\d+)\.(\d+)\.(\d+)\b/u);
141
+ return match === null ? undefined : `${match[1]}.${match[2]}.${match[3]}`;
142
+ }
143
+
144
+ /** True when `version` is at least {@link OBSCURA_GUARDED_VERSION}. */
145
+ export function obscuraVersionIsGuarded(version: string | undefined): boolean {
146
+ if (version === undefined) return false;
147
+ const [major = 0, minor = 0, patch = 0] = version.split(".").map(Number);
148
+ return major > 0 || minor > 1 || (minor === 1 && patch >= 8);
149
+ }
150
+
151
+ export interface ObscuraVersionProbeOptions {
152
+ readonly command: string;
153
+ readonly argsBefore?: readonly string[];
154
+ readonly env?: Readonly<Record<string, string>>;
155
+ readonly cwd?: string;
156
+ readonly signal?: AbortSignal;
157
+ readonly timeoutMs?: number;
158
+ }
159
+
160
+ export interface ObscuraVersionProbe {
161
+ readonly version?: string;
162
+ /** False when the probe failed, the output was unparseable, or the version predates the guard. */
163
+ readonly guarded: boolean;
164
+ }
165
+
166
+ /** One bounded `obscura --version` run per package setup; any failure is a "not guarded" result. */
167
+ export async function probeObscuraVersion(options: ObscuraVersionProbeOptions): Promise<ObscuraVersionProbe> {
168
+ try {
169
+ const run = await runObscuraCli({
170
+ command: options.command,
171
+ ...(options.argsBefore === undefined ? {} : { argsBefore: options.argsBefore }),
172
+ ...(options.env === undefined ? {} : { env: options.env }),
173
+ ...(options.cwd === undefined ? {} : { cwd: options.cwd }),
174
+ ...(options.signal === undefined ? {} : { signal: options.signal }),
175
+ args: ["--version"],
176
+ timeoutMs: options.timeoutMs ?? 5_000,
177
+ maxOutputBytes: 64 * 1024,
178
+ });
179
+ const version = parseObscuraVersion(run.stdout.trim() === "" ? run.stderr : run.stdout);
180
+ return { ...(version === undefined ? {} : { version }), guarded: obscuraVersionIsGuarded(version) };
181
+ } catch {
182
+ return { guarded: false };
183
+ }
184
+ }
185
+
186
+ export interface ValidateObscuraUrlOptions {
187
+ readonly allowedHostnames?: readonly string[];
188
+ readonly resolver?: MediaHostnameResolver;
189
+ readonly signal?: AbortSignal;
190
+ }
191
+
192
+ function isStringArray(value: unknown): value is readonly string[] {
193
+ return Array.isArray(value);
194
+ }
195
+
196
+ /** Public HTTP(S) URL validation and DNS pre-resolution for anything handed to the Obscura CLI. */
197
+ export async function validateObscuraWebUrl(input: string, options?: readonly string[] | ValidateObscuraUrlOptions): Promise<string> {
198
+ const opts: ValidateObscuraUrlOptions = options === undefined || isStringArray(options) ? { allowedHostnames: options } : options;
199
+ const allowedHostnames = opts.allowedHostnames;
200
+ const resolver = opts.resolver ?? defaultResolver;
201
+ const signal = opts.signal;
202
+
203
+ let parsed: URL;
204
+ try {
205
+ parsed = new URL(input);
206
+ } catch {
207
+ throw new ObscuraError("ERR_OBSCURA_SSRF", "URL is not a public HTTP(S) target: private, credentialed, or non-HTTP URLs are denied");
208
+ }
209
+
210
+ try {
211
+ assertSsrfAllowedUrl(input, allowedHostnames === undefined ? {} : { allowedHostnames });
212
+ } catch {
213
+ throw new ObscuraError("ERR_OBSCURA_SSRF", "URL is not a public HTTP(S) target: private, credentialed, or non-HTTP URLs are denied");
214
+ }
215
+
216
+ const hostname = normalizeHostname(parsed.hostname);
217
+ const family = isIP(hostname);
218
+ if (family !== 0) {
219
+ // Literal IP address was already validated by assertSsrfAllowedUrl.
220
+ return input;
221
+ }
222
+
223
+ if (signal?.aborted) throw new ObscuraError("ERR_OBSCURA_ABORTED", "obscura dns resolution aborted");
224
+
225
+ let addresses: readonly MediaHostAddress[];
226
+ try {
227
+ addresses = await resolver(hostname, signal ?? new AbortController().signal);
228
+ } catch (error) {
229
+ if (signal?.aborted) throw new ObscuraError("ERR_OBSCURA_ABORTED", "obscura dns resolution aborted");
230
+ throw new ObscuraError("ERR_OBSCURA_SSRF", `Failed to resolve hostname for Obscura target: ${hostname}`, { cause: error });
231
+ }
232
+
233
+ if (!addresses || addresses.length === 0) {
234
+ throw new ObscuraError("ERR_OBSCURA_SSRF", `Obscura target ${hostname} returned no addresses`);
235
+ }
236
+
237
+ for (const candidate of addresses) {
238
+ const candidateNormalized = normalizeHostname(candidate.address);
239
+ if (isIP(candidateNormalized) !== candidate.family) {
240
+ throw new ObscuraError("ERR_OBSCURA_SSRF", "obscura hostname resolver returned an invalid address");
241
+ }
242
+ const literal = candidate.family === 6 ? `[${candidateNormalized}]` : candidateNormalized;
243
+ try {
244
+ assertSsrfAllowedUrl(`${parsed.protocol}//${literal}`);
245
+ } catch {
246
+ throw new ObscuraError(
247
+ "ERR_OBSCURA_SSRF",
248
+ `Obscura target ${hostname} resolved to a private or denied address (${candidateNormalized})`,
249
+ );
250
+ }
251
+ }
252
+
253
+ return input;
254
+ }
@@ -0,0 +1,8 @@
1
+ export class ObscuraError extends Error {
2
+ readonly code: string;
3
+ constructor(code: string, message: string, options?: ErrorOptions) {
4
+ super(message, options);
5
+ this.name = "ObscuraError";
6
+ this.code = code;
7
+ }
8
+ }
@@ -0,0 +1,59 @@
1
+ export type { ObscuraCdpSession, ObscuraChromium, ObscuraPlaywright } from "./cdp.js";
2
+ export { connectObscuraCdp, endpointFromServeArgs, validateObscuraEndpoint } from "./cdp.js";
3
+ export { isObscuraReadTool } from "./classify.js";
4
+ export type {
5
+ ObscuraCliRunOptions,
6
+ ObscuraCliRunResult,
7
+ ObscuraVersionProbe,
8
+ ObscuraVersionProbeOptions,
9
+ ValidateObscuraUrlOptions,
10
+ } from "./cli.js";
11
+ export {
12
+ OBSCURA_GUARDED_VERSION,
13
+ obscuraVersionIsGuarded,
14
+ parseObscuraVersion,
15
+ probeObscuraVersion,
16
+ runObscuraCli,
17
+ validateObscuraWebUrl,
18
+ } from "./cli.js";
19
+ export { ObscuraError } from "./errors.js";
20
+ export {
21
+ DEFAULT_OBSCURA_PROCESS_LIMITS,
22
+ DEFAULT_OBSCURA_WEB_LIMITS,
23
+ HARD_OBSCURA_PROCESS_LIMITS,
24
+ HARD_OBSCURA_WEB_LIMITS,
25
+ type ObscuraProcessLimits,
26
+ type ObscuraWebLimits,
27
+ resolveObscuraProcessLimits,
28
+ resolveObscuraWebLimits,
29
+ } from "./limits.js";
30
+ export {
31
+ createObscuraMcpTools,
32
+ DEFAULT_OBSCURA_NAME_PREFIX,
33
+ DEFAULT_OBSCURA_SERVER_ID,
34
+ ObscuraMcpError,
35
+ type ObscuraMcpTools,
36
+ type ObscuraMcpToolsOptions,
37
+ } from "./mcp.js";
38
+ export type {
39
+ PlaywrightBrowser,
40
+ PlaywrightBrowserContext,
41
+ PlaywrightCdpSession,
42
+ PlaywrightDialog,
43
+ PlaywrightDownload,
44
+ PlaywrightLocator,
45
+ PlaywrightPage,
46
+ PlaywrightRequest,
47
+ PlaywrightRoute,
48
+ } from "./playwright.js";
49
+ export { resolveObscuraCommand, spawnObscuraProcess, validateObscuraCommand } from "./process.js";
50
+ export { DEFAULT_OBSCURA_SEARCH_PROFILE, type ObscuraSearchProfile, resolveObscuraSearchProfile } from "./search-profile.js";
51
+ export type {
52
+ ObscuraCloseOptions,
53
+ ObscuraExit,
54
+ ObscuraProcessOptions,
55
+ OwnedObscuraProcess,
56
+ } from "./types.js";
57
+ export { createObscuraWebTools, type ObscuraWebTools, type ObscuraWebToolsOptions } from "./web.js";
58
+
59
+ export const packageName = "@arnilo/prism-tools/web";
@@ -0,0 +1,92 @@
1
+ import { ObscuraError } from "./errors.js";
2
+
3
+ export interface ObscuraProcessLimits {
4
+ /** Bounded wait for a readiness probe before the owned process is killed. */
5
+ readonly startupTimeoutMs: number;
6
+ /** Grace period for SIGTERM before SIGKILL. */
7
+ readonly shutdownTimeoutMs: number;
8
+ /** Cap on retained stderr used for post-mortem diagnostics. */
9
+ readonly maxStderrBytes: number;
10
+ readonly maxArgvEntries: number;
11
+ readonly maxArgvBytes: number;
12
+ readonly maxEnvEntries: number;
13
+ readonly maxEnvValueBytes: number;
14
+ }
15
+
16
+ export const DEFAULT_OBSCURA_PROCESS_LIMITS: ObscuraProcessLimits = {
17
+ startupTimeoutMs: 10_000,
18
+ shutdownTimeoutMs: 5_000,
19
+ maxStderrBytes: 64 * 1024,
20
+ maxArgvEntries: 256,
21
+ maxArgvBytes: 64 * 1024,
22
+ maxEnvEntries: 64,
23
+ maxEnvValueBytes: 16 * 1024,
24
+ };
25
+
26
+ export const HARD_OBSCURA_PROCESS_LIMITS: ObscuraProcessLimits = {
27
+ startupTimeoutMs: 120_000,
28
+ shutdownTimeoutMs: 30_000,
29
+ maxStderrBytes: 1024 * 1024,
30
+ maxArgvEntries: 1_000,
31
+ maxArgvBytes: 1024 * 1024,
32
+ maxEnvEntries: 256,
33
+ maxEnvValueBytes: 64 * 1024,
34
+ };
35
+
36
+ export function resolveObscuraProcessLimits(input: Partial<ObscuraProcessLimits> = {}): ObscuraProcessLimits {
37
+ const out = {} as Record<keyof ObscuraProcessLimits, number>;
38
+ for (const key of Object.keys(DEFAULT_OBSCURA_PROCESS_LIMITS) as (keyof ObscuraProcessLimits)[]) {
39
+ const value = input[key] ?? DEFAULT_OBSCURA_PROCESS_LIMITS[key];
40
+ if (!Number.isFinite(value) || value < 0 || value > HARD_OBSCURA_PROCESS_LIMITS[key]) {
41
+ throw new ObscuraError("ERR_OBSCURA_LIMIT", `Obscura limit ${key} out of range`);
42
+ }
43
+ out[key] = value;
44
+ }
45
+ return out;
46
+ }
47
+
48
+ /** Bounds for the CLI-backed web tools (search/fetch/scrape child processes). */
49
+ export interface ObscuraWebLimits {
50
+ readonly maxQueryBytes: number;
51
+ readonly maxResults: number;
52
+ readonly maxUrls: number;
53
+ readonly maxConcurrency: number;
54
+ readonly maxOutputBytes: number;
55
+ readonly maxStderrBytes: number;
56
+ readonly timeoutMs: number;
57
+ readonly maxEvalBytes: number;
58
+ }
59
+
60
+ export const DEFAULT_OBSCURA_WEB_LIMITS: ObscuraWebLimits = {
61
+ maxQueryBytes: 4096,
62
+ maxResults: 10,
63
+ maxUrls: 25,
64
+ maxConcurrency: 5,
65
+ maxOutputBytes: 2 * 1024 * 1024,
66
+ maxStderrBytes: 64 * 1024,
67
+ timeoutMs: 30_000,
68
+ maxEvalBytes: 4096,
69
+ };
70
+
71
+ export const HARD_OBSCURA_WEB_LIMITS: ObscuraWebLimits = {
72
+ maxQueryBytes: 16 * 1024,
73
+ maxResults: 100,
74
+ maxUrls: 200,
75
+ maxConcurrency: 32,
76
+ maxOutputBytes: 8 * 1024 * 1024,
77
+ maxStderrBytes: 256 * 1024,
78
+ timeoutMs: 120_000,
79
+ maxEvalBytes: 16 * 1024,
80
+ };
81
+
82
+ export function resolveObscuraWebLimits(input: Partial<ObscuraWebLimits> = {}): ObscuraWebLimits {
83
+ const out = {} as Record<keyof ObscuraWebLimits, number>;
84
+ for (const key of Object.keys(DEFAULT_OBSCURA_WEB_LIMITS) as (keyof ObscuraWebLimits)[]) {
85
+ const value = input[key] ?? DEFAULT_OBSCURA_WEB_LIMITS[key];
86
+ if (!Number.isFinite(value) || value <= 0 || value > HARD_OBSCURA_WEB_LIMITS[key]) {
87
+ throw new ObscuraError("ERR_OBSCURA_LIMIT", `Obscura web limit ${key} out of range`);
88
+ }
89
+ out[key] = value;
90
+ }
91
+ return out;
92
+ }
@@ -0,0 +1,104 @@
1
+ import type { ToolDefinition, ToolResult } from "@arnilo/prism";
2
+ import type { ConnectMcpToolsOptions, McpToolBridge, McpTransportConfig } from "@arnilo/prism-extensions/mcp";
3
+ import { isObscuraReadTool } from "./classify.js";
4
+ import { resolveObscuraProcessLimits } from "./limits.js";
5
+ import { validateObscuraCommand } from "./process.js";
6
+
7
+ export const DEFAULT_OBSCURA_SERVER_ID = "obscura";
8
+ export const DEFAULT_OBSCURA_NAME_PREFIX = "obscura_";
9
+
10
+ export interface ObscuraMcpToolsOptions {
11
+ /** stdio (`obscura mcp` or a Docker argv) or Streamable HTTP transport config. */
12
+ readonly transport: McpTransportConfig;
13
+ readonly serverId?: string;
14
+ /** Default `obscura_` so Obscura tools coexist with `@arnilo/prism-tools/browser`; `""` keeps native Obscura names. */
15
+ readonly namePrefix?: string;
16
+ /**
17
+ * Streamable HTTP endpoints outside loopback require this explicit opt-in; the
18
+ * endpoint still needs a secure transport/auth per `@arnilo/prism-extensions/mcp` policy.
19
+ */
20
+ readonly allowRemoteHttp?: boolean;
21
+ readonly signal?: AbortSignal;
22
+ /** Test seam: replace the MCP bridge connection. Defaults to a dynamic `@arnilo/prism-extensions/mcp` import. */
23
+ readonly connect?: (options: ConnectMcpToolsOptions) => Promise<McpToolBridge>;
24
+ }
25
+
26
+ export interface ObscuraMcpTools {
27
+ readonly tools: readonly ToolDefinition[];
28
+ /** Re-list upstream tools (e.g. after an Obscura upgrade changes the tool set). */
29
+ refresh(): Promise<void>;
30
+ close(): Promise<void>;
31
+ }
32
+
33
+ export class ObscuraMcpError extends Error {
34
+ constructor(message: string) {
35
+ super(message);
36
+ this.name = "ObscuraMcpError";
37
+ }
38
+ }
39
+
40
+ function resolveTransport(options: ObscuraMcpToolsOptions): McpTransportConfig {
41
+ const transport = options.transport;
42
+ if (transport.type === "stdio") {
43
+ // Fail closed on the same command policy as owned processes (absolute, bounded, no insecure flags).
44
+ validateObscuraCommand(
45
+ { command: transport.command, args: transport.args, env: transport.env, cwd: transport.cwd },
46
+ resolveObscuraProcessLimits(),
47
+ );
48
+ return transport;
49
+ }
50
+ if (transport.type === "raw") {
51
+ return transport;
52
+ }
53
+ const url = new URL(transport.url);
54
+ const loopback = ["127.0.0.1", "::1", "[::1]", "localhost"].includes(url.hostname.toLowerCase());
55
+ if (!loopback && !options.allowRemoteHttp) {
56
+ throw new ObscuraMcpError(`non-loopback MCP HTTP endpoint ${url.hostname} requires explicit allowRemoteHttp`);
57
+ }
58
+ return transport;
59
+ }
60
+
61
+ /**
62
+ * Bridge the complete Obscura MCP surface into Prism tools. Every advertised tool is
63
+ * exposed (no static allow-list): reads are effect-free, known mutations and unknown
64
+ * future tools are exclusive serialized external mutations.
65
+ */
66
+ export async function createObscuraMcpTools(options: ObscuraMcpToolsOptions): Promise<ObscuraMcpTools> {
67
+ // Dynamic import: the MCP bridge is only loaded when this surface is actually used, so importing
68
+ // `@arnilo/prism-tools/web` never pulls `@arnilo/prism-extensions/mcp`.
69
+ const connect = options.connect ?? (await import("@arnilo/prism-extensions/mcp")).connectMcpTools;
70
+ const bridge = await connect({
71
+ serverId: options.serverId ?? DEFAULT_OBSCURA_SERVER_ID,
72
+ transport: resolveTransport(options),
73
+ namePrefix: options.namePrefix ?? DEFAULT_OBSCURA_NAME_PREFIX,
74
+ effect: ({ remoteName }) => (isObscuraReadTool(remoteName) ? { kind: "none", idempotency: "none" } : undefined),
75
+ ...(options.signal === undefined ? {} : { signal: options.signal }),
76
+ });
77
+ return wrapObscuraBridge(bridge);
78
+ }
79
+
80
+ function wrapObscuraBridge(bridge: McpToolBridge): ObscuraMcpTools {
81
+ // Obscura keeps one live page: mutating tools dispatch strictly sequentially.
82
+ let mutationTail: Promise<unknown> = Promise.resolve();
83
+ const tools = () =>
84
+ bridge.tools.map((tool) => {
85
+ if (typeof tool.effect !== "function" && tool.effect?.kind === "none") return tool;
86
+ const execute = tool.execute.bind(tool);
87
+ return {
88
+ ...tool,
89
+ exclusive: true,
90
+ execute: (args: Parameters<typeof execute>[0], context: Parameters<typeof execute>[1]): Promise<ToolResult> => {
91
+ const run = mutationTail.then(() => execute(args, context));
92
+ mutationTail = run.catch(() => undefined);
93
+ return run;
94
+ },
95
+ } satisfies ToolDefinition;
96
+ });
97
+ return {
98
+ get tools() {
99
+ return tools();
100
+ },
101
+ refresh: () => bridge.refresh(),
102
+ close: () => bridge.close(),
103
+ };
104
+ }
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Structural Playwright surface the Obscura CDP composition consumes.
3
+ *
4
+ * Mirrors the subset of `packages/tools/browser/src/types.ts` that `connectObscuraCdp` needs,
5
+ * so this package carries no runtime or type dependency on the browser package. The two copies
6
+ * are structurally identical; a later phase that consolidates browser automation can share one.
7
+ */
8
+ export interface PlaywrightLocator {
9
+ click(options?: { timeout?: number }): Promise<void>;
10
+ fill(value: string, options?: { timeout?: number }): Promise<void>;
11
+ type?(text: string, options?: { timeout?: number; delay?: number }): Promise<void>;
12
+ pressSequentially?(text: string, options?: { timeout?: number; delay?: number }): Promise<void>;
13
+ selectOption(
14
+ values: string | readonly string[] | { label?: string; value?: string } | ReadonlyArray<{ label?: string; value?: string }>,
15
+ options?: { timeout?: number },
16
+ ): Promise<string[]>;
17
+ check(options?: { timeout?: number }): Promise<void>;
18
+ uncheck(options?: { timeout?: number }): Promise<void>;
19
+ scrollIntoViewIfNeeded?(options?: { timeout?: number }): Promise<void>;
20
+ setInputFiles?(
21
+ files: string | readonly string[] | { name: string; mimeType: string; buffer: Buffer },
22
+ options?: { timeout?: number },
23
+ ): Promise<void>;
24
+ count(): Promise<number>;
25
+ first(): PlaywrightLocator;
26
+ nth(index: number): PlaywrightLocator;
27
+ }
28
+
29
+ export interface PlaywrightDialog {
30
+ type(): string;
31
+ message(): string;
32
+ accept(promptText?: string): Promise<void>;
33
+ dismiss(): Promise<void>;
34
+ }
35
+
36
+ export interface PlaywrightRequest {
37
+ url(): string;
38
+ resourceType?(): string;
39
+ redirectedFrom?(): PlaywrightRequest | null;
40
+ method?(): string;
41
+ }
42
+
43
+ export interface PlaywrightRoute {
44
+ request(): PlaywrightRequest;
45
+ continue(options?: { url?: string; headers?: Record<string, string> }): Promise<void>;
46
+ abort(errorCode?: string): Promise<void>;
47
+ fulfill?(options?: { status?: number; body?: string | Buffer; contentType?: string }): Promise<void>;
48
+ }
49
+
50
+ export interface PlaywrightDownload {
51
+ url(): string;
52
+ suggestedFilename(): string;
53
+ createReadStream?(): Promise<NodeJS.ReadableStream | null>;
54
+ saveAs?(path: string): Promise<void>;
55
+ cancel?(): Promise<void>;
56
+ failure?(): Promise<string | null>;
57
+ }
58
+
59
+ export interface PlaywrightPage {
60
+ readonly url: () => string;
61
+ title(): Promise<string>;
62
+ goto(url: string, options?: { timeout?: number; waitUntil?: "load" | "domcontentloaded" | "networkidle" | "commit" }): Promise<unknown>;
63
+ ariaSnapshot(options?: { mode?: "ai" | "default"; depth?: number; boxes?: boolean; timeout?: number }): Promise<string>;
64
+ screenshot?(options?: {
65
+ type?: "png" | "jpeg";
66
+ fullPage?: boolean;
67
+ clip?: { x: number; y: number; width: number; height: number };
68
+ timeout?: number;
69
+ }): Promise<Buffer>;
70
+ locator(selector: string): PlaywrightLocator;
71
+ getByRole(role: string, options?: { name?: string | RegExp; exact?: boolean }): PlaywrightLocator;
72
+ getByLabel(text: string | RegExp, options?: { exact?: boolean }): PlaywrightLocator;
73
+ getByTestId(testId: string | RegExp): PlaywrightLocator;
74
+ getByText(text: string | RegExp, options?: { exact?: boolean }): PlaywrightLocator;
75
+ waitForTimeout?(timeout: number): Promise<void>;
76
+ waitForURL?(url: string | RegExp, options?: { timeout?: number }): Promise<void>;
77
+ waitForSelector?(selector: string, options?: { timeout?: number }): Promise<unknown>;
78
+ close(): Promise<void>;
79
+ isClosed(): boolean;
80
+ on(event: "dialog", handler: (dialog: PlaywrightDialog) => void): void;
81
+ on(event: "popup" | "close" | "crash" | "download", handler: (page?: PlaywrightPage | PlaywrightDownload) => void): void;
82
+ off?(event: string, handler: (...args: never[]) => void): void;
83
+ once?(event: string, handler: (...args: never[]) => void): void;
84
+ mouse?: {
85
+ wheel(deltaX: number, deltaY: number): Promise<void>;
86
+ };
87
+ evaluate?<T = unknown>(pageFunction: string | ((arg: unknown) => T | Promise<T>), arg?: unknown): Promise<T>;
88
+ }
89
+
90
+ export interface PlaywrightBrowserContext {
91
+ newPage(): Promise<PlaywrightPage>;
92
+ pages(): PlaywrightPage[];
93
+ close(): Promise<void>;
94
+ on(event: "page" | "download", handler: (pageOrDownload: PlaywrightPage | PlaywrightDownload) => void): void;
95
+ off?(event: string, handler: (...args: never[]) => void): void;
96
+ route?(url: string | RegExp, handler: (route: PlaywrightRoute) => unknown): Promise<void>;
97
+ unroute?(url: string | RegExp, handler?: (route: PlaywrightRoute) => unknown): Promise<void>;
98
+ setDefaultTimeout?(timeout: number): void;
99
+ setDefaultNavigationTimeout?(timeout: number): void;
100
+ /** CDP (Chromium only): page-level Chrome DevTools Protocol session. */
101
+ newCDPSession?(page: PlaywrightPage): Promise<PlaywrightCdpSession>;
102
+ }
103
+
104
+ export interface PlaywrightBrowser {
105
+ newContext(options?: {
106
+ serviceWorkers?: "allow" | "block";
107
+ acceptDownloads?: boolean;
108
+ javaScriptEnabled?: boolean;
109
+ userAgent?: string;
110
+ viewport?: { width: number; height: number } | null;
111
+ // Host may pass storageState; Prism never returns or persists it.
112
+ storageState?: string | { cookies?: unknown[]; origins?: unknown[] };
113
+ proxy?: { server: string; bypass?: string; username?: string; password?: string };
114
+ }): Promise<PlaywrightBrowserContext>;
115
+ isConnected?(): boolean;
116
+ version?(): string;
117
+ close?(): Promise<void>;
118
+ /** CDP (Chromium only): browser-level Chrome DevTools Protocol session. */
119
+ newBrowserCDPSession?(): Promise<PlaywrightCdpSession>;
120
+ }
121
+
122
+ /**
123
+ * Structural Chrome DevTools Protocol session surface (playwright-core CDPSession).
124
+ * Hosts that want CDP tools must supply a Chromium-based Playwright Browser whose
125
+ * contexts expose newCDPSession(page); fakes in tests supply the same surface.
126
+ * No playwright import occurs at package load time.
127
+ */
128
+ export interface PlaywrightCdpSession {
129
+ send<T = unknown>(method: string, params?: Record<string, unknown>): Promise<T>;
130
+ on(event: string, handler: (params: Record<string, unknown>) => void): void;
131
+ off?(event: string, handler: (params: Record<string, unknown>) => void): void;
132
+ detach?(): Promise<void>;
133
+ }