@inneranimalmedia/agentsam-sdk 2.6.2 → 2.6.3

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 (497) hide show
  1. package/AGENTSAM.md +45 -1
  2. package/README.md +80 -0
  3. package/apps/README.md +34 -0
  4. package/apps/cad-creator/README.md +728 -0
  5. package/apps/cad-creator/shared/cad/package.json +19 -0
  6. package/apps/cad-creator/shared/cad/src/domain/operations.ts +7 -0
  7. package/apps/cad-creator/shared/cad/src/domain/project-contract.d.ts +3 -0
  8. package/apps/cad-creator/shared/cad/src/domain/project-contract.js +75 -0
  9. package/apps/cad-creator/shared/cad/src/domain/project-tools.d.ts +1 -0
  10. package/apps/cad-creator/shared/cad/src/domain/project-tools.js +24 -0
  11. package/apps/cad-creator/shared/cad/src/domain/validation.ts +191 -0
  12. package/apps/cad-creator/shared/cad/src/index.ts +4 -0
  13. package/apps/cad-creator/shared/cad/src/robotics/types.ts +232 -0
  14. package/apps/cad-creator/shared/cad/src/types.ts +507 -0
  15. package/apps/cad-creator/shared/cad/tsconfig.json +14 -0
  16. package/docs/AUTORAG.md +58 -0
  17. package/docs/BRAND_INTELLIGENCE.md +30 -0
  18. package/docs/CLI_SHELL.md +4 -2
  19. package/docs/CMS_CONTEXTUAL_COMPOSER.md +38 -0
  20. package/docs/MERKLE.md +4 -0
  21. package/docs/PROJECT_CONFIG.md +3 -0
  22. package/docs/REPOSITORY_KNOWLEDGE.md +2 -0
  23. package/docs/THEME_REFINERY.md +120 -0
  24. package/docs/architecture/PROVIDER-TOOLS-AND-COMPACTION.md +60 -0
  25. package/docs/architecture/STORAGE.md +87 -0
  26. package/docs/cad-project-tools.md +69 -0
  27. package/docs/cms-scaffolding-pattern-reference.md +73 -0
  28. package/docs/plans/AGENTSAM-INTERACTIVE-UI-REQUIREMENTS-codex-tui-20260919.md +113 -0
  29. package/docs/plans/AGENTSAM-INTERACTIVE-UI-REQUIREMENTS.md +85 -0
  30. package/docs/plans/AGENTSAM-MCP-CLIENT-2026-09-19.md +181 -0
  31. package/docs/plans/ASBD-PORTABLE-WORKGRAPH-UI-DEFERRED.md +34 -0
  32. package/docs/plans/ASTRA-BRIEF-2026-09-18.md +258 -0
  33. package/docs/plans/MULTI-AGENT-SPRINTS-2026-09-19.md +373 -0
  34. package/docs/plans/NEXT-AGENT-HANDOFF.md +167 -0
  35. package/docs/plans/RECONCILIATION-2026-09-19.md +178 -0
  36. package/docs/plugins.md +43 -0
  37. package/docs/tools/README.md +57 -0
  38. package/docs/tools/agent-and-orchestration.md +49 -0
  39. package/docs/tools/browser-and-research.md +46 -0
  40. package/docs/tools/cloudflare-platform.md +32 -0
  41. package/docs/tools/cms.md +25 -0
  42. package/docs/tools/communications.md +41 -0
  43. package/docs/tools/database-and-storage.md +62 -0
  44. package/docs/tools/design-and-media.md +64 -0
  45. package/docs/tools/filesystem-and-code.md +55 -0
  46. package/docs/tools/github.md +56 -0
  47. package/docs/tools/integrations-and-misc.md +16 -0
  48. package/docs/tools/memory.md +21 -0
  49. package/docs/tools/terminal-and-execution.md +29 -0
  50. package/docs/tools/tickets-and-platform.md +30 -0
  51. package/migrations/d1/0001_agentsam_plugin_runtime.sql +177 -0
  52. package/migrations/d1/0002_agentsam_ticket_ownership.sql +8 -0
  53. package/migrations/d1/0002_dynamic_model_policies.sql +23 -0
  54. package/migrations/d1/0003_expand_tool_handler_families.sql +18 -0
  55. package/migrations/d1/0004_project_aware_retrieval_lanes.sql +24 -0
  56. package/migrations/d1/0005_portable_knowledge_identity.sql +104 -0
  57. package/migrations/d1/0006_repair_ops_trail_account_scope.sql +14 -0
  58. package/migrations/d1/0007_repair_ops_trail_agent_run_account.sql +13 -0
  59. package/migrations/d1/0008_backfill_knowledge_run_legacy_tenant.sql +14 -0
  60. package/migrations/d1/0009_normalize_cloudflare_plugin_installations.sql +137 -0
  61. package/migrations/runtime/0001_cli_runtime.sql +67 -0
  62. package/migrations/runtime/0002_project_sessions.sql +15 -0
  63. package/migrations/runtime/0003_provider_continuations.sql +8 -0
  64. package/package.json +92 -12
  65. package/packages/agentsam-brand/README.md +21 -0
  66. package/packages/agentsam-brand/package.json +22 -0
  67. package/packages/agentsam-brand/src/contract.js +59 -0
  68. package/packages/agentsam-brand/src/extract.js +126 -0
  69. package/packages/agentsam-brand/src/goap-actions.js +73 -0
  70. package/packages/agentsam-brand/src/index.js +48 -0
  71. package/packages/agentsam-brand/src/plan.js +115 -0
  72. package/packages/agentsam-brand/src/resolve.js +139 -0
  73. package/packages/agentsam-brand/src/scan.js +250 -0
  74. package/packages/agentsam-brand/test/brand-scan.test.mjs +106 -0
  75. package/packages/agentsam-contracts/README.md +23 -0
  76. package/packages/agentsam-contracts/package.json +32 -0
  77. package/packages/agentsam-contracts/src/adapter.ts +25 -0
  78. package/packages/agentsam-contracts/src/agent.ts +35 -0
  79. package/packages/agentsam-contracts/src/artifacts.ts +33 -0
  80. package/packages/agentsam-contracts/src/authority.ts +29 -0
  81. package/packages/agentsam-contracts/src/context.ts +16 -0
  82. package/packages/agentsam-contracts/src/errors.ts +46 -0
  83. package/packages/agentsam-contracts/src/events.ts +47 -0
  84. package/packages/agentsam-contracts/src/execution.ts +50 -0
  85. package/packages/agentsam-contracts/src/hooks.ts +40 -0
  86. package/packages/agentsam-contracts/src/identity.ts +16 -0
  87. package/packages/agentsam-contracts/src/index.ts +14 -0
  88. package/packages/agentsam-contracts/src/models.ts +9 -0
  89. package/packages/agentsam-contracts/src/providers.ts +33 -0
  90. package/packages/agentsam-contracts/src/repository.ts +64 -0
  91. package/packages/agentsam-contracts/src/tools.ts +98 -0
  92. package/packages/agentsam-contracts/test/contracts.test.mjs +16 -0
  93. package/packages/agentsam-contracts/test/errors-catalog.test.mjs +25 -0
  94. package/packages/agentsam-contracts/test/repository.test.mjs +18 -0
  95. package/packages/agentsam-contracts/tsconfig.json +12 -0
  96. package/packages/agentsam-errors/package.json +17 -0
  97. package/packages/agentsam-errors/src/adapters/anthropic.js +15 -0
  98. package/packages/agentsam-errors/src/adapters/cad.js +109 -0
  99. package/packages/agentsam-errors/src/adapters/cloudflare.js +21 -0
  100. package/packages/agentsam-errors/src/adapters/cursor.js +4 -0
  101. package/packages/agentsam-errors/src/adapters/device.js +38 -0
  102. package/packages/agentsam-errors/src/adapters/docker.js +28 -0
  103. package/packages/agentsam-errors/src/adapters/gcp.js +14 -0
  104. package/packages/agentsam-errors/src/adapters/github.js +22 -0
  105. package/packages/agentsam-errors/src/adapters/google.js +17 -0
  106. package/packages/agentsam-errors/src/adapters/index.js +55 -0
  107. package/packages/agentsam-errors/src/adapters/internal.js +40 -0
  108. package/packages/agentsam-errors/src/adapters/oauth.js +24 -0
  109. package/packages/agentsam-errors/src/adapters/openai.js +17 -0
  110. package/packages/agentsam-errors/src/adapters/process.js +35 -0
  111. package/packages/agentsam-errors/src/adapters/provider.js +114 -0
  112. package/packages/agentsam-errors/src/envelope.js +186 -0
  113. package/packages/agentsam-errors/src/error.js +24 -0
  114. package/packages/agentsam-errors/src/fingerprint.js +35 -0
  115. package/packages/agentsam-errors/src/index.js +10 -0
  116. package/packages/agentsam-errors/src/normalize.js +30 -0
  117. package/packages/agentsam-errors/src/redaction.js +52 -0
  118. package/packages/agentsam-errors/src/render.js +16 -0
  119. package/packages/agentsam-errors/src/retry.js +10 -0
  120. package/packages/agentsam-errors/src/transport.js +52 -0
  121. package/packages/agentsam-errors/src/vocabulary.js +320 -0
  122. package/packages/agentsam-errors/test/envelope.test.mjs +70 -0
  123. package/packages/agentsam-errors/test/providers.test.mjs +99 -0
  124. package/packages/agentsam-errors/test/redaction.test.mjs +21 -0
  125. package/packages/agentsam-errors/test/runtime-cad-device.test.mjs +76 -0
  126. package/packages/agentsam-errors/test/transport.test.mjs +46 -0
  127. package/packages/agentsam-knowledge/package.json +15 -0
  128. package/packages/agentsam-knowledge/src/autorag/index.js +64 -0
  129. package/packages/agentsam-knowledge/src/backends/index.js +26 -0
  130. package/packages/agentsam-knowledge/src/index.js +3 -0
  131. package/packages/agentsam-knowledge/src/providers/index.js +95 -0
  132. package/packages/agentsam-knowledge/test/autorag.test.mjs +42 -0
  133. package/packages/agentsam-nav/README.md +40 -0
  134. package/packages/agentsam-nav/dist/Nav.d.ts +43 -0
  135. package/packages/agentsam-nav/dist/NavCollapsible.d.ts +10 -0
  136. package/packages/agentsam-nav/dist/NavContent.d.ts +2 -0
  137. package/packages/agentsam-nav/dist/NavFooter.d.ts +2 -0
  138. package/packages/agentsam-nav/dist/NavGroup.d.ts +3 -0
  139. package/packages/agentsam-nav/dist/NavHeader.d.ts +2 -0
  140. package/packages/agentsam-nav/dist/NavMenu.d.ts +22 -0
  141. package/packages/agentsam-nav/dist/NavProvider.d.ts +35 -0
  142. package/packages/agentsam-nav/dist/NavTrigger.d.ts +2 -0
  143. package/packages/agentsam-nav/dist/Surfaces.d.ts +41 -0
  144. package/packages/agentsam-nav/dist/browser.d.ts +11 -0
  145. package/packages/agentsam-nav/dist/browser.global.js +132 -0
  146. package/packages/agentsam-nav/dist/browser.js +613 -0
  147. package/packages/agentsam-nav/dist/contracts.d.ts +76 -0
  148. package/packages/agentsam-nav/dist/index.d.ts +11 -0
  149. package/packages/agentsam-nav/dist/index.js +614 -0
  150. package/packages/agentsam-nav/dist/legacy.css +83 -0
  151. package/packages/agentsam-nav/dist/shell.css +113 -0
  152. package/packages/agentsam-nav/dist/theme.css +113 -0
  153. package/packages/agentsam-nav/dist/utils.d.ts +1 -0
  154. package/packages/agentsam-nav/package.json +43 -0
  155. package/packages/agentsam-queue-control/README.md +107 -0
  156. package/packages/agentsam-queue-control/package.json +31 -0
  157. package/packages/agentsam-queue-control/schemas/job-envelope.schema.json +56 -0
  158. package/packages/agentsam-queue-control/src/adapters/cloudflare.js +152 -0
  159. package/packages/agentsam-queue-control/src/adapters/memory.js +38 -0
  160. package/packages/agentsam-queue-control/src/contracts.js +130 -0
  161. package/packages/agentsam-queue-control/src/control-plane.js +141 -0
  162. package/packages/agentsam-queue-control/src/dispatch.js +43 -0
  163. package/packages/agentsam-queue-control/src/index.js +7 -0
  164. package/packages/agentsam-queue-control/src/policy.js +88 -0
  165. package/packages/agentsam-queue-control/src/topology.js +66 -0
  166. package/packages/agentsam-queue-control/test/queue-control.test.mjs +100 -0
  167. package/packages/agentsam-repository/src/goap.js +718 -0
  168. package/packages/agentsam-repository/src/goap.js.bak-20260922011251 +670 -0
  169. package/packages/agentsam-repository/src/index.js +5 -0
  170. package/packages/agentsam-repository/src/merkle/cloudflare-persistence.js +2 -2
  171. package/packages/agentsam-repository/src/tickets.js +184 -0
  172. package/packages/agentsam-repository/src/work-tracking.js +199 -0
  173. package/packages/agentsam-repository/src/workspace-state.js +176 -0
  174. package/packages/agentsam-repository/test/goap-tickets-workspace-state.test.mjs +152 -0
  175. package/packages/connectors/cloudflare/src/index.js +297 -15
  176. package/packages/connectors/cloudflare/src/owner.js +43 -40
  177. package/packages/connectors/cloudflare/src/routes.js +167 -26
  178. package/packages/connectors/cloudflare/tests/connector.test.mjs +112 -2
  179. package/packages/heuristic-theme/README.md +11 -0
  180. package/packages/heuristic-theme/package.json +25 -0
  181. package/packages/heuristic-theme/src/index.js +2 -0
  182. package/packages/heuristic-theme/src/registry.js +36 -0
  183. package/packages/heuristic-theme/src/theme.js +41 -0
  184. package/packages/heuristic-theme/test/theme.test.mjs +26 -0
  185. package/packages/identity/.agentsam/features/oauth-login-portal/agentsam.feature.json +64 -0
  186. package/packages/identity/.agentsam/features/oauth-login-portal/providers.json +96 -0
  187. package/packages/identity/.agentsam/features/oauth-login-portal/resources.json +47 -0
  188. package/packages/identity/.agentsam/features/oauth-login-portal/routes.json +74 -0
  189. package/packages/identity/.agentsam/features/oauth-login-portal/ui.json +35 -0
  190. package/packages/identity/package.json +3 -2
  191. package/packages/identity/src/adapters/cloudflare-d1/ids.js +4 -0
  192. package/packages/identity/src/adapters/cloudflare-d1/index.js +39 -1
  193. package/packages/identity/src/contracts/provider.js +3 -2
  194. package/packages/identity/src/frontend/auth-portal/pages/login.html +7 -0
  195. package/packages/identity/src/index.js +2 -0
  196. package/packages/identity/src/oauth/credentials.js +13 -0
  197. package/packages/identity/src/oauth/iam-platform.js +5 -5
  198. package/packages/identity/src/providers/cloudflare/index.js +19 -0
  199. package/packages/identity/src/providers/cloudflare/mapper.js +21 -0
  200. package/packages/identity/src/providers/cloudflare/oauth.js +48 -0
  201. package/packages/identity/src/providers/cloudflare/profile.js +28 -0
  202. package/packages/identity/src/providers/index.js +18 -2
  203. package/packages/identity/src/server/identity-service.js +13 -3
  204. package/packages/identity/src/server/worker-router.js +63 -8
  205. package/packages/identity/tests/identity-service.test.mjs +15 -0
  206. package/packages/providers/completeful/README.md +38 -0
  207. package/packages/providers/completeful/package.json +29 -0
  208. package/packages/providers/completeful/src/client.js +162 -0
  209. package/packages/providers/completeful/src/events.js +49 -0
  210. package/packages/providers/completeful/src/index.js +22 -0
  211. package/packages/providers/completeful/src/tools.js +579 -0
  212. package/packages/providers/completeful/src/webhooks.js +55 -0
  213. package/packages/providers/completeful/test/provider.test.mjs +196 -0
  214. package/packages/theme-church-site/README.md +10 -0
  215. package/packages/theme-church-site/package.json +30 -0
  216. package/packages/theme-church-site/src/harvest.json +14 -0
  217. package/packages/theme-church-site/src/index.js +84 -0
  218. package/packages/theme-church-site/test/theme.test.mjs +19 -0
  219. package/packages/theme-companions-site/README.md +10 -0
  220. package/packages/theme-companions-site/package.json +30 -0
  221. package/packages/theme-companions-site/src/harvest.json +12 -0
  222. package/packages/theme-companions-site/src/index.js +82 -0
  223. package/packages/theme-companions-site/test/theme.test.mjs +19 -0
  224. package/packages/theme-floors-site/README.md +10 -0
  225. package/packages/theme-floors-site/package.json +30 -0
  226. package/packages/theme-floors-site/src/harvest.json +14 -0
  227. package/packages/theme-floors-site/src/index.js +82 -0
  228. package/packages/theme-floors-site/test/theme.test.mjs +19 -0
  229. package/packages/theme-fuelnfree-site/README.md +10 -0
  230. package/packages/theme-fuelnfree-site/package.json +30 -0
  231. package/packages/theme-fuelnfree-site/src/harvest.json +13 -0
  232. package/packages/theme-fuelnfree-site/src/index.js +81 -0
  233. package/packages/theme-fuelnfree-site/test/theme.test.mjs +19 -0
  234. package/packages/theme-handyman-site/README.md +10 -0
  235. package/packages/theme-handyman-site/package.json +30 -0
  236. package/packages/theme-handyman-site/src/harvest.json +10 -0
  237. package/packages/theme-handyman-site/src/index.js +83 -0
  238. package/packages/theme-handyman-site/test/theme.test.mjs +19 -0
  239. package/packages/theme-insurance-site/README.md +10 -0
  240. package/packages/theme-insurance-site/package.json +30 -0
  241. package/packages/theme-insurance-site/src/harvest.json +10 -0
  242. package/packages/theme-insurance-site/src/index.js +83 -0
  243. package/packages/theme-insurance-site/test/theme.test.mjs +19 -0
  244. package/packages/theme-shinshu-site/README.md +10 -0
  245. package/packages/theme-shinshu-site/package.json +30 -0
  246. package/packages/theme-shinshu-site/src/harvest.json +12 -0
  247. package/packages/theme-shinshu-site/src/index.js +83 -0
  248. package/packages/theme-shinshu-site/test/theme.test.mjs +19 -0
  249. package/packages/work-graph/README.md +49 -0
  250. package/packages/work-graph/package.json +19 -0
  251. package/packages/work-graph/prototype/README.md +32 -0
  252. package/packages/work-graph/prototype/data/demo-workgraph.js +47 -0
  253. package/packages/work-graph/prototype/renderers/timeline-model.js +21 -0
  254. package/packages/work-graph/prototype/renderers/workgraph-runtime.js +38 -0
  255. package/packages/work-graph/prototype-gnantt.html +655 -0
  256. package/packages/work-graph/src/adapters/business/projects.js +23 -0
  257. package/packages/work-graph/src/adapters/engineering/git.js +22 -0
  258. package/packages/work-graph/src/adapters/engineering/mcp.js +22 -0
  259. package/packages/work-graph/src/index.js +76 -0
  260. package/packages/work-graph/src/renderers/gantt-model.js +11 -0
  261. package/packages/work-graph/src/renderers/timeline.js +16 -0
  262. package/packages/work-graph/test/work-graph.test.mjs +37 -0
  263. package/protocol/README.md +12 -0
  264. package/protocol/capabilities/cloudflare-cpu-audit-input.schema.json +30 -6
  265. package/protocol/capabilities/cloudflare-cpu-profile-input.schema.json +18 -4
  266. package/protocol/capabilities/cloudflare-wrangler-native-input.schema.json +59 -10
  267. package/protocol/capabilities/knowledge-search-input.schema.json +35 -0
  268. package/protocol/capabilities/manifest.json +163 -1
  269. package/protocol/capabilities/repository-audit-input.schema.json +39 -6
  270. package/protocol/capabilities/repository-snapshot-input.schema.json +15 -3
  271. package/protocol/capabilities/terminal-exec-input.schema.json +55 -0
  272. package/protocol/commerce/catalog.v1.json +50 -0
  273. package/protocol/errors/error-catalog.json +164 -0
  274. package/protocol/errors/error-envelope.schema.json +544 -0
  275. package/protocol/features/README.md +57 -0
  276. package/protocol/features/agentsam.feature.v1.schema.json +290 -0
  277. package/protocol/features/catalog.json +65 -0
  278. package/protocol/features/examples/provider-resend.feature.json +17 -0
  279. package/protocol/go/agentsam-go-runtime.v1.json +17 -0
  280. package/protocol/knowledge/LIFECYCLE.md +140 -0
  281. package/protocol/knowledge/README.md +4 -0
  282. package/protocol/presets/catalog.json +128 -19
  283. package/protocol/rpc/v1/errors.proto +24 -0
  284. package/protocol/theme-refinery/d1-reconciliation.md +48 -0
  285. package/protocol/theme-refinery/product-metadata.schema.json +27 -0
  286. package/protocol/theme-refinery/receipts/products-registry-batch-20260924.json +318 -0
  287. package/protocol/theme-refinery/receipts/theme-harvest-20260924.json +472 -0
  288. package/protocol/theme-refinery/reconciliation-receipt.schema.json +83 -0
  289. package/services/cad/server.py +249 -2
  290. package/src/agent/capability-adapter.js +15 -5
  291. package/src/agent/index.js +2 -1
  292. package/src/agent/model-turn.js +51 -0
  293. package/src/agent/responses-runner.js +304 -38
  294. package/src/capabilities/index.js +1 -0
  295. package/src/capabilities/terminal-exec.js +78 -0
  296. package/src/cli.js +117 -9
  297. package/src/cloudflare/index.js +6 -0
  298. package/src/cloudflare/runtime-status.js +393 -0
  299. package/src/cloudflare/wrangler.js +17 -1
  300. package/src/commands/app.js +106 -0
  301. package/src/commands/autorag.js +77 -0
  302. package/src/commands/brand.js +293 -0
  303. package/src/commands/cad.js +1 -0
  304. package/src/commands/connections.js +126 -29
  305. package/src/commands/context-economics.js +8 -0
  306. package/src/commands/db.js +7 -0
  307. package/src/commands/env.js +5 -4
  308. package/src/commands/eval.js +209 -14
  309. package/src/commands/go.js +365 -0
  310. package/src/commands/goap.js +176 -0
  311. package/src/commands/identity-init.js +27 -3
  312. package/src/commands/identity-protocol.js +195 -0
  313. package/src/commands/knowledge.js +64 -5
  314. package/src/commands/mcp.js +341 -0
  315. package/src/commands/merkle-persist.js +3 -1
  316. package/src/commands/merkle.js +18 -3
  317. package/src/commands/models.js +109 -23
  318. package/src/commands/plugins.js +175 -0
  319. package/src/commands/preferences.js +28 -8
  320. package/src/commands/product.js +53 -10
  321. package/src/commands/providers.js +118 -37
  322. package/src/commands/resume.js +9 -5
  323. package/src/commands/runtime-status.js +154 -0
  324. package/src/commands/shell.js +466 -55
  325. package/src/commands/status.js +82 -7
  326. package/src/commands/tunnel.js +228 -195
  327. package/src/commands/whoami.js +78 -6
  328. package/src/context/budget.js +6 -0
  329. package/src/context/index.js +2 -1
  330. package/src/context/project-card.js +75 -0
  331. package/src/errors/contract.js +34 -211
  332. package/src/errors/diagnostic.js +95 -51
  333. package/src/errors/index.js +6 -13
  334. package/src/eval/index.js +6 -0
  335. package/src/eval/live.js +439 -0
  336. package/src/features/resolve.js +242 -0
  337. package/src/go/build.js +108 -0
  338. package/src/go/cloudflare.js +207 -0
  339. package/src/go/contract.js +139 -0
  340. package/src/go/discover.js +96 -0
  341. package/src/go/index.js +13 -0
  342. package/src/go/receipts.js +77 -0
  343. package/src/go/registry.js +223 -0
  344. package/src/go/verify.js +31 -0
  345. package/src/index.js +100 -1
  346. package/src/knowledge/config.js +13 -5
  347. package/src/knowledge/engine.js +23 -8
  348. package/src/knowledge/index.js +1 -0
  349. package/src/knowledge/lane-registry.js +46 -0
  350. package/src/knowledge/providers/gemini.js +48 -8
  351. package/src/knowledge/service/client.js +13 -1
  352. package/src/knowledge/service/grpc-codec.js +156 -53
  353. package/src/knowledge/service/job-engine.js +133 -11
  354. package/src/knowledge/service/job-worker.js +34 -5
  355. package/src/knowledge/service/server.js +10 -1
  356. package/src/knowledge/store-discovery.js +77 -0
  357. package/src/lib/account-session.js +8 -2
  358. package/src/lib/agent-instructions.js +3 -0
  359. package/src/lib/auth.js +7 -3
  360. package/src/lib/cad/blender.js +42 -3
  361. package/src/lib/cad/d1-project-store.js +43 -0
  362. package/src/lib/cad/discovery.js +616 -0
  363. package/src/lib/cad/docker-executor.js +352 -0
  364. package/src/lib/cad/freecad.js +253 -0
  365. package/src/lib/cad/index.js +40 -0
  366. package/src/lib/cad/openscad.js +198 -0
  367. package/src/lib/cad/project-cli.d.ts +2 -0
  368. package/src/lib/cad/project-cli.js +21 -0
  369. package/src/lib/cad/project-contract.d.ts +3 -0
  370. package/src/lib/cad/project-contract.js +1 -0
  371. package/src/lib/cad/project-recipe.js +30 -0
  372. package/src/lib/cad/project-runtime.d.ts +2 -0
  373. package/src/lib/cad/project-runtime.js +53 -0
  374. package/src/lib/cad/project-store.js +25 -0
  375. package/src/lib/cad/project-workflows.js +31 -0
  376. package/src/lib/cad-docker.js +21 -2
  377. package/src/lib/cli-preferences.js +17 -2
  378. package/src/lib/core-client.js +37 -18
  379. package/src/lib/deploy/local-studio.js +6 -5
  380. package/src/lib/dockerize.js +3 -0
  381. package/src/lib/execution-approvals.js +1 -0
  382. package/src/lib/identity-scaffold.js +4 -1
  383. package/src/lib/knowledge-docker.js +9 -1
  384. package/src/lib/local-sessions.js +124 -34
  385. package/src/lib/local-status.js +35 -14
  386. package/src/lib/project-config.js +9 -0
  387. package/src/lib/provider-credentials.js +73 -11
  388. package/src/lib/scaffold/resolve-cloudflare-account.js +37 -0
  389. package/src/lib/scaffold/wizards/cms.js +2 -8
  390. package/src/lib/scaffold/wizards/worker-api.js +2 -8
  391. package/src/lib/slash-commands.js +9 -2
  392. package/src/local/migrations.js +109 -1
  393. package/src/local/runtime-store.js +31 -5
  394. package/src/local/sqlite.js +36 -1
  395. package/src/mcp/authority.js +348 -0
  396. package/src/mcp/client-adapters.js +431 -0
  397. package/src/mcp/client.js +172 -0
  398. package/src/mcp/index.js +47 -0
  399. package/src/mcp/telemetry.js +103 -0
  400. package/src/models/catalog.js +329 -51
  401. package/src/models/discovery.js +24 -4
  402. package/src/models/index.js +2 -0
  403. package/src/models/inventory-core.js +182 -0
  404. package/src/models/policy.js +20 -0
  405. package/src/plugins/cloudflare.js +103 -0
  406. package/src/plugins/completeful.js +69 -0
  407. package/src/plugins/contracts.js +86 -0
  408. package/src/plugins/index.js +11 -0
  409. package/src/plugins/registry.js +207 -0
  410. package/src/plugins/resource-scope.js +45 -0
  411. package/src/plugins/runtime.js +118 -0
  412. package/src/plugins/vectorize.js +31 -0
  413. package/src/progression/engine.js +171 -0
  414. package/src/progression/index.js +1 -0
  415. package/src/providers/cloudflare-chat.js +1 -1
  416. package/src/providers/gemini-generate-content.js +2 -1
  417. package/src/providers/openai-responses.js +45 -16
  418. package/src/providers/tool-schema.js +85 -0
  419. package/src/repository/index.js +29 -0
  420. package/src/rpc/generated/errors_pb.js +961 -1
  421. package/src/security/local-vault.js +415 -0
  422. package/src/security/process.js +20 -4
  423. package/src/status/actions.js +192 -0
  424. package/src/tools/hydrate.js +5 -1
  425. package/src/tools/index.js +7 -0
  426. package/src/tools/redact.js +64 -0
  427. package/src/tools/registry.js +83 -0
  428. package/src/tools/runtime.js +257 -0
  429. package/src/tools/search.js +21 -8
  430. package/src/ui/ansi.js +117 -3
  431. package/src/ui/cli/activity.js +76 -7
  432. package/src/ui/cli/footer.js +110 -9
  433. package/src/ui/cli/help.js +11 -4
  434. package/src/ui/wireframes.js +166 -0
  435. package/test/account-session.test.mjs +28 -0
  436. package/test/apps-scaffold-contract.test.mjs +16 -1
  437. package/test/capabilities.test.mjs +1 -1
  438. package/test/cli/eval-live.test.mjs +219 -0
  439. package/test/cli/go.test.mjs +71 -0
  440. package/test/cli/local-vault-and-provider-setup.test.mjs +268 -0
  441. package/test/cli/mcp-client.test.mjs +245 -0
  442. package/test/cli/runtime-ui.test.mjs +69 -2
  443. package/test/cli/status-actions.test.mjs +88 -0
  444. package/test/cli/wireframes-go-registry.test.mjs +54 -0
  445. package/test/cloudflare-connector.test.mjs +3 -6
  446. package/test/cloudflare-runtime.test.mjs +8 -1
  447. package/test/context.test.mjs +15 -0
  448. package/test/error-diagnostics.test.mjs +9 -0
  449. package/test/fixtures/cad/courtyard-house.json +208 -0
  450. package/test/go/cloudflare-probe.test.mjs +53 -0
  451. package/test/integration/app-command.test.mjs +55 -0
  452. package/test/integration/cad-discovery.test.mjs +158 -0
  453. package/test/integration/cad-docker-executor.test.mjs +249 -0
  454. package/test/integration/cad-execution.test.mjs +184 -0
  455. package/test/integration/cad-project-app.test.mjs +31 -0
  456. package/test/integration/cad-project-d1.test.mjs +25 -0
  457. package/test/integration/cad-project-native.test.mjs +24 -0
  458. package/test/integration/cad-project-workflow.test.mjs +9 -0
  459. package/test/integration/cad-project.test.mjs +82 -0
  460. package/test/integration/cli-help.test.mjs +4 -0
  461. package/test/integration/cms-site-tenancy-contract.test.mjs +256 -0
  462. package/test/integration/core-client.integration.test.mjs +55 -0
  463. package/test/integration/error-runtime-rpc.test.mjs +71 -0
  464. package/test/integration/features-resolve.test.mjs +128 -0
  465. package/test/integration/install-script.test.mjs +107 -0
  466. package/test/integration/inventory-core.test.mjs +53 -0
  467. package/test/integration/plugins-cloudflare.integration.test.mjs +28 -0
  468. package/test/integration/provider-env-cli.test.mjs +1 -1
  469. package/test/integration/runtime-migrations.test.mjs +6 -1
  470. package/test/integration/runtime-status.integration.test.mjs +211 -0
  471. package/test/integration/scaffold-cloudflare.test.mjs +46 -0
  472. package/test/integration/storage-architecture.test.mjs +154 -0
  473. package/test/integration/store-discovery.test.mjs +44 -0
  474. package/test/integration/terminal-exec.integration.test.mjs +86 -0
  475. package/test/integration/tool-runtime.test.mjs +124 -0
  476. package/test/integration/tool-schema.test.mjs +59 -0
  477. package/test/knowledge-service.test.mjs +4 -0
  478. package/test/local-sessions.test.mjs +11 -2
  479. package/test/local-studio-deploy.test.mjs +1 -1
  480. package/test/model-catalog.test.mjs +28 -1
  481. package/test/models.test.mjs +159 -5
  482. package/test/openai-responses.test.mjs +60 -0
  483. package/test/provider-credentials.test.mjs +15 -5
  484. package/test/responses-runner.test.mjs +321 -6
  485. package/test/shell.test.mjs +149 -4
  486. package/test/smoke.mjs +2 -2
  487. package/test/tools-search.test.mjs +33 -0
  488. package/test/unit/website-assets-bindings.test.mjs +60 -0
  489. package/test/whoami-resume.test.mjs +82 -3
  490. package/examples/gorilla-shell/README.md +0 -15
  491. package/src/lib/gorilla-template.js +0 -54
  492. package/templates/gorilla-shell/App.tsx +0 -639
  493. package/templates/gorilla-shell/README.md +0 -34
  494. package/templates/gorilla-shell/index.html +0 -15
  495. package/templates/gorilla-shell/main.jsx +0 -9
  496. package/templates/gorilla-shell/package.json +0 -19
  497. package/templates/gorilla-shell/vite.config.js +0 -21
@@ -5,23 +5,83 @@ import { fork } from 'node:child_process';
5
5
  import { DatabaseSync } from 'node:sqlite';
6
6
  import { fileURLToPath } from 'node:url';
7
7
  import { fingerprint, validateConfig } from '../config.js';
8
+ import {
9
+ AgentSamError,
10
+ ERROR_CODE,
11
+ ERROR_REASON,
12
+ createErrorEnvelope,
13
+ normalizeError,
14
+ parseError,
15
+ } from '../../errors/index.js';
8
16
 
9
17
  const defaultWorkerPath = fileURLToPath(new URL('./job-worker.js', import.meta.url));
10
18
  const TERMINAL_STATUSES = new Set(['completed', 'failed']);
11
19
 
20
+ function serviceReason(code) {
21
+ switch (code) {
22
+ case ERROR_CODE.UNAUTHENTICATED: return ERROR_REASON.AUTH_INVALID;
23
+ case ERROR_CODE.PERMISSION_DENIED: return ERROR_REASON.PERMISSION_DENIED;
24
+ case ERROR_CODE.NOT_FOUND: return ERROR_REASON.TARGET_NOT_FOUND;
25
+ case ERROR_CODE.ABORTED: return ERROR_REASON.CONFLICT;
26
+ case ERROR_CODE.RESOURCE_EXHAUSTED: return ERROR_REASON.CAPACITY_EXHAUSTED;
27
+ case ERROR_CODE.UNAVAILABLE: return ERROR_REASON.TRANSPORT_UNREACHABLE;
28
+ case ERROR_CODE.DEADLINE_EXCEEDED: return ERROR_REASON.DEADLINE_EXCEEDED;
29
+ case ERROR_CODE.INVALID_ARGUMENT: return ERROR_REASON.INPUT_INVALID;
30
+ default: return ERROR_REASON.INTERNAL;
31
+ }
32
+ }
33
+
12
34
  export function serviceError(status, message, code) {
13
- return Object.assign(new Error(message), { status, code });
35
+ const canonical = code === 'CONFLICT' ? ERROR_CODE.ABORTED : (Object.values(ERROR_CODE).includes(code) ? code : ERROR_CODE.INTERNAL);
36
+ const envelope = createErrorEnvelope({
37
+ code: canonical,
38
+ reason: serviceReason(canonical),
39
+ message,
40
+ http_status: status,
41
+ retryable: [429, 503, 504].includes(Number(status)),
42
+ source: { kind: 'agentsam', name: 'agentsam-knowledge', service: 'job_engine' },
43
+ resolution_owner: canonical === ERROR_CODE.UNAVAILABLE ? 'agentsam' : undefined,
44
+ domain: 'knowledge',
45
+ stage: 'request',
46
+ });
47
+ return new AgentSamError(envelope);
48
+ }
49
+
50
+ function decodeFailure(row) {
51
+ if (row?.failure_json) {
52
+ try { return parseError(row.failure_json); }
53
+ catch {
54
+ return createErrorEnvelope({
55
+ reason: ERROR_REASON.INTERNAL_CONTRACT_VIOLATION,
56
+ message: 'Stored knowledge failure could not be decoded.',
57
+ source: { kind: 'agentsam', name: 'agentsam-knowledge', service: 'job_engine' },
58
+ domain: 'knowledge',
59
+ stage: 'persistence',
60
+ });
61
+ }
62
+ }
63
+ if (!row?.error) return null;
64
+ return createErrorEnvelope({
65
+ reason: ERROR_REASON.EXECUTION_FAILED,
66
+ message: row.error,
67
+ source: { kind: 'agentsam', name: 'agentsam-knowledge', service: 'legacy_job_row' },
68
+ domain: 'knowledge',
69
+ stage: 'execute',
70
+ });
14
71
  }
15
72
 
16
73
  function decode(row) {
17
- return row && {
74
+ if (!row) return null;
75
+ const failure = decodeFailure(row);
76
+ return {
18
77
  id: row.id,
19
78
  status: row.status,
20
79
  attempts: row.attempts,
21
80
  created_at: row.created_at,
22
81
  updated_at: row.updated_at,
23
82
  result: row.result ? JSON.parse(row.result) : null,
24
- error: row.error,
83
+ failure,
84
+ error: failure?.message || row.error || null,
25
85
  };
26
86
  }
27
87
 
@@ -100,10 +160,22 @@ export function createKnowledgeJobEngine({
100
160
  db.exec(`PRAGMA journal_mode=WAL; PRAGMA busy_timeout=5000;
101
161
  CREATE TABLE IF NOT EXISTS jobs (id TEXT PRIMARY KEY, idem TEXT UNIQUE, digest TEXT NOT NULL,
102
162
  payload TEXT NOT NULL, status TEXT NOT NULL, attempts INTEGER NOT NULL DEFAULT 0,
103
- created_at TEXT NOT NULL, updated_at TEXT NOT NULL, result TEXT, error TEXT);
163
+ created_at TEXT NOT NULL, updated_at TEXT NOT NULL, result TEXT, error TEXT, failure_json TEXT);
104
164
  CREATE INDEX IF NOT EXISTS jobs_pending ON jobs(status, created_at);`);
165
+ const columns = new Set(db.prepare('PRAGMA table_info(jobs)').all().map(row => row.name));
166
+ if (!columns.has('failure_json')) db.exec('ALTER TABLE jobs ADD COLUMN failure_json TEXT');
105
167
  fs.chmodSync(jobsFile, 0o600);
106
- db.prepare("UPDATE jobs SET status=CASE WHEN attempts>=3 THEN 'failed' ELSE 'queued' END, error=CASE WHEN attempts>=3 THEN 'Interrupted three times; submit a new job after investigation.' ELSE NULL END WHERE status='running'").run();
168
+ const interruptedFailure = createErrorEnvelope({
169
+ reason: ERROR_REASON.EXECUTION_FAILED,
170
+ message: 'Interrupted three times; submit a new job after investigation.',
171
+ source: { kind: 'agentsam', name: 'agentsam-knowledge', service: 'job_engine' },
172
+ domain: 'knowledge',
173
+ stage: 'recovery',
174
+ });
175
+ db.prepare("UPDATE jobs SET status=CASE WHEN attempts>=3 THEN 'failed' ELSE 'queued' END, error=CASE WHEN attempts>=3 THEN ? ELSE NULL END, failure_json=CASE WHEN attempts>=3 THEN ? ELSE NULL END WHERE status='running'").run(
176
+ interruptedFailure.message,
177
+ JSON.stringify(interruptedFailure),
178
+ );
107
179
 
108
180
  let child = null;
109
181
  let closing = false;
@@ -120,11 +192,17 @@ export function createKnowledgeJobEngine({
120
192
  }
121
193
  if (TERMINAL_STATUSES.has(job.status)) watchers.delete(job.id);
122
194
  };
123
- const updateStatus = (id, status, { result = null, error = null } = {}) => {
124
- db.prepare('UPDATE jobs SET status=?,result=?,error=?,updated_at=? WHERE id=?').run(
195
+ const updateStatus = (id, status, { result = null, failure = null, error = null } = {}) => {
196
+ const normalizedFailure = failure
197
+ ? normalizeError(failure, { source: { kind: 'agentsam', name: 'agentsam-knowledge', service: 'job_engine' }, domain: 'knowledge', stage: 'execute' })
198
+ : error
199
+ ? createErrorEnvelope({ reason: ERROR_REASON.EXECUTION_FAILED, message: error, source: { kind: 'agentsam', name: 'agentsam-knowledge', service: 'job_engine' }, domain: 'knowledge', stage: 'execute' })
200
+ : null;
201
+ db.prepare('UPDATE jobs SET status=?,result=?,error=?,failure_json=?,updated_at=? WHERE id=?').run(
125
202
  status,
126
203
  result === null ? null : JSON.stringify(result),
127
- error,
204
+ normalizedFailure?.message || null,
205
+ normalizedFailure ? JSON.stringify(normalizedFailure) : null,
128
206
  new Date().toISOString(),
129
207
  id,
130
208
  );
@@ -145,15 +223,49 @@ export function createKnowledgeJobEngine({
145
223
  child = fork(workerPath, [], { execArgv: [], stdio: ['ignore', 'ignore', 'ignore', 'ipc'], env: { ...process.env, GIT_OPTIONAL_LOCKS: '0' } });
146
224
  const timer = setTimeout(() => { timedOut = true; child?.kill('SIGKILL'); }, jobTimeoutMs);
147
225
  child.once('message', value => { response = value; });
148
- child.once('error', () => { response = { ok: false, error: 'Could not start indexing process.' }; });
226
+ child.once('error', (cause) => {
227
+ response = {
228
+ ok: false,
229
+ failure: createErrorEnvelope({
230
+ reason: ERROR_REASON.INTERNAL_DEPENDENCY_FAILED,
231
+ message: 'Could not start indexing process.',
232
+ source: { kind: 'agentsam', name: 'agentsam-knowledge', service: 'job_worker' },
233
+ domain: 'knowledge',
234
+ stage: 'spawn',
235
+ native: { code: cause?.code || null, exception_type: cause?.name || null, stack: cause?.stack || null },
236
+ }),
237
+ };
238
+ });
149
239
  child.once('close', () => {
150
240
  clearTimeout(timer);
151
241
  child = null;
152
242
  if (!closing) {
153
243
  const ok = response?.ok && !timedOut;
244
+ let failure = null;
245
+ if (!ok) {
246
+ if (timedOut) {
247
+ failure = createErrorEnvelope({
248
+ reason: ERROR_REASON.EXECUTION_TIMEOUT,
249
+ message: 'Knowledge job exceeded its time limit; narrow the scope and retry.',
250
+ source: { kind: 'runtime', name: 'agentsam-knowledge-worker' },
251
+ domain: 'knowledge',
252
+ stage: 'execute',
253
+ });
254
+ } else if (response?.failure) {
255
+ failure = normalizeError(response.failure, { source: { kind: 'agentsam', name: 'agentsam-knowledge', service: 'job_worker' }, domain: 'knowledge', stage: 'execute' });
256
+ } else {
257
+ failure = createErrorEnvelope({
258
+ reason: ERROR_REASON.EXECUTION_FAILED,
259
+ message: response?.error || 'Indexing process exited unexpectedly.',
260
+ source: { kind: 'agentsam', name: 'agentsam-knowledge', service: 'job_worker' },
261
+ domain: 'knowledge',
262
+ stage: 'execute',
263
+ });
264
+ }
265
+ }
154
266
  updateStatus(row.id, ok ? 'completed' : 'failed', {
155
267
  result: ok ? response.result : null,
156
- error: ok ? null : timedOut ? 'Job exceeded its time limit; narrow the scope.' : response?.error || 'Indexing process exited unexpectedly.',
268
+ failure,
157
269
  });
158
270
  }
159
271
  pumping = false;
@@ -162,7 +274,17 @@ export function createKnowledgeJobEngine({
162
274
  const payload = JSON.parse(row.payload);
163
275
  const registered = registry[payload.request.repository];
164
276
  if (!registered || registered.config.repository_id !== payload.config.repository_id || fingerprint(registered.config.scope) !== payload.registered_scope || (!allowEmbeddings && ((payload.request.embed && payload.request.operation !== 'plan') || payload.request.semantic))) {
165
- response = { ok: false, error: 'Repository registration changed; resubmit this job.' };
277
+ response = {
278
+ ok: false,
279
+ failure: createErrorEnvelope({
280
+ reason: ERROR_REASON.REPOSITORY_CHANGED,
281
+ message: 'Repository registration changed; resubmit this job.',
282
+ source: { kind: 'agentsam', name: 'agentsam-knowledge', service: 'repository_registry' },
283
+ domain: 'repository',
284
+ stage: 'execute',
285
+ resource: { type: 'repository', id: payload.config.repository_id || null },
286
+ }),
287
+ };
166
288
  child.kill();
167
289
  return;
168
290
  }
@@ -3,12 +3,27 @@ import { openSqliteStore } from '../stores/sqlite.js';
3
3
  import { createGeminiEmbedder } from '../providers/gemini.js';
4
4
  import { inventory } from '../source.js';
5
5
  import { scopeKey } from '../config.js';
6
+ import {
7
+ AgentSamError,
8
+ ERROR_REASON,
9
+ createErrorEnvelope,
10
+ normalizeError,
11
+ } from '../../errors/index.js';
6
12
 
7
13
  // Parsing and vector ranking run in a child process, keeping HTTP acceptance responsive.
8
14
  process.once('message', async ({ root, config, filename, request, maxFiles }) => {
9
15
  let store;
10
16
  try {
11
- if (request.operation !== 'search' && inventory(root, config.scope).length > maxFiles) throw new Error(`Scope exceeds ${maxFiles} files; choose a smaller include set.`);
17
+ if (request.operation !== 'search' && inventory(root, config.scope).length > maxFiles) throw new AgentSamError(createErrorEnvelope({
18
+ reason: ERROR_REASON.INPUT_OUT_OF_RANGE,
19
+ message: `Scope exceeds ${maxFiles} files; choose a smaller include set.`,
20
+ source: { kind: 'user', name: 'knowledge_request' },
21
+ resolution_owner: 'user',
22
+ domain: 'knowledge',
23
+ stage: 'inventory',
24
+ remediation: { action: 'reduce_scope', message: 'Narrow the repository include scope and retry.' },
25
+ resource: { type: 'repository', id: config.repository_id || null },
26
+ }));
12
27
  store = await openSqliteStore(filename);
13
28
  const embedder = request.operation !== 'plan' && (request.embed || request.semantic) ? createGeminiEmbedder({ apiKey: process.env.GEMINI_API_KEY }) : undefined;
14
29
  let result;
@@ -18,7 +33,15 @@ process.once('message', async ({ root, config, filename, request, maxFiles }) =>
18
33
  const generation = request.generation_id ? await store.getGeneration(scopeKey(config), request.generation_id) : await store.active(scopeKey(config));
19
34
  const under = (file, selection) => selection === '.' || file === selection || file.startsWith(selection + '/');
20
35
  if (generation?.files.some(file => !config.scope.include.some(p => under(file.path, p)) || config.scope.exclude.some(p => under(file.path, p)))) {
21
- throw new Error('Generation exceeds the requested scope; select a matching scope or reindex.');
36
+ throw new AgentSamError(createErrorEnvelope({
37
+ reason: ERROR_REASON.PRECONDITION_FAILED,
38
+ message: 'Generation exceeds the requested scope; select a matching scope or reindex.',
39
+ source: { kind: 'user', name: 'knowledge_request' },
40
+ domain: 'knowledge',
41
+ stage: 'search',
42
+ remediation: { action: 'change_configuration', message: 'Select a matching indexed scope or reindex the requested scope.' },
43
+ resource: { type: 'repository', id: config.repository_id || null },
44
+ }));
22
45
  }
23
46
  result = await retrieve({ store, config, text: request.query, semantic: request.semantic, embedder,
24
47
  topK: request.top_k, tokenBudget: request.token_budget, generationId: request.generation_id });
@@ -27,8 +50,14 @@ process.once('message', async ({ root, config, filename, request, maxFiles }) =>
27
50
  process.send({ ok: true, result }, () => process.exit(0));
28
51
  } catch (error) {
29
52
  await store?.close();
30
- // Provider error strings may include sensitive request details. Never persist them.
31
- const message = request.embed || request.semantic ? 'Embedding job failed; check provider configuration, budgets, and availability.' : String(error.message).slice(0, 500);
32
- process.send({ ok: false, error: message }, () => process.exit(1));
53
+ const failure = normalizeError(error, {
54
+ source: { kind: 'agentsam', name: 'agentsam-knowledge', service: 'job_worker' },
55
+ domain: 'knowledge',
56
+ stage: request.embed || request.semantic ? 'embedding' : request.operation || 'execute',
57
+ message: request.embed || request.semantic
58
+ ? 'Embedding job failed; inspect the canonical failure for provider/configuration details.'
59
+ : undefined,
60
+ });
61
+ process.send({ ok: false, failure }, () => process.exit(1));
33
62
  }
34
63
  });
@@ -4,6 +4,7 @@ import path from 'node:path';
4
4
  import { fileURLToPath } from 'node:url';
5
5
  import { createBearerTokenVerifier } from './auth.js';
6
6
  import { createKnowledgeJobEngine, serviceError } from './job-engine.js';
7
+ import { normalizeError, toHttpError } from '../../errors/index.js';
7
8
 
8
9
  async function readBody(req) {
9
10
  const chunks = [];
@@ -44,7 +45,15 @@ export async function startKnowledgeHttpServer({ engine, token, verifyToken, por
44
45
  const { job, created } = engine.submitJob(await readBody(req), { idempotencyKey: req.headers['idempotency-key'] });
45
46
  return send(created ? 202 : 200, job);
46
47
  } catch (error) {
47
- if (!res.writableEnded) send(error.status || 500, { error: error.status ? error.message : 'Service request failed.' });
48
+ if (!res.writableEnded) {
49
+ const envelope = normalizeError(error, {
50
+ source: { kind: 'agentsam', name: 'agentsam-knowledge', service: 'http_server' },
51
+ domain: 'knowledge',
52
+ stage: 'request',
53
+ });
54
+ const httpError = toHttpError(envelope);
55
+ send(httpError.status, httpError.body);
56
+ }
48
57
  }
49
58
  });
50
59
  server.requestTimeout = 15000;
@@ -0,0 +1,77 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { CONFIG_PATH, readConfig, validateConfig, defaultConfig } from './config.js';
4
+ import { findCliProjectRoot } from '../lib/cli-preferences.js';
5
+ import { runtimeDatabasePath } from '../local/runtime-store.js';
6
+ import { getRepositoryId, portableRepositoryIdFromGit, tryReadProjectConfig } from '../lib/project-config.js';
7
+
8
+ // Configuration evidence only. No connection probes, credential reads, or schema writes.
9
+ export async function discoverProjectStores(cwd, env = process.env) {
10
+ const root = findCliProjectRoot(cwd);
11
+ const config = fs.existsSync(path.join(root, CONFIG_PATH)) ? readConfig(root) : null;
12
+ const candidates = [
13
+ { id: 'runtime:sqlite', driver: 'sqlite', role: 'runtime', path: runtimeDatabasePath(root), selected: true },
14
+ { id: 'knowledge:sqlite', driver: 'sqlite', role: 'knowledge', path: path.join(root, '.agentsam/knowledge/index.sqlite'), selected: !config || config.storage.driver === 'sqlite', selectable: true },
15
+ ];
16
+ const envNames = new Set(['AGENTSAM_DATABASE_URL', 'DATABASE_URL', 'POSTGRES_URL', config?.storage?.connection_env].filter(Boolean));
17
+ for (const name of envNames) {
18
+ if (!Object.hasOwn(env, name) && name !== config?.storage?.connection_env) continue;
19
+ candidates.push({ id: `knowledge:postgres:${name}`, driver: 'postgres', role: 'knowledge', connection_env: name, configured: Boolean(env[name]), selected: config?.storage?.driver === 'postgres' && config.storage.connection_env === name, selectable: true });
20
+ }
21
+ const warnings = [];
22
+ let visited = 0;
23
+ const skip = new Set(['node_modules', '.git', '.agentsam', '.output', 'dist', 'build', 'vendor', '.wrangler']);
24
+ const configs = [];
25
+ function scan(dir, depth) {
26
+ if (depth > 5 || visited >= 4000) return;
27
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
28
+ if (++visited >= 4000) break;
29
+ if (entry.isSymbolicLink() || skip.has(entry.name)) continue;
30
+ const file = path.join(dir, entry.name);
31
+ if (entry.isDirectory()) scan(file, depth + 1);
32
+ else if (['wrangler.json', 'wrangler.jsonc'].includes(entry.name)) configs.push(file);
33
+ else if (entry.name === 'wrangler.toml') warnings.push(`${path.relative(root, file)}: TOML discovery is not implemented; inspect this configuration explicitly.`);
34
+ }
35
+ }
36
+ scan(root, 0);
37
+ if (visited >= 4000) warnings.push('Discovery reached its 4000-entry bound; inspect additional config paths explicitly.');
38
+ if (configs.length) {
39
+ const { parseConfigFileTextToJson } = await import('typescript');
40
+ for (const file of configs) {
41
+ const source = path.relative(root, file);
42
+ if (fs.statSync(file).size > 1024 * 1024) { warnings.push(`${source}: configuration too large`); continue; }
43
+ const parsed = parseConfigFileTextToJson(file, fs.readFileSync(file, 'utf8'));
44
+ if (parsed.error) { warnings.push(`${source}: invalid JSONC`); continue; }
45
+ const add = (cfg, environment = null) => {
46
+ for (const [key, driver, label] of [['d1_databases', 'd1', 'database_name'], ['hyperdrive', 'postgres-hyperdrive', 'id'], ['r2_buckets', 'r2', 'bucket_name']]) {
47
+ for (const binding of Array.isArray(cfg?.[key]) ? cfg[key] : []) {
48
+ candidates.push({ id: `${source}:${environment || 'default'}:${binding.binding}`, driver, role: 'application', binding: binding.binding, name: binding[label], source, environment, selectable: false, status: 'declared; connectivity not verified' });
49
+ }
50
+ }
51
+ };
52
+ add(parsed.config);
53
+ for (const [environment, cfg] of Object.entries(parsed.config?.env || {})) add(cfg, environment);
54
+ }
55
+ }
56
+ return { root, candidates, warnings, knowledge_config: CONFIG_PATH };
57
+ }
58
+
59
+ export function selectKnowledgeStore(cwd, driver, connectionEnv) {
60
+ const root = findCliProjectRoot(cwd);
61
+ if (!['sqlite', 'postgres'].includes(driver)) throw new Error('knowledge_store_adapter_unavailable: choose sqlite or postgres; D1 application bindings retain their existing authority');
62
+ const filename = path.join(root, CONFIG_PATH);
63
+ let config;
64
+ if (fs.existsSync(filename)) config = readConfig(root);
65
+ else {
66
+ const repositoryId = getRepositoryId(tryReadProjectConfig(root)) || portableRepositoryIdFromGit(root);
67
+ if (!repositoryId) throw new Error('repository_identity_required: run agentsam init . --yes first');
68
+ config = defaultConfig({ repositoryId });
69
+ }
70
+ config.storage = driver === 'sqlite' ? { driver } : { driver, connection_env: connectionEnv || 'AGENTSAM_DATABASE_URL' };
71
+ config = validateConfig(config);
72
+ fs.mkdirSync(path.dirname(filename), { recursive: true, mode: 0o700 });
73
+ const temp = `${filename}.${process.pid}.tmp`;
74
+ fs.writeFileSync(temp, JSON.stringify(config, null, 2) + '\n', { mode: 0o600 });
75
+ fs.renameSync(temp, filename);
76
+ return { storage: config.storage, config: CONFIG_PATH, next: driver === 'sqlite' ? 'agentsam index run' : 'agentsam index setup-store', note: 'Selection saved. Existing data remains in its original store; no migration or connection probe ran.' };
77
+ }
@@ -147,8 +147,14 @@ export function resolveBrowserSessionCredential(options = {}) {
147
147
  */
148
148
  export function resolveAccountAuth(options = {}) {
149
149
  const apiKey = resolveAccountApiKey(options);
150
- if (apiKey.value || apiKey.error) return apiKey;
151
- return resolveBrowserSessionCredential(options);
150
+ if (apiKey.value) return apiKey;
151
+ if (clean(options.explicit) && apiKey.error) return apiKey;
152
+ const browser = resolveBrowserSessionCredential(options);
153
+ if (browser.value) {
154
+ return apiKey.error ? { ...browser, fallback_error: apiKey.error } : browser;
155
+ }
156
+ if (browser.error) return browser;
157
+ return apiKey.error ? apiKey : browser;
152
158
  }
153
159
 
154
160
  export function describeAccountSession(options = {}) {
@@ -6,6 +6,9 @@ import { findProjectRules } from './project-rules.js';
6
6
  export const AGENT_RUNTIME_FILENAME = 'AGENTSAM.md';
7
7
  export const AGENT_INSTRUCTION_PRECEDENCE = Object.freeze(['AGENTSAM.md', '.agentsamrules']);
8
8
 
9
+ /** Provider/editor adapters that must redirect to AGENTSAM.md — never compiled as policy. */
10
+ export const AGENT_INSTRUCTION_COMPAT_SHIMS = Object.freeze(['AGENTS.md', 'CLAUDE.md']);
11
+
9
12
  function sha256(value) {
10
13
  return `sha256:${createHash('sha256').update(value).digest('hex')}`;
11
14
  }
package/src/lib/auth.js CHANGED
@@ -137,12 +137,15 @@ export async function refreshAccountSession(options = {}) {
137
137
  */
138
138
  export async function resolveAccountAuthority(options = {}) {
139
139
  const apiKey = resolveAccountApiKey(options);
140
- if (apiKey.value || apiKey.error) return apiKey;
140
+ if (apiKey.value) return apiKey;
141
+ if (clean(options.explicit) && apiKey.error) return apiKey;
141
142
 
142
143
  let session = readAccountSession(options);
143
- if (!session?.access_token) return { value: '', source: null, kind: null, session: null };
144
+ if (!session?.access_token) {
145
+ return apiKey.error ? apiKey : { value: '', source: null, kind: null, session: null };
146
+ }
144
147
 
145
- if (isBrowserSessionExpired(session, options)) {
148
+ if (options.forceRefresh === true || isBrowserSessionExpired(session, options)) {
146
149
  if (!session.refresh_token) {
147
150
  return {
148
151
  value: '',
@@ -171,6 +174,7 @@ export async function resolveAccountAuthority(options = {}) {
171
174
  source: 'agentsam_browser_oauth',
172
175
  kind: 'browser_oauth',
173
176
  session,
177
+ fallback_error: apiKey.error || null,
174
178
  };
175
179
  }
176
180
 
@@ -4,9 +4,11 @@ import path from 'node:path';
4
4
  import { createHash } from 'node:crypto';
5
5
  import { fileURLToPath } from 'node:url';
6
6
  import { runProcess } from '../../security/process.js';
7
+ import { probeDockerServiceHealth, executeBlenderDocker } from './docker-executor.js';
7
8
 
8
9
  const sdkRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../..');
9
- export const BLENDER_ADAPTER_PATH = path.join(sdkRoot, 'services/cad/blender/adapter.py');
10
+ const packagedAdapter = path.join(path.dirname(fileURLToPath(import.meta.url)), 'cad/blender/adapter.py');
11
+ export const BLENDER_ADAPTER_PATH = fs.existsSync(packagedAdapter) ? packagedAdapter : path.join(sdkRoot, 'services/cad/blender/adapter.py');
10
12
  export const BLENDER_RESULT_PREFIX = 'AGENTSAM_RESULT=';
11
13
  export const BLENDER_EXPORT_FORMATS = Object.freeze(['glb', 'stl', 'obj']);
12
14
  export const BLENDER_RECIPE_OPS = Object.freeze([
@@ -172,9 +174,46 @@ async function invokeBlender({
172
174
  runProcessImpl = runProcess,
173
175
  }) {
174
176
  const binary = discoverBlender({ blenderBin });
175
- if (!binary) throw new Error('Blender is not installed or could not be discovered; use --blender-bin or AGENTSAM_BLENDER_BIN');
176
- if (!fs.existsSync(BLENDER_ADAPTER_PATH)) throw new Error(`Bundled Blender adapter is missing: ${BLENDER_ADAPTER_PATH}`);
177
177
  const timeout = boundedInteger(timeoutSeconds, 120, 1, 600, 'timeout');
178
+
179
+ if (!binary || !fs.existsSync(BLENDER_ADAPTER_PATH)) {
180
+ try {
181
+ const dockerHealth = await probeDockerServiceHealth();
182
+ if (dockerHealth.available && dockerHealth.tools?.blender?.installed) {
183
+ // Forward the full operation request (recipe/scene/camera/width/height/
184
+ // format/objects/collection/apply_modifiers as applicable) — the
185
+ // docker service has no access to `request.output`'s local path, so
186
+ // strip it and let the container pick its own temp output path.
187
+ const { output: _localOutput, ...requestRest } = request || {};
188
+ const inputBase64 = input && fs.existsSync(input) ? fs.readFileSync(input).toString('base64') : null;
189
+
190
+ const dockerRes = await executeBlenderDocker({
191
+ operation,
192
+ request: requestRest,
193
+ inputBase64,
194
+ format: requestRest.format
195
+ || (operation === 'build' ? 'blend' : operation === 'render_preview' ? 'png' : 'glb'),
196
+ filename: request.output ? path.basename(request.output) : undefined,
197
+ timeoutMs: timeout * 1000,
198
+ });
199
+
200
+ if (request.output && dockerRes.artifactBase64) {
201
+ const outputPath = path.resolve(cwd, request.output);
202
+ fs.mkdirSync(path.dirname(outputPath), { recursive: true });
203
+ fs.writeFileSync(outputPath, Buffer.from(dockerRes.artifactBase64, 'base64'));
204
+ }
205
+
206
+ return {
207
+ result: dockerRes.result || { ok: true, blender_version: dockerHealth.tools.blender.version },
208
+ binary: `docker://${dockerHealth.service || 'agentsam-cad'}/blender`,
209
+ duration_ms: dockerRes.durationMs,
210
+ execution_lane: 'docker_service',
211
+ };
212
+ }
213
+ } catch {}
214
+
215
+ throw new Error('Blender is not installed or could not be discovered; use --blender-bin, AGENTSAM_BLENDER_BIN, or launch AgentSam CAD Docker service');
216
+ }
178
217
  const requestDir = fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-blender-'));
179
218
  const requestPath = path.join(requestDir, 'request.json');
180
219
  fs.writeFileSync(requestPath, JSON.stringify({ schema_version: 1, ...request }, null, 2), { mode: 0o600 });
@@ -0,0 +1,43 @@
1
+ import {randomUUID} from 'node:crypto';
2
+ import {requireValidProject} from './project-contract.js';
3
+ import {projectHash} from './project-store.js';
4
+ // Reuses blueprint documents + immutable R2 scene snapshots. No new tables.
5
+ // scope is supplied by the authenticated host, never by tool arguments.
6
+ export class D1ProjectStore {
7
+ constructor({db,objects,bucket,scope}) {
8
+ if(!scope?.account_id||!scope?.workspace_id||!scope?.tenant_id||!bucket)throw new Error('authenticated_design_scope_required');
9
+ this.db=db;this.objects=objects;this.bucket=bucket;this.scope=scope;
10
+ }
11
+ async read(id,revision){
12
+ const s=this.scope;
13
+ const row=await this.db.prepare("SELECT * FROM designstudio_design_blueprints WHERE id=? AND tenant_id=? AND workspace_id=? AND json_extract(intent_json,'$.account_id')=?").bind(id,s.tenant_id,s.workspace_id,s.account_id).first();
14
+ if(!row)throw new Error('project_not_found');
15
+ const current=JSON.parse(row.generation_config_json||'{}').project_revision;
16
+ if(revision==null||revision===current){const p=JSON.parse(row.sketch_json);return {project:p,revision:current,content_hash:projectHash(p)};}
17
+ const snapshot=await this.db.prepare("SELECT r2_key FROM scene_snapshots WHERE project_id=? AND user_id=? AND workspace_id=? AND tenant_id=? AND version=? AND project_type='CAD_PROJECT'").bind(id,s.account_id,s.workspace_id,s.tenant_id,revision).first();
18
+ if(!snapshot)throw new Error('revision_not_found');
19
+ const object=await this.objects.get(snapshot.r2_key);if(!object)throw new Error('revision_object_missing');
20
+ const saved=JSON.parse(await object.text());requireValidProject(saved.project);if(saved.content_hash!==projectHash(saved.project))throw new Error('revision_digest_mismatch');return saved;
21
+ }
22
+ async save(project,expectedRevision,message='Saved project'){
23
+ requireValidProject(project);
24
+ if(!Number.isSafeInteger(expectedRevision)||expectedRevision<0)throw new Error('expected_revision_required');
25
+ const s=this.scope,revision=expectedRevision+1,now=Math.floor(Date.now()/1000),id='scene_'+randomUUID().replaceAll('-','');
26
+ const p={...structuredClone(project),version:revision,updatedAt:Date.now()};
27
+ const saved={project:p,revision,content_hash:projectHash(p),message,created_at:now};
28
+ const key='design-projects/'+encodeURIComponent(s.account_id)+'/'+encodeURIComponent(p.id)+'/'+revision+'/'+saved.content_hash+'.json';
29
+ await this.objects.put(key,JSON.stringify(saved),{httpMetadata:{contentType:'application/json'}});
30
+ const statements=[];
31
+ if(expectedRevision===0){
32
+ statements.push(this.db.prepare("INSERT INTO designstudio_design_blueprints (id,tenant_id,workspace_id,title,intent_json,sketch_json,generation_config_json,status) VALUES (?,?,?,?,?,?,?,'structured')").bind(p.id,s.tenant_id,s.workspace_id,p.name,JSON.stringify({account_id:s.account_id,contract:'cad.project.v1'}),JSON.stringify(p),JSON.stringify({project_revision:revision,content_hash:saved.content_hash})));
33
+ }else{
34
+ statements.push(this.db.prepare("UPDATE designstudio_design_blueprints SET title=?,sketch_json=?,generation_config_json=json_set(generation_config_json,'$.project_revision',?,'$.content_hash',?),updated_at=datetime('now') WHERE id=? AND tenant_id=? AND workspace_id=? AND json_extract(intent_json,'$.account_id')=? AND json_extract(generation_config_json,'$.project_revision')=?").bind(p.name,JSON.stringify(p),revision,saved.content_hash,p.id,s.tenant_id,s.workspace_id,s.account_id,expectedRevision));
35
+ }
36
+ // D1 batch is transactional; changes() guards the snapshot against a failed CAS.
37
+ statements.push(this.db.prepare("INSERT INTO scene_snapshots (id,workspace_id,user_id,tenant_id,name,project_type,entity_count,r2_key,r2_bucket,project_id,version,description,created_at,updated_at) SELECT ?,?,?,?,?,'CAD_PROJECT',?,?,?,?,?,?,?,? WHERE changes()=1").bind(id,s.workspace_id,s.account_id,s.tenant_id,p.name,p.walls.length+p.rooms.length+p.doors.length+p.windows.length,key,this.bucket,p.id,revision,message,now,now));
38
+ let results;try{results=await this.db.batch(statements);}catch(e){throw new Error('project_save_failed:'+e.message);}
39
+ if(results[0]?.meta?.changes!==1)throw new Error('revision_conflict');
40
+ return saved;
41
+ }
42
+ async restore(id,revision,expectedRevision){const row=await this.read(id,revision);return this.save(row.project,expectedRevision,'Restored revision '+revision);}
43
+ }