@zackbart/connecta 0.34.1 → 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 (429) hide show
  1. package/CHANGELOG.md +363 -0
  2. package/README.md +62 -106
  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 +12 -7
  53. package/dist/connectors/api-connector.js +142 -56
  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/remote-mcp.d.ts +10 -30
  58. package/dist/connectors/remote-mcp.js +955 -563
  59. package/dist/d1.js +10 -243
  60. package/dist/derived-context.js +5 -0
  61. package/dist/describe-config.d.ts +3 -1
  62. package/dist/describe-config.js +2 -0
  63. package/dist/downstream-input.js +347 -260
  64. package/dist/errors.d.ts +87 -6
  65. package/dist/errors.js +114 -4
  66. package/dist/execute.js +87 -50
  67. package/dist/executor-admission.js +3 -0
  68. package/dist/executors/quickjs.js +163 -112
  69. package/dist/guarded-transport.js +50 -0
  70. package/dist/guest-runtime.js +1 -1
  71. package/dist/http/client.js +439 -0
  72. package/dist/http/errors.js +558 -0
  73. package/dist/http/fields.js +49 -0
  74. package/dist/http/hatch-paging.js +318 -0
  75. package/dist/http/hatch.js +1279 -0
  76. package/dist/http/json-schema.js +267 -0
  77. package/dist/http/node-transport.js +241 -0
  78. package/dist/http/oauth.js +162 -0
  79. package/dist/http/paging.js +228 -0
  80. package/dist/http/provider.js +221 -0
  81. package/dist/http/safety.js +82 -0
  82. package/dist/http/services.js +79 -0
  83. package/dist/http/tools.js +383 -0
  84. package/dist/http/vendor-index.js +138 -0
  85. package/dist/http/vendor.js +448 -0
  86. package/dist/http/write-request.js +66 -0
  87. package/dist/http-policy.d.ts +11 -0
  88. package/dist/http-policy.js +45 -0
  89. package/dist/inbound-credential.js +1 -1
  90. package/dist/index.d.ts +2 -2
  91. package/dist/index.js +4 -0
  92. package/dist/invocation-auth.js +30 -19
  93. package/dist/invocation.js +218 -85
  94. package/dist/mcp-result.js +0 -4
  95. package/dist/membership.d.ts +4 -0
  96. package/dist/meta-output.js +1 -1
  97. package/dist/meta-tools.js +531 -406
  98. package/dist/native-recovery.js +52 -0
  99. package/dist/native-tools.js +382 -0
  100. package/dist/node.d.ts +4 -3
  101. package/dist/node.js +45 -8
  102. package/dist/oauth-handoff.js +177 -104
  103. package/dist/oauth-partition.js +6 -20
  104. package/dist/oauth-sealing.js +6 -7
  105. package/dist/operation-vocabulary.js +101 -0
  106. package/dist/operator-record.d.ts +2 -2
  107. package/dist/operator-record.js +17 -4
  108. package/dist/operator-ui/agents.d.ts +5 -4
  109. package/dist/operator-ui/agents.js +17 -7
  110. package/dist/operator-ui/config-summary.js +5 -4
  111. package/dist/operator-ui/connection-map.js +7 -5
  112. package/dist/operator-ui/contract.d.ts +7 -3
  113. package/dist/operator-ui/endpoints.js +4 -13
  114. package/dist/operator-ui/fix-prompts.d.ts +1 -1
  115. package/dist/operator-ui/fix-prompts.js +0 -8
  116. package/dist/operator-ui/generated.js +3 -3
  117. package/dist/operator-ui/model.d.ts +2 -3
  118. package/dist/operator-ui/overview.js +5 -2
  119. package/dist/operator-ui/setup-commands.js +0 -4
  120. package/dist/operator-ui/view.d.ts +2 -25
  121. package/dist/operator-ui/view.js +2 -76
  122. package/dist/program-writes.js +47 -26
  123. package/dist/provider-call-facts.d.ts +115 -0
  124. package/dist/provider-call-facts.js +182 -0
  125. package/dist/provider-call.d.ts +112 -0
  126. package/dist/provider-call.js +271 -0
  127. package/dist/provider.d.ts +65 -31
  128. package/dist/provider.js +116 -39
  129. package/dist/providers/_shared/google/hatch.js +91 -0
  130. package/dist/providers/_shared/google/kit.js +537 -0
  131. package/dist/providers/_shared/google/result-size.js +15 -2
  132. package/dist/providers/_shared/google/service-account.d.ts +2 -1
  133. package/dist/providers/_shared/google/service-account.js +8 -4
  134. package/dist/providers/_shared/google/workspace.d.ts +6 -210
  135. package/dist/providers/_shared/google/workspace.js +6 -425
  136. package/dist/providers/_shared/rest/compact-index.js +86 -0
  137. package/dist/providers/_shared/rest/dispatch.js +3 -23
  138. package/dist/providers/_shared/rest/kit.js +546 -0
  139. package/dist/providers/_shared/rest/operation-index.js +230 -14
  140. package/dist/providers/_shared/rest/response-media.js +11 -0
  141. package/dist/providers/_shared/rest/tools.js +101 -78
  142. package/dist/providers/_shared/rest/value-safety.js +353 -195
  143. package/dist/providers/_shared/sensitive-fields.js +27 -0
  144. package/dist/providers/breeze/api.js +584 -0
  145. package/dist/providers/breeze/index.d.ts +1 -3
  146. package/dist/providers/breeze/index.js +67 -1420
  147. package/dist/providers/breeze/openapi.generated.js +60 -0
  148. package/dist/providers/breeze/skill.generated.js +2 -6
  149. package/dist/providers/breeze/tools.js +696 -0
  150. package/dist/providers/ccb/api.js +496 -0
  151. package/dist/providers/ccb/index.d.ts +15 -37
  152. package/dist/providers/ccb/index.js +77 -1702
  153. package/dist/providers/ccb/lib/constants.d.ts +34 -0
  154. package/dist/providers/ccb/lib/constants.js +74 -0
  155. package/dist/providers/ccb/lib/guide.js +9 -0
  156. package/dist/providers/ccb/lib/verdicts.js +387 -0
  157. package/dist/providers/ccb/openapi.generated.js +397 -0
  158. package/dist/providers/ccb/safety.js +295 -0
  159. package/dist/providers/ccb/skill.generated.js +2 -6
  160. package/dist/providers/ccb/tools.js +853 -0
  161. package/dist/providers/cloudflare/api.js +1066 -0
  162. package/dist/providers/cloudflare/index.d.ts +5 -22
  163. package/dist/providers/cloudflare/index.js +79 -197
  164. package/dist/providers/cloudflare/lib/config.d.ts +16 -0
  165. package/dist/providers/cloudflare/lib/config.js +2 -0
  166. package/dist/providers/cloudflare/lib/discovery.js +29 -0
  167. package/dist/providers/cloudflare/{graphql.js → lib/graphql.js} +1 -1
  168. package/dist/providers/cloudflare/lib/hatch.js +103 -0
  169. package/dist/providers/cloudflare/lib/path-bounds.js +28 -0
  170. package/dist/providers/cloudflare/lib/response-media.js +75 -0
  171. package/dist/providers/cloudflare/openapi.generated.js +4 -3
  172. package/dist/providers/cloudflare/{value-safety.js → safety.js} +487 -0
  173. package/dist/providers/cloudflare/skill.generated.js +2 -10
  174. package/dist/providers/cloudflare/tools.js +360 -0
  175. package/dist/providers/docs/api.js +51 -0
  176. package/dist/providers/docs/index.d.ts +1 -12
  177. package/dist/providers/docs/index.js +53 -1165
  178. package/dist/providers/docs/lib/constants.d.ts +18 -0
  179. package/dist/providers/docs/lib/constants.js +18 -0
  180. package/dist/providers/docs/lib/discovery.js +26 -0
  181. package/dist/providers/docs/lib/requests.js +48 -0
  182. package/dist/providers/docs/lib/schemas.js +168 -0
  183. package/dist/providers/docs/openapi.generated.js +16 -0
  184. package/dist/providers/docs/safety.js +54 -0
  185. package/dist/providers/docs/skill.generated.js +2 -6
  186. package/dist/providers/docs/tools.js +802 -0
  187. package/dist/providers/drive/api.js +177 -0
  188. package/dist/providers/drive/index.d.ts +1 -12
  189. package/dist/providers/drive/index.js +38 -1448
  190. package/dist/providers/drive/lib/constants.d.ts +6 -0
  191. package/dist/providers/drive/lib/constants.js +6 -0
  192. package/dist/providers/drive/lib/contracts.js +532 -0
  193. package/dist/providers/drive/lib/hatch.js +197 -0
  194. package/dist/providers/drive/openapi.generated.js +77 -0
  195. package/dist/providers/drive/safety.js +90 -0
  196. package/dist/providers/drive/skill.generated.js +2 -6
  197. package/dist/providers/drive/tools.js +1290 -0
  198. package/dist/providers/forms/api.js +71 -0
  199. package/dist/providers/forms/index.d.ts +1 -12
  200. package/dist/providers/forms/index.js +49 -1145
  201. package/dist/providers/forms/lib/constants.d.ts +14 -0
  202. package/dist/providers/forms/lib/constants.js +19 -0
  203. package/dist/providers/forms/lib/hatch.js +72 -0
  204. package/dist/providers/forms/openapi.generated.js +23 -0
  205. package/dist/providers/forms/safety.js +34 -0
  206. package/dist/providers/forms/skill.generated.js +2 -8
  207. package/dist/providers/forms/tools.js +1024 -0
  208. package/dist/providers/github/api.js +150 -0
  209. package/dist/providers/github/index.d.ts +4 -5
  210. package/dist/providers/github/index.js +30 -87
  211. package/dist/providers/github/{auth.d.ts → lib/auth.d.ts} +5 -3
  212. package/dist/providers/github/{auth.js → lib/auth.js} +40 -43
  213. package/dist/providers/github/lib/discovery.js +132 -0
  214. package/dist/providers/github/lib/operations.js +58 -0
  215. package/dist/providers/github/{scope.d.ts → lib/scope.d.ts} +2 -0
  216. package/dist/providers/github/{scope.js → lib/scope.js} +25 -1
  217. package/dist/providers/github/openapi.generated.js +1216 -0
  218. package/dist/providers/github/safety.js +216 -0
  219. package/dist/providers/github/skill.generated.js +2 -5
  220. package/dist/providers/github/tools.js +506 -0
  221. package/dist/providers/gmail/api.js +114 -0
  222. package/dist/providers/gmail/index.d.ts +1 -12
  223. package/dist/providers/gmail/index.js +73 -1621
  224. package/dist/providers/gmail/lib/constants.d.ts +13 -0
  225. package/dist/providers/gmail/lib/constants.js +16 -0
  226. package/dist/providers/gmail/lib/index.js +173 -0
  227. package/dist/providers/gmail/lib/schemas.js +176 -0
  228. package/dist/providers/gmail/lib/threading.js +120 -0
  229. package/dist/providers/gmail/openapi.generated.js +92 -0
  230. package/dist/providers/gmail/safety.js +21 -0
  231. package/dist/providers/gmail/skill.generated.js +2 -6
  232. package/dist/providers/gmail/tools.js +1435 -0
  233. package/dist/providers/overflow/api.js +1008 -0
  234. package/dist/providers/overflow/index.d.ts +1 -17
  235. package/dist/providers/overflow/index.js +60 -1488
  236. package/dist/providers/overflow/skill.generated.js +2 -5
  237. package/dist/providers/overflow/tools.js +873 -0
  238. package/dist/providers/planning-center/api.js +467 -0
  239. package/dist/providers/planning-center/index.d.ts +4 -35
  240. package/dist/providers/planning-center/index.js +69 -2445
  241. package/dist/providers/planning-center/lib/constants.d.ts +58 -0
  242. package/dist/providers/planning-center/lib/constants.js +83 -0
  243. package/dist/providers/planning-center/lib/discovery.js +40 -0
  244. package/dist/providers/planning-center/lib/guide.js +39 -0
  245. package/dist/providers/planning-center/lib/json-api.js +83 -0
  246. package/dist/providers/planning-center/lib/verdicts.js +1758 -0
  247. package/dist/providers/planning-center/openapi.generated.js +1764 -0
  248. package/dist/providers/planning-center/safety.js +188 -0
  249. package/dist/providers/planning-center/skill.generated.js +2 -27
  250. package/dist/providers/planning-center/tools.js +1010 -0
  251. package/dist/providers/sheets/api.js +133 -0
  252. package/dist/providers/sheets/index.d.ts +4 -16
  253. package/dist/providers/sheets/index.js +61 -1172
  254. package/dist/providers/sheets/lib/constants.d.ts +14 -0
  255. package/dist/providers/sheets/lib/constants.js +14 -0
  256. package/dist/providers/sheets/lib/hatch.js +163 -0
  257. package/dist/providers/sheets/lib/requests.js +105 -0
  258. package/dist/providers/sheets/lib/schemas.js +138 -0
  259. package/dist/providers/sheets/openapi.generated.js +30 -0
  260. package/dist/providers/sheets/safety.js +27 -0
  261. package/dist/providers/sheets/skill.generated.js +2 -7
  262. package/dist/providers/sheets/tools.js +734 -0
  263. package/dist/providers/slides/api.js +147 -0
  264. package/dist/providers/slides/index.d.ts +2 -10
  265. package/dist/providers/slides/index.js +48 -2555
  266. package/dist/providers/slides/lib/constants.d.ts +11 -0
  267. package/dist/providers/slides/lib/constants.js +11 -0
  268. package/dist/providers/slides/lib/requests.js +60 -0
  269. package/dist/providers/slides/lib/schemas.js +565 -0
  270. package/dist/providers/slides/openapi.generated.js +18 -0
  271. package/dist/providers/slides/skill.generated.js +2 -6
  272. package/dist/providers/slides/tools.js +1968 -0
  273. package/dist/providers/stripe/api.js +401 -0
  274. package/dist/providers/stripe/index.d.ts +5 -27
  275. package/dist/providers/stripe/index.js +74 -210
  276. package/dist/providers/stripe/lib/config.d.ts +4 -0
  277. package/dist/providers/stripe/lib/config.js +2 -0
  278. package/dist/providers/stripe/openapi.generated.js +4 -3
  279. package/dist/providers/stripe/{value-safety.js → safety.js} +5 -5
  280. package/dist/providers/stripe/skill.generated.js +2 -11
  281. package/dist/providers/stripe/tools.js +77 -0
  282. package/dist/providers/tithely/api.js +531 -0
  283. package/dist/providers/tithely/index.d.ts +17 -0
  284. package/dist/providers/tithely/index.js +86 -965
  285. package/dist/providers/tithely/skill.generated.js +2 -5
  286. package/dist/providers/tithely/tools.js +426 -0
  287. package/dist/providers/vercel/api.js +551 -0
  288. package/dist/providers/vercel/index.d.ts +9 -25
  289. package/dist/providers/vercel/index.js +66 -260
  290. package/dist/providers/vercel/lib/config.d.ts +2 -0
  291. package/dist/providers/vercel/lib/config.js +2 -0
  292. package/dist/providers/vercel/lib/index.js +117 -0
  293. package/dist/providers/vercel/lib/logs.js +100 -0
  294. package/dist/providers/vercel/lib/pin.js +270 -0
  295. package/dist/providers/vercel/openapi.generated.js +10 -5
  296. package/dist/providers/vercel/{value-safety.js → safety.js} +247 -38
  297. package/dist/providers/vercel/skill.generated.js +2 -7
  298. package/dist/providers/vercel/tools.js +642 -0
  299. package/dist/redaction-identity.js +47 -0
  300. package/dist/redaction-marker.js +125 -0
  301. package/dist/registry.d.ts +21 -15
  302. package/dist/registry.js +409 -376
  303. package/dist/routes/access-tokens.js +1 -1
  304. package/dist/routes/actor-labels.js +1 -1
  305. package/dist/routes/connect.js +1 -1
  306. package/dist/routes/dispatch.js +103 -0
  307. package/dist/routes/mcp.js +170 -79
  308. package/dist/routes/oauth.js +3 -1
  309. package/dist/routes/operator.js +2 -2
  310. package/dist/routes/shared.d.ts +5 -4
  311. package/dist/routes/shared.js +244 -177
  312. package/dist/routes/skills.js +10 -8
  313. package/dist/routes/ui-config.js +27 -3
  314. package/dist/routes/ui-data.js +21 -20
  315. package/dist/routes/ui.js +1 -1
  316. package/dist/runtime/call-admission.js +0 -26
  317. package/dist/runtime/call-entry.js +30 -0
  318. package/dist/runtime/call.js +556 -0
  319. package/dist/runtime/connector-scope.js +7 -0
  320. package/dist/runtime/credential-probe.js +34 -0
  321. package/dist/runtime/executor.js +40 -0
  322. package/dist/runtime/native-storage.js +63 -0
  323. package/dist/runtime/registry.js +27 -0
  324. package/dist/runtime/request-scope.js +72 -0
  325. package/dist/runtime/run.js +15 -7
  326. package/dist/runtime/shared-read.js +34 -5
  327. package/dist/runtime/storage.js +34 -21
  328. package/dist/sent-secrets.d.ts +194 -37
  329. package/dist/sent-secrets.js +1743 -340
  330. package/dist/server.js +5 -56
  331. package/dist/skills.js +322 -222
  332. package/dist/sqlite.js +15 -14
  333. package/dist/storage/d1-copy.js +255 -0
  334. package/dist/storage/d1-driver.js +15 -0
  335. package/dist/storage/keys.js +28 -0
  336. package/dist/storage/sql-driver.js +88 -0
  337. package/dist/storage/sql-native.js +544 -0
  338. package/dist/storage/sql-schema.d.ts +6 -0
  339. package/dist/storage/sql-schema.js +15 -0
  340. package/dist/storage/sql.d.ts +14 -20
  341. package/dist/storage/sql.js +29 -535
  342. package/dist/timeout.js +0 -26
  343. package/dist/tool-safety.js +20 -10
  344. package/dist/types.d.ts +7 -109
  345. package/dist/upward.js +3 -0
  346. package/dist/usage-guide.js +3 -1
  347. package/dist/validate.d.ts +4 -2
  348. package/dist/validate.js +86 -9
  349. package/dist/version.d.ts +1 -1
  350. package/dist/version.js +1 -1
  351. package/dist/worker.js +312 -292
  352. package/dist/workspace-subject.js +5 -1
  353. package/dist/write-outcome.js +454 -34
  354. package/documentation/README.md +27 -7
  355. package/documentation/architecture.md +2547 -226
  356. package/documentation/auth.md +821 -98
  357. package/documentation/code-mode.md +49 -16
  358. package/documentation/deploying.md +164 -20
  359. package/documentation/hosted-mcp-migration.md +460 -0
  360. package/documentation/integrating.md +129 -144
  361. package/documentation/meta-tools.md +409 -32
  362. package/documentation/operating.md +27 -3
  363. package/documentation/operator-tests.md +3 -0
  364. package/documentation/operator-ui.md +68 -45
  365. package/documentation/provider-auth-migration.md +16 -63
  366. package/documentation/provider-migration-0.29.md +10 -5
  367. package/documentation/provider-migration-0.35.md +975 -0
  368. package/documentation/providers.md +965 -0
  369. package/examples/worker/AGENTS.md +23 -9
  370. package/examples/worker/README.md +254 -135
  371. package/examples/worker/alchemy.run.ts +116 -0
  372. package/examples/worker/gitignore +10 -0
  373. package/examples/worker/src/connecta.config.ts +23 -21
  374. package/examples/worker/wrangler.jsonc +14 -5
  375. package/guides/connecting-agents.md +157 -0
  376. package/guides/how-it-works.md +156 -0
  377. package/guides/safety-and-trust.md +153 -0
  378. package/package.json +27 -46
  379. package/templates/node/.env.example +3 -0
  380. package/templates/node/README.md +22 -2
  381. package/templates/node/docker-compose.yml +1 -0
  382. package/templates/node/package.json +3 -2
  383. package/templates/node/src/connecta.config.ts +8 -0
  384. package/dist/catalog-drift.d.ts +0 -138
  385. package/dist/catalog-drift.js +0 -578
  386. package/dist/providers/_shared/request-token.js +0 -83
  387. package/dist/providers/_shared/rest/operation-index.d.ts +0 -133
  388. package/dist/providers/_shared/rest/tools.d.ts +0 -141
  389. package/dist/providers/_shared/rest/value-safety.d.ts +0 -201
  390. package/dist/providers/basecamp/index.d.ts +0 -45
  391. package/dist/providers/basecamp/index.js +0 -997
  392. package/dist/providers/basecamp/skill.generated.js +0 -9
  393. package/dist/providers/cloudflare/rest.d.ts +0 -37
  394. package/dist/providers/cloudflare/rest.js +0 -1097
  395. package/dist/providers/github/hosted.js +0 -218
  396. package/dist/providers/github/rest.js +0 -321
  397. package/dist/providers/infisical/index.d.ts +0 -7
  398. package/dist/providers/infisical/index.js +0 -713
  399. package/dist/providers/infisical/skill.generated.js +0 -8
  400. package/dist/providers/intercom/index.d.ts +0 -24
  401. package/dist/providers/intercom/index.js +0 -121
  402. package/dist/providers/intercom/skill.generated.js +0 -8
  403. package/dist/providers/linear/index.d.ts +0 -55
  404. package/dist/providers/linear/index.js +0 -537
  405. package/dist/providers/linear/skill.generated.js +0 -8
  406. package/dist/providers/mixpanel/index.d.ts +0 -59
  407. package/dist/providers/mixpanel/index.js +0 -472
  408. package/dist/providers/mixpanel/operations.js +0 -20
  409. package/dist/providers/mixpanel/rest.js +0 -603
  410. package/dist/providers/mixpanel/skill.generated.js +0 -10
  411. package/dist/providers/mixpanel/value-safety.js +0 -16
  412. package/dist/providers/notion/index.d.ts +0 -67
  413. package/dist/providers/notion/index.js +0 -368
  414. package/dist/providers/notion/openapi.generated.js +0 -75
  415. package/dist/providers/notion/rest.d.ts +0 -24
  416. package/dist/providers/notion/rest.js +0 -1226
  417. package/dist/providers/notion/skill.generated.js +0 -11
  418. package/dist/providers/notion/value-safety.js +0 -56
  419. package/dist/providers/revenuecat/index.d.ts +0 -51
  420. package/dist/providers/revenuecat/index.js +0 -697
  421. package/dist/providers/revenuecat/skill.generated.js +0 -11
  422. package/dist/providers/stripe/rest.d.ts +0 -14
  423. package/dist/providers/stripe/rest.js +0 -402
  424. package/dist/providers/vercel/rest.d.ts +0 -20
  425. package/dist/providers/vercel/rest.js +0 -1020
  426. package/dist/providers/wispr-flow/index.d.ts +0 -14
  427. package/dist/providers/wispr-flow/index.js +0 -117
  428. package/dist/providers/wispr-flow/skill.generated.js +0 -8
  429. /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,7 +539,8 @@ 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."),
@@ -486,7 +569,8 @@ export class InvocationService {
486
569
  if (invalid)
487
570
  return classifyCallError(invalid);
488
571
  }
489
- if (write && context.beforeWrite) {
572
+ // Source writes keep program write accounting; only effective writes spend W10 budget.
573
+ if (writeLike && context.beforeWrite) {
490
574
  const decision = yield* context.beforeWrite(target, args ?? {});
491
575
  if (decision.kind === "refuse") {
492
576
  unrecorded = decision.unrecorded === true;
@@ -496,44 +580,71 @@ export class InvocationService {
496
580
  if (callSignal?.aborted)
497
581
  return yield* Effect.fail(callSignal.reason);
498
582
  attempts = 1;
499
- const call = async (permit) => {
500
- const connectorContext = this.registry.contextFor(target.connector.id, this.catalog.baseUrl, this.catalog.requestScope, defined({ signal: callSignal, timeoutMs: context.timeoutMs, defer: this.catalog.defer }));
501
- attachCallAdmission(connectorContext, permit);
502
- 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);
503
598
  sentSecrets.include(sentSecretsFor(connectorContext));
504
- dispatchContext = connectorContext;
505
- 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* () {
506
606
  if (target.connector.credential) {
507
607
  if (!connectorContext.credential) {
508
608
  throw new ConnectorCallError("auth_required", "Operator-managed credential storage is not configured. Call " +
509
609
  `authorize_connector({ connector: "${target.connector.id}" }).`);
510
610
  }
511
- if (!(await connectorContext.credential.getAll())) {
611
+ if (!(yield* Context.get(lease.services, Credentials).values)) {
512
612
  throw new ConnectorCallError("auth_required", `Connector "${target.connector.id}" has no stored credential. Call authorize_connector.`);
513
613
  }
514
614
  }
515
- await resolveInvocationAuth(target.connector, connectorContext);
516
- }
517
- catch (error) {
518
- 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;
519
618
  preInvocationAuthFailure = code === "auth_required" || code === "downstream_oauth_required";
520
- throw error;
521
- }
619
+ })));
522
620
  // Cancellation can arrive during admission or context construction.
523
621
  if (admissionSignal?.aborted)
524
622
  throw admissionSignal.reason;
525
623
  dispatchedToConnector = true;
526
624
  recordCallEntry(this.catalog.requestScope, {
527
625
  address: canonicalAddress,
528
- classification: write ? "write" : "read",
626
+ classification: writeLike ? "write" : "read",
529
627
  fresh: target.classificationFresh === true,
530
628
  }, target.definition);
531
- return await target.connector.callTool(target.toolName, args ?? {}, connectorContext,
532
- // The connector may retain or mutate its definition. Keep the
533
- // invocation's classification and schema private, even during
534
- // this call, and give every dispatch its own deep copy.
535
- { definition: structuredClone(target.definition), ...defined({ input }) });
536
- };
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
+ });
537
648
  // The permit belongs to this scope, so success, failure, and the
538
649
  // deadline's interruption all release it. Interruption stops the
539
650
  // wait instead of waiting for the connector, so an uncooperative one
@@ -546,17 +657,16 @@ export class InvocationService {
546
657
  stage = "downstream";
547
658
  const reply = yield* timed((elapsed) => {
548
659
  connectorMs += elapsed;
549
- }, Effect.tryPromise({
550
- try: () => Promise.resolve(call(permit)),
551
- catch: (error) => error,
552
- }));
660
+ }, call(permit));
553
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.
554
665
  if (!context.processInputRequired)
555
- throw new ConnectorCallError("input_required_unsupported", "The downstream returned input_required. Use the equivalent direct MCP call to provide input.");
556
- const value = yield* Effect.tryPromise({
557
- try: () => Promise.resolve(context.processInputRequired(reply, target, sentSecrets)),
558
- catch: (error) => error,
559
- });
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]);
560
670
  return { inputRequired: true, value };
561
671
  }
562
672
  assertDownstreamOutputSafe(this.catalog.requestScope, reply);
@@ -572,11 +682,23 @@ export class InvocationService {
572
682
  return yield* Effect.fail(callSignal.reason);
573
683
  if (!dispatchedToConnector && admissionSignal?.aborted)
574
684
  return callerCancelledDetails();
575
- const attemptError = Cause.squash(attempt.cause);
576
- answered = answeredFailure(attemptError);
577
- return isCallerCancellation(attemptError, context.requestSignal)
578
- ? callerCancelledDetails()
579
- : 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;
580
702
  }
581
703
  if ("inputRequired" in attempt.value) {
582
704
  inputRequiredValue = { value: attempt.value.value };
@@ -613,9 +735,11 @@ export class InvocationService {
613
735
  : dispatch());
614
736
  if (Exit.isFailure(dispatched)) {
615
737
  const failure = Cause.squash(dispatched.cause);
738
+ failureAdvice = resendAdviceOf(failure);
739
+ failureKeyAdvice = keyResendAdviceOf(failure);
616
740
  const details = context.requestSignal?.aborted
617
741
  ? callerCancelledDetails()
618
- : carryFailureFacts(failure, classifyCallError(sentSecrets.redact(failure)));
742
+ : carryFailureFacts(failure, classifyWithoutAdvice(sentSecrets.redact(failure)));
619
743
  return failed(details);
620
744
  }
621
745
  if (dispatched.value)
@@ -625,14 +749,21 @@ export class InvocationService {
625
749
  if (!completed) {
626
750
  return yield* Effect.die(new Error("Invocation completed without a resolved tool"));
627
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
+ }
628
762
  const processResult = context.processResult;
629
763
  const processing = inputRequiredValue
630
764
  ? Effect.succeed(inputRequiredValue.value)
631
765
  : processResult
632
- ? Effect.tryPromise({
633
- try: () => Promise.resolve(processResult(sentSecrets.redact(result), completed, sentSecrets, valueFormat, rawResult)),
634
- catch: (error) => error,
635
- })
766
+ ? authCall(processResult, [sentSecrets.redact(result), completed, sentSecrets, valueFormat, rawResult])
636
767
  : Effect.succeed(result);
637
768
  const processed = yield* Effect.exit(timed((elapsed) => {
638
769
  resultProcessingMs += elapsed;
@@ -671,9 +802,11 @@ export class InvocationService {
671
802
  }
672
803
  }).pipe(Effect.flatMap((outcome) => outcome.ok
673
804
  ? Effect.succeed(outcome)
674
- : Effect.promise(async () => ({
675
- ...outcome,
676
- error: await withAuthorizationHandoff(this.catalog.requestScope, outcome.error),
677
- }))));
805
+ : withAuthorizationHandoffEffect(this.catalog.requestScope, outcome.error).pipe(Effect.map((error) => ({ ...outcome, error })))));
678
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
+ })();
679
812
  }
@@ -33,7 +33,3 @@ export function downstreamValue(kind, result) {
33
33
  }
34
34
  return { data: result, format: "json" };
35
35
  }
36
- /** Preserve the raw-value API for internal callers that already know its format. */
37
- export function unwrapMcpResult(kind, result) {
38
- return downstreamValue(kind, result).data;
39
- }