@inneranimalmedia/agentsam-sdk 2.6.9 → 2.6.11

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 (392) hide show
  1. package/README.md +21 -0
  2. package/TRADEMARKS.md +22 -0
  3. package/apps/README.md +3 -0
  4. package/apps/cad-creator/LICENSE +21 -0
  5. package/apps/cad-creator/README.md +4 -1
  6. package/apps/cad-creator/shared/cad/package.json +1 -1
  7. package/apps/client-cms-editor/LICENSE +21 -0
  8. package/apps/client-cms-editor/README.md +3 -0
  9. package/apps/client-cms-editor/backend/package.json +3 -3
  10. package/apps/client-cms-editor/frontend/package.json +4 -4
  11. package/apps/client-cms-editor/package-lock.json +43 -43
  12. package/apps/client-cms-editor/package.json +3 -3
  13. package/apps/client-cms-editor/reference/harvest/HARVEST_RECEIPT.json +1 -1
  14. package/apps/client-cms-editor/reference/harvest/README.md +1 -1
  15. package/apps/client-cms-editor/reference/harvest/plans/ARCHIVE-INTAKE.md +1 -1
  16. package/apps/client-cms-editor/reference/harvest/plans/HARVEST-INDEX.md +1 -1
  17. package/apps/client-cms-editor/reference/harvest/plans/TOOLING-LAB.md +1 -1
  18. package/apps/client-cms-editor/shared/cms/package.json +2 -2
  19. package/docs/MINI.md +4 -2
  20. package/docs/REPO_FILE_MAP.txt +0 -1
  21. package/docs/SOURCE_ARCHITECTURE.md +1 -1
  22. package/docs/architecture/DUAL_ANALYTICS_PRODUCT.md +140 -0
  23. package/docs/architecture/HOOKS-MODELS-SELF-HOSTING-PLAN.md +199 -0
  24. package/docs/content-studio/REVISION_GATE_2026-09-27.md +1 -1
  25. package/docs/engineering/go-portability/01-product-project-deployment-authority.md +69 -0
  26. package/docs/engineering/provider-internal-renames/01-lane-initialization.md +20 -0
  27. package/docs/engineering/provider-internal-renames/01a-runtime-environment-contract.md +115 -0
  28. package/docs/engineering/provider-internal-renames/02-cfoa.md +57 -0
  29. package/docs/engineering/provider-internal-renames/03-gclioa.md +32 -0
  30. package/docs/engineering/provider-internal-renames/04-goaude.md +50 -0
  31. package/docs/engineering/provider-internal-renames/05-gdrv.md +33 -0
  32. package/docs/engineering/provider-internal-renames/06-verification.md +103 -0
  33. package/docs/engineering/provider-internal-renames/README.md +77 -0
  34. package/docs/engineering/provider-internal-renames/runtime-environment-contract.json +220 -0
  35. package/docs/engineering/test-diagnostics/go-cli-test-hang-20261003.md +49 -0
  36. package/docs/engineering/test-diagnostics/go-skip-deploy-docker-fix.md +90 -0
  37. package/docs/knowledge-service-verification.md +3 -3
  38. package/docs/plans/AGENTSAM-SUSPEND-QUEUE-KNOWLEDGE-RDP-2026-10-03.md +870 -0
  39. package/docs/plans/LOCAL-STUDIO-GRADUATION-2026-09-26.md +9 -9
  40. package/docs/plans/MACHINE-FIRST-APPS-TUI-2026-09-24.md +11 -11
  41. package/docs/plans/RECONCILIATION-2026-09-19.md +6 -6
  42. package/docs/plans/SAM_WORK_PROTOCOL.md +667 -0
  43. package/docs/plans/TOMORROW-EXTENSIVE-TODO-2026-09-26.md +2 -2
  44. package/docs/plans/UNIVERSAL-INGEST-MACHINE-FIRST-2026-09-24.md +3 -3
  45. package/examples/hyperspace-demo/index.html +16 -0
  46. package/examples/hyperspace-demo/package.json +21 -0
  47. package/examples/hyperspace-demo/src/main.tsx +277 -0
  48. package/examples/hyperspace-demo/tsconfig.json +9 -0
  49. package/examples/hyperspace-demo/vite.config.ts +24 -0
  50. package/migrations/d1/0020_agentsam_receipt_catalog.sql +35 -0
  51. package/migrations/runtime/0005_agentsam_hooks.sql +87 -0
  52. package/migrations/runtime/0006_agent_run_suspend_activity.sql +53 -0
  53. package/migrations/runtime/0007_queue_control.sql +40 -0
  54. package/migrations/runtime/0008_agent_run_dependencies.sql +24 -0
  55. package/migrations/runtime/0008_analytics_legacy_bootstrap.sql +43 -0
  56. package/migrations/runtime/0009_analytics_authority.sql +108 -0
  57. package/package.json +45 -14
  58. package/packages/agentsam-brand/README.md +3 -0
  59. package/packages/agentsam-brand/package.json +2 -2
  60. package/packages/agentsam-brand/src/core/v2/compile.js +1 -1
  61. package/packages/agentsam-brand/src/core/v2/schema.js +1 -1
  62. package/packages/agentsam-contracts/dist/adapter.d.ts +22 -0
  63. package/packages/agentsam-contracts/dist/adapter.js +0 -0
  64. package/packages/agentsam-contracts/dist/agent.d.ts +66 -0
  65. package/packages/agentsam-contracts/dist/agent.js +15 -0
  66. package/packages/agentsam-contracts/dist/artifacts.d.ts +70 -0
  67. package/packages/agentsam-contracts/dist/artifacts.js +0 -0
  68. package/packages/agentsam-contracts/dist/authority.d.ts +21 -0
  69. package/packages/agentsam-contracts/dist/authority.js +0 -0
  70. package/packages/agentsam-contracts/dist/context.d.ts +14 -0
  71. package/packages/agentsam-contracts/dist/context.js +0 -0
  72. package/packages/agentsam-contracts/dist/errors.d.ts +121 -0
  73. package/packages/agentsam-contracts/dist/errors.js +5 -0
  74. package/packages/agentsam-contracts/dist/events.d.ts +53 -0
  75. package/packages/agentsam-contracts/dist/events.js +0 -0
  76. package/packages/agentsam-contracts/dist/execution.d.ts +38 -0
  77. package/packages/agentsam-contracts/dist/execution.js +0 -0
  78. package/packages/agentsam-contracts/dist/hooks.d.ts +31 -0
  79. package/packages/agentsam-contracts/dist/hooks.js +0 -0
  80. package/packages/agentsam-contracts/dist/identity.d.ts +15 -0
  81. package/packages/agentsam-contracts/dist/identity.js +0 -0
  82. package/packages/agentsam-contracts/dist/index.d.ts +16 -0
  83. package/packages/agentsam-contracts/dist/index.js +164 -0
  84. package/packages/agentsam-contracts/dist/models.d.ts +9 -0
  85. package/packages/agentsam-contracts/dist/models.js +0 -0
  86. package/packages/agentsam-contracts/dist/providers.d.ts +27 -0
  87. package/packages/agentsam-contracts/dist/providers.js +0 -0
  88. package/packages/agentsam-contracts/dist/repository.d.ts +56 -0
  89. package/packages/agentsam-contracts/dist/repository.js +15 -0
  90. package/packages/agentsam-contracts/dist/run.d.ts +113 -0
  91. package/packages/agentsam-contracts/dist/run.js +132 -0
  92. package/packages/agentsam-contracts/dist/tools.d.ts +82 -0
  93. package/packages/agentsam-contracts/dist/tools.js +0 -0
  94. package/packages/agentsam-contracts/dist/widgets.d.ts +38 -0
  95. package/packages/agentsam-contracts/dist/widgets.js +0 -0
  96. package/packages/agentsam-contracts/package.json +9 -1
  97. package/packages/agentsam-contracts/scripts/build.mjs +1 -1
  98. package/packages/agentsam-contracts/src/agent.ts +78 -3
  99. package/packages/agentsam-contracts/src/errors.ts +19 -10
  100. package/packages/agentsam-contracts/src/index.ts +2 -0
  101. package/packages/agentsam-contracts/src/run.ts +320 -0
  102. package/packages/agentsam-contracts/src/widgets.ts +58 -0
  103. package/packages/agentsam-contracts/test/contracts.test.mjs +1 -1
  104. package/packages/agentsam-contracts/test/run-contract.test.mjs +94 -0
  105. package/packages/agentsam-errors/package.json +11 -3
  106. package/packages/agentsam-errors/protocol/agentsam.error.v2.schema.json +821 -0
  107. package/packages/agentsam-errors/protocol/error-catalog.json +3512 -0
  108. package/packages/agentsam-errors/src/envelope.js +63 -11
  109. package/packages/agentsam-errors/src/error.js +6 -0
  110. package/packages/agentsam-errors/src/fingerprint.js +9 -1
  111. package/packages/agentsam-errors/src/normalize.js +51 -6
  112. package/packages/agentsam-errors/src/recovery.js +9 -35
  113. package/packages/agentsam-errors/src/transport.js +6 -1
  114. package/packages/agentsam-errors/src/vocabulary.js +515 -126
  115. package/packages/agentsam-errors/test/catalog-v2.test.mjs +106 -0
  116. package/packages/agentsam-errors/types/index.d.ts +157 -0
  117. package/packages/agentsam-goap/README.md +3 -0
  118. package/packages/agentsam-goap/package.json +2 -2
  119. package/packages/agentsam-hooks/README.md +206 -0
  120. package/packages/agentsam-hooks/bin/agentsam-hooks.mjs +64 -0
  121. package/packages/agentsam-hooks/bindings/go/command.go +55 -0
  122. package/packages/agentsam-hooks/bindings/go/errors_generated.go +402 -0
  123. package/packages/agentsam-hooks/bindings/go/go.mod +3 -0
  124. package/packages/agentsam-hooks/bindings/go/hooks.go +285 -0
  125. package/packages/agentsam-hooks/bindings/go/hooks_test.go +48 -0
  126. package/packages/agentsam-hooks/bindings/rust/Cargo.toml +11 -0
  127. package/packages/agentsam-hooks/bindings/rust/src/errors_generated.rs +396 -0
  128. package/packages/agentsam-hooks/bindings/rust/src/lib.rs +397 -0
  129. package/packages/agentsam-hooks/package.json +69 -0
  130. package/packages/agentsam-hooks/schema/manifest.json +54 -0
  131. package/packages/agentsam-hooks/scripts/clean-protocol.mjs +17 -0
  132. package/packages/agentsam-hooks/scripts/sync-protocol.mjs +27 -0
  133. package/packages/agentsam-hooks/src/adapters/agents.js +108 -0
  134. package/packages/agentsam-hooks/src/adapters/callback.js +4 -0
  135. package/packages/agentsam-hooks/src/adapters/capability.js +122 -0
  136. package/packages/agentsam-hooks/src/adapters/command.js +104 -0
  137. package/packages/agentsam-hooks/src/adapters/composite.js +31 -0
  138. package/packages/agentsam-hooks/src/adapters/http.js +58 -0
  139. package/packages/agentsam-hooks/src/adapters/lsp.js +116 -0
  140. package/packages/agentsam-hooks/src/adapters/mcp.js +76 -0
  141. package/packages/agentsam-hooks/src/adapters/provider.js +129 -0
  142. package/packages/agentsam-hooks/src/config.js +143 -0
  143. package/packages/agentsam-hooks/src/contracts.js +284 -0
  144. package/packages/agentsam-hooks/src/errors-generated.js +2732 -0
  145. package/packages/agentsam-hooks/src/index.d.ts +209 -0
  146. package/packages/agentsam-hooks/src/index.js +14 -0
  147. package/packages/agentsam-hooks/src/policy.js +34 -0
  148. package/packages/agentsam-hooks/src/runtime.js +312 -0
  149. package/packages/agentsam-hooks/src/store.js +264 -0
  150. package/packages/agentsam-hooks/test/adapters.test.mjs +216 -0
  151. package/packages/agentsam-hooks/test/runtime.test.mjs +258 -0
  152. package/packages/agentsam-knowledge/package.json +1 -1
  153. package/packages/agentsam-knowledge/src/backends/index.js +1 -1
  154. package/packages/agentsam-merch/README.md +62 -0
  155. package/packages/agentsam-merch/bin/agentsam-merch.mjs +16 -0
  156. package/packages/agentsam-merch/package.json +65 -0
  157. package/packages/agentsam-merch/profiles/completeful/dtg-back-large.json +42 -0
  158. package/packages/agentsam-merch/profiles/completeful/laser-engraving.json +39 -0
  159. package/packages/agentsam-merch/profiles/generic/embroidery-digitization.json +22 -0
  160. package/packages/agentsam-merch/schemas/collection-candidate.schema.json +66 -0
  161. package/packages/agentsam-merch/schemas/manufacturing-profile.schema.json +221 -0
  162. package/packages/agentsam-merch/src/adapters-completeful.js +50 -0
  163. package/packages/agentsam-merch/src/cli.js +93 -0
  164. package/packages/agentsam-merch/src/collection-lab.js +60 -0
  165. package/packages/agentsam-merch/src/compatibility.js +501 -0
  166. package/packages/agentsam-merch/src/derivatives.js +112 -0
  167. package/packages/agentsam-merch/src/index.d.ts +316 -0
  168. package/packages/agentsam-merch/src/index.js +46 -0
  169. package/packages/agentsam-merch/src/node/index.d.ts +58 -0
  170. package/packages/agentsam-merch/src/node/index.js +6 -0
  171. package/packages/agentsam-merch/src/node/raster.js +142 -0
  172. package/packages/agentsam-merch/src/node/vector.js +239 -0
  173. package/packages/agentsam-merch/src/product-concepts.js +118 -0
  174. package/packages/agentsam-merch/src/profile-registry.js +104 -0
  175. package/packages/agentsam-merch/src/profile.js +158 -0
  176. package/packages/agentsam-merch/src/transforms.js +215 -0
  177. package/packages/agentsam-merch/test/merch.test.mjs +332 -0
  178. package/packages/agentsam-merch/test/node-transforms.test.mjs +149 -0
  179. package/packages/agentsam-nav/dist/Nav.d.ts +43 -0
  180. package/packages/agentsam-nav/dist/NavCollapsible.d.ts +10 -0
  181. package/packages/agentsam-nav/dist/NavContent.d.ts +2 -0
  182. package/packages/agentsam-nav/dist/NavFooter.d.ts +2 -0
  183. package/packages/agentsam-nav/dist/NavGroup.d.ts +3 -0
  184. package/packages/agentsam-nav/dist/NavHeader.d.ts +2 -0
  185. package/packages/agentsam-nav/dist/NavMenu.d.ts +22 -0
  186. package/packages/agentsam-nav/dist/NavProvider.d.ts +35 -0
  187. package/packages/agentsam-nav/dist/NavTrigger.d.ts +2 -0
  188. package/packages/agentsam-nav/dist/Surfaces.d.ts +41 -0
  189. package/packages/agentsam-nav/dist/browser.d.ts +11 -0
  190. package/packages/agentsam-nav/dist/browser.global.js +172 -0
  191. package/packages/agentsam-nav/dist/browser.js +9688 -0
  192. package/packages/agentsam-nav/dist/contracts.d.ts +76 -0
  193. package/packages/agentsam-nav/dist/index.d.ts +11 -0
  194. package/packages/agentsam-nav/dist/index.js +9689 -0
  195. package/packages/agentsam-nav/dist/legacy.css +83 -0
  196. package/packages/agentsam-nav/dist/shell.css +113 -0
  197. package/packages/agentsam-nav/dist/theme.css +113 -0
  198. package/packages/agentsam-nav/dist/utils.d.ts +1 -0
  199. package/packages/agentsam-nav/package.json +1 -1
  200. package/packages/agentsam-queue-control/README.md +4 -1
  201. package/packages/agentsam-queue-control/package.json +4 -3
  202. package/packages/agentsam-queue-control/schemas/job-envelope.schema.json +111 -11
  203. package/packages/agentsam-queue-control/src/adapters/cloudflare.js +34 -6
  204. package/packages/agentsam-queue-control/src/adapters/memory.js +11 -2
  205. package/packages/agentsam-queue-control/src/adapters/sqlite.js +259 -0
  206. package/packages/agentsam-queue-control/src/contracts.js +207 -3
  207. package/packages/agentsam-queue-control/src/control-plane.js +62 -2
  208. package/packages/agentsam-queue-control/src/index.js +1 -0
  209. package/packages/agentsam-queue-control/test/queue-control.test.mjs +310 -0
  210. package/packages/agentsam-queue-control/test/sqlite-adapter.test.mjs +91 -0
  211. package/packages/agentsam-rapid-rust/README.md +3 -0
  212. package/packages/agentsam-repository/README.md +3 -0
  213. package/packages/agentsam-repository/package.json +1 -1
  214. package/packages/agentsam-vault/package.json +1 -1
  215. package/packages/agentsam-workbench/README.md +43 -0
  216. package/packages/agentsam-workbench/package.json +14 -4
  217. package/packages/agentsam-workbench/src/agent/AgentConversationSurface.tsx +108 -0
  218. package/packages/agentsam-workbench/src/agent/AgentPanel.tsx +25 -8
  219. package/packages/agentsam-workbench/src/agent/AgentRuntimeField.tsx +152 -0
  220. package/packages/agentsam-workbench/src/agent/Composer.tsx +10 -1
  221. package/packages/agentsam-workbench/src/agent/RunMode.ts +26 -0
  222. package/packages/agentsam-workbench/src/agent/Thread.tsx +18 -3
  223. package/packages/agentsam-workbench/src/agent/index.ts +3 -0
  224. package/packages/agentsam-workbench/src/index.ts +4 -0
  225. package/packages/agentsam-workbench/src/manufacturing/PreflightIndicator.tsx +203 -0
  226. package/packages/agentsam-workbench/src/manufacturing/index.ts +2 -0
  227. package/packages/agentsam-workbench/src/manufacturing/loading.ts +147 -0
  228. package/packages/agentsam-workbench/src/widgets/BuiltinWidget.tsx +22 -0
  229. package/packages/agentsam-workbench/src/widgets/CountdownWidget.tsx +68 -0
  230. package/packages/agentsam-workbench/src/widgets/WidgetFrame.tsx +56 -0
  231. package/packages/agentsam-workbench/src/widgets/countdown.ts +25 -0
  232. package/packages/agentsam-workbench/src/widgets/index.ts +6 -0
  233. package/packages/agentsam-workbench/src/widgets/registry.ts +13 -0
  234. package/packages/agentsam-workbench/src/widgets/useCountdown.ts +128 -0
  235. package/packages/agentsam-workbench/src/widgets/widgets.css +102 -0
  236. package/packages/connectors/{cloudflare → cfoa}/package.json +3 -3
  237. package/packages/heuristic-theme/package.json +1 -1
  238. package/packages/identity/README.md +3 -0
  239. package/packages/identity/backend/README.md +3 -0
  240. package/packages/identity/package.json +2 -2
  241. package/packages/identity/src/frontend/auth-portal/README.md +3 -0
  242. package/packages/identity/src/index.js +1 -1
  243. package/packages/identity/src/oauth/README.md +4 -1
  244. package/packages/identity/src/oauth/credentials.js +1 -1
  245. package/packages/identity/src/server/worker-router.js +1 -1
  246. package/packages/identity/tests/google-desktop-identity-login.test.mjs +1 -1
  247. package/packages/identity/tests/lane1-packed-consumer.test.mjs +1 -1
  248. package/packages/identity/tests/oauth-presets-accounts-ssot.test.mjs +1 -1
  249. package/packages/providers/completeful/package.json +1 -1
  250. package/packages/theme-church-site/package.json +2 -2
  251. package/packages/theme-companions-site/package.json +2 -2
  252. package/packages/theme-floors-site/package.json +2 -2
  253. package/packages/theme-fuelnfree-site/package.json +2 -2
  254. package/packages/theme-handyman-site/package.json +2 -2
  255. package/packages/theme-insurance-site/package.json +2 -2
  256. package/packages/theme-scenes/package.json +1 -1
  257. package/packages/theme-shinshu-site/package.json +2 -2
  258. package/packages/work-graph/package.json +1 -1
  259. package/protocol/apps/agentsam.app.v1.schema.json +1 -1
  260. package/protocol/apps/agentsam.host-install.v1.schema.json +1 -1
  261. package/protocol/assets/asset-record.v1.schema.json +1 -1
  262. package/protocol/brand/brandpack.v1.schema.json +1 -1
  263. package/protocol/capabilities/capability-manifest.schema.json +1 -1
  264. package/protocol/capabilities/knowledge-search-input.schema.json +1 -0
  265. package/protocol/credentials/issue.v1.schema.json +1 -1
  266. package/protocol/database/agentsam.schema-pack.v1.schema.json +1 -1
  267. package/protocol/database/connection.v1.schema.json +1 -1
  268. package/protocol/embeddings/embedding-profile.v1.schema.json +1 -1
  269. package/protocol/errors/README.md +36 -0
  270. package/protocol/errors/agentsam.error.v2.schema.json +821 -0
  271. package/protocol/errors/error-catalog.json +3506 -158
  272. package/protocol/errors/error-envelope.schema.json +195 -52
  273. package/protocol/errors/recovery.v1.schema.json +1 -1
  274. package/protocol/features/agentsam.feature.v1.schema.json +1 -1
  275. package/protocol/hooks/README.md +18 -0
  276. package/protocol/hooks/agentsam.hook.output.v1.schema.json +27 -0
  277. package/protocol/hooks/agentsam.hook.receipt.v1.schema.json +61 -0
  278. package/protocol/hooks/agentsam.hook.v1.schema.json +35 -0
  279. package/protocol/hooks/agentsam.hooks.config.v1.schema.json +78 -0
  280. package/protocol/local-engine/benchmark.v1.schema.json +1 -1
  281. package/protocol/local-engine/engine.v1.schema.json +1 -1
  282. package/protocol/models/README.md +3 -0
  283. package/protocol/models/model-inventory-v2.schema.json +1 -1
  284. package/protocol/models/provider-model-snapshot.v1.schema.json +22 -0
  285. package/protocol/receipts/agentsam.receipt.v1.json +95 -0
  286. package/protocol/rpc/v1/errors.proto +1 -0
  287. package/protocol/runtime/agentsam.runtime.v1.schema.json +1 -1
  288. package/protocol/runtime/workspace-fs.v1.schema.json +1 -1
  289. package/protocol/sam/activity.v1.schema.json +1 -1
  290. package/protocol/sam/answer.v1.schema.json +1 -1
  291. package/protocol/sam/calibration.v1.schema.json +1 -1
  292. package/protocol/sam/decision-receipt.v1.schema.json +1 -1
  293. package/protocol/sam/evaluation.v1.schema.json +1 -1
  294. package/protocol/sam/operation.schema.json +1 -1
  295. package/protocol/sam/outcome.v1.schema.json +1 -1
  296. package/protocol/sam/question.v1.schema.json +1 -1
  297. package/protocol/sam/result.schema.json +1 -1
  298. package/protocol/sam/state.v1.schema.json +1 -1
  299. package/protocol/scoring/scorecard.v1.schema.json +1 -1
  300. package/protocol/skills/agentsam.interaction.v1.schema.json +1 -1
  301. package/protocol/skills/agentsam.skill.v1.schema.json +1 -1
  302. package/protocol/theme-refinery/product-metadata.schema.json +1 -1
  303. package/protocol/theme-refinery/receipts/products-registry-batch-20260924.json +6 -6
  304. package/protocol/theme-refinery/receipts/theme-harvest-20260924.json +6 -6
  305. package/protocol/theme-refinery/reconciliation-receipt.schema.json +1 -1
  306. package/protocol/ui/icon.v1.schema.json +1 -1
  307. package/python/README.md +20 -0
  308. package/python/agentsam_sdk/errors/__init__.py +4 -0
  309. package/python/agentsam_sdk/errors/vocabulary.py +2730 -0
  310. package/python/agentsam_sdk/hooks/__init__.py +32 -0
  311. package/python/agentsam_sdk/hooks/adapters.py +132 -0
  312. package/python/agentsam_sdk/hooks/contracts.py +121 -0
  313. package/python/agentsam_sdk/hooks/runtime.py +253 -0
  314. package/python/tests/test_hooks.py +115 -0
  315. package/skills/README.md +3 -0
  316. package/src/acp/agent-executor.js +106 -0
  317. package/src/acp/client.js +316 -0
  318. package/src/acp/dependencies.js +426 -0
  319. package/src/acp/http.js +207 -0
  320. package/src/acp/index.js +22 -0
  321. package/src/acp/runs.js +125 -0
  322. package/src/acp/runtime-selection.js +180 -0
  323. package/src/agent/responses-runner.js +145 -1
  324. package/src/cli/command-catalog.js +4 -0
  325. package/src/cli.js +33 -0
  326. package/src/commands/cheat-sheet.js +1 -0
  327. package/src/commands/cloudflare-login.js +1 -1
  328. package/src/commands/cloudflare.js +2 -2
  329. package/src/commands/connections.js +1 -1
  330. package/src/commands/go.js +76 -6
  331. package/src/commands/hooks.js +260 -0
  332. package/src/commands/merch.js +5 -0
  333. package/src/commands/mini.js +1 -1
  334. package/src/commands/models.js +1 -1
  335. package/src/commands/receipts.js +140 -0
  336. package/src/commands/run.js +253 -0
  337. package/src/commands/shell.js +114 -9
  338. package/src/errors/diagnostic.js +9 -9
  339. package/src/go/container.js +1 -1
  340. package/src/go/contract.js +61 -18
  341. package/src/go/discover.js +0 -4
  342. package/src/go/index.js +13 -1
  343. package/src/go/probe.js +109 -0
  344. package/src/go/{cloudflare.js → providers/cloudflare.js} +36 -136
  345. package/src/go/verify.js +1 -1
  346. package/src/index.js +32 -0
  347. package/src/indexing/ingest/inventory.js +1 -1
  348. package/src/knowledge/service/grpc-codec.js +2 -0
  349. package/src/lib/deploy/local-studio.js +2 -2
  350. package/src/lib/mini/scaffold.js +1 -1
  351. package/src/lib/slash-commands.js +1 -0
  352. package/src/lib/whoami-capabilities.js +1 -1
  353. package/src/local/runtime-store.js +54 -0
  354. package/src/mcp/cloudflare-bundles.js +1 -1
  355. package/src/models/catalog.js +0 -49
  356. package/src/models/inventory-core.js +69 -0
  357. package/src/plugins/index.js +9 -1
  358. package/src/plugins/registry.js +115 -6
  359. package/src/receipts/contract.js +68 -0
  360. package/src/receipts/index.js +20 -0
  361. package/src/receipts/prune.js +64 -0
  362. package/src/receipts/sinks.js +285 -0
  363. package/src/rpc/generated/errors_pb.js +49 -1
  364. package/src/tools/runtime.js +13 -5
  365. package/templates/mini/gadget/app.js +15 -40
  366. package/templates/mini/gadget/index.html +7 -7
  367. package/templates/mini/shared/style.css +1 -1
  368. /package/packages/connectors/{cloudflare → cfoa}/OAUTH_STORAGE_AUDIT.md +0 -0
  369. /package/packages/connectors/{cloudflare → cfoa}/src/api-client.js +0 -0
  370. /package/packages/connectors/{cloudflare → cfoa}/src/capabilities.js +0 -0
  371. /package/packages/connectors/{cloudflare → cfoa}/src/credential.js +0 -0
  372. /package/packages/connectors/{cloudflare → cfoa}/src/families/brand-protection.js +0 -0
  373. /package/packages/connectors/{cloudflare → cfoa}/src/families/keyless.js +0 -0
  374. /package/packages/connectors/{cloudflare → cfoa}/src/families/pages.js +0 -0
  375. /package/packages/connectors/{cloudflare → cfoa}/src/families/scanner.js +0 -0
  376. /package/packages/connectors/{cloudflare → cfoa}/src/families/snippets.js +0 -0
  377. /package/packages/connectors/{cloudflare → cfoa}/src/families/tag-gateway.js +0 -0
  378. /package/packages/connectors/{cloudflare → cfoa}/src/families/tags.js +0 -0
  379. /package/packages/connectors/{cloudflare → cfoa}/src/families/token-validation.js +0 -0
  380. /package/packages/connectors/{cloudflare → cfoa}/src/families/vectorize.js +0 -0
  381. /package/packages/connectors/{cloudflare → cfoa}/src/families/workflows.js +0 -0
  382. /package/packages/connectors/{cloudflare → cfoa}/src/index.js +0 -0
  383. /package/packages/connectors/{cloudflare → cfoa}/src/oauth-persist.js +0 -0
  384. /package/packages/connectors/{cloudflare → cfoa}/src/owner.js +0 -0
  385. /package/packages/connectors/{cloudflare → cfoa}/src/permission-options.js +0 -0
  386. /package/packages/connectors/{cloudflare → cfoa}/src/routes.js +0 -0
  387. /package/packages/connectors/{cloudflare → cfoa}/src/scope-catalog.js +0 -0
  388. /package/packages/connectors/{cloudflare → cfoa}/src/vault.js +0 -0
  389. /package/packages/connectors/{cloudflare → cfoa}/tests/capabilities.test.mjs +0 -0
  390. /package/packages/connectors/{cloudflare → cfoa}/tests/connector.test.mjs +0 -0
  391. /package/packages/connectors/{cloudflare → cfoa}/tests/oauth-persist.test.mjs +0 -0
  392. /package/packages/identity/src/oauth/{google-desktop-exchange.js → goaude.js} +0 -0
@@ -0,0 +1,259 @@
1
+ import { assertJobEnvelope } from '../contracts.js';
2
+
3
+ function rows(result) {
4
+ if (Array.isArray(result)) return result;
5
+ if (Array.isArray(result?.results)) return result.results;
6
+ return [];
7
+ }
8
+
9
+ function changes(result) {
10
+ if (Number.isFinite(Number(result?.changes))) return Number(result.changes);
11
+ if (Number.isFinite(Number(result?.meta?.changes))) return Number(result.meta.changes);
12
+ return 0;
13
+ }
14
+
15
+ function clean(value) {
16
+ return value == null ? '' : String(value).trim();
17
+ }
18
+
19
+ function parseJob(row) {
20
+ if (!row) return null;
21
+ const body = JSON.parse(row.job_json);
22
+ return {
23
+ ...body,
24
+ status: row.status,
25
+ available_at: Number(row.available_at),
26
+ attempt: Number(row.attempt),
27
+ lease_owner: row.lease_owner || null,
28
+ lease_expires_at: row.lease_expires_at == null ? null : Number(row.lease_expires_at),
29
+ lease_generation: Number(row.lease_generation || 0),
30
+ };
31
+ }
32
+
33
+ const PRIORITY_SQL = "CASE priority WHEN 'urgent' THEN 4 WHEN 'high' THEN 3 WHEN 'normal' THEN 2 ELSE 1 END";
34
+
35
+ /**
36
+ * Durable provider-neutral queue adapter over AgentSam's D1-shaped DB contract.
37
+ * Local SQLite is the reference host; other hosts may supply the same prepare/bind API.
38
+ */
39
+ export class SqliteQueueAdapter {
40
+ constructor({
41
+ database,
42
+ leaseOwner = 'sqlite-' + process.pid,
43
+ leaseTtlSeconds = 60,
44
+ } = {}) {
45
+ if (!database || typeof database.prepare !== 'function') {
46
+ throw new TypeError('database with prepare() is required');
47
+ }
48
+ this.database = database;
49
+ this.leaseOwner = clean(leaseOwner) || ('sqlite-' + process.pid);
50
+ this.leaseTtlSeconds = Math.max(1, Number(leaseTtlSeconds) || 60);
51
+ }
52
+
53
+ async publish(queue, job) {
54
+ assertJobEnvelope(job);
55
+ const physicalQueue = clean(queue);
56
+ if (!physicalQueue) throw new TypeError('queue is required');
57
+
58
+ const existing = await this.database.prepare(
59
+ 'SELECT id, status FROM agentsam_queue_job WHERE account_id = ? AND idempotency_key = ? LIMIT 1'
60
+ ).bind(job.account_id, job.idempotency_key).first();
61
+
62
+ if (existing && existing.id !== job.id) {
63
+ return {
64
+ provider: 'sqlite',
65
+ queue: physicalQueue,
66
+ accepted: 0,
67
+ deduplicated: true,
68
+ existing_job_id: existing.id,
69
+ existing_status: existing.status,
70
+ };
71
+ }
72
+
73
+ const maxAttempts = Math.max(1, Number(job.retry?.max_attempts) || 3);
74
+ const now = Math.floor(Date.now() / 1000);
75
+ const sql = [
76
+ 'INSERT INTO agentsam_queue_job (',
77
+ 'id, account_id, physical_queue, logical_queue, kind, status, priority,',
78
+ 'available_at, attempt, max_attempts, idempotency_key, source_run_id,',
79
+ 'step_id, lease_owner, lease_expires_at, lease_generation, job_json,',
80
+ 'created_at_unix, updated_at_unix',
81
+ ') VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
82
+ 'ON CONFLICT(id) DO UPDATE SET',
83
+ 'physical_queue = excluded.physical_queue,',
84
+ 'logical_queue = excluded.logical_queue,',
85
+ 'kind = excluded.kind,',
86
+ 'status = excluded.status,',
87
+ 'priority = excluded.priority,',
88
+ 'available_at = excluded.available_at,',
89
+ 'attempt = excluded.attempt,',
90
+ 'max_attempts = excluded.max_attempts,',
91
+ 'source_run_id = excluded.source_run_id,',
92
+ 'step_id = excluded.step_id,',
93
+ 'lease_owner = excluded.lease_owner,',
94
+ 'lease_expires_at = excluded.lease_expires_at,',
95
+ 'lease_generation = excluded.lease_generation,',
96
+ 'job_json = excluded.job_json,',
97
+ 'result_json = NULL, error_json = NULL, completed_at_unix = NULL,',
98
+ 'updated_at_unix = excluded.updated_at_unix'
99
+ ].join(' ');
100
+
101
+ await this.database.prepare(sql).bind(
102
+ job.id,
103
+ job.account_id,
104
+ physicalQueue,
105
+ job.logical_queue,
106
+ job.kind,
107
+ job.status,
108
+ job.priority,
109
+ job.available_at,
110
+ job.attempt,
111
+ maxAttempts,
112
+ job.idempotency_key,
113
+ job.source_run_id,
114
+ job.step_id,
115
+ job.lease_owner,
116
+ job.lease_expires_at,
117
+ job.lease_generation || 0,
118
+ JSON.stringify(job),
119
+ job.created_at || now,
120
+ now,
121
+ ).run();
122
+
123
+ return { provider: 'sqlite', queue: physicalQueue, accepted: 1, deduplicated: false };
124
+ }
125
+
126
+ async publishBatch(queue, jobs) {
127
+ let accepted = 0;
128
+ let deduplicated = 0;
129
+ for (const job of jobs) {
130
+ const result = await this.publish(queue, job);
131
+ accepted += Number(result.accepted || 0);
132
+ if (result.deduplicated) deduplicated += 1;
133
+ }
134
+ return { provider: 'sqlite', queue, accepted, deduplicated };
135
+ }
136
+
137
+ async pull(queue, max = 1, {
138
+ now = Math.floor(Date.now() / 1000),
139
+ owner = this.leaseOwner,
140
+ ttl_seconds = this.leaseTtlSeconds,
141
+ } = {}) {
142
+ const physicalQueue = clean(queue);
143
+ const leaseOwner = clean(owner);
144
+ if (!physicalQueue) throw new TypeError('queue is required');
145
+ if (!leaseOwner) throw new TypeError('lease owner is required');
146
+
147
+ const limit = Math.max(1, Math.floor(Number(max) || 1));
148
+ const ttl = Math.max(1, Math.floor(Number(ttl_seconds) || this.leaseTtlSeconds));
149
+ const selectSql = [
150
+ 'SELECT * FROM agentsam_queue_job',
151
+ 'WHERE physical_queue = ?',
152
+ "AND status IN ('queued','retry_scheduled','waiting','claimed')",
153
+ 'AND available_at <= ?',
154
+ 'AND (lease_expires_at IS NULL OR lease_expires_at <= ?)',
155
+ 'ORDER BY ' + PRIORITY_SQL + ' DESC, available_at ASC, created_at_unix ASC',
156
+ 'LIMIT ?'
157
+ ].join(' ');
158
+
159
+ const result = await this.database.prepare(selectSql).bind(
160
+ physicalQueue, now, now, limit
161
+ ).all();
162
+
163
+ const claimed = [];
164
+ for (const row of rows(result)) {
165
+ const leaseExpiresAt = now + ttl;
166
+ const updateSql = [
167
+ "UPDATE agentsam_queue_job SET status = 'claimed',",
168
+ 'lease_owner = ?, lease_expires_at = ?,',
169
+ 'lease_generation = lease_generation + 1, updated_at_unix = ?',
170
+ 'WHERE id = ?',
171
+ "AND status IN ('queued','retry_scheduled','waiting','claimed')",
172
+ 'AND available_at <= ?',
173
+ 'AND (lease_expires_at IS NULL OR lease_expires_at <= ?)'
174
+ ].join(' ');
175
+ const update = await this.database.prepare(updateSql).bind(
176
+ leaseOwner, leaseExpiresAt, now, row.id, now, now
177
+ ).run();
178
+
179
+ if (changes(update) !== 1) continue;
180
+ const current = await this.database.prepare(
181
+ 'SELECT * FROM agentsam_queue_job WHERE id = ? LIMIT 1'
182
+ ).bind(row.id).first();
183
+ if (current) claimed.push(parseJob(current));
184
+ }
185
+ return claimed;
186
+ }
187
+
188
+ async ack(jobOrId, {
189
+ status = 'completed',
190
+ result = null,
191
+ error = null,
192
+ now = Math.floor(Date.now() / 1000),
193
+ } = {}) {
194
+ const id = typeof jobOrId === 'string' ? jobOrId : jobOrId?.id;
195
+ if (!clean(id)) throw new TypeError('job id is required');
196
+ const sql = [
197
+ 'UPDATE agentsam_queue_job SET status = ?,',
198
+ 'lease_owner = NULL, lease_expires_at = NULL,',
199
+ 'result_json = ?, error_json = ?, completed_at_unix = ?, updated_at_unix = ?',
200
+ 'WHERE id = ?'
201
+ ].join(' ');
202
+ const update = await this.database.prepare(sql).bind(
203
+ status,
204
+ result == null ? null : JSON.stringify(result),
205
+ error == null ? null : JSON.stringify(error),
206
+ now,
207
+ now,
208
+ id,
209
+ ).run();
210
+ return { provider: 'sqlite', job_id: id, status, updated: changes(update) };
211
+ }
212
+
213
+ async release(jobOrId, {
214
+ status = 'queued',
215
+ available_at = Math.floor(Date.now() / 1000),
216
+ now = Math.floor(Date.now() / 1000),
217
+ } = {}) {
218
+ const id = typeof jobOrId === 'string' ? jobOrId : jobOrId?.id;
219
+ if (!clean(id)) throw new TypeError('job id is required');
220
+ const sql = [
221
+ 'UPDATE agentsam_queue_job SET status = ?, available_at = ?,',
222
+ 'lease_owner = NULL, lease_expires_at = NULL, updated_at_unix = ?',
223
+ 'WHERE id = ?'
224
+ ].join(' ');
225
+ const update = await this.database.prepare(sql).bind(
226
+ status, available_at, now, id
227
+ ).run();
228
+ return { provider: 'sqlite', job_id: id, status, updated: changes(update), available_at };
229
+ }
230
+
231
+ async get(id) {
232
+ const row = await this.database.prepare(
233
+ 'SELECT * FROM agentsam_queue_job WHERE id = ? LIMIT 1'
234
+ ).bind(id).first();
235
+ return parseJob(row);
236
+ }
237
+
238
+ async depth(queue, { now = null, includeTerminal = false } = {}) {
239
+ const clauses = ['physical_queue = ?'];
240
+ const values = [queue];
241
+ if (!includeTerminal) clauses.push("status NOT IN ('completed','failed','cancelled')");
242
+ if (now != null) {
243
+ clauses.push('available_at <= ?');
244
+ values.push(now);
245
+ }
246
+ const sql = 'SELECT COUNT(*) AS count FROM agentsam_queue_job WHERE ' + clauses.join(' AND ');
247
+ const row = await this.database.prepare(sql).bind(...values).first();
248
+ return Number(row?.count || 0);
249
+ }
250
+
251
+ async ensureTopology(topology) {
252
+ await this.database.prepare('SELECT id FROM agentsam_queue_job LIMIT 1').all();
253
+ return {
254
+ provider: 'sqlite',
255
+ created: [],
256
+ existing: [...new Set(Object.values(topology?.routes || {}))],
257
+ };
258
+ }
259
+ }
@@ -7,6 +7,7 @@ export const JOB_STATUSES = Object.freeze([
7
7
  'waiting',
8
8
  'batch_waiting',
9
9
  'awaiting_input',
10
+ 'retry_scheduled',
10
11
  'completed',
11
12
  'failed',
12
13
  'cancelled',
@@ -36,6 +37,7 @@ export const DEFAULT_RETRY_POLICY = Object.freeze({
36
37
  backoff: 'exponential',
37
38
  initial_delay_ms: 1_000,
38
39
  max_delay_ms: 60_000,
40
+ jitter: true,
39
41
  });
40
42
 
41
43
  function clean(value) {
@@ -48,6 +50,198 @@ function assertEnum(value, allowed, field) {
48
50
  }
49
51
  }
50
52
 
53
+ function epochSeconds(value, fallback, field = 'timestamp') {
54
+ if (value == null || value === '') return fallback;
55
+ const numeric = Number(value);
56
+ if (!Number.isFinite(numeric) || numeric < 0) throw new TypeError(`${field} must be a non-negative epoch second`);
57
+ return Math.floor(numeric);
58
+ }
59
+
60
+ export function computeRetryDelayMs(retry = DEFAULT_RETRY_POLICY, attempt = 1, random = Math.random) {
61
+ const policy = { ...DEFAULT_RETRY_POLICY, ...(retry || {}) };
62
+ const n = Math.max(1, Number.isInteger(attempt) ? attempt : 1);
63
+ const initial = Math.max(0, Number(policy.initial_delay_ms) || 0);
64
+ const maximum = Math.max(initial, Number(policy.max_delay_ms) || initial);
65
+ let delay = policy.backoff === 'exponential'
66
+ ? initial * (2 ** (n - 1))
67
+ : initial;
68
+ delay = Math.min(maximum, delay);
69
+ if (policy.jitter && delay > 0) {
70
+ const sample = Math.max(0, Math.min(1, Number(random()) || 0));
71
+ delay = Math.floor((delay / 2) + ((delay / 2) * sample));
72
+ }
73
+ return Math.max(0, Math.floor(delay));
74
+ }
75
+
76
+ export function createRetrySchedule(job, { now_ms = Date.now(), random = Math.random, error = null } = {}) {
77
+ assertJobEnvelope(job);
78
+ const nextAttempt = (Number.isInteger(job.attempt) ? job.attempt : 0) + 1;
79
+ const maxAttempts = Math.max(1, Number(job.retry?.max_attempts) || DEFAULT_RETRY_POLICY.max_attempts);
80
+ if (nextAttempt >= maxAttempts) {
81
+ return {
82
+ retryable: false,
83
+ exhausted: true,
84
+ attempt: nextAttempt,
85
+ delay_ms: 0,
86
+ available_at: null,
87
+ job: null,
88
+ };
89
+ }
90
+ const delayMs = computeRetryDelayMs(job.retry, nextAttempt, random);
91
+ const availableAt = Math.ceil((Number(now_ms) + delayMs) / 1000);
92
+ return {
93
+ retryable: true,
94
+ exhausted: false,
95
+ attempt: nextAttempt,
96
+ delay_ms: delayMs,
97
+ available_at: availableAt,
98
+ job: {
99
+ ...job,
100
+ status: 'retry_scheduled',
101
+ attempt: nextAttempt,
102
+ available_at: availableAt,
103
+ lease_owner: null,
104
+ lease_expires_at: null,
105
+ metadata: {
106
+ ...(job.metadata || {}),
107
+ ...(error ? { last_error: String(error?.message || error) } : {}),
108
+ },
109
+ },
110
+ };
111
+ }
112
+
113
+ export function createDeadLetterJob(job, {
114
+ error = null,
115
+ attempt = (Number.isInteger(job?.attempt) ? job.attempt : 0) + 1,
116
+ now = Math.floor(Date.now() / 1000),
117
+ } = {}) {
118
+ assertJobEnvelope(job);
119
+ const originalKey = clean(job.idempotency_key) || job.id;
120
+ return createJobEnvelope({
121
+ id: job.id + ':dlq:' + attempt,
122
+ account_id: job.account_id,
123
+ kind: 'dead_letter',
124
+ logical_queue: 'dead_letter',
125
+ executor: 'queue',
126
+ priority: job.priority === 'urgent' ? 'urgent' : 'high',
127
+ parent_job_id: job.id,
128
+ conversation_id: job.conversation_id,
129
+ agent_id: job.agent_id,
130
+ source_run_id: job.source_run_id,
131
+ step_id: job.step_id,
132
+ idempotency_key: originalKey + ':dlq:' + attempt,
133
+ payload: {
134
+ original_job: job,
135
+ failure: error == null ? null : {
136
+ message: String(error?.message || error),
137
+ code: clean(error?.code) || null,
138
+ },
139
+ },
140
+ metadata: {
141
+ ...(job.metadata || {}),
142
+ dead_letter: true,
143
+ original_job_id: job.id,
144
+ original_kind: job.kind,
145
+ exhausted_attempt: attempt,
146
+ },
147
+ retry: {
148
+ max_attempts: 1,
149
+ backoff: 'fixed',
150
+ initial_delay_ms: 0,
151
+ max_delay_ms: 0,
152
+ jitter: false,
153
+ },
154
+ attempt: 0,
155
+ available_at: now,
156
+ created_at: now,
157
+ });
158
+ }
159
+
160
+ export function isJobAvailable(job, now = Math.floor(Date.now() / 1000)) {
161
+ return (job?.available_at ?? 0) <= now;
162
+ }
163
+
164
+ export function jobExecutionIdentity(job) {
165
+ assertJobEnvelope(job);
166
+ return Object.freeze({
167
+ job_id: job.id,
168
+ run_id: job.source_run_id ?? null,
169
+ step_id: job.step_id ?? null,
170
+ attempt: job.attempt ?? 0,
171
+ idempotency_key: clean(job.idempotency_key) || job.id,
172
+ lease_owner: job.lease_owner ?? null,
173
+ lease_expires_at: job.lease_expires_at ?? null,
174
+ lease_generation: job.lease_generation ?? 0,
175
+ });
176
+ }
177
+
178
+ export function canClaimJobLease(job, { now = Math.floor(Date.now() / 1000), owner = null } = {}) {
179
+ assertJobEnvelope(job);
180
+ if (isTerminalJobStatus(job.status)) return false;
181
+ if (!isJobAvailable(job, now)) return false;
182
+ const leaseOwner = clean(job.lease_owner);
183
+ const leaseExpiresAt = job.lease_expires_at == null
184
+ ? null
185
+ : epochSeconds(job.lease_expires_at, null, 'lease_expires_at');
186
+ if (!leaseOwner || leaseExpiresAt == null || leaseExpiresAt <= now) return true;
187
+ return Boolean(owner && leaseOwner === clean(owner));
188
+ }
189
+
190
+ export function claimJobLease(job, { owner, now = Math.floor(Date.now() / 1000), ttl_seconds = 60 } = {}) {
191
+ assertJobEnvelope(job);
192
+ const leaseOwner = clean(owner);
193
+ if (!leaseOwner) throw new TypeError('lease owner is required');
194
+ const ttl = Math.max(1, Math.floor(Number(ttl_seconds) || 0));
195
+ if (!canClaimJobLease(job, { now, owner: leaseOwner })) {
196
+ const error = new Error(isJobAvailable(job, now) ? 'job_lease_held' : 'job_not_available');
197
+ error.code = isJobAvailable(job, now) ? 'lease_held' : 'job_not_available';
198
+ throw error;
199
+ }
200
+ return {
201
+ ...job,
202
+ status: 'claimed',
203
+ lease_owner: leaseOwner,
204
+ lease_expires_at: now + ttl,
205
+ lease_generation: Math.max(0, Number(job.lease_generation) || 0) + 1,
206
+ };
207
+ }
208
+
209
+ export function refreshJobLease(job, { owner, now = Math.floor(Date.now() / 1000), ttl_seconds = 60 } = {}) {
210
+ assertJobEnvelope(job);
211
+ const leaseOwner = clean(owner);
212
+ if (!leaseOwner || leaseOwner !== clean(job.lease_owner)) {
213
+ const error = new Error('job_lease_owner_mismatch');
214
+ error.code = 'lease_owner_mismatch';
215
+ throw error;
216
+ }
217
+ const currentExpiry = epochSeconds(job.lease_expires_at, 0, 'lease_expires_at');
218
+ if (currentExpiry <= now) {
219
+ const error = new Error('job_lease_expired');
220
+ error.code = 'lease_expired';
221
+ throw error;
222
+ }
223
+ const ttl = Math.max(1, Math.floor(Number(ttl_seconds) || 0));
224
+ return { ...job, lease_expires_at: now + ttl };
225
+ }
226
+
227
+ export function releaseJobLease(job, { owner, status = 'queued', available_at = job.available_at } = {}) {
228
+ assertJobEnvelope(job);
229
+ const leaseOwner = clean(owner);
230
+ if (leaseOwner && clean(job.lease_owner) && leaseOwner !== clean(job.lease_owner)) {
231
+ const error = new Error('job_lease_owner_mismatch');
232
+ error.code = 'lease_owner_mismatch';
233
+ throw error;
234
+ }
235
+ assertEnum(status, JOB_STATUSES, 'status');
236
+ return {
237
+ ...job,
238
+ status,
239
+ available_at: epochSeconds(available_at, job.available_at, 'available_at'),
240
+ lease_owner: null,
241
+ lease_expires_at: null,
242
+ };
243
+ }
244
+
51
245
  export function createJobEnvelope(input = {}) {
52
246
  const kind = clean(input.kind);
53
247
  if (!kind) throw new TypeError('kind is required');
@@ -56,6 +250,8 @@ export function createJobEnvelope(input = {}) {
56
250
  if (!accountId) throw new TypeError('account_id is required');
57
251
 
58
252
  const now = input.created_at ?? Math.floor(Date.now() / 1000);
253
+ const availableAt = epochSeconds(input.available_at ?? input.availableAt, now, 'available_at');
254
+ const id = clean(input.id) || `job_${randomUUID().replaceAll('-', '')}`;
59
255
  const priority = input.priority ?? 'normal';
60
256
  assertEnum(priority, JOB_PRIORITIES, 'priority');
61
257
 
@@ -64,7 +260,7 @@ export function createJobEnvelope(input = {}) {
64
260
 
65
261
  return {
66
262
  schema_version: '1',
67
- id: clean(input.id) || `job_${randomUUID().replaceAll('-', '')}`,
263
+ id,
68
264
  account_id: accountId,
69
265
  kind,
70
266
  logical_queue: clean(input.logical_queue) || null,
@@ -74,8 +270,12 @@ export function createJobEnvelope(input = {}) {
74
270
  parent_job_id: clean(input.parent_job_id) || null,
75
271
  conversation_id: clean(input.conversation_id) || null,
76
272
  agent_id: clean(input.agent_id) || null,
77
- source_run_id: clean(input.source_run_id) || null,
78
- idempotency_key: clean(input.idempotency_key) || null,
273
+ source_run_id: clean(input.source_run_id ?? input.run_id) || null,
274
+ step_id: clean(input.step_id) || null,
275
+ idempotency_key: clean(input.idempotency_key ?? input.idempotencyKey) || id,
276
+ lease_owner: clean(input.lease_owner) || null,
277
+ lease_expires_at: input.lease_expires_at == null ? null : epochSeconds(input.lease_expires_at, null, 'lease_expires_at'),
278
+ lease_generation: Number.isInteger(input.lease_generation) ? Math.max(0, input.lease_generation) : 0,
79
279
  payload: input.payload ?? null,
80
280
  payload_ref: clean(input.payload_ref) || null,
81
281
  metadata: input.metadata && typeof input.metadata === 'object' ? input.metadata : {},
@@ -84,6 +284,7 @@ export function createJobEnvelope(input = {}) {
84
284
  ...(input.retry && typeof input.retry === 'object' ? input.retry : {}),
85
285
  },
86
286
  attempt: Number.isInteger(input.attempt) ? input.attempt : 0,
287
+ available_at: availableAt,
87
288
  created_at: now,
88
289
  };
89
290
  }
@@ -97,6 +298,9 @@ export function assertJobEnvelope(job) {
97
298
  assertEnum(job.priority ?? 'normal', JOB_PRIORITIES, 'job.priority');
98
299
  assertEnum(job.executor ?? 'queue', EXECUTOR_KINDS, 'job.executor');
99
300
  assertEnum(job.status ?? 'queued', JOB_STATUSES, 'job.status');
301
+ epochSeconds(job.available_at, job.created_at ?? 0, 'job.available_at');
302
+ if (job.lease_expires_at != null) epochSeconds(job.lease_expires_at, null, 'job.lease_expires_at');
303
+ if (job.lease_owner && job.lease_expires_at == null) throw new TypeError('job.lease_expires_at is required when job.lease_owner is set');
100
304
  return job;
101
305
  }
102
306
 
@@ -1,4 +1,4 @@
1
- import { createJobEnvelope, assertJobEnvelope } from './contracts.js';
1
+ import { createJobEnvelope, assertJobEnvelope, computeRetryDelayMs, createRetrySchedule, createDeadLetterJob } from './contracts.js';
2
2
  import { buildQueueTopology, resolvePhysicalQueue } from './topology.js';
3
3
  import { routeWork, shouldRequireProvisionApproval } from './policy.js';
4
4
  import { JobDispatcher } from './dispatch.js';
@@ -117,6 +117,16 @@ export class QueueControl {
117
117
  return this.adapter.ensureTopology(this.topology, options);
118
118
  }
119
119
 
120
+ async deadLetter(job, error, { attempt = (job.attempt || 0) + 1 } = {}) {
121
+ const deadLetter = createDeadLetterJob(job, { error, attempt });
122
+ const queue = resolvePhysicalQueue(this.topology, 'dead_letter');
123
+ const receipt = await this.adapter.publish(queue, deadLetter, {
124
+ logical_queue: 'dead_letter',
125
+ dead_letter: true,
126
+ });
127
+ return { job: deadLetter, queue, receipt: receipt ?? null };
128
+ }
129
+
120
130
  async consume(messages, context = {}) {
121
131
  const results = [];
122
132
  for (const message of messages) {
@@ -127,12 +137,62 @@ export class QueueControl {
127
137
  if (typeof message?.ack === 'function') message.ack();
128
138
  results.push({ job_id: job.id, ok: true, result });
129
139
  } catch (error) {
130
- if (typeof message?.retry === 'function') message.retry();
140
+ let retry = null;
141
+ if (typeof message?.retry === 'function') {
142
+ const attempt = Number.isInteger(message.attempts) ? message.attempts : (job.attempt + 1);
143
+ const maxAttempts = Math.max(1, Number(job.retry?.max_attempts) || 3);
144
+ if (attempt >= maxAttempts) {
145
+ // Do not ACK an exhausted provider-managed message here. A configured
146
+ // provider DLQ is the crash-safe fallback; retry/failure delivery lets
147
+ // the provider move it after max_retries instead of silently deleting it.
148
+ const delayMs = computeRetryDelayMs(job.retry, attempt);
149
+ const delaySeconds = Math.max(0, Math.ceil(delayMs / 1000));
150
+ message.retry(delaySeconds > 0 ? { delaySeconds } : undefined);
151
+ retry = {
152
+ scheduled: false,
153
+ exhausted: true,
154
+ provider_managed: true,
155
+ delegated_to_provider_dlq: true,
156
+ attempt,
157
+ delay_ms: delayMs,
158
+ delay_seconds: delaySeconds,
159
+ };
160
+ } else {
161
+ const delayMs = computeRetryDelayMs(job.retry, attempt);
162
+ const delaySeconds = Math.max(0, Math.ceil(delayMs / 1000));
163
+ message.retry(delaySeconds > 0 ? { delaySeconds } : undefined);
164
+ retry = { scheduled: true, provider_managed: true, attempt, delay_ms: delayMs, delay_seconds: delaySeconds };
165
+ }
166
+ } else if (job.logical_queue) {
167
+ const schedule = createRetrySchedule(job, { error });
168
+ if (schedule.retryable && schedule.job) {
169
+ const queue = resolvePhysicalQueue(this.topology, job.logical_queue);
170
+ await this.adapter.publish(queue, schedule.job, { logical_queue: job.logical_queue });
171
+ retry = {
172
+ scheduled: true,
173
+ provider_managed: false,
174
+ delay_ms: schedule.delay_ms,
175
+ available_at: schedule.available_at,
176
+ attempt: schedule.attempt,
177
+ };
178
+ } else {
179
+ const deadLetter = await this.deadLetter(job, error, { attempt: schedule.attempt });
180
+ retry = {
181
+ scheduled: false,
182
+ exhausted: true,
183
+ attempt: schedule.attempt,
184
+ dead_lettered: true,
185
+ dead_letter_job_id: deadLetter.job.id,
186
+ dead_letter_queue: deadLetter.queue,
187
+ };
188
+ }
189
+ }
131
190
  results.push({
132
191
  job_id: job.id,
133
192
  ok: false,
134
193
  error: String(error?.message || error),
135
194
  code: error?.code ?? null,
195
+ retry,
136
196
  });
137
197
  }
138
198
  }
@@ -5,3 +5,4 @@ export * from './dispatch.js';
5
5
  export * from './control-plane.js';
6
6
  export * from './adapters/memory.js';
7
7
  export * from './adapters/cloudflare.js';
8
+ export * from './adapters/sqlite.js';