@arnilo/prism-tools 0.0.0-stage → 0.13.0

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 +410 -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 +28 -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 +545 -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,53 @@
1
+ /**
2
+ * Helpers for aligning browser policy with a Task 1 disposable sandbox workspace.
3
+ * No Playwright dependency — mounts and network attestation only.
4
+ */
5
+ import type { BrowserDownloadOptions } from "./downloads.js";
6
+ import type { BrowserNetworkPolicy } from "./network.js";
7
+ import type { BrowserUploadOptions } from "./uploads.js";
8
+
9
+ export interface SharedSandboxBrowserAlignment {
10
+ /** Host workspace root mirrored as sandbox `/workspace`. */
11
+ readonly workspaceRoot: string;
12
+ /** Host quarantine directory mirrored as sandbox `/downloads`. */
13
+ readonly downloadsRoot: string;
14
+ /**
15
+ * Required for real external browsing. Playwright routing remains defense in depth;
16
+ * the host proxy/firewall owns DNS and private egress.
17
+ */
18
+ readonly containedProxyAttestation?: BrowserNetworkPolicy["containedProxyAttestation"];
19
+ readonly approveDownloadRelease?: BrowserDownloadOptions["approveRelease"];
20
+ readonly allowLoopback?: boolean;
21
+ readonly allowPrivateHosts?: boolean;
22
+ }
23
+
24
+ export interface SharedSandboxBrowserOptions {
25
+ readonly networkPolicy: BrowserNetworkPolicy;
26
+ readonly uploads: BrowserUploadOptions;
27
+ readonly downloads: BrowserDownloadOptions;
28
+ }
29
+
30
+ /**
31
+ * Build browser manager/tool options that share the disposable sandbox workspace
32
+ * and download quarantine mounts. Callers still supply the Playwright Browser and
33
+ * must close the browser context before disposing the sandbox.
34
+ */
35
+ export function createSharedSandboxBrowserOptions(input: SharedSandboxBrowserAlignment): SharedSandboxBrowserOptions {
36
+ if (!input.workspaceRoot || !input.downloadsRoot) {
37
+ throw new Error("workspaceRoot and downloadsRoot are required");
38
+ }
39
+ const networkPolicy: BrowserNetworkPolicy = {
40
+ requireContainedProxy: true,
41
+ allowLoopback: input.allowLoopback ?? false,
42
+ allowPrivateHosts: input.allowPrivateHosts ?? false,
43
+ ...(input.containedProxyAttestation ? { containedProxyAttestation: input.containedProxyAttestation } : {}),
44
+ };
45
+ return {
46
+ networkPolicy,
47
+ uploads: { roots: [input.workspaceRoot] },
48
+ downloads: {
49
+ quarantine: input.downloadsRoot,
50
+ ...(input.approveDownloadRelease ? { approveRelease: input.approveDownloadRelease } : {}),
51
+ },
52
+ };
53
+ }
@@ -0,0 +1,99 @@
1
+ import { randomBytes } from "node:crypto";
2
+ import { BrowserError } from "./errors.js";
3
+ import type { ResolvedBrowserLimits } from "./limits.js";
4
+ import { parseSnapshotRefs } from "./targets.js";
5
+ import type { BrowserSnapshotResult, PlaywrightPage, SnapshotRefInfo } from "./types.js";
6
+
7
+ export interface LiveSnapshot {
8
+ readonly snapshotId: string;
9
+ readonly pageId: string;
10
+ readonly url: string;
11
+ readonly title: string;
12
+ readonly ariaSnapshot: string;
13
+ readonly refs: ReadonlyMap<string, SnapshotRefInfo>;
14
+ readonly truncated: boolean;
15
+ readonly truncatedBy?: "bytes" | "refs" | "depth";
16
+ readonly createdAt: number;
17
+ }
18
+
19
+ export function createSnapshotId(): string {
20
+ return `snap_${randomBytes(8).toString("hex")}`;
21
+ }
22
+
23
+ export async function captureAriaSnapshot(page: PlaywrightPage, pageId: string, limits: ResolvedBrowserLimits): Promise<LiveSnapshot> {
24
+ let yaml: string;
25
+ try {
26
+ yaml = await page.ariaSnapshot({
27
+ mode: "ai",
28
+ depth: limits.maxSnapshotDepth,
29
+ timeout: limits.actionTimeoutMs,
30
+ });
31
+ } catch (error) {
32
+ throw new BrowserError("ERR_PRISM_BROWSER", `ariaSnapshot failed: ${error instanceof Error ? error.message : String(error)}`);
33
+ }
34
+ if (typeof yaml !== "string") {
35
+ throw new BrowserError("ERR_PRISM_BROWSER", "ariaSnapshot returned a non-string value");
36
+ }
37
+
38
+ let truncated = false;
39
+ let truncatedBy: LiveSnapshot["truncatedBy"];
40
+ const bytes = Buffer.byteLength(yaml, "utf8");
41
+ if (bytes > limits.maxSnapshotBytes) {
42
+ yaml = Buffer.from(yaml, "utf8").subarray(0, limits.maxSnapshotBytes).toString("utf8");
43
+ // Avoid cutting mid-line for readability.
44
+ const lastNl = yaml.lastIndexOf("\n");
45
+ if (lastNl > 0) yaml = yaml.slice(0, lastNl);
46
+ truncated = true;
47
+ truncatedBy = "bytes";
48
+ }
49
+
50
+ const parsed = parseSnapshotRefs(yaml, limits.maxSnapshotRefs);
51
+ if (parsed.truncatedByRefs) {
52
+ truncated = true;
53
+ truncatedBy = truncatedBy ?? "refs";
54
+ }
55
+
56
+ let url = "";
57
+ let title = "";
58
+ try {
59
+ url = page.url();
60
+ } catch {
61
+ url = "";
62
+ }
63
+ try {
64
+ title = await page.title();
65
+ } catch {
66
+ title = "";
67
+ }
68
+
69
+ return {
70
+ snapshotId: createSnapshotId(),
71
+ pageId,
72
+ url: boundText(url, 2_048),
73
+ title: boundText(title, 1_024),
74
+ ariaSnapshot: yaml,
75
+ refs: parsed.refs,
76
+ truncated,
77
+ truncatedBy,
78
+ createdAt: Date.now(),
79
+ };
80
+ }
81
+
82
+ export function toSnapshotResult(snapshot: LiveSnapshot): BrowserSnapshotResult {
83
+ return {
84
+ snapshotId: snapshot.snapshotId,
85
+ pageId: snapshot.pageId,
86
+ url: snapshot.url,
87
+ title: snapshot.title,
88
+ ariaSnapshot: snapshot.ariaSnapshot,
89
+ refCount: snapshot.refs.size,
90
+ truncated: snapshot.truncated,
91
+ ...(snapshot.truncatedBy ? { truncatedBy: snapshot.truncatedBy } : {}),
92
+ };
93
+ }
94
+
95
+ function boundText(value: string, maxBytes: number): string {
96
+ const buf = Buffer.from(value, "utf8");
97
+ if (buf.byteLength <= maxBytes) return value;
98
+ return buf.subarray(0, maxBytes).toString("utf8");
99
+ }
@@ -0,0 +1,165 @@
1
+ import { BrowserError } from "./errors.js";
2
+ import type { BrowserTarget, PlaywrightLocator, PlaywrightPage, SnapshotRefInfo } from "./types.js";
3
+
4
+ const REF_PATTERN = /^e\d+$/u;
5
+
6
+ export function assertValidRef(ref: string): string {
7
+ if (typeof ref !== "string" || !REF_PATTERN.test(ref)) {
8
+ throw new BrowserError("ERR_PRISM_BROWSER_TARGET", `Invalid snapshot ref: ${String(ref).slice(0, 64)}`);
9
+ }
10
+ return ref;
11
+ }
12
+
13
+ /**
14
+ * Parse AI-mode aria snapshot YAML into a bounded ref table.
15
+ * Refs are snapshot-scoped; callers invalidate the table after mutations.
16
+ */
17
+ export function parseSnapshotRefs(
18
+ ariaSnapshot: string,
19
+ maxRefs: number,
20
+ ): {
21
+ refs: Map<string, SnapshotRefInfo>;
22
+ truncatedByRefs: boolean;
23
+ } {
24
+ const refs = new Map<string, SnapshotRefInfo>();
25
+ let truncatedByRefs = false;
26
+ for (const line of ariaSnapshot.split("\n")) {
27
+ const refMatch = /\[ref=(e\d+)\]/u.exec(line);
28
+ if (!refMatch) continue;
29
+ if (refs.size >= maxRefs) {
30
+ truncatedByRefs = true;
31
+ break;
32
+ }
33
+ const ref = refMatch[1]!;
34
+ if (refs.has(ref)) continue;
35
+ const roleMatch = /^\s*-\s+([A-Za-z][A-Za-z0-9_-]*)/u.exec(line);
36
+ const nameMatch = matchQuotedYamlString(line);
37
+ refs.set(ref, {
38
+ ref,
39
+ role: roleMatch?.[1],
40
+ name: nameMatch !== undefined ? unescapeYamlString(nameMatch) : undefined,
41
+ });
42
+ }
43
+ return { refs, truncatedByRefs };
44
+ }
45
+
46
+ // Linear quoted-string scanner replaces `/"((?:\\.|[^"\\])*)"/u` (CodeQL js/polynomial-redos, alert 3):
47
+ // first unescaped-quote-delimited segment, undefined when absent or unterminated.
48
+ function matchQuotedYamlString(line: string): string | undefined {
49
+ const open = line.indexOf('"');
50
+ if (open === -1) return undefined;
51
+ let i = open + 1;
52
+ while (i < line.length) {
53
+ const c = line[i];
54
+ if (c === "\\") {
55
+ i += 2;
56
+ continue;
57
+ }
58
+ if (c === '"') return line.slice(open + 1, i);
59
+ i += 1;
60
+ }
61
+ return undefined;
62
+ }
63
+ function unescapeYamlString(value: string): string {
64
+ return value.replace(/\\(["\\])/gu, "$1");
65
+ }
66
+
67
+ export function normalizeTarget(raw: unknown): BrowserTarget {
68
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
69
+ throw new BrowserError("ERR_PRISM_BROWSER_TARGET", "target must be an object");
70
+ }
71
+ const obj = raw as Record<string, unknown>;
72
+ const keys = Object.keys(obj);
73
+ if ("selector" in obj || "evaluate" in obj) {
74
+ throw new BrowserError("ERR_PRISM_BROWSER_TARGET", "selector/evaluate targets are not supported");
75
+ }
76
+ if (typeof obj.css === "string") {
77
+ if (keys.some((k) => k !== "css")) {
78
+ throw new BrowserError("ERR_PRISM_BROWSER_TARGET", "css target must only include css");
79
+ }
80
+ return { css: obj.css };
81
+ }
82
+ if (typeof obj.xpath === "string") {
83
+ if (keys.some((k) => k !== "xpath")) {
84
+ throw new BrowserError("ERR_PRISM_BROWSER_TARGET", "xpath target must only include xpath");
85
+ }
86
+ return { xpath: obj.xpath };
87
+ }
88
+ if (typeof obj.ref === "string") {
89
+ if (keys.some((k) => k !== "ref")) {
90
+ throw new BrowserError("ERR_PRISM_BROWSER_TARGET", "ref target must only include ref");
91
+ }
92
+ return { ref: assertValidRef(obj.ref) };
93
+ }
94
+ if (typeof obj.role === "string") {
95
+ const name = obj.name === undefined ? undefined : String(obj.name);
96
+ const exact = obj.exact === true;
97
+ return { role: obj.role, ...(name !== undefined ? { name } : {}), exact };
98
+ }
99
+ if (typeof obj.label === "string") {
100
+ return { label: obj.label, exact: obj.exact === true };
101
+ }
102
+ if (typeof obj.testId === "string") {
103
+ return { testId: obj.testId };
104
+ }
105
+ if (typeof obj.text === "string") {
106
+ return { text: obj.text, exact: obj.exact === true };
107
+ }
108
+ throw new BrowserError("ERR_PRISM_BROWSER_TARGET", "target must be one of ref, role(+name), label, testId, or text");
109
+ }
110
+
111
+ /**
112
+ * Resolve a target against a page. Ref targets require a live snapshot table and
113
+ * use Playwright's built-in `aria-ref=` selector engine (same mechanism as MCP).
114
+ */
115
+ export async function resolveTargetLocator(
116
+ page: PlaywrightPage,
117
+ target: BrowserTarget,
118
+ refs: ReadonlyMap<string, SnapshotRefInfo> | undefined,
119
+ snapshotId: string | undefined,
120
+ ): Promise<PlaywrightLocator> {
121
+ if ("ref" in target) {
122
+ if (!snapshotId || !refs) {
123
+ throw new BrowserError("ERR_PRISM_BROWSER_TARGET", "ref actions require a current snapshotId");
124
+ }
125
+ assertValidRef(target.ref);
126
+ if (!refs.has(target.ref)) {
127
+ throw new BrowserError("ERR_PRISM_BROWSER_TARGET", `Stale or unknown ref ${target.ref} for snapshot ${snapshotId}`);
128
+ }
129
+ return page.locator(`aria-ref=${target.ref}`);
130
+ }
131
+ if ("role" in target) {
132
+ return page.getByRole(target.role, {
133
+ ...(target.name !== undefined ? { name: target.name } : {}),
134
+ exact: target.exact === true,
135
+ });
136
+ }
137
+ if ("label" in target) {
138
+ return page.getByLabel(target.label, { exact: target.exact === true });
139
+ }
140
+ if ("testId" in target) {
141
+ return page.getByTestId(target.testId);
142
+ }
143
+ if ("css" in target) {
144
+ return page.locator(target.css);
145
+ }
146
+ if ("xpath" in target) {
147
+ return page.locator(`xpath=${target.xpath}`);
148
+ }
149
+ return page.getByText(target.text, { exact: target.exact === true });
150
+ }
151
+
152
+ /** Enforce strict single-match semantics before acting. */
153
+ export async function requireUniqueLocator(locator: PlaywrightLocator): Promise<PlaywrightLocator> {
154
+ const count = await locator.count();
155
+ if (count === 0) {
156
+ throw new BrowserError("ERR_PRISM_BROWSER_TARGET", "No element matched the target");
157
+ }
158
+ if (count > 1) {
159
+ throw new BrowserError(
160
+ "ERR_PRISM_BROWSER_TARGET",
161
+ `Ambiguous target matched ${count} elements; refine role/name/label/testId or use a snapshot ref`,
162
+ );
163
+ }
164
+ return locator.first();
165
+ }