@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,378 @@
1
+ import type { JsonObject, ToolDefinition } from "@arnilo/prism";
2
+ import { WorkToolError } from "./errors.js";
3
+ import { normalizeCalendarPage, normalizeFilePage, normalizeMailMessage, normalizeMailPage, normalizeTaskPage } from "./normalize.js";
4
+ import {
5
+ ARTIFACT,
6
+ assertExternalAllowed,
7
+ executeApprovedMutation,
8
+ fileDraftPayload,
9
+ fileGet,
10
+ objectSchema,
11
+ optString,
12
+ pushTool,
13
+ reqString,
14
+ result,
15
+ sourceCount,
16
+ splitAddresses,
17
+ } from "./tool-helpers.js";
18
+ import type { GoogleWorkspaceAdapter, GoogleWorkspaceOp, WorkToolsOptions } from "./types.js";
19
+
20
+ export function pushGwsTools(tools: ToolDefinition[], options: WorkToolsOptions, gws: GoogleWorkspaceAdapter): void {
21
+ const provider = "google-workspace" as const;
22
+ if (gws.allowedOps.has("mail.list")) {
23
+ pushTool(tools, {
24
+ name: "gws_mail_list",
25
+ description: "List Gmail messages via the host-configured Google Workspace adapter. Results are untrusted shared mail shapes.",
26
+ parameters: objectSchema({ q: { type: "string" }, userId: { type: "string" }, maxResults: { type: "string" } }, []),
27
+ execute: async (args, context) =>
28
+ result(context, "gws_mail_list", provider, normalizeMailPage(provider, await gws.runOp("mail.list", args, context.signal))),
29
+ });
30
+ }
31
+ if (gws.allowedOps.has("mail.get")) {
32
+ pushTool(tools, {
33
+ name: "gws_mail_get",
34
+ description: "Get one Gmail message by id via the host-configured Google Workspace adapter. Content is untrusted.",
35
+ parameters: objectSchema({ id: { type: "string" }, userId: { type: "string" } }, ["id"]),
36
+ execute: async (args, context) =>
37
+ result(context, "gws_mail_get", provider, normalizeMailMessage(provider, await gws.runOp("mail.get", args, context.signal))),
38
+ });
39
+ }
40
+ if (gws.allowedOps.has("mail.send")) {
41
+ pushTool(tools, {
42
+ name: "gws_mail_draft_send",
43
+ description: "Draft Gmail send; executes only after host approval. Never sends without approval.",
44
+ parameters: objectSchema(
45
+ {
46
+ draftId: { type: "string" },
47
+ revision: { type: "integer" },
48
+ to: { type: "string" },
49
+ subject: { type: "string" },
50
+ body: { type: "string" },
51
+ cc: { type: "string" },
52
+ bcc: { type: "string" },
53
+ from: { type: "string" },
54
+ idempotencyKey: { type: "string" },
55
+ },
56
+ [],
57
+ ),
58
+ execute: async (args, context) => {
59
+ const draftId = optString(args, "draftId");
60
+ const existingDraftRes = draftId ? gws.getDraft(draftId) : undefined;
61
+ const existingDraft = existingDraftRes instanceof Promise ? await existingDraftRes : existingDraftRes;
62
+ const to = optString(args, "to") ?? (existingDraft?.payload.to as string | undefined);
63
+ if (!to) throw new WorkToolError("ERR_PRISM_WORK_INPUT", "to must be a non-empty string");
64
+ const subject = optString(args, "subject") ?? (existingDraft?.payload.subject as string | undefined);
65
+ if (!subject) throw new WorkToolError("ERR_PRISM_WORK_INPUT", "subject must be a non-empty string");
66
+ const body = optString(args, "body") ?? (existingDraft?.payload.body as string | undefined);
67
+ if (!body) throw new WorkToolError("ERR_PRISM_WORK_INPUT", "body must be a non-empty string");
68
+ assertExternalAllowed(options, [
69
+ ...splitAddresses(to),
70
+ ...splitAddresses(optString(args, "cc") ?? (existingDraft?.payload.cc as string | undefined) ?? ""),
71
+ ...splitAddresses(optString(args, "bcc") ?? (existingDraft?.payload.bcc as string | undefined) ?? ""),
72
+ ]);
73
+ const payload: JsonObject = {
74
+ to,
75
+ subject,
76
+ body,
77
+ ...((optString(args, "cc") ?? existingDraft?.payload.cc) ? { cc: optString(args, "cc") ?? existingDraft?.payload.cc } : {}),
78
+ ...((optString(args, "bcc") ?? existingDraft?.payload.bcc) ? { bcc: optString(args, "bcc") ?? existingDraft?.payload.bcc } : {}),
79
+ ...((optString(args, "from") ?? existingDraft?.payload.from)
80
+ ? { from: optString(args, "from") ?? existingDraft?.payload.from }
81
+ : {}),
82
+ ...(draftId ? { draftId } : {}),
83
+ ...(typeof args.revision === "number" ? { revision: args.revision } : {}),
84
+ };
85
+ return result(context, "gws_mail_draft_send", provider, await executeApprovedMutation(options, gws, "mail.send", payload, context));
86
+ },
87
+ });
88
+ }
89
+ if (gws.allowedOps.has("calendar.list")) {
90
+ pushTool(tools, {
91
+ name: "gws_calendar_list",
92
+ description: "List Google Calendar events via the host-configured Google Workspace adapter. Shared calendar shapes.",
93
+ parameters: objectSchema(
94
+ {
95
+ calendarId: { type: "string" },
96
+ timeMin: { type: "string" },
97
+ timeMax: { type: "string" },
98
+ maxResults: { type: "string" },
99
+ },
100
+ [],
101
+ ),
102
+ execute: async (args, context) =>
103
+ result(
104
+ context,
105
+ "gws_calendar_list",
106
+ provider,
107
+ normalizeCalendarPage(provider, await gws.runOp("calendar.list", args, context.signal)),
108
+ ),
109
+ });
110
+ }
111
+ if (gws.allowedOps.has("calendar.add")) {
112
+ pushTool(tools, {
113
+ name: "gws_calendar_draft_add",
114
+ description: "Draft a Google Calendar event; executes only after host approval.",
115
+ parameters: objectSchema(
116
+ {
117
+ draftId: { type: "string" },
118
+ revision: { type: "integer" },
119
+ summary: { type: "string" },
120
+ start: { type: "string" },
121
+ end: { type: "string" },
122
+ calendarId: { type: "string" },
123
+ idempotencyKey: { type: "string" },
124
+ },
125
+ [],
126
+ ),
127
+ execute: async (args, context) => {
128
+ const draftId = optString(args, "draftId");
129
+ const existingDraftRes = draftId ? gws.getDraft(draftId) : undefined;
130
+ const existingDraft = existingDraftRes instanceof Promise ? await existingDraftRes : existingDraftRes;
131
+ const summary = optString(args, "summary") ?? (existingDraft?.payload.summary as string | undefined);
132
+ if (!summary) throw new WorkToolError("ERR_PRISM_WORK_INPUT", "summary must be a non-empty string");
133
+ const start = optString(args, "start") ?? (existingDraft?.payload.start as string | undefined);
134
+ if (!start) throw new WorkToolError("ERR_PRISM_WORK_INPUT", "start must be a non-empty string");
135
+ const end = optString(args, "end") ?? (existingDraft?.payload.end as string | undefined);
136
+ if (!end) throw new WorkToolError("ERR_PRISM_WORK_INPUT", "end must be a non-empty string");
137
+ const payload: JsonObject = {
138
+ summary,
139
+ start,
140
+ end,
141
+ ...((optString(args, "calendarId") ?? existingDraft?.payload.calendarId)
142
+ ? { calendarId: optString(args, "calendarId") ?? existingDraft?.payload.calendarId }
143
+ : {}),
144
+ ...(draftId ? { draftId } : {}),
145
+ ...(typeof args.revision === "number" ? { revision: args.revision } : {}),
146
+ };
147
+ return result(
148
+ context,
149
+ "gws_calendar_draft_add",
150
+ provider,
151
+ await executeApprovedMutation(options, gws, "calendar.add" satisfies GoogleWorkspaceOp, payload, context),
152
+ );
153
+ },
154
+ });
155
+ }
156
+ if (gws.allowedOps.has("file.list")) {
157
+ pushTool(tools, {
158
+ name: "gws_file_list",
159
+ description: "List Drive files via the host-configured Google Workspace adapter. Shared file shapes; pageAll fetches bounded pages.",
160
+ parameters: objectSchema({ q: { type: "string" }, pageSize: { type: "string" }, pageAll: { type: "string" } }, []),
161
+ execute: async (args, context) => {
162
+ const raw = await gws.runOp("file.list", args, context.signal);
163
+ // --page-all returns an array of page objects; flatten files.
164
+ const merged = Array.isArray(raw)
165
+ ? {
166
+ files: raw.flatMap((page) => {
167
+ const files = (page as { files?: unknown })?.files;
168
+ return Array.isArray(files) ? files : [];
169
+ }),
170
+ }
171
+ : raw;
172
+ return result(context, "gws_file_list", provider, normalizeFilePage(provider, merged));
173
+ },
174
+ });
175
+ }
176
+ if (gws.allowedOps.has("file.get")) {
177
+ pushTool(tools, {
178
+ name: "gws_file_get",
179
+ description: "Download a Google Drive file by id into a host artifact or contained sandbox path. Downloaded bytes are untrusted.",
180
+ parameters: objectSchema({ id: { type: "string" }, destPath: { type: "string" } }, ["id"]),
181
+ execute: async (args, context) => result(context, "gws_file_get", provider, await fileGet(options, gws, provider, args, context)),
182
+ });
183
+ }
184
+ if (gws.allowedOps.has("file.add")) {
185
+ pushTool(tools, {
186
+ name: "gws_file_draft_upload",
187
+ description: "Draft a Drive upload from a host path, artifact, or contained sandbox path; executes only after host approval.",
188
+ parameters: objectSchema(
189
+ {
190
+ name: { type: "string" },
191
+ filePath: { type: "string" },
192
+ sandboxPath: { type: "string" },
193
+ artifact: ARTIFACT,
194
+ parentId: { type: "string" },
195
+ draftId: { type: "string" },
196
+ revision: { type: "integer", minimum: 1 },
197
+ idempotencyKey: { type: "string" },
198
+ },
199
+ [],
200
+ ),
201
+ execute: async (args, context) => {
202
+ const source = sourceCount(args);
203
+ if (source === 0 && typeof args.draftId !== "string")
204
+ throw new WorkToolError("ERR_PRISM_WORK_INPUT", "file upload requires a source");
205
+ if (source > 0) reqString(args, "name");
206
+ const payload = source === 0 ? args : await fileDraftPayload(options, provider, args, context);
207
+ return result(
208
+ context,
209
+ "gws_file_draft_upload",
210
+ provider,
211
+ await executeApprovedMutation(options, gws, "file.add", payload, context),
212
+ );
213
+ },
214
+ });
215
+ }
216
+ if (gws.allowedOps.has("file.share")) {
217
+ pushTool(tools, {
218
+ name: "gws_file_draft_share",
219
+ description: "Draft a Drive permission (domain/user only; anyone denied). Requires approval.",
220
+ parameters: objectSchema(
221
+ {
222
+ fileId: { type: "string" },
223
+ type: { type: "string" },
224
+ role: { type: "string" },
225
+ domain: { type: "string" },
226
+ emailAddress: { type: "string" },
227
+ idempotencyKey: { type: "string" },
228
+ },
229
+ ["fileId", "type"],
230
+ ),
231
+ execute: async (args, context) => {
232
+ if (reqString(args, "type") === "user") {
233
+ assertExternalAllowed(options, [reqString(args, "emailAddress")]);
234
+ }
235
+ return result(context, "gws_file_draft_share", provider, await executeApprovedMutation(options, gws, "file.share", args, context));
236
+ },
237
+ });
238
+ }
239
+ if (gws.allowedOps.has("task.list")) {
240
+ pushTool(tools, {
241
+ name: "gws_task_list",
242
+ description: "List Google Tasks via the host-configured Google Workspace adapter. Shared task shapes.",
243
+ parameters: objectSchema({ tasklist: { type: "string" } }, []),
244
+ execute: async (args, context) =>
245
+ result(context, "gws_task_list", provider, normalizeTaskPage(provider, await gws.runOp("task.list", args, context.signal))),
246
+ });
247
+ }
248
+ if (gws.allowedOps.has("task.add")) {
249
+ pushTool(tools, {
250
+ name: "gws_task_draft_add",
251
+ description: "Draft a Google Task; executes only after host approval.",
252
+ parameters: objectSchema(
253
+ {
254
+ title: { type: "string" },
255
+ tasklist: { type: "string" },
256
+ idempotencyKey: { type: "string" },
257
+ },
258
+ ["title"],
259
+ ),
260
+ execute: async (args, context) =>
261
+ result(context, "gws_task_draft_add", provider, await executeApprovedMutation(options, gws, "task.add", args, context)),
262
+ });
263
+ }
264
+ if (gws.allowedOps.has("task.complete")) {
265
+ pushTool(tools, {
266
+ name: "gws_task_draft_complete",
267
+ description: "Draft Google Task completion; executes only after host approval.",
268
+ parameters: objectSchema(
269
+ {
270
+ id: { type: "string" },
271
+ tasklist: { type: "string" },
272
+ idempotencyKey: { type: "string" },
273
+ },
274
+ ["id"],
275
+ ),
276
+ execute: async (args, context) =>
277
+ result(context, "gws_task_draft_complete", provider, await executeApprovedMutation(options, gws, "task.complete", args, context)),
278
+ });
279
+ }
280
+ if (gws.allowedOps.has("docs.create")) {
281
+ pushTool(tools, {
282
+ name: "gws_docs_draft_create",
283
+ description: "Draft a Google Doc create (capability-gated); requires approval.",
284
+ parameters: objectSchema({ title: { type: "string" }, idempotencyKey: { type: "string" } }, ["title"]),
285
+ execute: async (args, context) =>
286
+ result(context, "gws_docs_draft_create", provider, await executeApprovedMutation(options, gws, "docs.create", args, context)),
287
+ });
288
+ }
289
+ if (gws.allowedOps.has("docs.update")) {
290
+ pushTool(tools, {
291
+ name: "gws_docs_draft_update",
292
+ description: "Draft a fixed-shape Google Docs text update; executes only after host approval.",
293
+ parameters: objectSchema(
294
+ {
295
+ documentId: { type: "string" },
296
+ replaceAllText: {
297
+ type: "object",
298
+ properties: { containsText: { type: "string" }, replaceText: { type: "string" } },
299
+ required: ["containsText", "replaceText"],
300
+ additionalProperties: false,
301
+ },
302
+ insertText: {
303
+ type: "object",
304
+ properties: { locationIndex: { type: "integer", minimum: 1 }, text: { type: "string" } },
305
+ required: ["locationIndex", "text"],
306
+ additionalProperties: false,
307
+ },
308
+ draftId: { type: "string" },
309
+ revision: { type: "integer", minimum: 1 },
310
+ idempotencyKey: { type: "string" },
311
+ },
312
+ [],
313
+ ),
314
+ execute: async (args, context) =>
315
+ result(context, "gws_docs_draft_update", provider, await executeApprovedMutation(options, gws, "docs.update", args, context)),
316
+ });
317
+ }
318
+ if (gws.allowedOps.has("sheets.create")) {
319
+ pushTool(tools, {
320
+ name: "gws_sheets_draft_create",
321
+ description: "Draft a Google Sheet create (capability-gated); requires approval.",
322
+ parameters: objectSchema({ title: { type: "string" }, idempotencyKey: { type: "string" } }, ["title"]),
323
+ execute: async (args, context) =>
324
+ result(context, "gws_sheets_draft_create", provider, await executeApprovedMutation(options, gws, "sheets.create", args, context)),
325
+ });
326
+ }
327
+ if (gws.allowedOps.has("sheets.update")) {
328
+ pushTool(tools, {
329
+ name: "gws_sheets_draft_update",
330
+ description: "Draft a fixed-shape Google Sheets values update; executes only after host approval.",
331
+ parameters: objectSchema(
332
+ {
333
+ spreadsheetId: { type: "string" },
334
+ range: { type: "string" },
335
+ values: { type: "array", items: { type: "array", items: { type: "string" } } },
336
+ draftId: { type: "string" },
337
+ revision: { type: "integer", minimum: 1 },
338
+ idempotencyKey: { type: "string" },
339
+ },
340
+ [],
341
+ ),
342
+ execute: async (args, context) =>
343
+ result(context, "gws_sheets_draft_update", provider, await executeApprovedMutation(options, gws, "sheets.update", args, context)),
344
+ });
345
+ }
346
+ if (gws.allowedOps.has("slides.create")) {
347
+ pushTool(tools, {
348
+ name: "gws_slides_draft_create",
349
+ description: "Draft a Google Slides create (capability-gated); requires approval.",
350
+ parameters: objectSchema({ title: { type: "string" }, idempotencyKey: { type: "string" } }, ["title"]),
351
+ execute: async (args, context) =>
352
+ result(context, "gws_slides_draft_create", provider, await executeApprovedMutation(options, gws, "slides.create", args, context)),
353
+ });
354
+ }
355
+ if (gws.allowedOps.has("slides.update")) {
356
+ pushTool(tools, {
357
+ name: "gws_slides_draft_update",
358
+ description: "Draft a fixed-shape Google Slides text update; executes only after host approval.",
359
+ parameters: objectSchema(
360
+ {
361
+ presentationId: { type: "string" },
362
+ insertText: {
363
+ type: "object",
364
+ properties: { objectId: { type: "string" }, text: { type: "string" } },
365
+ required: ["objectId", "text"],
366
+ additionalProperties: false,
367
+ },
368
+ draftId: { type: "string" },
369
+ revision: { type: "integer", minimum: 1 },
370
+ idempotencyKey: { type: "string" },
371
+ },
372
+ [],
373
+ ),
374
+ execute: async (args, context) =>
375
+ result(context, "gws_slides_draft_update", provider, await executeApprovedMutation(options, gws, "slides.update", args, context)),
376
+ });
377
+ }
378
+ }
@@ -0,0 +1,123 @@
1
+ import { pinnedFetch } from "@arnilo/prism/net";
2
+ import { WorkToolError } from "./errors.js";
3
+ import { type AgentIdentity } from "./identity.js";
4
+ import type { ResolvedWorkLimits, WorkTokenProvider } from "./types.js";
5
+
6
+ interface WorkHttpClientOptions {
7
+ readonly identity: AgentIdentity;
8
+ readonly tokenProvider: WorkTokenProvider;
9
+ readonly accessEnvVar: string;
10
+ readonly allowedOrigins: readonly string[];
11
+ readonly limits: ResolvedWorkLimits;
12
+ readonly fetch?: typeof globalThis.fetch;
13
+ }
14
+
15
+ interface WorkHttpRequest {
16
+ readonly url: URL;
17
+ readonly method?: string;
18
+ readonly headers?: HeadersInit;
19
+ readonly body?: string | Uint8Array;
20
+ readonly responseType?: "bytes";
21
+ readonly maxResponseBytes?: number;
22
+ readonly signal?: AbortSignal;
23
+ }
24
+
25
+ type WorkHttpClient = (request: WorkHttpRequest) => Promise<unknown>;
26
+
27
+ /** Creates a bounded, pinned, token-at-the-edge HTTP client for work adapters. */
28
+ export function createWorkHttpClient(options: WorkHttpClientOptions): WorkHttpClient {
29
+ const allowedOrigins = new Set(options.allowedOrigins);
30
+
31
+ return async (request) => {
32
+ if (!allowedOrigins.has(request.url.origin)) {
33
+ throw new WorkToolError("ERR_PRISM_WORK_POLICY", `Connector request origin ${request.url.origin} is not allowed`);
34
+ }
35
+ const env = await options.tokenProvider.tokenEnv(options.identity, request.signal);
36
+ const token = env?.[options.accessEnvVar];
37
+ if (typeof token !== "string" || !token) {
38
+ throw new WorkToolError("ERR_PRISM_WORK_CREDENTIAL", "Connector credential unavailable, expired, or revoked");
39
+ }
40
+ if (request.body !== undefined && bodyBytes(request.body) > options.limits.maxRequestBytes) {
41
+ throw new WorkToolError("ERR_PRISM_WORK_LIMIT", "Request body exceeds byte limit");
42
+ }
43
+ const maxResponseBytes = request.maxResponseBytes ?? options.limits.maxResponseBytes;
44
+ if (
45
+ !Number.isSafeInteger(maxResponseBytes) ||
46
+ maxResponseBytes < 0 ||
47
+ (request.responseType === "bytes" && maxResponseBytes > options.limits.maxFileBytes)
48
+ ) {
49
+ throw new WorkToolError("ERR_PRISM_WORK_LIMIT", "Response byte limit is invalid");
50
+ }
51
+
52
+ const headers = new Headers(request.headers);
53
+ headers.set("authorization", `Bearer ${token}`);
54
+ headers.set("accept", request.responseType === "bytes" ? "application/octet-stream" : "application/json");
55
+ let response: Response;
56
+ try {
57
+ response = await (
58
+ options.fetch ??
59
+ ((url: URL, init?: RequestInit) => pinnedFetch(url, init, { errorPrefix: "Work connector HTTP", maxResponseBytes }))
60
+ )(request.url, {
61
+ method: request.method ?? "GET",
62
+ headers,
63
+ ...(request.body === undefined ? {} : { body: request.body as unknown as BodyInit }),
64
+ signal: request.signal,
65
+ });
66
+ } catch {
67
+ throw new WorkToolError("ERR_PRISM_WORK_HTTP", "Connector request failed");
68
+ }
69
+ if (!response.ok) {
70
+ await response.body?.cancel().catch(() => undefined);
71
+ throw new WorkToolError("ERR_PRISM_WORK_HTTP", `Connector request failed (${response.status})`);
72
+ }
73
+ if (request.responseType === "bytes") return readBytes(response, maxResponseBytes, request.signal);
74
+ const text = await response.text();
75
+ if (Buffer.byteLength(text, "utf8") > maxResponseBytes) {
76
+ throw new WorkToolError("ERR_PRISM_WORK_LIMIT", "Response body exceeds byte limit");
77
+ }
78
+ if (!text) return {};
79
+ try {
80
+ return JSON.parse(text);
81
+ } catch {
82
+ throw new WorkToolError("ERR_PRISM_WORK_HTTP", "Connector response was not valid JSON");
83
+ }
84
+ };
85
+ }
86
+
87
+ async function readBytes(response: Response, maxBytes: number, signal?: AbortSignal): Promise<Uint8Array> {
88
+ const length = Number(response.headers.get("content-length"));
89
+ if (Number.isFinite(length) && length > maxBytes) {
90
+ await response.body?.cancel().catch(() => undefined);
91
+ throw new WorkToolError("ERR_PRISM_WORK_LIMIT", "Response body exceeds byte limit");
92
+ }
93
+ const reader = response.body?.getReader();
94
+ if (!reader) return new Uint8Array();
95
+ const chunks: Uint8Array[] = [];
96
+ let total = 0;
97
+ try {
98
+ for (;;) {
99
+ signal?.throwIfAborted();
100
+ const { done, value } = await reader.read();
101
+ if (done) break;
102
+ total += value.byteLength;
103
+ if (total > maxBytes) {
104
+ await reader.cancel().catch(() => undefined);
105
+ throw new WorkToolError("ERR_PRISM_WORK_LIMIT", "Response body exceeds byte limit");
106
+ }
107
+ chunks.push(value);
108
+ }
109
+ } finally {
110
+ reader.releaseLock();
111
+ }
112
+ const bytes = new Uint8Array(total);
113
+ let offset = 0;
114
+ for (const chunk of chunks) {
115
+ bytes.set(chunk, offset);
116
+ offset += chunk.byteLength;
117
+ }
118
+ return bytes;
119
+ }
120
+
121
+ function bodyBytes(value: string | Uint8Array): number {
122
+ return typeof value === "string" ? Buffer.byteLength(value, "utf8") : value.byteLength;
123
+ }