@zackbart/connecta 0.34.0 → 0.35.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 (428) hide show
  1. package/CHANGELOG.md +393 -0
  2. package/README.md +62 -105
  3. package/SECURITY.md +3 -2
  4. package/bin/connecta.mjs +41 -16
  5. package/bin/version.mjs +1 -1
  6. package/dist/access-tokens.d.ts +2 -1
  7. package/dist/access-tokens.js +66 -30
  8. package/dist/activity.d.ts +1 -1
  9. package/dist/activity.js +2 -0
  10. package/dist/agent-config.d.ts +23 -0
  11. package/dist/agent-config.js +59 -0
  12. package/dist/agent-description.js +16 -0
  13. package/dist/agent-identity.js +4 -4
  14. package/dist/agent-observation.js +39 -0
  15. package/dist/auth/clerk-sdk/client.d.ts +2 -0
  16. package/dist/auth/clerk-sdk/generated.js +554 -563
  17. package/dist/auth/clerk-transport.js +70 -3
  18. package/dist/auth/clerk.d.ts +13 -0
  19. package/dist/auth/clerk.js +653 -246
  20. package/dist/auth/cloudflare-access.js +46 -42
  21. package/dist/auth/downstream-client-metadata.js +2 -2
  22. package/dist/auth/downstream-oauth.js +2051 -1160
  23. package/dist/auth/downstream-revocation.js +88 -88
  24. package/dist/auth/native-call.js +20 -0
  25. package/dist/auth/native.js +184 -0
  26. package/dist/auth/oauth-start-reset.js +11 -5
  27. package/dist/auth/oauth-token-response.js +121 -102
  28. package/dist/auth/oauth-v2-migration.js +97 -78
  29. package/dist/auth/renewable-grant.js +10 -0
  30. package/dist/auth/static-oauth.js +663 -271
  31. package/dist/auth/vercel-agent.js +266 -0
  32. package/dist/auth-admission.js +204 -0
  33. package/dist/auth-elicitation.js +350 -241
  34. package/dist/authorization-handoff.js +164 -90
  35. package/dist/call-admission-context.js +3 -10
  36. package/dist/call-admission.js +2 -0
  37. package/dist/call-classification.js +9 -0
  38. package/dist/call-recovery.js +32 -13
  39. package/dist/canonical-json.js +8 -0
  40. package/dist/catalog-cache.js +369 -213
  41. package/dist/catalog-service.js +659 -530
  42. package/dist/catalog.js +5 -1
  43. package/dist/concurrency.js +0 -25
  44. package/dist/config-defaults.d.ts +1 -0
  45. package/dist/config-defaults.js +1 -0
  46. package/dist/config-schema.d.ts +3 -1
  47. package/dist/config-schema.js +13 -3
  48. package/dist/config.d.ts +40 -6
  49. package/dist/config.js +40 -26
  50. package/dist/connector-caller.d.ts +4 -0
  51. package/dist/connector-caller.js +17 -4
  52. package/dist/connectors/api-connector.d.ts +15 -7
  53. package/dist/connectors/api-connector.js +147 -57
  54. package/dist/connectors/guarded-fetch.d.ts +51 -17
  55. package/dist/connectors/guarded-fetch.js +215 -121
  56. package/dist/connectors/negotiation-cache.js +20 -10
  57. package/dist/connectors/option-shapes.js +1 -1
  58. package/dist/connectors/remote-mcp.d.ts +12 -30
  59. package/dist/connectors/remote-mcp.js +960 -564
  60. package/dist/d1.js +10 -243
  61. package/dist/derived-context.js +5 -0
  62. package/dist/describe-config.d.ts +5 -1
  63. package/dist/describe-config.js +3 -0
  64. package/dist/downstream-input.js +347 -260
  65. package/dist/errors.d.ts +87 -6
  66. package/dist/errors.js +114 -4
  67. package/dist/execute.js +87 -50
  68. package/dist/executor-admission.js +3 -0
  69. package/dist/executors/quickjs.js +163 -112
  70. package/dist/guarded-transport.js +50 -0
  71. package/dist/guest-runtime.js +1 -1
  72. package/dist/http/client.js +439 -0
  73. package/dist/http/errors.js +558 -0
  74. package/dist/http/fields.js +49 -0
  75. package/dist/http/hatch-paging.js +318 -0
  76. package/dist/http/hatch.js +1279 -0
  77. package/dist/http/json-schema.js +267 -0
  78. package/dist/http/node-transport.js +241 -0
  79. package/dist/http/oauth.js +162 -0
  80. package/dist/http/paging.js +228 -0
  81. package/dist/http/provider.js +221 -0
  82. package/dist/http/safety.js +82 -0
  83. package/dist/http/services.js +79 -0
  84. package/dist/http/tools.js +383 -0
  85. package/dist/http/vendor-index.js +138 -0
  86. package/dist/http/vendor.js +448 -0
  87. package/dist/http/write-request.js +66 -0
  88. package/dist/http-policy.d.ts +11 -0
  89. package/dist/http-policy.js +45 -0
  90. package/dist/inbound-credential.js +1 -1
  91. package/dist/index.d.ts +2 -2
  92. package/dist/index.js +4 -0
  93. package/dist/invocation-auth.js +30 -19
  94. package/dist/invocation.js +221 -87
  95. package/dist/mcp-result.js +0 -4
  96. package/dist/membership.d.ts +4 -0
  97. package/dist/meta-output.js +1 -1
  98. package/dist/meta-tools.js +534 -408
  99. package/dist/native-recovery.js +52 -0
  100. package/dist/native-tools.js +382 -0
  101. package/dist/node.d.ts +4 -3
  102. package/dist/node.js +45 -8
  103. package/dist/oauth-handoff.js +177 -104
  104. package/dist/oauth-partition.js +6 -20
  105. package/dist/oauth-sealing.js +6 -7
  106. package/dist/operation-vocabulary.js +101 -0
  107. package/dist/operator-record.d.ts +2 -2
  108. package/dist/operator-record.js +17 -4
  109. package/dist/operator-ui/agents.d.ts +5 -4
  110. package/dist/operator-ui/agents.js +17 -7
  111. package/dist/operator-ui/config-summary.js +8 -4
  112. package/dist/operator-ui/connection-map.js +9 -6
  113. package/dist/operator-ui/contract.d.ts +7 -3
  114. package/dist/operator-ui/endpoints.js +5 -14
  115. package/dist/operator-ui/fix-prompts.d.ts +1 -1
  116. package/dist/operator-ui/fix-prompts.js +0 -8
  117. package/dist/operator-ui/generated.js +3 -3
  118. package/dist/operator-ui/health.js +52 -0
  119. package/dist/operator-ui/model.d.ts +2 -3
  120. package/dist/operator-ui/overview.js +11 -19
  121. package/dist/operator-ui/setup-commands.js +0 -4
  122. package/dist/operator-ui/view.d.ts +5 -29
  123. package/dist/operator-ui/view.js +3 -59
  124. package/dist/program-writes.js +47 -26
  125. package/dist/provider-call-facts.d.ts +115 -0
  126. package/dist/provider-call-facts.js +182 -0
  127. package/dist/provider-call.d.ts +112 -0
  128. package/dist/provider-call.js +271 -0
  129. package/dist/provider.d.ts +71 -32
  130. package/dist/provider.js +134 -40
  131. package/dist/providers/_shared/google/hatch.js +91 -0
  132. package/dist/providers/_shared/google/kit.js +537 -0
  133. package/dist/providers/_shared/google/result-size.js +15 -2
  134. package/dist/providers/_shared/google/service-account.d.ts +2 -1
  135. package/dist/providers/_shared/google/service-account.js +8 -4
  136. package/dist/providers/_shared/google/workspace.d.ts +8 -209
  137. package/dist/providers/_shared/google/workspace.js +7 -426
  138. package/dist/providers/_shared/rest/compact-index.js +86 -0
  139. package/dist/providers/_shared/rest/dispatch.js +3 -23
  140. package/dist/providers/_shared/rest/kit.js +546 -0
  141. package/dist/providers/_shared/rest/operation-index.js +230 -14
  142. package/dist/providers/_shared/rest/response-media.js +11 -0
  143. package/dist/providers/_shared/rest/tools.js +101 -78
  144. package/dist/providers/_shared/rest/value-safety.js +353 -195
  145. package/dist/providers/_shared/sensitive-fields.js +27 -0
  146. package/dist/providers/breeze/api.js +584 -0
  147. package/dist/providers/breeze/index.d.ts +3 -3
  148. package/dist/providers/breeze/index.js +67 -1420
  149. package/dist/providers/breeze/openapi.generated.js +60 -0
  150. package/dist/providers/breeze/skill.generated.js +2 -6
  151. package/dist/providers/breeze/tools.js +696 -0
  152. package/dist/providers/ccb/api.js +496 -0
  153. package/dist/providers/ccb/index.d.ts +17 -37
  154. package/dist/providers/ccb/index.js +77 -1702
  155. package/dist/providers/ccb/lib/constants.d.ts +34 -0
  156. package/dist/providers/ccb/lib/constants.js +74 -0
  157. package/dist/providers/ccb/lib/guide.js +9 -0
  158. package/dist/providers/ccb/lib/verdicts.js +387 -0
  159. package/dist/providers/ccb/openapi.generated.js +397 -0
  160. package/dist/providers/ccb/safety.js +295 -0
  161. package/dist/providers/ccb/skill.generated.js +2 -6
  162. package/dist/providers/ccb/tools.js +853 -0
  163. package/dist/providers/cloudflare/api.js +1066 -0
  164. package/dist/providers/cloudflare/index.d.ts +7 -22
  165. package/dist/providers/cloudflare/index.js +80 -194
  166. package/dist/providers/cloudflare/lib/config.d.ts +16 -0
  167. package/dist/providers/cloudflare/lib/config.js +2 -0
  168. package/dist/providers/cloudflare/lib/discovery.js +29 -0
  169. package/dist/providers/cloudflare/{graphql.js → lib/graphql.js} +1 -1
  170. package/dist/providers/cloudflare/lib/hatch.js +103 -0
  171. package/dist/providers/cloudflare/lib/path-bounds.js +28 -0
  172. package/dist/providers/cloudflare/lib/response-media.js +75 -0
  173. package/dist/providers/cloudflare/openapi.generated.js +3299 -3208
  174. package/dist/providers/cloudflare/{value-safety.js → safety.js} +538 -18
  175. package/dist/providers/cloudflare/skill.generated.js +2 -10
  176. package/dist/providers/cloudflare/tools.js +360 -0
  177. package/dist/providers/docs/api.js +51 -0
  178. package/dist/providers/docs/index.d.ts +1 -12
  179. package/dist/providers/docs/index.js +53 -1165
  180. package/dist/providers/docs/lib/constants.d.ts +18 -0
  181. package/dist/providers/docs/lib/constants.js +18 -0
  182. package/dist/providers/docs/lib/discovery.js +26 -0
  183. package/dist/providers/docs/lib/requests.js +48 -0
  184. package/dist/providers/docs/lib/schemas.js +168 -0
  185. package/dist/providers/docs/openapi.generated.js +16 -0
  186. package/dist/providers/docs/safety.js +54 -0
  187. package/dist/providers/docs/skill.generated.js +2 -6
  188. package/dist/providers/docs/tools.js +802 -0
  189. package/dist/providers/drive/api.js +177 -0
  190. package/dist/providers/drive/index.d.ts +1 -12
  191. package/dist/providers/drive/index.js +38 -1448
  192. package/dist/providers/drive/lib/constants.d.ts +6 -0
  193. package/dist/providers/drive/lib/constants.js +6 -0
  194. package/dist/providers/drive/lib/contracts.js +532 -0
  195. package/dist/providers/drive/lib/hatch.js +197 -0
  196. package/dist/providers/drive/openapi.generated.js +77 -0
  197. package/dist/providers/drive/safety.js +90 -0
  198. package/dist/providers/drive/skill.generated.js +2 -6
  199. package/dist/providers/drive/tools.js +1290 -0
  200. package/dist/providers/forms/api.js +71 -0
  201. package/dist/providers/forms/index.d.ts +1 -12
  202. package/dist/providers/forms/index.js +49 -1145
  203. package/dist/providers/forms/lib/constants.d.ts +14 -0
  204. package/dist/providers/forms/lib/constants.js +19 -0
  205. package/dist/providers/forms/lib/hatch.js +72 -0
  206. package/dist/providers/forms/openapi.generated.js +23 -0
  207. package/dist/providers/forms/safety.js +34 -0
  208. package/dist/providers/forms/skill.generated.js +2 -8
  209. package/dist/providers/forms/tools.js +1024 -0
  210. package/dist/providers/github/api.js +150 -0
  211. package/dist/providers/github/index.d.ts +4 -5
  212. package/dist/providers/github/index.js +30 -87
  213. package/dist/providers/github/{auth.d.ts → lib/auth.d.ts} +5 -3
  214. package/dist/providers/github/{auth.js → lib/auth.js} +40 -43
  215. package/dist/providers/github/lib/discovery.js +132 -0
  216. package/dist/providers/github/lib/operations.js +58 -0
  217. package/dist/providers/github/{scope.d.ts → lib/scope.d.ts} +2 -0
  218. package/dist/providers/github/{scope.js → lib/scope.js} +25 -1
  219. package/dist/providers/github/openapi.generated.js +1216 -0
  220. package/dist/providers/github/safety.js +216 -0
  221. package/dist/providers/github/skill.generated.js +2 -5
  222. package/dist/providers/github/tools.js +506 -0
  223. package/dist/providers/gmail/api.js +114 -0
  224. package/dist/providers/gmail/index.d.ts +1 -12
  225. package/dist/providers/gmail/index.js +73 -1621
  226. package/dist/providers/gmail/lib/constants.d.ts +13 -0
  227. package/dist/providers/gmail/lib/constants.js +16 -0
  228. package/dist/providers/gmail/lib/index.js +173 -0
  229. package/dist/providers/gmail/lib/schemas.js +176 -0
  230. package/dist/providers/gmail/lib/threading.js +120 -0
  231. package/dist/providers/gmail/openapi.generated.js +92 -0
  232. package/dist/providers/gmail/safety.js +21 -0
  233. package/dist/providers/gmail/skill.generated.js +2 -6
  234. package/dist/providers/gmail/tools.js +1435 -0
  235. package/dist/providers/overflow/api.js +1008 -0
  236. package/dist/providers/overflow/index.d.ts +3 -17
  237. package/dist/providers/overflow/index.js +60 -1488
  238. package/dist/providers/overflow/skill.generated.js +2 -5
  239. package/dist/providers/overflow/tools.js +873 -0
  240. package/dist/providers/planning-center/api.js +467 -0
  241. package/dist/providers/planning-center/index.d.ts +6 -35
  242. package/dist/providers/planning-center/index.js +69 -2445
  243. package/dist/providers/planning-center/lib/constants.d.ts +58 -0
  244. package/dist/providers/planning-center/lib/constants.js +83 -0
  245. package/dist/providers/planning-center/lib/discovery.js +40 -0
  246. package/dist/providers/planning-center/lib/guide.js +39 -0
  247. package/dist/providers/planning-center/lib/json-api.js +83 -0
  248. package/dist/providers/planning-center/lib/verdicts.js +1758 -0
  249. package/dist/providers/planning-center/openapi.generated.js +1764 -0
  250. package/dist/providers/planning-center/safety.js +188 -0
  251. package/dist/providers/planning-center/skill.generated.js +2 -27
  252. package/dist/providers/planning-center/tools.js +1010 -0
  253. package/dist/providers/sheets/api.js +133 -0
  254. package/dist/providers/sheets/index.d.ts +4 -16
  255. package/dist/providers/sheets/index.js +61 -1172
  256. package/dist/providers/sheets/lib/constants.d.ts +14 -0
  257. package/dist/providers/sheets/lib/constants.js +14 -0
  258. package/dist/providers/sheets/lib/hatch.js +163 -0
  259. package/dist/providers/sheets/lib/requests.js +105 -0
  260. package/dist/providers/sheets/lib/schemas.js +138 -0
  261. package/dist/providers/sheets/openapi.generated.js +30 -0
  262. package/dist/providers/sheets/safety.js +27 -0
  263. package/dist/providers/sheets/skill.generated.js +2 -7
  264. package/dist/providers/sheets/tools.js +734 -0
  265. package/dist/providers/slides/api.js +147 -0
  266. package/dist/providers/slides/index.d.ts +2 -10
  267. package/dist/providers/slides/index.js +48 -2555
  268. package/dist/providers/slides/lib/constants.d.ts +11 -0
  269. package/dist/providers/slides/lib/constants.js +11 -0
  270. package/dist/providers/slides/lib/requests.js +60 -0
  271. package/dist/providers/slides/lib/schemas.js +565 -0
  272. package/dist/providers/slides/openapi.generated.js +18 -0
  273. package/dist/providers/slides/skill.generated.js +2 -6
  274. package/dist/providers/slides/tools.js +1968 -0
  275. package/dist/providers/stripe/api.js +401 -0
  276. package/dist/providers/stripe/index.d.ts +7 -27
  277. package/dist/providers/stripe/index.js +75 -191
  278. package/dist/providers/stripe/lib/config.d.ts +4 -0
  279. package/dist/providers/stripe/lib/config.js +2 -0
  280. package/dist/providers/stripe/openapi.generated.js +4 -3
  281. package/dist/providers/stripe/{value-safety.js → safety.js} +5 -5
  282. package/dist/providers/stripe/skill.generated.js +2 -10
  283. package/dist/providers/stripe/tools.js +77 -0
  284. package/dist/providers/tithely/api.js +531 -0
  285. package/dist/providers/tithely/index.d.ts +19 -0
  286. package/dist/providers/tithely/index.js +86 -965
  287. package/dist/providers/tithely/skill.generated.js +2 -5
  288. package/dist/providers/tithely/tools.js +426 -0
  289. package/dist/providers/vercel/api.js +551 -0
  290. package/dist/providers/vercel/index.d.ts +11 -25
  291. package/dist/providers/vercel/index.js +67 -261
  292. package/dist/providers/vercel/lib/config.d.ts +2 -0
  293. package/dist/providers/vercel/lib/config.js +2 -0
  294. package/dist/providers/vercel/lib/index.js +117 -0
  295. package/dist/providers/vercel/lib/logs.js +100 -0
  296. package/dist/providers/vercel/lib/pin.js +270 -0
  297. package/dist/providers/vercel/openapi.generated.js +398 -376
  298. package/dist/providers/vercel/{value-safety.js → safety.js} +261 -42
  299. package/dist/providers/vercel/skill.generated.js +2 -7
  300. package/dist/providers/vercel/tools.js +642 -0
  301. package/dist/redaction-identity.js +47 -0
  302. package/dist/redaction-marker.js +125 -0
  303. package/dist/registry.d.ts +30 -28
  304. package/dist/registry.js +446 -413
  305. package/dist/routes/access-tokens.js +1 -1
  306. package/dist/routes/actor-labels.js +1 -1
  307. package/dist/routes/connect.js +1 -1
  308. package/dist/routes/dispatch.js +103 -0
  309. package/dist/routes/mcp.js +170 -79
  310. package/dist/routes/oauth.js +3 -1
  311. package/dist/routes/operator.js +2 -2
  312. package/dist/routes/shared.d.ts +5 -4
  313. package/dist/routes/shared.js +244 -177
  314. package/dist/routes/skills.js +10 -8
  315. package/dist/routes/ui-config.js +27 -3
  316. package/dist/routes/ui-data.js +29 -22
  317. package/dist/routes/ui.js +1 -1
  318. package/dist/runtime/call-admission.js +0 -26
  319. package/dist/runtime/call-entry.js +30 -0
  320. package/dist/runtime/call.js +556 -0
  321. package/dist/runtime/connector-scope.js +7 -0
  322. package/dist/runtime/credential-probe.js +34 -0
  323. package/dist/runtime/executor.js +40 -0
  324. package/dist/runtime/native-storage.js +63 -0
  325. package/dist/runtime/registry.js +27 -0
  326. package/dist/runtime/request-scope.js +72 -0
  327. package/dist/runtime/run.js +15 -7
  328. package/dist/runtime/shared-read.js +34 -5
  329. package/dist/runtime/storage.js +34 -21
  330. package/dist/sent-secrets.d.ts +194 -37
  331. package/dist/sent-secrets.js +1743 -340
  332. package/dist/server.js +5 -56
  333. package/dist/skills.js +330 -224
  334. package/dist/sqlite.js +15 -14
  335. package/dist/storage/d1-copy.js +255 -0
  336. package/dist/storage/d1-driver.js +15 -0
  337. package/dist/storage/keys.js +28 -0
  338. package/dist/storage/sql-driver.js +88 -0
  339. package/dist/storage/sql-native.js +544 -0
  340. package/dist/storage/sql-schema.d.ts +6 -0
  341. package/dist/storage/sql-schema.js +15 -0
  342. package/dist/storage/sql.d.ts +14 -20
  343. package/dist/storage/sql.js +29 -535
  344. package/dist/timeout.js +0 -26
  345. package/dist/tool-safety.js +20 -10
  346. package/dist/types.d.ts +11 -99
  347. package/dist/upward.js +3 -0
  348. package/dist/usage-guide.js +3 -1
  349. package/dist/validate.d.ts +4 -2
  350. package/dist/validate.js +86 -9
  351. package/dist/version.d.ts +1 -1
  352. package/dist/version.js +1 -1
  353. package/dist/worker.js +312 -292
  354. package/dist/workspace-subject.js +5 -1
  355. package/dist/write-outcome.js +454 -34
  356. package/documentation/README.md +27 -7
  357. package/documentation/architecture.md +2550 -186
  358. package/documentation/auth.md +821 -98
  359. package/documentation/code-mode.md +56 -21
  360. package/documentation/deploying.md +164 -20
  361. package/documentation/hosted-mcp-migration.md +460 -0
  362. package/documentation/integrating.md +144 -105
  363. package/documentation/meta-tools.md +411 -34
  364. package/documentation/operating.md +28 -4
  365. package/documentation/operator-tests.md +11 -2
  366. package/documentation/operator-ui.md +103 -33
  367. package/documentation/provider-auth-migration.md +38 -63
  368. package/documentation/provider-migration-0.29.md +10 -5
  369. package/documentation/provider-migration-0.35.md +975 -0
  370. package/documentation/providers.md +965 -0
  371. package/examples/worker/AGENTS.md +23 -9
  372. package/examples/worker/README.md +254 -135
  373. package/examples/worker/alchemy.run.ts +116 -0
  374. package/examples/worker/gitignore +10 -0
  375. package/examples/worker/src/connecta.config.ts +23 -21
  376. package/examples/worker/wrangler.jsonc +14 -5
  377. package/guides/connecting-agents.md +157 -0
  378. package/guides/how-it-works.md +156 -0
  379. package/guides/safety-and-trust.md +153 -0
  380. package/package.json +27 -42
  381. package/templates/node/.env.example +3 -0
  382. package/templates/node/README.md +22 -2
  383. package/templates/node/docker-compose.yml +1 -0
  384. package/templates/node/package.json +3 -2
  385. package/templates/node/src/connecta.config.ts +8 -0
  386. package/dist/catalog-drift.d.ts +0 -134
  387. package/dist/catalog-drift.js +0 -493
  388. package/dist/providers/_shared/request-token.js +0 -83
  389. package/dist/providers/_shared/rest/operation-index.d.ts +0 -133
  390. package/dist/providers/_shared/rest/tools.d.ts +0 -141
  391. package/dist/providers/_shared/rest/value-safety.d.ts +0 -201
  392. package/dist/providers/basecamp/index.d.ts +0 -43
  393. package/dist/providers/basecamp/index.js +0 -997
  394. package/dist/providers/basecamp/skill.generated.js +0 -9
  395. package/dist/providers/cloudflare/rest.d.ts +0 -37
  396. package/dist/providers/cloudflare/rest.js +0 -1078
  397. package/dist/providers/github/hosted.js +0 -218
  398. package/dist/providers/github/rest.js +0 -321
  399. package/dist/providers/infisical/index.d.ts +0 -7
  400. package/dist/providers/infisical/index.js +0 -713
  401. package/dist/providers/infisical/skill.generated.js +0 -8
  402. package/dist/providers/linear/index.d.ts +0 -55
  403. package/dist/providers/linear/index.js +0 -352
  404. package/dist/providers/linear/skill.generated.js +0 -8
  405. package/dist/providers/mixpanel/index.d.ts +0 -57
  406. package/dist/providers/mixpanel/index.js +0 -468
  407. package/dist/providers/mixpanel/operations.js +0 -20
  408. package/dist/providers/mixpanel/rest.js +0 -603
  409. package/dist/providers/mixpanel/skill.generated.js +0 -10
  410. package/dist/providers/mixpanel/value-safety.js +0 -16
  411. package/dist/providers/notion/index.d.ts +0 -65
  412. package/dist/providers/notion/index.js +0 -368
  413. package/dist/providers/notion/openapi.generated.js +0 -75
  414. package/dist/providers/notion/rest.d.ts +0 -24
  415. package/dist/providers/notion/rest.js +0 -1226
  416. package/dist/providers/notion/skill.generated.js +0 -11
  417. package/dist/providers/notion/value-safety.js +0 -56
  418. package/dist/providers/revenuecat/index.d.ts +0 -49
  419. package/dist/providers/revenuecat/index.js +0 -557
  420. package/dist/providers/revenuecat/skill.generated.js +0 -11
  421. package/dist/providers/stripe/rest.d.ts +0 -14
  422. package/dist/providers/stripe/rest.js +0 -402
  423. package/dist/providers/vercel/rest.d.ts +0 -20
  424. package/dist/providers/vercel/rest.js +0 -1020
  425. package/dist/providers/wispr-flow/index.d.ts +0 -14
  426. package/dist/providers/wispr-flow/index.js +0 -117
  427. package/dist/providers/wispr-flow/skill.generated.js +0 -8
  428. /package/dist/providers/github/{key.js → lib/key.js} +0 -0
@@ -1,31 +1,39 @@
1
- import { vettedSchemaDigest } from "./catalog-drift.js";
1
+ import { authCall, authFlow, registerAuth } from "./auth/native.js";
2
+ import { upwardStep } from "./upward.js";
3
+ import { runEdge } from "./runtime/run.js";
4
+ import { Effect } from "effect";
5
+ import { requestOwner } from "./runtime/request-scope.js";
6
+ import { cloneTool, sourceClassification } from "./tool-safety.js";
2
7
  // Only built-in factories register local credential checks. This hook is not
3
8
  // part of Connector, and a replacement callTool cannot inherit its proof.
4
9
  const checks = new WeakMap();
5
10
  export function registerInvocationAuth(connector, check) {
6
11
  checks.set(connector, { callTool: connector.callTool, check });
7
12
  }
8
- /** Local credential resolution only, before entering any connector call. */
9
- export async function resolveInvocationAuth(connector, ctx) {
10
- const entry = checks.get(connector);
11
- if (entry?.callTool === connector.callTool)
12
- await entry.check(ctx);
13
+ /**
14
+ * Local credential resolution only, before entering any connector call.
15
+ * `callTool` is the function the invocation will invoke, read once.
16
+ */
17
+ export function resolveInvocationAuthEffect(connector, callTool, ctx) {
18
+ return Effect.suspend(() => {
19
+ const entry = checks.get(connector);
20
+ return entry?.callTool === callTool ? authCall(entry.check, [ctx]) : Effect.void;
21
+ });
13
22
  }
14
- const requests = new WeakMap();
15
23
  function requestFor(scope) {
16
- let facts = requests.get(scope);
17
- if (!facts) {
18
- facts = { entered: [], authFailures: new Map(), retryReads: new Map() };
19
- requests.set(scope, facts);
20
- }
21
- return facts;
24
+ return requestOwner(scope).retained.invocations;
22
25
  }
23
26
  /** Bind the verdict, annotation facts and schemas used for this call. */
24
27
  export async function classificationDigest(definition) {
25
28
  try {
26
- const schema = await vettedSchemaDigest(definition);
29
+ const schema = { inputSchema: definition.inputSchema, outputSchema: definition.outputSchema };
27
30
  const annotations = Object.entries(definition.annotations ?? {}).sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0));
28
- const bytes = new TextEncoder().encode(JSON.stringify({ classification: definition.classification, annotations, schema }));
31
+ const bytes = new TextEncoder().encode(JSON.stringify({
32
+ classification: definition.classification,
33
+ source: sourceClassification(definition),
34
+ annotations,
35
+ schema,
36
+ }));
29
37
  return Array.from(new Uint8Array(await crypto.subtle.digest("SHA-256", bytes)), (byte) => byte.toString(16).padStart(2, "0")).join("");
30
38
  }
31
39
  catch {
@@ -37,7 +45,7 @@ export async function classificationDigest(definition) {
37
45
  export function recordCallEntry(scope, call, definition) {
38
46
  // Snapshot synchronously. Recovery hashes this private copy only when it
39
47
  // needs a replay binding, without changing ordinary admission or completion.
40
- requestFor(scope).entered.push({ ...call, definition: structuredClone(definition) });
48
+ requestFor(scope).entered.push({ ...call, definition: cloneTool(definition) });
41
49
  }
42
50
  export function bindReplayReads(scope, reads) {
43
51
  requestFor(scope).retryReads = new Map(reads.map((read) => [read.address, read.digest]));
@@ -50,13 +58,16 @@ export function recordAuthFailure(scope, connector, eligible) {
50
58
  const failures = requestFor(scope).authFailures;
51
59
  failures.set(connector, eligible && failures.get(connector) !== false);
52
60
  }
53
- export async function authRecoveryFacts(scope, connector) {
61
+ export function authRecoveryFacts(scope, connector) {
62
+ return runEdge(authRecoveryFactsNative(scope, connector));
63
+ }
64
+ const authRecoveryFactsNative = /* @__PURE__ */ registerAuth(authRecoveryFacts, (scope, connector) => authFlow(function* () {
54
65
  const facts = requestFor(scope);
55
66
  const writeEntered = facts.entered.some((call) => call.classification === "write");
56
67
  const reads = new Map();
57
68
  let unsafeEntered = writeEntered;
58
69
  for (const call of facts.entered) {
59
- const digest = await classificationDigest(call.definition);
70
+ const digest = yield* upwardStep(authCall(classificationDigest, [call.definition]));
60
71
  unsafeEntered ||= !call.fresh || !digest || (reads.has(call.address) && reads.get(call.address) !== digest);
61
72
  reads.set(call.address, digest);
62
73
  }
@@ -66,4 +77,4 @@ export async function authRecoveryFacts(scope, connector) {
66
77
  eligible: !unsafeEntered && facts.authFailures.get(connector) === true,
67
78
  reads: [...reads].map(([address, digest]) => ({ address, digest })),
68
79
  };
69
- }
80
+ }));
@@ -1,20 +1,25 @@
1
- import { withAuthorizationHandoff } from "./authorization-handoff.js";
1
+ import { authCall, registerAuthMethod } from "./auth/native.js";
2
+ import { withAuthorizationHandoffEffect } from "./authorization-handoff.js";
2
3
  import { hasControlCharacters } from "./tool-name.js";
3
- import { writeRefusal } from "./tool-safety.js";
4
- import { Cause, Effect, Exit } from "effect";
5
- import { isCallAdmissionError } from "./call-admission.js";
6
- import { attachCallAdmission } from "./call-admission-context.js";
7
- import { boundedEchoText, classificationCode, classifyCallError, ConnectorCallError, echoedCallArgs, framingError, } from "./errors.js";
4
+ import { cloneTool, isWriteLike, writeRefusal } from "./tool-safety.js";
5
+ import { Cause, Context, Effect, Exit } from "effect";
6
+ import { CallAdmissionError, isCallAdmissionError } from "./call-admission.js";
7
+ import { boundedEchoText, classificationCode, classifyCallError, classifyWithoutAdvice, ConnectorCallError, echoedCallArgs, framingError, keyResendAdviceOf, resendAdviceOf, withResendAdvice, } from "./errors.js";
8
8
  import { downstreamValue } from "./mcp-result.js";
9
9
  import { carryFailureFacts, classifiedFailure, failureRecord, logFailure, recordedToolName, } from "./operator-record.js";
10
10
  import { splitAddress } from "./registry.js";
11
- import { runEdge, withDeadlineEffect } from "./runtime/run.js";
11
+ import { causeError, runEdge, withDeadlineEffect } from "./runtime/run.js";
12
12
  import { validateCatalogToolInput } from "./validate.js";
13
- import { sentSecretsFor, sentSecretsForRequest, trackCredentialReads } from "./sent-secrets.js";
14
- import { recoveryFor } from "./call-recovery.js";
15
- import { classifyWriteOutcome } from "./write-outcome.js";
16
- import { classificationDigest, recordAuthFailure, recordCallEntry, replayClassificationDigest, resolveInvocationAuth, } from "./invocation-auth.js";
13
+ import { sentSecretsFor, sentSecretsForRequest } from "./sent-secrets.js";
14
+ import { recoveryRecord, recordRecoveryFacts } from "./call-recovery.js";
15
+ import { callFromContext, contextView, viewServices, Credentials } from "./runtime/call.js";
16
+ import { chargeCallBudget } from "./runtime/call-admission.js";
17
+ import { callEntry } from "./runtime/call-entry.js";
18
+ import { forgetProviderFailure, isKnownProviderFailure, isSettledWrite, keyProtectsCall, knownCallFailure, onlyAuxiliaryRequests, knownProviderFailure, openLogicalCall, } from "./provider-call.js";
19
+ import { classifyWriteOutcome, settleWrite, settleWriteResult } from "./write-outcome.js";
20
+ import { classificationDigest, recordAuthFailure, recordCallEntry, replayClassificationDigest, resolveInvocationAuthEffect, } from "./invocation-auth.js";
17
21
  import { downstreamContinuation, recordDownstreamArgumentEcho, isDownstreamInputResult, assertDownstreamOutputSafe, } from "./downstream-input-context.js";
22
+ import { keepErrorName } from "./redaction-identity.js";
18
23
  function defined(values) {
19
24
  return Object.fromEntries(Object.entries(values).filter(([, value]) => value !== undefined));
20
25
  }
@@ -74,8 +79,8 @@ function isCallerCancellation(error, signal) {
74
79
  }
75
80
  /**
76
81
  * A downstream MCP tool answered with `isError`. Classified exactly as the
77
- * plain `Error`: untyped, non-retryable, and marked so
78
- * a write's outcome can tell "the service said no" from "nobody answered".
82
+ * plain `Error`: untyped and non-retryable. It is a read's answer; for a
83
+ * write it is a 2xx reply after which the handler may have applied it.
79
84
  */
80
85
  class DownstreamToolError extends Error {
81
86
  }
@@ -97,13 +102,18 @@ function assertRawMcpSuccess(kind, result) {
97
102
  .join("") || "Downstream tool call failed"));
98
103
  }
99
104
  /**
100
- * Whether a failed attempt is the downstream tool's own answer: an MCP
101
- * `isError`. A connector's typed error is not, by itself, one — a response
102
- * too large to read or a refused redirect comes after the request was acted
103
- * on — so its code decides instead (`classifyWriteOutcome`).
105
+ * Whether a failed attempt is the downstream tool's own answer. For a read:
106
+ * an MCP `isError`, or a boundary's known refusal/unsent failure. For a
107
+ * write, only refusal provenance that holds for the whole logical call
108
+ * (`knownCallFailure`); an `isError` arrives over a 2xx after the handler
109
+ * ran. A typed error alone is not proof: a body ceiling, refused redirect, or
110
+ * handler error may follow execution. Boundaries supply provenance, never
111
+ * wording.
104
112
  */
105
- function answeredFailure(error) {
106
- return error instanceof DownstreamToolError;
113
+ function answeredFailure(error, write, call) {
114
+ if (!write)
115
+ return error instanceof DownstreamToolError || isKnownProviderFailure(error);
116
+ return knownCallFailure(call, error);
107
117
  }
108
118
  export class InvocationFailure extends Error {
109
119
  details;
@@ -131,6 +141,7 @@ export class InvocationFailure extends Error {
131
141
  this.data = details;
132
142
  }
133
143
  }
144
+ keepErrorName(InvocationFailure, "InvocationFailure");
134
145
  /**
135
146
  * Shared downstream invocation engine. Address/catalog resolution is delegated
136
147
  * to the request-local CatalogService; every remaining call semantic lives
@@ -149,6 +160,7 @@ export class InvocationService {
149
160
  this.registry = registry;
150
161
  this.catalog = catalog;
151
162
  this.activity = activity;
163
+ void InvocationService.nativePrograms;
152
164
  }
153
165
  invoke(address, args, context) {
154
166
  return runEdge(this.pipeline(address, args, context));
@@ -169,11 +181,20 @@ export class InvocationService {
169
181
  let attempts = 0;
170
182
  let resultBytes;
171
183
  let dispatchedToConnector = false;
172
- // The context a dispatched call ran with, read for recovery facts the
173
- // connector recorded before an interrupting deadline (call-recovery.ts).
174
- let dispatchContext;
184
+ // The logical call bridge; recovery is a separate invocation-owned record.
185
+ let logicalCall;
186
+ // The served class owns gating and presentation. Physical source-write
187
+ // provenance additionally owns failure settlement, after dispatch only.
188
+ const sentSourceWrite = () => logicalCall?.sent.some((request) => request.sourceWrite === true) === true;
189
+ const recoveryState = recoveryRecord();
175
190
  let preInvocationAuthFailure = false;
176
191
  let answered = false;
192
+ // A dispatched failure's advice to send it again, composed by enrich
193
+ // only once the outcome allows it (resendAdvice), and its advice to
194
+ // reuse an idempotency key, only where that key protects the whole
195
+ // logical call (keyResendAdvice, keyProtectsCall).
196
+ let failureAdvice;
197
+ let failureKeyAdvice;
177
198
  const sentSecrets = sentSecretsForRequest(this.catalog.requestScope);
178
199
  context.sentSecrets?.include(sentSecrets);
179
200
  // A write gate's refusal that is no attempt; see WriteGateDecision.
@@ -207,7 +228,7 @@ export class InvocationService {
207
228
  connectorId: identity.connectorId,
208
229
  toolName,
209
230
  address: `${identity.connectorId}.${toolName}`,
210
- source: context.source,
231
+ source: context.activitySource ?? context.source,
211
232
  outcome,
212
233
  ...(activityTarget?.connector.authScope === "personal" ? { personal: true } : {}),
213
234
  durationMs: Date.now() - started,
@@ -220,20 +241,33 @@ export class InvocationService {
220
241
  }),
221
242
  });
222
243
  };
223
- const enrich = (error, target) => {
244
+ const enrich = (error, target, settled) => {
224
245
  if (!target)
225
246
  return error;
226
- const recovery = recoveryFor(dispatchContext);
227
- const recoveryRetry = recovery?.["idempotencyKey"]
247
+ const recovery = recoveryState.facts;
248
+ const enteredWrite = dispatchedToConnector &&
249
+ ((resolved !== undefined && resolved.definition.classification !== "read") || sentSourceWrite());
250
+ // A known answer alone is not dispatch evidence. Require an owned,
251
+ // complete ledger with a positively recorded auxiliary resource read;
252
+ // an empty ledger, custom entry or interruption proves nothing.
253
+ const mayHaveWritten = enteredWrite && (error.writeOutcome === "unknown" || !(answered && onlyAuxiliaryRequests(logicalCall)));
254
+ // A recorded key is a diagnostic; advice to reuse it needs proof that
255
+ // it protects the whole logical call, not one request inside it. Q8's
256
+ // settled verdict is final: no enricher adds advice to it.
257
+ const recoveryRetry = !settled && keyProtectsCall(logicalCall, recovery?.["idempotencyKey"])
228
258
  ? " A deliberate retry with uncertainCall.recovery.idempotencyKey and the exact original arguments cannot repeat the write while the vendor retains that key (Stripe keeps v1 keys at least 24 hours); after that, look the object up before retrying."
229
259
  : "";
230
- if (isTimeoutFailure(error) && dispatchedToConnector && resolved?.definition.classification === "write") {
260
+ if (isTimeoutFailure(error) && mayHaveWritten) {
261
+ // An empty ledger's known mark cannot settle this timeout. Keep
262
+ // program accounting conservative as well as its displayed code.
263
+ answered = false;
231
264
  const echoed = argumentEcho;
232
265
  return {
233
266
  ...error,
234
267
  code: "write_outcome_unknown",
235
268
  message: `${error.message} Its outcome is unknown. Check the target before repeating this call.`,
236
269
  retryable: false,
270
+ ...(sentSourceWrite() ? { writeOutcome: "unknown" } : {}),
237
271
  connector: target.connector.id,
238
272
  operation: `${target.connector.id}.${target.toolName}`,
239
273
  uncertainCall: {
@@ -251,14 +285,35 @@ export class InvocationService {
251
285
  : " The arguments could not be echoed safely; use the exact arguments you sent."),
252
286
  };
253
287
  }
288
+ if (mayHaveWritten &&
289
+ (error.code === "auth_required" || error.code === "downstream_oauth_required") &&
290
+ !logicalCall?.sent.some((request) => request.dispatched)) {
291
+ // An empty resource ledger cannot settle this auth failure. Keep
292
+ // actual resource-refusal provenance, but withdraw an empty ledger's
293
+ // known mark before composing advice and counting program writes.
294
+ answered = false;
295
+ forgetProviderFailure(error);
296
+ }
297
+ // A dispatched write without refusal provenance is unknown whatever
298
+ // its connector's code says, a custom connector's included: never
299
+ // retryable, and no advice below may tell the agent to retry it.
300
+ const unknownWrite = mayHaveWritten && classifyWriteOutcome({ ok: false, dispatched: true, answered, error }) === "unknown";
301
+ if (unknownWrite)
302
+ error = { ...error, retryable: false, writeOutcome: "unknown" };
303
+ // The failure's advice to send it again was kept apart until now, and
304
+ // joins its message only where the outcome allows it: never on a write
305
+ // whose outcome is unknown, whatever redaction did to the message.
306
+ // Key-reuse advice also needs its key to protect the logical call.
307
+ else if (!settled) {
308
+ if (failureKeyAdvice && keyProtectsCall(logicalCall, failureKeyAdvice.key))
309
+ error = { ...error, message: withResendAdvice(error.message, failureKeyAdvice.advice) };
310
+ if (failureAdvice !== undefined)
311
+ error = { ...error, message: withResendAdvice(error.message, failureAdvice) };
312
+ }
254
313
  // Any other dispatched write whose outcome is unknown (a lost response
255
314
  // body, a 5xx, an unreadable reply) keeps the facts its connector
256
315
  // recorded before dispatch, here and through program write accounting.
257
- if (recovery &&
258
- !error.uncertainCall &&
259
- dispatchedToConnector &&
260
- resolved?.definition.classification === "write" &&
261
- classifyWriteOutcome({ ok: false, dispatched: true, answered, error }) === "unknown") {
316
+ if (recovery && !error.uncertainCall && unknownWrite) {
262
317
  const echoed = argumentEcho;
263
318
  error = {
264
319
  ...error,
@@ -274,11 +329,16 @@ export class InvocationService {
274
329
  if (error.code === "auth_required" && target.connector.startAuth) {
275
330
  error = { ...error, code: "downstream_oauth_required" };
276
331
  }
277
- const enteredWrite = resolved?.definition.classification === "write" && dispatchedToConnector;
278
332
  switch (error.code) {
279
333
  case "input_required_unsupported":
280
334
  if (context.processInputRequired)
281
335
  return error;
336
+ // Resending could apply the write twice: reconcile first.
337
+ if (unknownWrite)
338
+ return {
339
+ ...error,
340
+ retry: "Do not resend this write. Re-read its target to check whether it took effect before any fresh call.",
341
+ };
282
342
  return {
283
343
  ...error,
284
344
  nextAction: {
@@ -293,6 +353,8 @@ export class InvocationService {
293
353
  },
294
354
  };
295
355
  case "destructive_tool_requires_approval": {
356
+ if (settled)
357
+ return error;
296
358
  const echoed = argumentEcho;
297
359
  return {
298
360
  ...error,
@@ -318,17 +380,22 @@ export class InvocationService {
318
380
  connector: target.connector.id,
319
381
  operation: `${target.connector.id}.${target.toolName}`,
320
382
  recovery: recoveryMode(this.registry, target.connector, this.catalog.baseUrl),
321
- ...(enteredWrite ? { reconciliationRequired: true, retryable: false } : {}),
383
+ ...(unknownWrite ? { reconciliationRequired: true, retryable: false } : {}),
322
384
  nextAction: {
323
385
  tool: "authorize_connector",
324
386
  arguments: { connector: target.connector.id },
325
387
  operatorHandoff: "Give the URL and instructions it returns to the operator.",
326
388
  },
327
- retry: enteredWrite
389
+ retry: unknownWrite
328
390
  ? "This write may have partially run. Reconcile its target before retrying after the operator completes recovery."
329
- : `Retry ${target.connector.id}.${target.toolName} after the operator completes recovery.`,
391
+ : enteredWrite && logicalCall?.sent.some((request) => request.dispatched)
392
+ ? `Fix the credentials, then retry ${target.connector.id}.${target.toolName}.`
393
+ : `Retry ${target.connector.id}.${target.toolName} after the operator completes recovery.`,
330
394
  };
331
395
  case "provider_permission_denied":
396
+ // A write whose outcome is unknown is never told to retry.
397
+ if (error.writeOutcome === "unknown")
398
+ return error;
332
399
  return {
333
400
  ...error,
334
401
  connector: target.connector.id,
@@ -336,7 +403,7 @@ export class InvocationService {
336
403
  retry: "Ask the provider's resource owner or administrator to grant the required permission or scope, then retry. Repeating the call or reconnecting alone will not grant access.",
337
404
  };
338
405
  case "invalid_args":
339
- if (!error.validation)
406
+ if (!error.validation || error.writeOutcome === "unknown")
340
407
  return error;
341
408
  return {
342
409
  ...error,
@@ -354,13 +421,27 @@ export class InvocationService {
354
421
  };
355
422
  let stage = "catalog";
356
423
  const failed = (error) => {
424
+ // Q8 (settleWrite): this invocation's deadline or its caller cut off
425
+ // a write. No connector failure arrives, so the logical call's
426
+ // recorded requests alone decide whether a 401 left it unknown.
427
+ if (dispatchedToConnector &&
428
+ (resolved?.definition.classification !== "read" || sentSourceWrite()) &&
429
+ (error.code === "cancelled" || isTimeoutFailure(error))) {
430
+ const departed = settleWrite(logicalCall?.sent ?? [], undefined, true);
431
+ if (departed !== undefined) {
432
+ failureAdvice = failureKeyAdvice = undefined;
433
+ error = carryFailureFacts(departed, classifyWithoutAdvice(sentSecrets.redact(departed)));
434
+ }
435
+ }
357
436
  const diagnostics = timing();
358
437
  const target = resolved ?? activityTarget;
359
438
  if (target && (error.code === "auth_required" || error.code === "downstream_oauth_required")) {
360
- recordAuthFailure(this.catalog.requestScope, target.connector.id, (resolved?.definition.classification === "read" && resolved.classificationFresh === true) ||
439
+ recordAuthFailure(this.catalog.requestScope, target.connector.id, (resolved !== undefined && !isWriteLike(resolved.definition) && resolved.classificationFresh === true) ||
361
440
  preInvocationAuthFailure ||
362
441
  (!resolved && context.source === "call_tool"));
363
442
  }
443
+ // Read before any step below rebuilds the details: Q8's verdict is final.
444
+ const settled = isSettledWrite(error);
364
445
  // Attach host deadline facts before write recovery changes the code.
365
446
  if (isTimeoutFailure(error)) {
366
447
  const elapsedMs = Date.now() - started;
@@ -372,7 +453,7 @@ export class InvocationService {
372
453
  };
373
454
  }
374
455
  // Downstream diagnostics were redacted under payload rules where they entered.
375
- const details = sentSecrets.redact(enrich(error, target), "envelope");
456
+ const details = carryFailureFacts(error, sentSecrets.redact(enrich(error, target, settled), "envelope"));
376
457
  const outcome = () => ({
377
458
  ok: false,
378
459
  durationMs: Date.now() - started,
@@ -395,7 +476,7 @@ export class InvocationService {
395
476
  connector: target.connector.id,
396
477
  // Named only when the catalog listed it (src/operator-record.ts).
397
478
  tool: resolved?.definition,
398
- source: context.source,
479
+ source: context.activitySource ?? context.source,
399
480
  attempts,
400
481
  durationMs: Date.now() - started,
401
482
  // Every refusal reaching `failed` is one connecta built: a
@@ -449,6 +530,7 @@ export class InvocationService {
449
530
  argumentEcho = echoedCallArgs(args ?? {}, target.definition.inputSchema);
450
531
  sentSecrets.arguments(args ?? {}, target.definition.inputSchema);
451
532
  const write = target.definition.classification !== "read";
533
+ const writeLike = isWriteLike(target.definition);
452
534
  const canonicalAddress = `${target.connector.id}.${target.toolName}`;
453
535
  const input = context.source !== "execute_code"
454
536
  ? downstreamContinuation(this.catalog.requestScope, target.connector.id, canonicalAddress)
@@ -457,16 +539,18 @@ export class InvocationService {
457
539
  recordDownstreamArgumentEcho(this.catalog.requestScope, argumentEcho);
458
540
  const expectedDigest = replayClassificationDigest(this.catalog.requestScope, canonicalAddress);
459
541
  if (expectedDigest !== undefined &&
460
- (target.classificationFresh !== true ||
542
+ (writeLike ||
543
+ target.classificationFresh !== true ||
461
544
  (yield* Effect.promise(() => classificationDigest(target.definition))) !== expectedDigest)) {
462
545
  return {
463
546
  ...framingError("auth_replay_refused", "An entered read no longer has the same fresh classification. Reconcile its target before starting a new request."),
464
547
  reconciliationRequired: true,
465
548
  };
466
549
  }
467
- const refusal = writeRefusal(target.definition.classification, context.source, context.readOnly);
550
+ const connectorReadOnly = target.connector.readOnly === true;
551
+ const refusal = writeRefusal(target.definition.classification, context.source, context.readOnly || connectorReadOnly);
468
552
  if (refusal === "read_only_endpoint") {
469
- return framingError("read_only_endpoint", `Tool "${canonicalAddress}" is a write, and this endpoint is read-only. Nothing here can send it.`);
553
+ return framingError("read_only_endpoint", `Tool "${canonicalAddress}" is a write, and ${connectorReadOnly ? `connector "${target.connector.id}"` : "this endpoint"} is read-only. Nothing here can send it.`);
470
554
  }
471
555
  if (refusal === "destructive_tool_requires_approval") {
472
556
  return framingError("destructive_tool_requires_approval", `Tool "${canonicalAddress}" is a write. Invoke it through call_destructive_tool so the MCP host can request approval.`);
@@ -485,7 +569,8 @@ export class InvocationService {
485
569
  if (invalid)
486
570
  return classifyCallError(invalid);
487
571
  }
488
- if (write && context.beforeWrite) {
572
+ // Source writes keep program write accounting; only effective writes spend W10 budget.
573
+ if (writeLike && context.beforeWrite) {
489
574
  const decision = yield* context.beforeWrite(target, args ?? {});
490
575
  if (decision.kind === "refuse") {
491
576
  unrecorded = decision.unrecorded === true;
@@ -495,44 +580,71 @@ export class InvocationService {
495
580
  if (callSignal?.aborted)
496
581
  return yield* Effect.fail(callSignal.reason);
497
582
  attempts = 1;
498
- const call = async (permit) => {
499
- const connectorContext = this.registry.contextFor(target.connector.id, this.catalog.baseUrl, this.catalog.requestScope, defined({ signal: callSignal, timeoutMs: context.timeoutMs, defer: this.catalog.defer }));
500
- attachCallAdmission(connectorContext, permit);
501
- trackCredentialReads(connectorContext);
583
+ const call = (permit) => Effect.gen({ self: this }, function* () {
584
+ const operationContext = this.registry.contextFor(target.connector.id, this.catalog.baseUrl, this.catalog.requestScope, defined({ signal: callSignal, timeoutMs: context.timeoutMs, defer: this.catalog.defer }));
585
+ const lease = callFromContext(operationContext, write ? "write" : "read", {
586
+ admitted: true,
587
+ // An invocation deadline aborts when its call finishes. A
588
+ // request-owned auxiliary must retain only request cancellation.
589
+ requestSourceSignal: context.requestSignal,
590
+ served: write ? "write" : "read",
591
+ charge: (signal) => runEdge(chargeCallBudget(permit, signal)),
592
+ chargeEffect: (signal) => chargeCallBudget(permit, signal),
593
+ chargeClosed: () => new CallAdmissionError("closed", "connector_call_failed", "This call has ended; its admission permit can no longer be charged."),
594
+ record: (facts) => recordRecoveryFacts(recoveryState, facts),
595
+ });
596
+ yield* Effect.addFinalizer(() => Effect.sync(lease.close));
597
+ const connectorContext = contextView(lease, operationContext);
502
598
  sentSecrets.include(sentSecretsFor(connectorContext));
503
- dispatchContext = connectorContext;
504
- try {
599
+ // The one object and function this call invokes, read once: its
600
+ // logical call, auth check, and dispatch all name them, so a
601
+ // connector that reassigns its own callTool mid-call changes none.
602
+ const connector = target.connector;
603
+ const callTool = connector.callTool;
604
+ logicalCall = openLogicalCall(connectorContext, connector, callTool);
605
+ yield* Effect.gen(function* () {
505
606
  if (target.connector.credential) {
506
607
  if (!connectorContext.credential) {
507
608
  throw new ConnectorCallError("auth_required", "Operator-managed credential storage is not configured. Call " +
508
609
  `authorize_connector({ connector: "${target.connector.id}" }).`);
509
610
  }
510
- if (!(await connectorContext.credential.getAll())) {
611
+ if (!(yield* Context.get(lease.services, Credentials).values)) {
511
612
  throw new ConnectorCallError("auth_required", `Connector "${target.connector.id}" has no stored credential. Call authorize_connector.`);
512
613
  }
513
614
  }
514
- await resolveInvocationAuth(target.connector, connectorContext);
515
- }
516
- catch (error) {
517
- const code = classifyCallError(error).code;
615
+ yield* resolveInvocationAuthEffect(connector, callTool, connectorContext);
616
+ }).pipe(Effect.onError((cause) => Effect.sync(() => {
617
+ const code = classifyCallError(causeError(cause, connectorContext.signal)).code;
518
618
  preInvocationAuthFailure = code === "auth_required" || code === "downstream_oauth_required";
519
- throw error;
520
- }
619
+ })));
521
620
  // Cancellation can arrive during admission or context construction.
522
621
  if (admissionSignal?.aborted)
523
622
  throw admissionSignal.reason;
524
623
  dispatchedToConnector = true;
525
624
  recordCallEntry(this.catalog.requestScope, {
526
625
  address: canonicalAddress,
527
- classification: write ? "write" : "read",
626
+ classification: writeLike ? "write" : "read",
528
627
  fresh: target.classificationFresh === true,
529
628
  }, target.definition);
530
- return await target.connector.callTool(target.toolName, args ?? {}, connectorContext,
531
- // The connector may retain or mutate its definition. Keep the
532
- // invocation's classification and schema private, even during
533
- // this call, and give every dispatch its own deep copy.
534
- { definition: structuredClone(target.definition), ...defined({ input }) });
535
- };
629
+ // Reflect.apply, never the function's own `call` or `apply`
630
+ // property, which anyone holding the function could replace.
631
+ const options = { definition: cloneTool(target.definition), ...defined({ input }) };
632
+ const entry = callEntry(connector, callTool);
633
+ if (entry)
634
+ return yield* entry(target.toolName, args ?? {}, options).pipe(Effect.provideContext(viewServices(connectorContext)));
635
+ return yield* Effect.tryPromise({
636
+ try: () => Reflect.apply(callTool, connector, [
637
+ target.toolName,
638
+ args ?? {},
639
+ connectorContext,
640
+ // The connector may retain or mutate its definition. Keep the
641
+ // invocation's classification and schema private, even during
642
+ // this call, and give every dispatch its own deep copy.
643
+ options,
644
+ ]),
645
+ catch: (error) => error,
646
+ });
647
+ });
536
648
  // The permit belongs to this scope, so success, failure, and the
537
649
  // deadline's interruption all release it. Interruption stops the
538
650
  // wait instead of waiting for the connector, so an uncooperative one
@@ -545,17 +657,16 @@ export class InvocationService {
545
657
  stage = "downstream";
546
658
  const reply = yield* timed((elapsed) => {
547
659
  connectorMs += elapsed;
548
- }, Effect.tryPromise({
549
- try: () => Promise.resolve(call(permit)),
550
- catch: (error) => error,
551
- }));
660
+ }, call(permit));
552
661
  if (target.connector.kind === "mcp" && isDownstreamInputResult(reply)) {
662
+ // The downstream suspended for input. A handler asks for
663
+ // input from inside its run, so a write may already have
664
+ // applied: only a read's suspension is a known answer.
553
665
  if (!context.processInputRequired)
554
- throw new ConnectorCallError("input_required_unsupported", "The downstream returned input_required. Use the equivalent direct MCP call to provide input.");
555
- const value = yield* Effect.tryPromise({
556
- try: () => Promise.resolve(context.processInputRequired(reply, target, sentSecrets)),
557
- catch: (error) => error,
558
- });
666
+ throw write
667
+ ? new ConnectorCallError("input_required_unsupported", "The downstream returned input_required after this write was sent, and this call cannot provide input. Whether the write took effect is unknown.", { writeOutcome: "unknown" })
668
+ : knownProviderFailure(new ConnectorCallError("input_required_unsupported", "The downstream returned input_required. Use the equivalent direct MCP call to provide input."));
669
+ const value = yield* authCall(context.processInputRequired, [reply, target, sentSecrets]);
559
670
  return { inputRequired: true, value };
560
671
  }
561
672
  assertDownstreamOutputSafe(this.catalog.requestScope, reply);
@@ -571,11 +682,23 @@ export class InvocationService {
571
682
  return yield* Effect.fail(callSignal.reason);
572
683
  if (!dispatchedToConnector && admissionSignal?.aborted)
573
684
  return callerCancelledDetails();
574
- const attemptError = Cause.squash(attempt.cause);
575
- answered = answeredFailure(attemptError);
576
- return isCallerCancellation(attemptError, context.requestSignal)
577
- ? callerCancelledDetails()
578
- : carryFailureFacts(attemptError, classifyCallError(sentSecrets.redact(attemptError)));
685
+ const thrown = Cause.squash(attempt.cause);
686
+ if (isCallerCancellation(thrown, context.requestSignal))
687
+ return callerCancelledDetails();
688
+ const failureWrite = write || sentSourceWrite();
689
+ answered = answeredFailure(thrown, failureWrite, logicalCall);
690
+ // Q8 is decided here for every served write, whatever its
691
+ // connector made of the 401: over the logical call's whole ledger.
692
+ const attemptError = failureWrite ? settleWrite(logicalCall?.sent ?? [], thrown, answered) : thrown;
693
+ if (attemptError !== thrown)
694
+ answered = false;
695
+ failureAdvice = resendAdviceOf(attemptError);
696
+ failureKeyAdvice = keyResendAdviceOf(attemptError);
697
+ const details = carryFailureFacts(attemptError, classifyWithoutAdvice(sentSecrets.redact(attemptError)));
698
+ // An inner call's verdict that does not hold for this one is withdrawn.
699
+ if (failureWrite && !answered)
700
+ forgetProviderFailure(details);
701
+ return details;
579
702
  }
580
703
  if ("inputRequired" in attempt.value) {
581
704
  inputRequiredValue = { value: attempt.value.value };
@@ -612,9 +735,11 @@ export class InvocationService {
612
735
  : dispatch());
613
736
  if (Exit.isFailure(dispatched)) {
614
737
  const failure = Cause.squash(dispatched.cause);
738
+ failureAdvice = resendAdviceOf(failure);
739
+ failureKeyAdvice = keyResendAdviceOf(failure);
615
740
  const details = context.requestSignal?.aborted
616
741
  ? callerCancelledDetails()
617
- : carryFailureFacts(failure, classifyCallError(sentSecrets.redact(failure)));
742
+ : carryFailureFacts(failure, classifyWithoutAdvice(sentSecrets.redact(failure)));
618
743
  return failed(details);
619
744
  }
620
745
  if (dispatched.value)
@@ -624,14 +749,21 @@ export class InvocationService {
624
749
  if (!completed) {
625
750
  return yield* Effect.die(new Error("Invocation completed without a resolved tool"));
626
751
  }
752
+ // Q8 settles a result too: a write an undeclared 401 left unknown is no
753
+ // success, whatever its handler made of the 401, and its result is not
754
+ // processed.
755
+ if (dispatchedToConnector && (completed.definition.classification !== "read" || sentSourceWrite())) {
756
+ const unknown = settleWriteResult(logicalCall?.sent ?? []);
757
+ if (unknown) {
758
+ failureAdvice = failureKeyAdvice = undefined;
759
+ return failed(carryFailureFacts(unknown, classifyWithoutAdvice(sentSecrets.redact(unknown))));
760
+ }
761
+ }
627
762
  const processResult = context.processResult;
628
763
  const processing = inputRequiredValue
629
764
  ? Effect.succeed(inputRequiredValue.value)
630
765
  : processResult
631
- ? Effect.tryPromise({
632
- try: () => Promise.resolve(processResult(sentSecrets.redact(result), completed, sentSecrets, valueFormat, rawResult)),
633
- catch: (error) => error,
634
- })
766
+ ? authCall(processResult, [sentSecrets.redact(result), completed, sentSecrets, valueFormat, rawResult])
635
767
  : Effect.succeed(result);
636
768
  const processed = yield* Effect.exit(timed((elapsed) => {
637
769
  resultProcessingMs += elapsed;
@@ -670,9 +802,11 @@ export class InvocationService {
670
802
  }
671
803
  }).pipe(Effect.flatMap((outcome) => outcome.ok
672
804
  ? Effect.succeed(outcome)
673
- : Effect.promise(async () => ({
674
- ...outcome,
675
- error: await withAuthorizationHandoff(this.catalog.requestScope, outcome.error),
676
- }))));
805
+ : withAuthorizationHandoffEffect(this.catalog.requestScope, outcome.error).pipe(Effect.map((error) => ({ ...outcome, error })))));
677
806
  }
807
+ static nativePrograms = /* @__PURE__ */ (() => {
808
+ registerAuthMethod(InvocationService.prototype, "invoke", function (address, args, context) {
809
+ return this.pipeline(address, args, context);
810
+ }, InvocationService.prototype.invoke);
811
+ })();
678
812
  }