@fased/fased 0.1.62 → 0.1.64

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 (341) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/README.md +38 -30
  3. package/config/dependency-ownership.json +1 -1
  4. package/config/signer-policies/README.md +49 -0
  5. package/config/signer-policies/agent.json.template +32 -0
  6. package/config/signer-policies/mining.json.template +69 -0
  7. package/config/signer-policies/network.json.template +5 -0
  8. package/config/signer-policies/vault.json.template +70 -0
  9. package/config/signer-protocol-v2.json +76 -0
  10. package/config/typescript-noemit-baseline.json +680 -0
  11. package/dist/agents/auth-profiles/store.js +267 -31
  12. package/dist/agents/bash-tools.exec.js +10 -4
  13. package/dist/agents/current-model-catalog.js +3 -3
  14. package/dist/agents/memory-search.js +7 -1
  15. package/dist/agents/model-catalog-access.js +1 -2
  16. package/dist/agents/model-catalog-snapshot.js +1 -1
  17. package/dist/agents/model-catalog-source.js +1 -1
  18. package/dist/agents/model-metadata.js +1 -1
  19. package/dist/agents/model-selection.js +2 -28
  20. package/dist/agents/models-config.providers.js +6 -6
  21. package/dist/agents/pi-embedded-runner/compact.js +15 -7
  22. package/dist/agents/pi-embedded-runner/model.js +1 -1
  23. package/dist/agents/pi-embedded-runner/run/attempt.js +24 -13
  24. package/dist/agents/pi-embedded-runner/run.js +2 -0
  25. package/dist/agents/pi-embedded-runner/tool-split.js +40 -2
  26. package/dist/agents/pi-tool-definition-adapter.js +16 -1
  27. package/dist/agents/pi-tools.js +2 -1
  28. package/dist/agents/sandbox/config.js +1 -1
  29. package/dist/agents/sandbox/context.js +27 -2
  30. package/dist/agents/skills/env-overrides.js +38 -28
  31. package/dist/agents/skills/trust.js +93 -0
  32. package/dist/agents/skills/workspace.js +128 -0
  33. package/dist/agents/skills-clawhub.js +36 -11
  34. package/dist/agents/skills-marketplace-scan.js +49 -0
  35. package/dist/agents/tools/marketplace-offer-draft-tool.js +1 -1
  36. package/dist/agents/tools/mining-tool.js +1 -1
  37. package/dist/agents/tools/session-status-tool.js +1 -1
  38. package/dist/agents/tools/wallet-action-tool.js +172 -36
  39. package/dist/agents/tools/wallet-skill-policy.js +65 -23
  40. package/dist/agents/tools/wallet-tool.js +7 -11
  41. package/dist/auto-reply/reply/directive-handling.fast-lane.js +2 -1
  42. package/dist/auto-reply/reply/directive-handling.impl.js +2 -1
  43. package/dist/auto-reply/reply/directive-handling.model.js +2 -1
  44. package/dist/auto-reply/reply/directive-handling.persist.js +2 -2
  45. package/dist/auto-reply/reply/get-reply-directives-apply.js +2 -0
  46. package/dist/auto-reply/reply/get-reply-inline-actions.js +25 -1
  47. package/dist/auto-reply/reply/model-selection.js +7 -4
  48. package/dist/auto-reply/reply/session-reset-model.js +4 -4
  49. package/dist/brand.js +1 -1
  50. package/dist/build-info.json +3 -3
  51. package/dist/canvas-host/a2ui/.bundle.hash +1 -1
  52. package/dist/channel-web.js +2 -2
  53. package/dist/cli/gateway-cli/run.js +8 -0
  54. package/dist/cli/program/command-registry.js +1 -1
  55. package/dist/cli/program/register.onboard.js +2 -3
  56. package/dist/cli/program/register.wallet.js +16 -123
  57. package/dist/cli/providers-cli.js +1 -1
  58. package/dist/cli/sat-cli.js +129 -2
  59. package/dist/cli/update-cli/update-command.js +260 -11
  60. package/dist/commands/auth-choice.apply.api-providers.js +3 -3
  61. package/dist/commands/doctor-config-flow.js +1 -1
  62. package/dist/commands/doctor-legacy-config.js +2 -13
  63. package/dist/commands/model-picker.js +6 -6
  64. package/dist/commands/models/auth.js +1 -1
  65. package/dist/commands/onboard-auth.config-gateways.js +1 -1
  66. package/dist/commands/onboard-auth.credentials.js +32 -8
  67. package/dist/commands/onboard-non-interactive/local/wallet-config.js +28 -27
  68. package/dist/commands/onboard-non-interactive/local.js +5 -1
  69. package/dist/commands/wallet.js +568 -1911
  70. package/dist/config/config.js +2 -2
  71. package/dist/config/io.js +64 -2
  72. package/dist/config/schema.help.js +8 -7
  73. package/dist/config/schema.labels.js +5 -4
  74. package/dist/config/zod-schema.agent-runtime.js +1 -0
  75. package/dist/config/zod-schema.js +5 -0
  76. package/dist/control-ui/assets/{app-DLil9VO1.js → app-bR-fO5ty.js} +1511 -1555
  77. package/dist/control-ui/assets/{config-CU5Zi8Dh.js → config-LeImukCW.js} +10 -10
  78. package/dist/control-ui/assets/{federation-D10Q4eP_.js → federation-DgA9e-Pn.js} +364 -422
  79. package/dist/control-ui/assets/{index-DdE_NIXo.js → index-ckCxHwjy.js} +3 -3
  80. package/dist/control-ui/assets/{mining-BdhMn18r.js → mining-BgHFh0ei.js} +134 -114
  81. package/dist/control-ui/assets/mining-commit-DFpB_4JN.js +2 -0
  82. package/dist/control-ui/assets/{open-external-url-DwSiwMPl.js → open-external-url-ulF1B-sA.js} +3 -3
  83. package/dist/control-ui/assets/{providers-QMn4w2_f.js → providers-CIx9fxc6.js} +2 -2
  84. package/dist/control-ui/assets/{wallet-C2g294QT.js → wallet-DvStR_AT.js} +259 -377
  85. package/dist/control-ui/index.html +1 -1
  86. package/dist/control-ui/version.json +1 -1
  87. package/dist/daemon/systemd-system.js +56 -50
  88. package/dist/extensions/sat-mining/src/protocol-contract.js +43 -3
  89. package/dist/extensions/sat-mining/src/rpc-read.js +235 -67
  90. package/dist/extensions/sat-mining/src/sat-bond-layout.js +5 -2
  91. package/dist/extensions/sat-mining/src/signer-codec-manifest.js +406 -0
  92. package/dist/extensions/sat-mining/src/solana-submit.js +1038 -397
  93. package/dist/extensions/sat-mining/src/submission-ledger.js +349 -0
  94. package/dist/federation/auto-connect.js +98 -8
  95. package/dist/federation/marketplace-capability-adapter.js +33 -7
  96. package/dist/federation/marketplace-delivery-outbox.js +196 -0
  97. package/dist/federation/marketplace-delivery.js +351 -215
  98. package/dist/federation/marketplace-direct-payment.js +272 -141
  99. package/dist/federation/marketplace-escrow.js +607 -249
  100. package/dist/federation/marketplace-settlement-ledger.js +352 -0
  101. package/dist/federation/offers.js +9 -7
  102. package/dist/federation/peer-auth-v2.js +529 -0
  103. package/dist/gateway/a2a-http.js +425 -96
  104. package/dist/gateway/a2a-settlement.js +259 -153
  105. package/dist/gateway/a2a-task-store.js +524 -0
  106. package/dist/gateway/auth.js +38 -2
  107. package/dist/gateway/config-reload.js +46 -33
  108. package/dist/gateway/durable-capacity.js +31 -0
  109. package/dist/gateway/federation-http.js +540 -135
  110. package/dist/gateway/federation-marketplace-run-store.js +397 -0
  111. package/dist/gateway/federation-marketplace.js +535 -230
  112. package/dist/gateway/mutating-admin-rpc-rate-limit.js +5 -0
  113. package/dist/gateway/security-path.js +1 -1
  114. package/dist/gateway/server-http.js +1084 -1205
  115. package/dist/gateway/server-methods/models.js +1 -1
  116. package/dist/gateway/server-methods/secrets.js +40 -0
  117. package/dist/gateway/server-methods.js +1 -2
  118. package/dist/gateway/server-reload-handlers.js +196 -66
  119. package/dist/gateway/server-runtime-config.js +1 -1
  120. package/dist/gateway/server-secrets-runtime.js +288 -0
  121. package/dist/gateway/server.impl.js +73 -42
  122. package/dist/gateway/sessions-patch.js +3 -5
  123. package/dist/index.js +4 -2
  124. package/dist/infra/fasedhub.js +64 -1
  125. package/dist/infra/local-source-paired-update.js +538 -0
  126. package/dist/infra/restart.js +41 -10
  127. package/dist/infra/update-runner.js +96 -0
  128. package/dist/light-update-status.js +11 -11
  129. package/dist/memory/backend-config.js +2 -1
  130. package/dist/memory/session-files.js +16 -2
  131. package/dist/plugin-sdk/{accounts-DxblobYM.js → accounts-Brn3-uWN.js} +1 -1
  132. package/dist/plugin-sdk/{actions-D4UNimWa.js → actions-DRu135h0.js} +2 -2
  133. package/dist/plugin-sdk/{active-listener-CFuy106s.js → active-listener-B_NMtgPL.js} +1 -1
  134. package/dist/plugin-sdk/{audio-preflight-Bwi2Oq03.js → audio-preflight-BYxAt775.js} +27 -27
  135. package/dist/plugin-sdk/{audit-Cs0K7LBp.js → audit-C5d2z5U1.js} +1 -1
  136. package/dist/plugin-sdk/{channel-access-D5aHoTY8.js → channel-access-CcFRdRPO.js} +1 -1
  137. package/dist/plugin-sdk/{channel-access-configure-Dvch9mMQ.js → channel-access-configure-DaI5wevh.js} +1 -1
  138. package/dist/plugin-sdk/channel-plugin-common.d.ts +3 -3
  139. package/dist/plugin-sdk/channel-plugin-common.js +4 -4
  140. package/dist/plugin-sdk/{chunk-B0FUGc5A.js → chunk-CyoyqpbG.js} +1 -1
  141. package/dist/plugin-sdk/{chunk-items-DzT4L4Ty.js → chunk-items-DIRHG2gJ.js} +1 -1
  142. package/dist/plugin-sdk/command-status.d.ts +2 -2
  143. package/dist/plugin-sdk/command-status.js +27 -27
  144. package/dist/plugin-sdk/{commands-registry-DmDRhRAU.js → commands-registry-BfqdEWdF.js} +2 -2
  145. package/dist/plugin-sdk/{common-CfUOowOp.js → common-HCcXU-NR.js} +1 -1
  146. package/dist/plugin-sdk/{config-mxULv0fQ.js → config-DlWVeLFB.js} +7113 -6877
  147. package/dist/plugin-sdk/{config-schema-BrkmtFxB.js → config-schema-BOT7kHb6.js} +6779 -3696
  148. package/dist/plugin-sdk/device-pair.d.ts +1 -1
  149. package/dist/plugin-sdk/discord.d.ts +6 -6
  150. package/dist/plugin-sdk/discord.js +19 -19
  151. package/dist/plugin-sdk/file-lock.js +35 -4
  152. package/dist/plugin-sdk/{filesystem-manager-ZoHU8oA7.js → filesystem-manager-DoI8IBNF.js} +1 -1
  153. package/dist/plugin-sdk/{group-mentions-BHRff6j8.d.ts → group-mentions-q3hUTCt7.d.ts} +1 -1
  154. package/dist/plugin-sdk/{handle-action-DbVCF9HZ.js → handle-action-hvwapMKg.js} +13 -13
  155. package/dist/plugin-sdk/{helpers-BXbdgs5H.js → helpers-DMBU4oTo.js} +1 -1
  156. package/dist/plugin-sdk/{image-ops-D7jPxaph.js → image-ops-DQi0n_Tt.js} +1 -1
  157. package/dist/plugin-sdk/index.d.ts +21 -39
  158. package/dist/plugin-sdk/index.js +29 -29
  159. package/dist/plugin-sdk/{login-BRxww6nv.js → login-Ca583Okc.js} +3 -3
  160. package/dist/plugin-sdk/{login-qr-DJXsk9XH.js → login-qr-CGciBSNP.js} +3 -3
  161. package/dist/plugin-sdk/{manager-Y2S_5IlI.js → manager-BegWxNYX.js} +4 -4
  162. package/dist/plugin-sdk/{markdown-tables-DHLFQqaF.js → markdown-tables-DCOXEUfZ.js} +1 -1
  163. package/dist/plugin-sdk/{media-Czo4carg.js → media-CAdQF5TG.js} +47 -47
  164. package/dist/plugin-sdk/{memory-search-DTjIMw8J.js → memory-search-CrFPOeTH.js} +4 -1
  165. package/dist/plugin-sdk/{monitor-M_ta2lMc.js → monitor-BCFDaqJ-.js} +31 -31
  166. package/dist/plugin-sdk/{monitor-wYVncM9w.js → monitor-BgbjRiPM.js} +32 -32
  167. package/dist/plugin-sdk/{openresponses-http-B2GmeSt4.js → openresponses-http-DFf87SMM.js} +27 -27
  168. package/dist/plugin-sdk/{optional-runtime-dependency-DdMbxS24.js → optional-runtime-dependency-0dznm3ZO.js} +1 -1
  169. package/dist/plugin-sdk/{outbound-Db8mRN6P.js → outbound-BgVDdHxx.js} +6 -6
  170. package/dist/plugin-sdk/{outbound-attachment-BqFjcypb.js → outbound-attachment-QqTnIhZL.js} +2 -2
  171. package/dist/plugin-sdk/{pairing-message-B3bHYGaw.d.ts → pairing-message-CS-9BHug.d.ts} +2 -2
  172. package/dist/plugin-sdk/{pairing-message-B3GC_7CD.js → pairing-message-D0CoLHRJ.js} +1 -1
  173. package/dist/plugin-sdk/{pairing-store-CQikgIbw.js → pairing-store-BChahgI2.js} +2 -2
  174. package/dist/plugin-sdk/{pi-model-discovery-CY3m5zJP.js → pi-model-discovery-BX_JLcEJ.js} +1 -1
  175. package/dist/plugin-sdk/{pi-model-discovery-runtime-DSh1T2pn.js → pi-model-discovery-runtime-DxTMz_XF.js} +2 -2
  176. package/dist/plugin-sdk/provider-web-search-config-contract.d.ts +2 -2
  177. package/dist/plugin-sdk/{pw-ai-AFUqn-tQ.js → pw-ai-natjh3rm.js} +3 -3
  178. package/dist/plugin-sdk/{qmd-manager-DSyx77KY.js → qmd-manager-CgRaTxUq.js} +1 -1
  179. package/dist/plugin-sdk/{query-expansion-CAI2kKLQ.js → query-expansion-BG3FgzF7.js} +14 -3
  180. package/dist/plugin-sdk/{replies-Fzh9PhXl.js → replies-ChYo5ZQM.js} +2 -2
  181. package/dist/plugin-sdk/{resolve-outbound-target-KpF3co6T.js → resolve-outbound-target-D-KGgHJZ.js} +1 -1
  182. package/dist/plugin-sdk/{resolve-route-CDl74O19.js → resolve-route-C8tvQm8Z.js} +1 -1
  183. package/dist/plugin-sdk/{retry-policy-D4uiqUOG.js → retry-policy-C6SjKjQA.js} +1 -1
  184. package/dist/plugin-sdk/{runtime-Bb6KRnCC.js → runtime-2B9_WKoI.js} +8 -3
  185. package/dist/plugin-sdk/{runtime-dependency-DLDmB94f.js → runtime-dependency-DczkvPxn.js} +2 -2
  186. package/dist/plugin-sdk/sat-runtime.d.ts +549 -309
  187. package/dist/plugin-sdk/sat-runtime.js +29 -29
  188. package/dist/plugin-sdk/{send-C4k4JuJN.js → send-B6KkGKZD.js} +6 -6
  189. package/dist/plugin-sdk/{send-D-uDKGIq.js → send-CFzGKJXo.js} +6 -6
  190. package/dist/plugin-sdk/{send-Du8ykP1k.js → send-DCO441U7.js} +8 -8
  191. package/dist/plugin-sdk/{send-5nFktR1n.js → send-gDoGA-7e.js} +5 -5
  192. package/dist/plugin-sdk/{send-Bfzf11VY.js → send-q9HXrSwK.js} +7 -7
  193. package/dist/plugin-sdk/{session-CS-Td9EM.js → session-DHD4ZKyG.js} +2 -2
  194. package/dist/plugin-sdk/{skill-commands-CFAlXWHk.js → skill-commands-FKEPLS7T.js} +201 -26
  195. package/dist/plugin-sdk/{slack-CxE1mfzj.js → slack-BUTt8cxK.js} +39 -39
  196. package/dist/plugin-sdk/{slack-actions-BcMkNv1Z.js → slack-actions-DhbMcp8M.js} +11 -11
  197. package/dist/plugin-sdk/slack.d.ts +6 -6
  198. package/dist/plugin-sdk/slack.js +9 -9
  199. package/dist/plugin-sdk/{sticker-cache-CGzGWu00.js → sticker-cache-D0wHVqjt.js} +3 -3
  200. package/dist/plugin-sdk/{tables-bFXyRpkx.js → tables-B3jr0Pvq.js} +1 -1
  201. package/dist/plugin-sdk/{targets-DH7a9lKB.js → targets-CtSbTxYX.js} +1 -1
  202. package/dist/plugin-sdk/{telegram-actions-DaEcYQ8r.js → telegram-actions-CC_qN4v0.js} +30 -30
  203. package/dist/plugin-sdk/telegram.d.ts +6 -6
  204. package/dist/plugin-sdk/telegram.js +8 -8
  205. package/dist/plugin-sdk/{thread-bindings.lifecycle-CgOvvdw8.js → thread-bindings.lifecycle-QbkNl-m6.js} +3 -3
  206. package/dist/plugin-sdk/{thread-bindings.state-CQpk44Hq.js → thread-bindings.state-D9hg_M1c.js} +2 -2
  207. package/dist/plugin-sdk/tmp-fased-dir-xOTGlzBE.d.ts +486 -0
  208. package/dist/plugin-sdk/{types-vcJrC_uv.d.ts → types-C3avNytw.d.ts} +3 -4
  209. package/dist/plugin-sdk/{types-DyhXnYUr.d.ts → types-D0kDG8l0.d.ts} +3 -2
  210. package/dist/plugin-sdk/{types-DFAW-n1J.d.ts → types-DWfbSAaM.d.ts} +2 -2
  211. package/dist/plugin-sdk/{types.plugin-_fbu40Re.d.ts → types.plugin-BcSBq42x.d.ts} +8 -3
  212. package/dist/plugin-sdk/{web-CInY-lCv.js → web-BXsJ1vqe.js} +32 -32
  213. package/dist/plugin-sdk/{whatsapp-actions-BtSc2CBv.js → whatsapp-actions-Bj_rOncr.js} +13 -13
  214. package/dist/plugin-sdk/{whatsapp-heartbeat-Bg9TuYzl.js → whatsapp-heartbeat-B1WHkJIg.js} +2 -2
  215. package/dist/plugin-sdk/whatsapp.d.ts +13 -13
  216. package/dist/plugin-sdk/whatsapp.js +12 -12
  217. package/dist/plugin-sdk/{wsl-C4DGFkOd.js → wsl-J-HscWxS.js} +3 -3
  218. package/dist/plugin-sdk/{zod-schema.providers-core-BEbNizPe.d.ts → zod-schema.providers-core-CIzCjXH9.d.ts} +61 -61
  219. package/dist/providers/refresh.js +1 -1
  220. package/dist/providers/registry.js +1 -1
  221. package/dist/secrets/apply.js +1 -1
  222. package/dist/secrets/runtime.js +1 -1
  223. package/dist/wallet/external-submission-ledger.js +376 -0
  224. package/dist/wallet/legacy-embedded-keystore.js +40 -0
  225. package/dist/wallet/local-socket-signer-archive.js +30 -0
  226. package/dist/wallet/local-socket-signer-lifecycle.js +97 -0
  227. package/dist/wallet/local-socket-signer-policy.js +166 -0
  228. package/dist/wallet/local-socket-signer-protocol.js +561 -118
  229. package/dist/wallet/native-signer-wallet-id.js +25 -0
  230. package/dist/wallet/providers/alchemy-adapter.js +3 -0
  231. package/dist/wallet/providers/local-socket-signer-adapter.js +380 -105
  232. package/dist/wallet/providers/turnkey-adapter.js +292 -34
  233. package/dist/wallet/providers/wallet-standard-adapter.js +100 -0
  234. package/dist/wallet/signer-network-admin.js +184 -0
  235. package/dist/wallet/signer-protocol-v2.generated.js +90 -0
  236. package/dist/wallet/solana-bond-signing.js +157 -69
  237. package/dist/wallet/solana-reviewed-transaction.js +375 -0
  238. package/dist/wallet/solana-swap.js +520 -64
  239. package/dist/wallet/solana-transaction-inspection.js +106 -4
  240. package/dist/wallet/solana-trigger.js +658 -320
  241. package/dist/wallet/turnkey-reviewed-state.js +370 -0
  242. package/dist/wallet/wallet-approval-auth.js +17 -28
  243. package/dist/wallet/wallet-atomic-state.js +53 -0
  244. package/dist/wallet/wallet-canary.js +0 -1
  245. package/dist/wallet/wallet-inbound-events.js +16 -11
  246. package/dist/wallet/wallet-policy-simulation.js +1 -1
  247. package/dist/wallet/wallet-policy.js +90 -36
  248. package/dist/wallet/wallet-provider-capabilities.js +28 -4
  249. package/dist/wallet/wallet-provider-registry.js +57 -44
  250. package/dist/wallet/wallet-provider-resolver.js +62 -63
  251. package/dist/wallet/wallet-runtime-config.js +28 -41
  252. package/dist/wallet/wallet-secrets-store.js +22 -0
  253. package/dist/wallet/wallet-send-approvals.js +1891 -589
  254. package/dist/wallet/wallet-send-execution-ledger.js +292 -0
  255. package/dist/wallet/wallet-settlement-links.js +14 -13
  256. package/dist/wallet/wallet-standard-review.js +353 -0
  257. package/dist/wallet/wallet-status.js +0 -9
  258. package/dist/wallet/wallet-task-ledger.js +16 -2
  259. package/dist/web/auto-reply/heartbeat-runner.js +1 -1
  260. package/dist/web/auto-reply/monitor.js +2 -2
  261. package/dist/wizard/host-security-capability.js +14 -23
  262. package/dist/wizard/onboarding.finalize.js +63 -184
  263. package/dist/wizard/onboarding.host-security.js +117 -1367
  264. package/dist/wizard/onboarding.js +172 -217
  265. package/dist/wizard/onboarding.wallet.js +232 -785
  266. package/extensions/acpx/package.json +1 -1
  267. package/extensions/bluebubbles/package.json +1 -1
  268. package/extensions/copilot-proxy/package.json +1 -1
  269. package/extensions/diagnostics-otel/package.json +1 -1
  270. package/extensions/fased-federation/package.json +1 -1
  271. package/extensions/google-gemini-cli-auth/package.json +1 -1
  272. package/extensions/imessage/package.json +1 -1
  273. package/extensions/irc/package.json +1 -1
  274. package/extensions/line/package.json +1 -1
  275. package/extensions/llm-task/package.json +1 -1
  276. package/extensions/lobster/package.json +1 -1
  277. package/extensions/matrix/CHANGELOG.md +12 -0
  278. package/extensions/matrix/package.json +1 -1
  279. package/extensions/mattermost/package.json +1 -1
  280. package/extensions/memory-core/package.json +2 -2
  281. package/extensions/memory-lancedb/package.json +1 -1
  282. package/extensions/minimax-portal-auth/package.json +1 -1
  283. package/extensions/msteams/CHANGELOG.md +12 -0
  284. package/extensions/msteams/package.json +1 -1
  285. package/extensions/nextcloud-talk/package.json +1 -1
  286. package/extensions/nostr/CHANGELOG.md +12 -0
  287. package/extensions/nostr/package.json +1 -1
  288. package/extensions/open-prose/package.json +1 -1
  289. package/extensions/sat-mining/index.ts +498 -153
  290. package/extensions/sat-mining/package.json +1 -1
  291. package/extensions/sat-mining/signer-codec-schema.v1.json +374 -0
  292. package/extensions/sat-mining/src/audit-store.ts +50 -5
  293. package/extensions/sat-mining/src/claim-service.ts +85 -14
  294. package/extensions/sat-mining/src/config.ts +9 -0
  295. package/extensions/sat-mining/src/cycle-progress.ts +16 -8
  296. package/extensions/sat-mining/src/epoch-service.ts +9 -5
  297. package/extensions/sat-mining/src/gateway-runner.ts +21 -1
  298. package/extensions/sat-mining/src/protocol-contract.ts +45 -1
  299. package/extensions/sat-mining/src/recovery-service.ts +312 -0
  300. package/extensions/sat-mining/src/round-watcher.ts +391 -81
  301. package/extensions/sat-mining/src/rpc-read.ts +330 -89
  302. package/extensions/sat-mining/src/runtime.ts +14 -0
  303. package/extensions/sat-mining/src/sat-bond-layout.ts +6 -0
  304. package/extensions/sat-mining/src/signer-codec-manifest.ts +429 -0
  305. package/extensions/sat-mining/src/solana-submit.ts +1199 -428
  306. package/extensions/sat-mining/src/submission-ledger.ts +433 -0
  307. package/extensions/signal/package.json +1 -1
  308. package/extensions/synology-chat/package.json +1 -1
  309. package/extensions/tlon/package.json +1 -1
  310. package/extensions/twitch/CHANGELOG.md +12 -0
  311. package/extensions/twitch/package.json +1 -1
  312. package/extensions/voice-call/CHANGELOG.md +12 -0
  313. package/extensions/voice-call/package.json +1 -1
  314. package/extensions/zalo/CHANGELOG.md +12 -0
  315. package/extensions/zalo/package.json +1 -1
  316. package/extensions/zalouser/CHANGELOG.md +12 -0
  317. package/extensions/zalouser/package.json +1 -1
  318. package/install.sh +4955 -0
  319. package/package.json +23 -5
  320. package/scripts/fased-host-updater.mjs +1421 -0
  321. package/scripts/fased-host-updaterctl.mjs +186 -0
  322. package/scripts/fased-managed-service.sh +36 -0
  323. package/scripts/fased-managed-updater.mjs +3065 -156
  324. package/scripts/fased-signer-enroll-hosting.sh +275 -0
  325. package/scripts/fased-signer-network-hosting.sh +143 -0
  326. package/scripts/fased-signer-owner-policy.mjs +1430 -0
  327. package/scripts/fased-signer-policy-hosting.sh +50 -0
  328. package/scripts/fased-signer-policy-local.sh +26 -0
  329. package/scripts/hosted-release-manifest.mjs +185 -0
  330. package/scripts/install-fased-signerd.sh +183 -108
  331. package/scripts/install-managed-runtime.mjs +212 -10
  332. package/scripts/managed-runtime-layout.mjs +75 -3
  333. package/scripts/migrate-hosted-signer-v2.mjs +58 -0
  334. package/scripts/start-managed.sh +169 -360
  335. package/dist/control-ui/assets/mining-commit-R-6nu87p.js +0 -2
  336. package/dist/plugin-sdk/tmp-fased-dir-CS6zsYEE.d.ts +0 -77
  337. package/dist/wallet/local-socket-signer-broker.js +0 -224
  338. package/dist/wallet/local-socket-signer-custody.js +0 -42
  339. package/dist/wallet/providers/embedded-keystore-adapter.js +0 -402
  340. package/dist/wallet/providers/privy-adapter.js +0 -80
  341. package/dist/wallet/wallet-custody.js +0 -1836
@@ -0,0 +1,524 @@
1
+ import { resolveStateDir } from "../config/paths.js";
2
+ import { resolveProcessScopedMap } from "../shared/process-scoped-map.js";
3
+ import { acquireFileLock, withFileLock } from "../plugin-sdk/file-lock.js";
4
+ import "../infra/file-lock.js";
5
+ import { serializeWalletState, writeWalletStateFileAtomically } from "../wallet/wallet-atomic-state.js";
6
+ import { emitDurableCapacityWarning } from "./durable-capacity.js";
7
+ import syncFs from "node:fs";
8
+ import path from "node:path";
9
+ import { createHash, randomBytes, timingSafeEqual } from "node:crypto";
10
+
11
+ //#region src/gateway/a2a-task-store.ts
12
+ const TASK_STATUSES = new Set([
13
+ "queued",
14
+ "running",
15
+ "succeeded",
16
+ "failed",
17
+ "canceled"
18
+ ]);
19
+ const LOCK_OPTIONS = {
20
+ retries: {
21
+ retries: 100,
22
+ factor: 1.15,
23
+ minTimeout: 10,
24
+ maxTimeout: 200,
25
+ randomize: true
26
+ },
27
+ stale: 3e4
28
+ };
29
+ const EXECUTION_LOCK_OPTIONS = {
30
+ retries: {
31
+ retries: 1,
32
+ factor: 1,
33
+ minTimeout: 10,
34
+ maxTimeout: 10,
35
+ randomize: false
36
+ },
37
+ stale: 3e4
38
+ };
39
+ const ACTIVE_EXECUTIONS = resolveProcessScopedMap(Symbol.for("fased.gateway.a2aTask.activeExecutions"));
40
+ const MAX_TASKS_PER_SENDER_PER_HOUR = 60;
41
+ const MAX_ACTIVE_TASKS_PER_SENDER = 8;
42
+ const MAX_RETAINED_TASKS = 5e3;
43
+ const MAX_TASK_FILES_ON_DISK = 1e4;
44
+ const MAX_PAYMENT_CHALLENGE_FILES = 1e4;
45
+ const MAX_PAYMENT_CLAIM_FILES = 1e5;
46
+ const TERMINAL_TASK_RETENTION_MS = 7 * 24 * 60 * 6e4;
47
+ const PAYMENT_CHALLENGE_TTL_MS = 10 * 6e4;
48
+ function canonicalJson(value) {
49
+ if (value === null || typeof value === "string" || typeof value === "boolean") {
50
+ return JSON.stringify(value);
51
+ }
52
+ if (typeof value === "number") {
53
+ if (!Number.isFinite(value)) {
54
+ throw new Error("A2A task intent contains a non-finite number");
55
+ }
56
+ return JSON.stringify(value);
57
+ }
58
+ if (Array.isArray(value)) {
59
+ return `[${value.map((entry) => canonicalJson(entry)).join(",")}]`;
60
+ }
61
+ if (value && typeof value === "object") {
62
+ const record = value;
63
+ return `{${Object.keys(record).filter((key) => record[key] !== undefined).toSorted().map((key) => `${JSON.stringify(key)}:${canonicalJson(record[key])}`).join(",")}}`;
64
+ }
65
+ throw new Error("A2A task intent contains an unsupported value");
66
+ }
67
+ function taskDigest(taskId) {
68
+ return createHash("sha256").update(taskId).digest("hex");
69
+ }
70
+ function taskDirectory(env) {
71
+ return path.join(resolveStateDir(env), "federation", "a2a-tasks");
72
+ }
73
+ function taskPath(taskId, env) {
74
+ return path.join(taskDirectory(env), `${taskDigest(taskId)}.json`);
75
+ }
76
+ function senderQuotaLockPath(senderHandle, env) {
77
+ const digest = createHash("sha256").update(senderHandle, "utf8").digest("hex");
78
+ return path.join(taskDirectory(env), ".sender-quotas", digest);
79
+ }
80
+ function taskCapacityLockPath(env) {
81
+ return path.join(taskDirectory(env), ".capacity");
82
+ }
83
+ function executionLockTarget(taskId, env) {
84
+ return path.join(taskDirectory(env), ".executions", taskDigest(taskId));
85
+ }
86
+ function paymentClaimPath(txRef, env) {
87
+ const digest = createHash("sha256").update(txRef, "utf8").digest("hex");
88
+ return path.join(taskDirectory(env), ".payment-claims", `${digest}.json`);
89
+ }
90
+ function paymentChallengeDirectory(env) {
91
+ return path.join(taskDirectory(env), ".payment-challenges");
92
+ }
93
+ function paymentChallengePath(taskId, env) {
94
+ return path.join(paymentChallengeDirectory(env), `${taskDigest(taskId)}.json`);
95
+ }
96
+ function paymentChallengeClaimLockPath(env) {
97
+ return path.join(paymentChallengeDirectory(env), ".claims");
98
+ }
99
+ function paymentClaimDirectory(env) {
100
+ return path.join(taskDirectory(env), ".payment-claims");
101
+ }
102
+ function paymentReferenceClaimLockPath(env) {
103
+ return path.join(paymentClaimDirectory(env), ".claims");
104
+ }
105
+ function listJsonLedgerFiles(directory) {
106
+ if (!syncFs.existsSync(directory)) {
107
+ return [];
108
+ }
109
+ return syncFs.readdirSync(directory).filter((name) => /^[a-f0-9]{64}\.json$/u.test(name));
110
+ }
111
+ function requireJsonLedgerCapacity(directory, maximum, label) {
112
+ const used = listJsonLedgerFiles(directory).length;
113
+ emitDurableCapacityWarning(label, used, maximum);
114
+ if (used >= maximum) {
115
+ throw new Error(`${label} reached its safe on-disk record limit`);
116
+ }
117
+ }
118
+ function pruneExpiredPaymentChallenges(env, nowMs) {
119
+ const directory = paymentChallengeDirectory(env);
120
+ for (const name of listJsonLedgerFiles(directory)) {
121
+ const filePath = path.join(directory, name);
122
+ try {
123
+ const raw = JSON.parse(syncFs.readFileSync(filePath, "utf8"));
124
+ if (!isRecord(raw) || typeof raw.taskId !== "string") {
125
+ continue;
126
+ }
127
+ const challenge = validatePaymentChallenge(raw, raw.taskId);
128
+ const expiredUnclaimed = challenge.status === "issued" && Date.parse(challenge.expiresAt) < nowMs;
129
+ const claimedAt = challenge.claimedAt ? Date.parse(challenge.claimedAt) : Number.NaN;
130
+ const orphanedClaim = challenge.status === "claimed" && !syncFs.existsSync(taskPath(challenge.taskId, env)) && Number.isFinite(claimedAt) && nowMs - claimedAt > TERMINAL_TASK_RETENTION_MS;
131
+ if (expiredUnclaimed || orphanedClaim) {
132
+ syncFs.unlinkSync(filePath);
133
+ }
134
+ } catch {}
135
+ }
136
+ }
137
+ function a2aTaskIntentDigest(intent) {
138
+ return `sha256:${createHash("sha256").update(canonicalJson(intent)).digest("hex")}`;
139
+ }
140
+ function isRecord(value) {
141
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
142
+ }
143
+ function isValidPaymentRecovery(value) {
144
+ if (!isRecord(value)) {
145
+ return false;
146
+ }
147
+ return (value.status === "refund-required" || value.status === "refunded" || value.status === "disputed") && typeof value.paymentTxRef === "string" && value.paymentTxRef.length > 0 && typeof value.reason === "string" && value.reason.length > 0 && typeof value.updatedAt === "string" && (value.refundTxRef === undefined || typeof value.refundTxRef === "string" && value.refundTxRef.length > 0) && (value.approvalRequestId === undefined || typeof value.approvalRequestId === "string" && value.approvalRequestId.length > 0);
148
+ }
149
+ function validatePaymentChallenge(value, expectedTaskId) {
150
+ if (!isRecord(value) || value.version !== 1 || value.taskId !== expectedTaskId || typeof value.challengeId !== "string" || !/^[0-9a-f]{64}$/u.test(value.challengeId) || typeof value.senderHandle !== "string" || !value.senderHandle.trim() || typeof value.offerId !== "string" || !value.offerId.trim() || typeof value.invoiceId !== "string" || !value.invoiceId.trim() || typeof value.receiptId !== "string" || !value.receiptId.trim() || typeof value.payerAddress !== "string" || !value.payerAddress.trim() || typeof value.payeeAddress !== "string" || !value.payeeAddress.trim() || typeof value.amount !== "number" || !Number.isSafeInteger(value.amount) || value.amount <= 0 || typeof value.currency !== "string" || !value.currency.trim() || !isRecord(value.asset) || value.asset.kind !== "native" && value.asset.kind !== "spl-token" || value.asset.address !== undefined && typeof value.asset.address !== "string" || typeof value.paymentMemo !== "string" || !/^fased:a2a-payment:v1:[0-9a-f]{64}$/u.test(value.paymentMemo) || value.status !== "issued" && value.status !== "claimed" || typeof value.issuedAt !== "string" || !Number.isFinite(Date.parse(value.issuedAt)) || typeof value.expiresAt !== "string" || !Number.isFinite(Date.parse(value.expiresAt)) || value.txRefDigest !== undefined && (typeof value.txRefDigest !== "string" || !/^sha256:[0-9a-f]{64}$/u.test(value.txRefDigest)) || value.claimedAt !== undefined && (typeof value.claimedAt !== "string" || !Number.isFinite(Date.parse(value.claimedAt)))) {
151
+ throw new Error("durable A2A payment challenge contains an invalid record");
152
+ }
153
+ return value;
154
+ }
155
+ function validateRecord(value, expectedTaskId) {
156
+ if (!isRecord(value) || value.version !== 2 || value.taskId !== expectedTaskId || typeof value.intentDigest !== "string" || !/^sha256:[0-9a-f]{64}$/u.test(value.intentDigest) || typeof value.accessTokenHash !== "string" || !/^[0-9a-f]{64}$/u.test(value.accessTokenHash) || typeof value.senderHandle !== "string" || typeof value.status !== "string" || !TASK_STATUSES.has(value.status) || typeof value.createdAt !== "string" || typeof value.updatedAt !== "string" || value.error !== undefined && typeof value.error !== "string" || value.paymentRecovery !== undefined && !isValidPaymentRecovery(value.paymentRecovery)) {
157
+ throw new Error("durable A2A task contains an invalid record");
158
+ }
159
+ return value;
160
+ }
161
+ function hashAccessToken(value) {
162
+ return createHash("sha256").update(`fased:a2a-task-access:v1:${value}`, "utf8").digest("hex");
163
+ }
164
+ function tokensMatch(expectedHash, token) {
165
+ const actual = Buffer.from(hashAccessToken(token), "hex");
166
+ const expected = Buffer.from(expectedHash, "hex");
167
+ return actual.length === expected.length && timingSafeEqual(actual, expected);
168
+ }
169
+ function normalizeNewAccessToken(value) {
170
+ const token = value?.trim() ?? "";
171
+ if (!token) {
172
+ return null;
173
+ }
174
+ if (token.length < 43 || token.length > 256 || !/^[A-Za-z0-9_-]+$/u.test(token)) {
175
+ throw new Error("caller-provided A2A task access token must be a strong base64url secret");
176
+ }
177
+ return token;
178
+ }
179
+ function listDurableRecords(env) {
180
+ const dir = taskDirectory(env);
181
+ if (!syncFs.existsSync(dir)) {
182
+ return [];
183
+ }
184
+ const records = [];
185
+ const taskFiles = syncFs.readdirSync(dir).filter((name) => /^[a-f0-9]{64}\.json$/u.test(name));
186
+ if (taskFiles.length > MAX_TASK_FILES_ON_DISK) {
187
+ throw new Error("A2A task store exceeds its safe on-disk record limit");
188
+ }
189
+ for (const name of taskFiles) {
190
+ try {
191
+ const raw = JSON.parse(syncFs.readFileSync(path.join(dir, name), "utf8"));
192
+ if (raw && typeof raw === "object" && typeof raw.taskId === "string") {
193
+ records.push(validateRecord(raw, raw.taskId));
194
+ }
195
+ } catch {}
196
+ }
197
+ return records;
198
+ }
199
+ function enforceSenderQuota(params) {
200
+ const now = Date.now();
201
+ const senderRecords = listDurableRecords(params.env).filter((record) => record.senderHandle === params.senderHandle);
202
+ const recent = senderRecords.filter((record) => now - Date.parse(record.createdAt) < 60 * 6e4);
203
+ if (recent.length >= MAX_TASKS_PER_SENDER_PER_HOUR) {
204
+ throw new Error("A2A sender hourly task quota exceeded");
205
+ }
206
+ const active = senderRecords.filter((record) => record.status === "queued" || record.status === "running");
207
+ if (active.length >= MAX_ACTIVE_TASKS_PER_SENDER) {
208
+ throw new Error("A2A sender active task quota exceeded");
209
+ }
210
+ }
211
+ function pruneDurableTasks(env) {
212
+ const now = Date.now();
213
+ const terminal = listDurableRecords(env).filter((record) => (record.status === "succeeded" || record.status === "failed" || record.status === "canceled") && record.paymentRecovery?.status !== "refund-required").toSorted((left, right) => Date.parse(left.updatedAt) - Date.parse(right.updatedAt));
214
+ const remove = terminal.filter((record, index) => now - Date.parse(record.updatedAt) > TERMINAL_TASK_RETENTION_MS || terminal.length - index > MAX_RETAINED_TASKS);
215
+ for (const record of remove) {
216
+ try {
217
+ syncFs.unlinkSync(taskPath(record.taskId, env));
218
+ } catch {}
219
+ }
220
+ }
221
+ function readDurableA2aPaymentChallenge(params) {
222
+ const env = params.env ?? process.env;
223
+ const taskId = params.taskId.trim();
224
+ if (!taskId) {
225
+ return null;
226
+ }
227
+ const filePath = paymentChallengePath(taskId, env);
228
+ if (!syncFs.existsSync(filePath)) {
229
+ return null;
230
+ }
231
+ try {
232
+ return validatePaymentChallenge(JSON.parse(syncFs.readFileSync(filePath, "utf8")), taskId);
233
+ } catch (error) {
234
+ throw new Error("durable A2A payment challenge is unreadable", { cause: error });
235
+ }
236
+ }
237
+ async function issueDurableA2aPaymentChallenge(params) {
238
+ const env = params.env ?? process.env;
239
+ const taskId = params.taskId.trim();
240
+ const senderHandle = params.senderHandle.trim().toLowerCase();
241
+ if (!taskId || taskId.length > 240 || !senderHandle || !params.offerId.trim()) {
242
+ throw new Error("A2A payment challenge identity is invalid");
243
+ }
244
+ if (!Number.isSafeInteger(params.amount) || params.amount <= 0) {
245
+ throw new Error("A2A payment challenge amount is invalid");
246
+ }
247
+ const filePath = paymentChallengePath(taskId, env);
248
+ syncFs.mkdirSync(path.dirname(filePath), {
249
+ recursive: true,
250
+ mode: 448
251
+ });
252
+ return await withFileLock(paymentChallengeClaimLockPath(env), LOCK_OPTIONS, async () => {
253
+ return await withFileLock(filePath, LOCK_OPTIONS, async () => {
254
+ const existing = readDurableA2aPaymentChallenge({
255
+ taskId,
256
+ env
257
+ });
258
+ const nowMs = params.nowMs ?? Date.now();
259
+ if (existing && Date.parse(existing.expiresAt) >= nowMs) {
260
+ if (existing.senderHandle !== senderHandle || existing.offerId !== params.offerId.trim() || existing.payerAddress !== params.payerAddress.trim() || existing.payeeAddress !== params.payeeAddress.trim() || existing.amount !== params.amount || existing.currency !== params.currency.trim().toUpperCase() || canonicalJson(existing.asset) !== canonicalJson(params.asset)) {
261
+ throw new Error("A2A taskId is already bound to different payment terms");
262
+ }
263
+ return existing;
264
+ }
265
+ if (existing?.status === "claimed") {
266
+ throw new Error("claimed A2A payment challenge cannot be replaced");
267
+ }
268
+ pruneExpiredPaymentChallenges(env, nowMs);
269
+ if (!existing) {
270
+ requireJsonLedgerCapacity(paymentChallengeDirectory(env), MAX_PAYMENT_CHALLENGE_FILES, "A2A payment challenge store");
271
+ }
272
+ const challengeId = randomBytes(32).toString("hex");
273
+ const issuedAt = new Date(nowMs).toISOString();
274
+ const record = {
275
+ version: 1,
276
+ challengeId,
277
+ taskId,
278
+ senderHandle,
279
+ offerId: params.offerId.trim(),
280
+ invoiceId: `invoice-${challengeId.slice(0, 32)}`,
281
+ receiptId: `receipt-${challengeId.slice(32)}`,
282
+ payerAddress: params.payerAddress.trim(),
283
+ payeeAddress: params.payeeAddress.trim(),
284
+ amount: params.amount,
285
+ currency: params.currency.trim().toUpperCase(),
286
+ asset: params.asset,
287
+ paymentMemo: `fased:a2a-payment:v1:${challengeId}`,
288
+ status: "issued",
289
+ issuedAt,
290
+ expiresAt: new Date(nowMs + PAYMENT_CHALLENGE_TTL_MS).toISOString()
291
+ };
292
+ writeWalletStateFileAtomically(filePath, serializeWalletState(record));
293
+ return record;
294
+ });
295
+ });
296
+ }
297
+ async function claimDurableA2aPaymentChallenge(params) {
298
+ const env = params.env ?? process.env;
299
+ const taskId = params.taskId.trim();
300
+ const txRefDigest = `sha256:${createHash("sha256").update(params.txRef.trim(), "utf8").digest("hex")}`;
301
+ return await withFileLock(paymentChallengeClaimLockPath(env), LOCK_OPTIONS, async () => {
302
+ const challenge = readDurableA2aPaymentChallenge({
303
+ taskId,
304
+ env
305
+ });
306
+ if (!challenge || challenge.challengeId !== params.challengeId.trim() || challenge.senderHandle !== params.senderHandle.trim().toLowerCase() || challenge.payerAddress !== params.payerAddress.trim()) {
307
+ throw new Error("A2A payment challenge identity does not match the verified settlement");
308
+ }
309
+ const challengeFiles = syncFs.existsSync(paymentChallengeDirectory(env)) ? syncFs.readdirSync(paymentChallengeDirectory(env)).filter((name) => /^[a-f0-9]{64}\.json$/u.test(name)) : [];
310
+ for (const name of challengeFiles) {
311
+ const raw = JSON.parse(syncFs.readFileSync(path.join(paymentChallengeDirectory(env), name), "utf8"));
312
+ if (isRecord(raw) && raw.txRefDigest === txRefDigest && raw.taskId !== taskId) {
313
+ throw new Error("payment transaction was already claimed by a different A2A task");
314
+ }
315
+ }
316
+ if (challenge.status === "claimed") {
317
+ if (challenge.txRefDigest !== txRefDigest) {
318
+ throw new Error("A2A payment challenge was already claimed by a different transaction");
319
+ }
320
+ return challenge;
321
+ }
322
+ const claimed = {
323
+ ...challenge,
324
+ status: "claimed",
325
+ txRefDigest,
326
+ claimedAt: new Date().toISOString()
327
+ };
328
+ writeWalletStateFileAtomically(paymentChallengePath(taskId, env), serializeWalletState(claimed));
329
+ return claimed;
330
+ });
331
+ }
332
+ function authorizeDurableA2aTask(params) {
333
+ const record = readDurableA2aTask({
334
+ taskId: params.taskId,
335
+ env: params.env
336
+ });
337
+ const token = params.accessToken.trim();
338
+ if (!record || !token || !tokensMatch(record.accessTokenHash, token)) {
339
+ return null;
340
+ }
341
+ return record;
342
+ }
343
+ function readDurableA2aTask(params) {
344
+ const taskId = params.taskId.trim();
345
+ if (!taskId) {
346
+ return null;
347
+ }
348
+ const filePath = taskPath(taskId, params.env ?? process.env);
349
+ if (!syncFs.existsSync(filePath)) {
350
+ return null;
351
+ }
352
+ try {
353
+ return validateRecord(JSON.parse(syncFs.readFileSync(filePath, "utf8")), taskId);
354
+ } catch (error) {
355
+ throw new Error("durable A2A task is unreadable; refusing to replace it", { cause: error });
356
+ }
357
+ }
358
+ function writeRecord(record, env) {
359
+ syncFs.mkdirSync(taskDirectory(env), {
360
+ recursive: true,
361
+ mode: 448
362
+ });
363
+ writeWalletStateFileAtomically(taskPath(record.taskId, env), serializeWalletState(record));
364
+ }
365
+ async function claimDurableA2aPaymentReference(params) {
366
+ const env = params.env ?? process.env;
367
+ const taskId = params.taskId.trim();
368
+ const txRef = params.txRef.trim();
369
+ if (!taskId || !txRef) {
370
+ throw new Error("A2A payment claim requires taskId and txRef");
371
+ }
372
+ const claimPath = paymentClaimPath(txRef, env);
373
+ await withFileLock(paymentReferenceClaimLockPath(env), LOCK_OPTIONS, async () => {
374
+ await withFileLock(claimPath, LOCK_OPTIONS, async () => {
375
+ if (syncFs.existsSync(claimPath)) {
376
+ const existing = JSON.parse(syncFs.readFileSync(claimPath, "utf8"));
377
+ if (!isRecord(existing) || existing.taskId !== taskId) {
378
+ throw new Error("payment transaction was already claimed by a different A2A task");
379
+ }
380
+ return;
381
+ }
382
+ const claimDir = path.dirname(claimPath);
383
+ syncFs.mkdirSync(claimDir, {
384
+ recursive: true,
385
+ mode: 448
386
+ });
387
+ requireJsonLedgerCapacity(claimDir, MAX_PAYMENT_CLAIM_FILES, "A2A payment transaction claim store");
388
+ writeWalletStateFileAtomically(claimPath, serializeWalletState({
389
+ version: 1,
390
+ taskId,
391
+ txRefDigest: `sha256:${createHash("sha256").update(txRef, "utf8").digest("hex")}`,
392
+ createdAt: new Date().toISOString()
393
+ }));
394
+ });
395
+ });
396
+ }
397
+ async function reserveDurableA2aTask(params) {
398
+ const env = params.env ?? process.env;
399
+ const taskId = params.taskId.trim();
400
+ if (!taskId || taskId.length > 240) {
401
+ throw new Error("A2A taskId is invalid");
402
+ }
403
+ const intentDigest = a2aTaskIntentDigest({
404
+ taskId,
405
+ senderHandle: params.senderHandle.trim(),
406
+ input: params.input,
407
+ marketplacePayment: params.marketplacePayment
408
+ });
409
+ syncFs.mkdirSync(taskDirectory(env), {
410
+ recursive: true,
411
+ mode: 448
412
+ });
413
+ const senderHandle = params.senderHandle.trim();
414
+ return await withFileLock(taskCapacityLockPath(env), LOCK_OPTIONS, async () => {
415
+ pruneDurableTasks(env);
416
+ return await withFileLock(senderQuotaLockPath(senderHandle, env), LOCK_OPTIONS, async () => {
417
+ return await withFileLock(taskPath(taskId, env), LOCK_OPTIONS, async () => {
418
+ const existing = readDurableA2aTask({
419
+ taskId,
420
+ env
421
+ });
422
+ if (existing) {
423
+ if (existing.intentDigest !== intentDigest) {
424
+ throw new Error("A2A taskId is already bound to a different immutable task intent");
425
+ }
426
+ if (!params.accessToken || !tokensMatch(existing.accessTokenHash, params.accessToken)) {
427
+ throw new Error("A2A taskId already exists and requires its task access token");
428
+ }
429
+ return {
430
+ record: existing,
431
+ created: false
432
+ };
433
+ }
434
+ enforceSenderQuota({
435
+ senderHandle,
436
+ env
437
+ });
438
+ requireJsonLedgerCapacity(taskDirectory(env), MAX_TASK_FILES_ON_DISK, "A2A task store");
439
+ const now = new Date().toISOString();
440
+ const accessToken = normalizeNewAccessToken(params.accessToken) ?? randomBytes(32).toString("base64url");
441
+ const record = {
442
+ version: 2,
443
+ taskId,
444
+ intentDigest,
445
+ accessTokenHash: hashAccessToken(accessToken),
446
+ senderHandle,
447
+ input: params.input,
448
+ ...params.marketplacePayment !== undefined ? { marketplacePayment: params.marketplacePayment } : {},
449
+ status: "queued",
450
+ createdAt: now,
451
+ updatedAt: now
452
+ };
453
+ writeRecord(record, env);
454
+ return {
455
+ record,
456
+ created: true,
457
+ accessToken
458
+ };
459
+ });
460
+ });
461
+ });
462
+ }
463
+ async function updateDurableA2aTask(params) {
464
+ const env = params.env ?? process.env;
465
+ const taskId = params.taskId.trim();
466
+ return await withFileLock(taskPath(taskId, env), LOCK_OPTIONS, async () => {
467
+ const record = readDurableA2aTask({
468
+ taskId,
469
+ env
470
+ });
471
+ if (!record) {
472
+ throw new Error("durable A2A task does not exist");
473
+ }
474
+ if (params.expectedStatuses && !params.expectedStatuses.includes(record.status)) {
475
+ throw new Error(`durable A2A task is ${record.status}; expected ${params.expectedStatuses.join(" or ")}`);
476
+ }
477
+ if (params.status) {
478
+ record.status = params.status;
479
+ }
480
+ if (params.output !== undefined) {
481
+ record.output = params.output;
482
+ }
483
+ if (params.error !== undefined) {
484
+ record.error = params.error;
485
+ }
486
+ if (params.settlement !== undefined) {
487
+ record.settlement = params.settlement;
488
+ }
489
+ if (params.paymentRecovery !== undefined) {
490
+ record.paymentRecovery = params.paymentRecovery;
491
+ }
492
+ record.updatedAt = new Date().toISOString();
493
+ writeRecord(record, env);
494
+ return record;
495
+ });
496
+ }
497
+ async function claimDurableA2aTaskExecution(params) {
498
+ const env = params.env ?? process.env;
499
+ const taskId = params.taskId.trim();
500
+ const key = `${taskDirectory(env)}\0${taskId}`;
501
+ if (ACTIVE_EXECUTIONS.has(key)) {
502
+ return null;
503
+ }
504
+ ACTIVE_EXECUTIONS.set(key, true);
505
+ let lock;
506
+ try {
507
+ lock = await acquireFileLock(executionLockTarget(taskId, env), EXECUTION_LOCK_OPTIONS);
508
+ } catch {
509
+ ACTIVE_EXECUTIONS.delete(key);
510
+ return null;
511
+ }
512
+ let released = false;
513
+ return async () => {
514
+ if (released) {
515
+ return;
516
+ }
517
+ released = true;
518
+ ACTIVE_EXECUTIONS.delete(key);
519
+ await lock.release();
520
+ };
521
+ }
522
+
523
+ //#endregion
524
+ export { authorizeDurableA2aTask, claimDurableA2aPaymentChallenge, claimDurableA2aTaskExecution, issueDurableA2aPaymentChallenge, readDurableA2aPaymentChallenge, readDurableA2aTask, reserveDurableA2aTask, updateDurableA2aTask };
@@ -54,6 +54,19 @@ function isLocalDirectRequest(req, trustedProxies, allowRealIpFallback) {
54
54
  }
55
55
  return false;
56
56
  }
57
+ /**
58
+ * Returns true only when the peer itself is loopback and the request carries
59
+ * no proxy-origin headers. This stricter predicate is required for auth mode
60
+ * "none"; configured proxies must never turn an unauthenticated request into
61
+ * a local one.
62
+ */
63
+ function isDirectLoopbackRequest(req, trustedProxies) {
64
+ if (!req) {
65
+ return false;
66
+ }
67
+ const remoteAddr = req.socket?.remoteAddress;
68
+ return isLoopbackAddress(remoteAddr) && !isTrustedProxyAddress(remoteAddr, trustedProxies) && !hasForwardedProxyHeaders(req);
69
+ }
57
70
  function getTailscaleUser(req) {
58
71
  if (!req) {
59
72
  return null;
@@ -81,7 +94,16 @@ function hasForwardedProxyHeaders(req) {
81
94
  if (!req) {
82
95
  return false;
83
96
  }
84
- return Boolean(req.headers["forwarded"] || req.headers["x-forwarded-for"] || req.headers["x-forwarded-host"] || req.headers["x-forwarded-proto"] || req.headers["x-real-ip"]);
97
+ return [
98
+ "forwarded",
99
+ "via",
100
+ "x-forwarded-for",
101
+ "x-forwarded-host",
102
+ "x-forwarded-port",
103
+ "x-forwarded-proto",
104
+ "x-forwarded-server",
105
+ "x-real-ip"
106
+ ].some((header) => Object.prototype.hasOwnProperty.call(req.headers, header));
85
107
  }
86
108
  function isTailscaleProxyRequest(req) {
87
109
  if (!req) {
@@ -270,6 +292,20 @@ async function authorizeGatewayConnect(params) {
270
292
  };
271
293
  }
272
294
  }
295
+ if (auth.mode === "none") {
296
+ if (!auth.allowTailscale && isDirectLoopbackRequest(req, trustedProxies)) {
297
+ limiter?.reset(ip, rateLimitScope);
298
+ return {
299
+ ok: true,
300
+ method: "none"
301
+ };
302
+ }
303
+ limiter?.recordFailure(ip, rateLimitScope);
304
+ return {
305
+ ok: false,
306
+ reason: "unauthorized"
307
+ };
308
+ }
273
309
  let sessionAuthResolved;
274
310
  const trySessionTokenAuth = async () => {
275
311
  if (sessionAuthResolved !== undefined) {
@@ -384,4 +420,4 @@ async function authorizeGatewayConnect(params) {
384
420
  }
385
421
 
386
422
  //#endregion
387
- export { assertGatewayAuthConfigured, authorizeGatewayConnect, isLocalDirectRequest, resolveGatewayAuth };
423
+ export { assertGatewayAuthConfigured, authorizeGatewayConnect, isDirectLoopbackRequest, isLocalDirectRequest, resolveGatewayAuth };