@inneranimalmedia/agentsam-sdk 2.6.2 → 2.6.4

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 (661) hide show
  1. package/AGENTSAM.md +51 -1
  2. package/README.md +95 -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/bin/agentsam +16 -1
  17. package/docs/AUTORAG.md +58 -0
  18. package/docs/BRAND_INTELLIGENCE.md +30 -0
  19. package/docs/CLI_SHELL.md +4 -2
  20. package/docs/CMS_CONTEXTUAL_COMPOSER.md +38 -0
  21. package/docs/MERKLE.md +4 -0
  22. package/docs/PROJECT_CONFIG.md +3 -0
  23. package/docs/REPOSITORY_KNOWLEDGE.md +2 -0
  24. package/docs/THEME_REFINERY.md +120 -0
  25. package/docs/architecture/AGENTSAM_DISTRIBUTION_OWNERSHIP.md +176 -0
  26. package/docs/architecture/AGENTSAM_GO_RUNTIME.md +282 -0
  27. package/docs/architecture/CODEBASEINDEX_GUIDED_PATH.md +202 -0
  28. package/docs/architecture/FS_E2E_CLOSURE_RECEIPT.md +59 -0
  29. package/docs/architecture/LOCAL_FS_AUTHORITY.md +38 -0
  30. package/docs/architecture/LOCAL_STUDIO_CLOUDFLARE_OAUTH.md +28 -0
  31. package/docs/architecture/PLAN_CLI_AND_LOCAL_STUDIO_DESKTOP.md +96 -0
  32. package/docs/architecture/PROVIDER-TOOLS-AND-COMPACTION.md +60 -0
  33. package/docs/architecture/SAM_ACTIVITY_RECOVERY_RECEIPT.md +39 -0
  34. package/docs/architecture/SAM_DECISION_WORK_RECEIPT.md +54 -0
  35. package/docs/architecture/SAM_KERNEL.md +181 -0
  36. package/docs/architecture/SAM_MACHINE_NORMALIZATION_PRECOMMIT_REPORT.md +208 -0
  37. package/docs/architecture/SLASH_SKILLS_PORTABLE.md +116 -0
  38. package/docs/architecture/STORAGE.md +87 -0
  39. package/docs/architecture/fs-e2e-receipt.latest.json +42 -0
  40. package/docs/architecture/previews/codebaseindex-guided-path/CODEBASEINDEX_GUIDED_PATH.md +202 -0
  41. package/docs/architecture/previews/codebaseindex-guided-path/index.html +321 -0
  42. package/docs/cad-project-tools.md +69 -0
  43. package/docs/cms-scaffolding-pattern-reference.md +73 -0
  44. package/docs/plans/AGENTSAM-INTERACTIVE-UI-REQUIREMENTS-codex-tui-20260919.md +113 -0
  45. package/docs/plans/AGENTSAM-INTERACTIVE-UI-REQUIREMENTS.md +85 -0
  46. package/docs/plans/AGENTSAM-MCP-CLIENT-2026-09-19.md +181 -0
  47. package/docs/plans/ASBD-PORTABLE-WORKGRAPH-UI-DEFERRED.md +34 -0
  48. package/docs/plans/ASTRA-BRIEF-2026-09-18.md +258 -0
  49. package/docs/plans/MULTI-AGENT-SPRINTS-2026-09-19.md +373 -0
  50. package/docs/plans/NEXT-AGENT-HANDOFF.md +167 -0
  51. package/docs/plans/RECONCILIATION-2026-09-19.md +178 -0
  52. package/docs/plugins.md +43 -0
  53. package/docs/tools/README.md +57 -0
  54. package/docs/tools/agent-and-orchestration.md +49 -0
  55. package/docs/tools/browser-and-research.md +46 -0
  56. package/docs/tools/cloudflare-platform.md +32 -0
  57. package/docs/tools/cms.md +25 -0
  58. package/docs/tools/communications.md +41 -0
  59. package/docs/tools/database-and-storage.md +62 -0
  60. package/docs/tools/design-and-media.md +64 -0
  61. package/docs/tools/filesystem-and-code.md +55 -0
  62. package/docs/tools/github.md +56 -0
  63. package/docs/tools/integrations-and-misc.md +16 -0
  64. package/docs/tools/memory.md +21 -0
  65. package/docs/tools/terminal-and-execution.md +29 -0
  66. package/docs/tools/tickets-and-platform.md +30 -0
  67. package/migrations/d1/0001_agentsam_plugin_runtime.sql +177 -0
  68. package/migrations/d1/0002_agentsam_ticket_ownership.sql +8 -0
  69. package/migrations/d1/0002_dynamic_model_policies.sql +23 -0
  70. package/migrations/d1/0003_expand_tool_handler_families.sql +18 -0
  71. package/migrations/d1/0004_project_aware_retrieval_lanes.sql +24 -0
  72. package/migrations/d1/0005_portable_knowledge_identity.sql +104 -0
  73. package/migrations/d1/0006_repair_ops_trail_account_scope.sql +14 -0
  74. package/migrations/d1/0007_repair_ops_trail_agent_run_account.sql +13 -0
  75. package/migrations/d1/0008_backfill_knowledge_run_legacy_tenant.sql +14 -0
  76. package/migrations/d1/0009_normalize_cloudflare_plugin_installations.sql +137 -0
  77. package/migrations/d1/0010_portable_tickets_memory.sql +140 -0
  78. package/migrations/d1/0011_agentsam_skill_v2.sql +185 -0
  79. package/migrations/d1/0011b_agentsam_skill_v2_cutover.sql +22 -0
  80. package/migrations/d1/0011c_agentsam_skill_v2_backfill.sql +76 -0
  81. package/migrations/d1/0011d_agentsam_skill_v2_retrieval_revisions.sql +50 -0
  82. package/migrations/d1/0012_agentsam_tools_required_seed.sql +67 -0
  83. package/migrations/d1/0013_identity_oauth_states.sql +15 -0
  84. package/migrations/d1/0014_auth_event_log.sql +20 -0
  85. package/migrations/d1/0015_identity_oauth_state_app_id.sql +3 -0
  86. package/migrations/d1/README_PORTABLE_CONTROL_PLANE.md +16 -0
  87. package/migrations/runtime/0001_cli_runtime.sql +67 -0
  88. package/migrations/runtime/0002_project_sessions.sql +15 -0
  89. package/migrations/runtime/0003_provider_continuations.sql +8 -0
  90. package/migrations/sqlite/agentsam_skill_retrieval.portable.sql +42 -0
  91. package/package.json +107 -12
  92. package/packages/agentsam-brand/README.md +21 -0
  93. package/packages/agentsam-brand/package.json +22 -0
  94. package/packages/agentsam-brand/src/contract.js +59 -0
  95. package/packages/agentsam-brand/src/extract.js +126 -0
  96. package/packages/agentsam-brand/src/goap-actions.js +73 -0
  97. package/packages/agentsam-brand/src/index.js +48 -0
  98. package/packages/agentsam-brand/src/plan.js +115 -0
  99. package/packages/agentsam-brand/src/resolve.js +139 -0
  100. package/packages/agentsam-brand/src/scan.js +250 -0
  101. package/packages/agentsam-brand/test/brand-scan.test.mjs +106 -0
  102. package/packages/agentsam-contracts/README.md +23 -0
  103. package/packages/agentsam-contracts/package.json +32 -0
  104. package/packages/agentsam-contracts/src/adapter.ts +25 -0
  105. package/packages/agentsam-contracts/src/agent.ts +35 -0
  106. package/packages/agentsam-contracts/src/artifacts.ts +33 -0
  107. package/packages/agentsam-contracts/src/authority.ts +29 -0
  108. package/packages/agentsam-contracts/src/context.ts +16 -0
  109. package/packages/agentsam-contracts/src/errors.ts +62 -0
  110. package/packages/agentsam-contracts/src/events.ts +47 -0
  111. package/packages/agentsam-contracts/src/execution.ts +50 -0
  112. package/packages/agentsam-contracts/src/hooks.ts +40 -0
  113. package/packages/agentsam-contracts/src/identity.ts +16 -0
  114. package/packages/agentsam-contracts/src/index.ts +14 -0
  115. package/packages/agentsam-contracts/src/models.ts +9 -0
  116. package/packages/agentsam-contracts/src/providers.ts +33 -0
  117. package/packages/agentsam-contracts/src/repository.ts +64 -0
  118. package/packages/agentsam-contracts/src/tools.ts +98 -0
  119. package/packages/agentsam-contracts/test/contracts.test.mjs +16 -0
  120. package/packages/agentsam-contracts/test/errors-catalog.test.mjs +25 -0
  121. package/packages/agentsam-contracts/test/repository.test.mjs +18 -0
  122. package/packages/agentsam-contracts/tsconfig.json +12 -0
  123. package/packages/agentsam-errors/package.json +17 -0
  124. package/packages/agentsam-errors/src/adapters/anthropic.js +15 -0
  125. package/packages/agentsam-errors/src/adapters/cad.js +109 -0
  126. package/packages/agentsam-errors/src/adapters/cloudflare.js +21 -0
  127. package/packages/agentsam-errors/src/adapters/cursor.js +4 -0
  128. package/packages/agentsam-errors/src/adapters/device.js +38 -0
  129. package/packages/agentsam-errors/src/adapters/docker.js +28 -0
  130. package/packages/agentsam-errors/src/adapters/gcp.js +14 -0
  131. package/packages/agentsam-errors/src/adapters/github.js +22 -0
  132. package/packages/agentsam-errors/src/adapters/google.js +17 -0
  133. package/packages/agentsam-errors/src/adapters/index.js +55 -0
  134. package/packages/agentsam-errors/src/adapters/internal.js +40 -0
  135. package/packages/agentsam-errors/src/adapters/oauth.js +24 -0
  136. package/packages/agentsam-errors/src/adapters/openai.js +17 -0
  137. package/packages/agentsam-errors/src/adapters/process.js +35 -0
  138. package/packages/agentsam-errors/src/adapters/provider.js +114 -0
  139. package/packages/agentsam-errors/src/envelope.js +239 -0
  140. package/packages/agentsam-errors/src/error.js +24 -0
  141. package/packages/agentsam-errors/src/fingerprint.js +35 -0
  142. package/packages/agentsam-errors/src/index.js +11 -0
  143. package/packages/agentsam-errors/src/normalize.js +30 -0
  144. package/packages/agentsam-errors/src/recovery.js +301 -0
  145. package/packages/agentsam-errors/src/redaction.js +52 -0
  146. package/packages/agentsam-errors/src/render.js +16 -0
  147. package/packages/agentsam-errors/src/retry.js +10 -0
  148. package/packages/agentsam-errors/src/transport.js +52 -0
  149. package/packages/agentsam-errors/src/vocabulary.js +320 -0
  150. package/packages/agentsam-errors/test/envelope.test.mjs +70 -0
  151. package/packages/agentsam-errors/test/providers.test.mjs +99 -0
  152. package/packages/agentsam-errors/test/redaction.test.mjs +21 -0
  153. package/packages/agentsam-errors/test/runtime-cad-device.test.mjs +76 -0
  154. package/packages/agentsam-errors/test/transport.test.mjs +46 -0
  155. package/packages/agentsam-knowledge/package.json +15 -0
  156. package/packages/agentsam-knowledge/src/autorag/index.js +64 -0
  157. package/packages/agentsam-knowledge/src/backends/index.js +26 -0
  158. package/packages/agentsam-knowledge/src/index.js +3 -0
  159. package/packages/agentsam-knowledge/src/providers/index.js +107 -0
  160. package/packages/agentsam-knowledge/test/autorag.test.mjs +42 -0
  161. package/packages/agentsam-nav/README.md +40 -0
  162. package/packages/agentsam-nav/dist/Nav.d.ts +43 -0
  163. package/packages/agentsam-nav/dist/NavCollapsible.d.ts +10 -0
  164. package/packages/agentsam-nav/dist/NavContent.d.ts +2 -0
  165. package/packages/agentsam-nav/dist/NavFooter.d.ts +2 -0
  166. package/packages/agentsam-nav/dist/NavGroup.d.ts +3 -0
  167. package/packages/agentsam-nav/dist/NavHeader.d.ts +2 -0
  168. package/packages/agentsam-nav/dist/NavMenu.d.ts +22 -0
  169. package/packages/agentsam-nav/dist/NavProvider.d.ts +35 -0
  170. package/packages/agentsam-nav/dist/NavTrigger.d.ts +2 -0
  171. package/packages/agentsam-nav/dist/Surfaces.d.ts +41 -0
  172. package/packages/agentsam-nav/dist/browser.d.ts +11 -0
  173. package/packages/agentsam-nav/dist/browser.global.js +132 -0
  174. package/packages/agentsam-nav/dist/browser.js +613 -0
  175. package/packages/agentsam-nav/dist/contracts.d.ts +76 -0
  176. package/packages/agentsam-nav/dist/index.d.ts +11 -0
  177. package/packages/agentsam-nav/dist/index.js +614 -0
  178. package/packages/agentsam-nav/dist/legacy.css +83 -0
  179. package/packages/agentsam-nav/dist/shell.css +113 -0
  180. package/packages/agentsam-nav/dist/theme.css +113 -0
  181. package/packages/agentsam-nav/dist/utils.d.ts +1 -0
  182. package/packages/agentsam-nav/package.json +43 -0
  183. package/packages/agentsam-queue-control/README.md +107 -0
  184. package/packages/agentsam-queue-control/package.json +31 -0
  185. package/packages/agentsam-queue-control/schemas/job-envelope.schema.json +56 -0
  186. package/packages/agentsam-queue-control/src/adapters/cloudflare.js +152 -0
  187. package/packages/agentsam-queue-control/src/adapters/memory.js +38 -0
  188. package/packages/agentsam-queue-control/src/contracts.js +130 -0
  189. package/packages/agentsam-queue-control/src/control-plane.js +141 -0
  190. package/packages/agentsam-queue-control/src/dispatch.js +43 -0
  191. package/packages/agentsam-queue-control/src/index.js +7 -0
  192. package/packages/agentsam-queue-control/src/policy.js +88 -0
  193. package/packages/agentsam-queue-control/src/topology.js +66 -0
  194. package/packages/agentsam-queue-control/test/queue-control.test.mjs +100 -0
  195. package/packages/agentsam-repository/src/goap.js +718 -0
  196. package/packages/agentsam-repository/src/goap.js.bak-20260922011251 +670 -0
  197. package/packages/agentsam-repository/src/index.js +5 -0
  198. package/packages/agentsam-repository/src/merkle/cloudflare-persistence.js +2 -2
  199. package/packages/agentsam-repository/src/tickets.js +184 -0
  200. package/packages/agentsam-repository/src/work-tracking.js +199 -0
  201. package/packages/agentsam-repository/src/workspace-state.js +176 -0
  202. package/packages/agentsam-repository/test/goap-tickets-workspace-state.test.mjs +152 -0
  203. package/packages/connectors/cloudflare/src/index.js +297 -15
  204. package/packages/connectors/cloudflare/src/owner.js +43 -40
  205. package/packages/connectors/cloudflare/src/routes.js +176 -26
  206. package/packages/connectors/cloudflare/tests/connector.test.mjs +137 -2
  207. package/packages/heuristic-theme/README.md +11 -0
  208. package/packages/heuristic-theme/package.json +25 -0
  209. package/packages/heuristic-theme/src/index.js +2 -0
  210. package/packages/heuristic-theme/src/registry.js +36 -0
  211. package/packages/heuristic-theme/src/theme.js +41 -0
  212. package/packages/heuristic-theme/test/theme.test.mjs +26 -0
  213. package/packages/identity/.agentsam/features/oauth-login-portal/agentsam.feature.json +64 -0
  214. package/packages/identity/.agentsam/features/oauth-login-portal/providers.json +96 -0
  215. package/packages/identity/.agentsam/features/oauth-login-portal/resources.json +47 -0
  216. package/packages/identity/.agentsam/features/oauth-login-portal/routes.json +83 -0
  217. package/packages/identity/.agentsam/features/oauth-login-portal/ui.json +35 -0
  218. package/packages/identity/docs/PORTABLE_IDENTITY_ARCHITECTURE.md +50 -0
  219. package/packages/identity/migrations/D1_SCHEMA_MAPPING.md +31 -0
  220. package/packages/identity/migrations/sqlite/001_identity_core.sql +99 -0
  221. package/packages/identity/migrations/sqlite/002_identity_oauth_client.sql +38 -0
  222. package/packages/identity/migrations/sqlite/003_identity_oauth_server.sql +64 -0
  223. package/packages/identity/package.json +4 -3
  224. package/packages/identity/src/adapters/cloudflare-d1/ids.js +4 -0
  225. package/packages/identity/src/adapters/cloudflare-d1/index.js +156 -18
  226. package/packages/identity/src/adapters/sqlite/index.js +319 -0
  227. package/packages/identity/src/app/verify-app.js +95 -0
  228. package/packages/identity/src/contracts/identity-store.js +115 -0
  229. package/packages/identity/src/contracts/provider.js +3 -2
  230. package/packages/identity/src/contracts/route-ids.js +30 -0
  231. package/packages/identity/src/contracts/route-projection.js +218 -0
  232. package/packages/identity/src/contracts/routes.js +11 -0
  233. package/packages/identity/src/core/browser-paths.js +4 -5
  234. package/packages/identity/src/core/constants.js +13 -8
  235. package/packages/identity/src/core/session-policy.js +32 -0
  236. package/packages/identity/src/frontend/auth-portal/pages/login.html +16 -9
  237. package/packages/identity/src/frontend/auth-portal/pages/reset.html +3 -3
  238. package/packages/identity/src/frontend/auth-portal/pages/signup.html +3 -3
  239. package/packages/identity/src/frontend/auth-portal/preview/dashboard-stub.html +1 -1
  240. package/packages/identity/src/index.js +27 -0
  241. package/packages/identity/src/oauth/README.md +10 -4
  242. package/packages/identity/src/oauth/credentials.js +31 -11
  243. package/packages/identity/src/oauth/finalize-inbound.js +1 -1
  244. package/packages/identity/src/oauth/iam-platform.js +13 -12
  245. package/packages/identity/src/oauth/redirect-paths.js +27 -36
  246. package/packages/identity/src/providers/cloudflare/index.js +19 -0
  247. package/packages/identity/src/providers/cloudflare/mapper.js +21 -0
  248. package/packages/identity/src/providers/cloudflare/oauth.js +48 -0
  249. package/packages/identity/src/providers/cloudflare/profile.js +28 -0
  250. package/packages/identity/src/providers/index.js +18 -2
  251. package/packages/identity/src/server/identity-service.js +35 -8
  252. package/packages/identity/src/server/mount-policy.js +30 -0
  253. package/packages/identity/src/server/post-auth.js +79 -0
  254. package/packages/identity/src/server/worker-router.js +153 -66
  255. package/packages/identity/tests/finalize-inbound-oauth.test.mjs +6 -6
  256. package/packages/identity/tests/iam-provider.test.mjs +1 -1
  257. package/packages/identity/tests/identity-service.test.mjs +47 -1
  258. package/packages/identity/tests/oauth-credentials.test.mjs +3 -1
  259. package/packages/identity/tests/portable-identity-architecture.test.mjs +157 -0
  260. package/packages/identity/tests/session-routes-policy.test.mjs +21 -0
  261. package/packages/providers/completeful/README.md +38 -0
  262. package/packages/providers/completeful/package.json +29 -0
  263. package/packages/providers/completeful/src/client.js +162 -0
  264. package/packages/providers/completeful/src/events.js +49 -0
  265. package/packages/providers/completeful/src/index.js +22 -0
  266. package/packages/providers/completeful/src/tools.js +579 -0
  267. package/packages/providers/completeful/src/webhooks.js +55 -0
  268. package/packages/providers/completeful/test/provider.test.mjs +196 -0
  269. package/packages/theme-church-site/README.md +10 -0
  270. package/packages/theme-church-site/package.json +31 -0
  271. package/packages/theme-church-site/src/harvest.json +14 -0
  272. package/packages/theme-church-site/src/index.js +85 -0
  273. package/packages/theme-church-site/test/theme.test.mjs +19 -0
  274. package/packages/theme-companions-site/README.md +10 -0
  275. package/packages/theme-companions-site/package.json +31 -0
  276. package/packages/theme-companions-site/src/harvest.json +12 -0
  277. package/packages/theme-companions-site/src/index.js +83 -0
  278. package/packages/theme-companions-site/test/theme.test.mjs +19 -0
  279. package/packages/theme-floors-site/README.md +10 -0
  280. package/packages/theme-floors-site/package.json +31 -0
  281. package/packages/theme-floors-site/src/harvest.json +14 -0
  282. package/packages/theme-floors-site/src/index.js +83 -0
  283. package/packages/theme-floors-site/test/theme.test.mjs +19 -0
  284. package/packages/theme-fuelnfree-site/README.md +10 -0
  285. package/packages/theme-fuelnfree-site/package.json +31 -0
  286. package/packages/theme-fuelnfree-site/src/harvest.json +13 -0
  287. package/packages/theme-fuelnfree-site/src/index.js +82 -0
  288. package/packages/theme-fuelnfree-site/test/theme.test.mjs +19 -0
  289. package/packages/theme-handyman-site/README.md +10 -0
  290. package/packages/theme-handyman-site/package.json +31 -0
  291. package/packages/theme-handyman-site/src/harvest.json +10 -0
  292. package/packages/theme-handyman-site/src/index.js +84 -0
  293. package/packages/theme-handyman-site/test/theme.test.mjs +19 -0
  294. package/packages/theme-insurance-site/README.md +10 -0
  295. package/packages/theme-insurance-site/package.json +31 -0
  296. package/packages/theme-insurance-site/src/harvest.json +10 -0
  297. package/packages/theme-insurance-site/src/index.js +84 -0
  298. package/packages/theme-insurance-site/test/theme.test.mjs +19 -0
  299. package/packages/theme-shinshu-site/README.md +10 -0
  300. package/packages/theme-shinshu-site/package.json +31 -0
  301. package/packages/theme-shinshu-site/src/harvest.json +12 -0
  302. package/packages/theme-shinshu-site/src/index.js +84 -0
  303. package/packages/theme-shinshu-site/test/theme.test.mjs +19 -0
  304. package/packages/work-graph/README.md +49 -0
  305. package/packages/work-graph/package.json +19 -0
  306. package/packages/work-graph/prototype/README.md +32 -0
  307. package/packages/work-graph/prototype/data/demo-workgraph.js +47 -0
  308. package/packages/work-graph/prototype/renderers/timeline-model.js +21 -0
  309. package/packages/work-graph/prototype/renderers/workgraph-runtime.js +38 -0
  310. package/packages/work-graph/prototype-gnantt.html +655 -0
  311. package/packages/work-graph/src/adapters/business/projects.js +23 -0
  312. package/packages/work-graph/src/adapters/engineering/git.js +22 -0
  313. package/packages/work-graph/src/adapters/engineering/mcp.js +22 -0
  314. package/packages/work-graph/src/index.js +76 -0
  315. package/packages/work-graph/src/renderers/gantt-model.js +11 -0
  316. package/packages/work-graph/src/renderers/timeline.js +16 -0
  317. package/packages/work-graph/test/work-graph.test.mjs +37 -0
  318. package/protocol/README.md +12 -0
  319. package/protocol/apps/agentsam.app.v1.schema.json +51 -0
  320. package/protocol/brand/brandpack.v1.schema.json +43 -0
  321. package/protocol/capabilities/cloudflare-cpu-audit-input.schema.json +30 -6
  322. package/protocol/capabilities/cloudflare-cpu-profile-input.schema.json +18 -4
  323. package/protocol/capabilities/cloudflare-wrangler-native-input.schema.json +59 -10
  324. package/protocol/capabilities/knowledge-search-input.schema.json +35 -0
  325. package/protocol/capabilities/manifest.json +163 -1
  326. package/protocol/capabilities/repository-audit-input.schema.json +39 -6
  327. package/protocol/capabilities/repository-snapshot-input.schema.json +15 -3
  328. package/protocol/capabilities/terminal-exec-input.schema.json +55 -0
  329. package/protocol/commerce/catalog.v1.json +50 -0
  330. package/protocol/credentials/issue.v1.schema.json +38 -0
  331. package/protocol/database/connection.v1.schema.json +41 -0
  332. package/protocol/embeddings/embedding-profile.v1.schema.json +20 -0
  333. package/protocol/errors/error-catalog.json +164 -0
  334. package/protocol/errors/error-envelope.schema.json +678 -0
  335. package/protocol/errors/recovery.v1.schema.json +50 -0
  336. package/protocol/features/README.md +57 -0
  337. package/protocol/features/agentsam.feature.v1.schema.json +290 -0
  338. package/protocol/features/catalog.json +65 -0
  339. package/protocol/features/examples/provider-resend.feature.json +17 -0
  340. package/protocol/go/agentsam-go-runtime.v1.json +17 -0
  341. package/protocol/knowledge/LIFECYCLE.md +140 -0
  342. package/protocol/knowledge/README.md +4 -0
  343. package/protocol/presets/catalog.json +128 -19
  344. package/protocol/rpc/v1/errors.proto +24 -0
  345. package/protocol/runtime/workspace-fs.v1.schema.json +71 -0
  346. package/protocol/sam/activity.v1.schema.json +48 -0
  347. package/protocol/sam/answer.v1.schema.json +35 -0
  348. package/protocol/sam/calibration.v1.schema.json +21 -0
  349. package/protocol/sam/decision-receipt.v1.schema.json +29 -0
  350. package/protocol/sam/evaluation.v1.schema.json +19 -0
  351. package/protocol/sam/operation.schema.json +66 -0
  352. package/protocol/sam/outcome.v1.schema.json +36 -0
  353. package/protocol/sam/question.v1.schema.json +26 -0
  354. package/protocol/sam/registry.seed.json +153 -0
  355. package/protocol/sam/result.schema.json +53 -0
  356. package/protocol/sam/state.v1.schema.json +23 -0
  357. package/protocol/skills/agentsam.interaction.v1.schema.json +50 -0
  358. package/protocol/skills/agentsam.skill.v1.schema.json +57 -0
  359. package/protocol/theme-refinery/d1-reconciliation.md +48 -0
  360. package/protocol/theme-refinery/product-metadata.schema.json +27 -0
  361. package/protocol/theme-refinery/receipts/products-registry-batch-20260924.json +318 -0
  362. package/protocol/theme-refinery/receipts/theme-harvest-20260924.json +472 -0
  363. package/protocol/theme-refinery/reconciliation-receipt.schema.json +83 -0
  364. package/protocol/ui/icon-registry.mjs +226 -0
  365. package/protocol/ui/icon.v1.schema.json +51 -0
  366. package/services/cad/server.py +249 -2
  367. package/skills/README.md +22 -9
  368. package/skills/agentsam-codebaseindex/SKILL.md +225 -0
  369. package/skills/catalog.json +14 -0
  370. package/src/agent/capability-adapter.js +15 -5
  371. package/src/agent/index.js +2 -1
  372. package/src/agent/model-turn.js +51 -0
  373. package/src/agent/responses-runner.js +304 -38
  374. package/src/capabilities/index.js +1 -0
  375. package/src/capabilities/terminal-exec.js +78 -0
  376. package/src/cli/command-catalog.js +130 -0
  377. package/src/cli/dispatch.js +48 -0
  378. package/src/cli.js +160 -10
  379. package/src/cloudflare/index.js +6 -0
  380. package/src/cloudflare/runtime-status.js +393 -0
  381. package/src/cloudflare/wrangler.js +17 -1
  382. package/src/commands/api-key.js +244 -0
  383. package/src/commands/app.js +138 -0
  384. package/src/commands/autorag.js +77 -0
  385. package/src/commands/brand.js +291 -0
  386. package/src/commands/cad.js +1 -0
  387. package/src/commands/codebaseindex.js +688 -0
  388. package/src/commands/connections.js +126 -29
  389. package/src/commands/context-economics.js +8 -0
  390. package/src/commands/db.js +7 -0
  391. package/src/commands/env.js +155 -27
  392. package/src/commands/eval.js +209 -14
  393. package/src/commands/go.js +678 -0
  394. package/src/commands/goap.js +176 -0
  395. package/src/commands/identity-init.js +27 -3
  396. package/src/commands/identity-protocol.js +195 -0
  397. package/src/commands/interaction-clack.js +115 -0
  398. package/src/commands/knowledge.js +64 -5
  399. package/src/commands/mcp.js +341 -0
  400. package/src/commands/merkle-persist.js +3 -1
  401. package/src/commands/merkle.js +18 -3
  402. package/src/commands/models.js +110 -24
  403. package/src/commands/plugins.js +175 -0
  404. package/src/commands/preferences.js +28 -8
  405. package/src/commands/product.js +53 -10
  406. package/src/commands/providers.js +173 -44
  407. package/src/commands/resume.js +9 -5
  408. package/src/commands/runtime-status.js +154 -0
  409. package/src/commands/shell.js +508 -56
  410. package/src/commands/skill.js +248 -0
  411. package/src/commands/skills.js +1 -1
  412. package/src/commands/start-local.js +4 -0
  413. package/src/commands/status.js +82 -7
  414. package/src/commands/tunnel.js +228 -195
  415. package/src/commands/whoami.js +156 -12
  416. package/src/context/budget.js +6 -0
  417. package/src/context/index.js +2 -1
  418. package/src/context/project-card.js +75 -0
  419. package/src/errors/contract.js +34 -211
  420. package/src/errors/diagnostic.js +95 -51
  421. package/src/errors/index.js +6 -13
  422. package/src/eval/index.js +6 -0
  423. package/src/eval/live.js +439 -0
  424. package/src/features/resolve.js +242 -0
  425. package/src/go/build.js +298 -0
  426. package/src/go/cloudflare.js +608 -0
  427. package/src/go/container.js +120 -0
  428. package/src/go/contract.js +144 -0
  429. package/src/go/discover.js +212 -0
  430. package/src/go/index.js +25 -0
  431. package/src/go/native-probe-runner.mjs +119 -0
  432. package/src/go/official-registry.js +280 -0
  433. package/src/go/official-release.js +10 -0
  434. package/src/go/receipts.js +144 -0
  435. package/src/go/verify.js +38 -0
  436. package/src/index.js +127 -1
  437. package/src/indexing/ingest/discover-models.js +298 -0
  438. package/src/indexing/ingest/inventory.js +243 -0
  439. package/src/indexing/ingest/job-graph.js +181 -0
  440. package/src/indexing/ingest/materials.js +210 -0
  441. package/src/knowledge/config.js +13 -5
  442. package/src/knowledge/engine.js +23 -8
  443. package/src/knowledge/index.js +1 -0
  444. package/src/knowledge/lane-registry.js +46 -0
  445. package/src/knowledge/providers/gemini.js +48 -8
  446. package/src/knowledge/service/client.js +13 -1
  447. package/src/knowledge/service/grpc-codec.js +156 -53
  448. package/src/knowledge/service/job-engine.js +133 -11
  449. package/src/knowledge/service/job-worker.js +34 -5
  450. package/src/knowledge/service/server.js +10 -1
  451. package/src/knowledge/store-discovery.js +77 -0
  452. package/src/lib/account-session.js +8 -2
  453. package/src/lib/agent-instructions.js +3 -0
  454. package/src/lib/auth.js +7 -3
  455. package/src/lib/cad/blender.js +42 -3
  456. package/src/lib/cad/d1-project-store.js +43 -0
  457. package/src/lib/cad/discovery.js +616 -0
  458. package/src/lib/cad/docker-executor.js +352 -0
  459. package/src/lib/cad/freecad.js +253 -0
  460. package/src/lib/cad/index.js +40 -0
  461. package/src/lib/cad/openscad.js +198 -0
  462. package/src/lib/cad/project-cli.d.ts +2 -0
  463. package/src/lib/cad/project-cli.js +21 -0
  464. package/src/lib/cad/project-contract.d.ts +3 -0
  465. package/src/lib/cad/project-contract.js +1 -0
  466. package/src/lib/cad/project-recipe.js +30 -0
  467. package/src/lib/cad/project-runtime.d.ts +2 -0
  468. package/src/lib/cad/project-runtime.js +53 -0
  469. package/src/lib/cad/project-store.js +25 -0
  470. package/src/lib/cad/project-workflows.js +31 -0
  471. package/src/lib/cad-docker.js +21 -2
  472. package/src/lib/cli-preferences.js +17 -2
  473. package/src/lib/core-client.js +37 -18
  474. package/src/lib/deploy/local-studio.js +6 -5
  475. package/src/lib/dockerize.js +3 -0
  476. package/src/lib/execution-approvals.js +1 -0
  477. package/src/lib/identity-scaffold.js +4 -1
  478. package/src/lib/knowledge-docker.js +9 -1
  479. package/src/lib/local-sessions.js +124 -34
  480. package/src/lib/local-status.js +35 -14
  481. package/src/lib/project-config.js +9 -0
  482. package/src/lib/provider-credentials.js +136 -32
  483. package/src/lib/scaffold/resolve-cloudflare-account.js +37 -0
  484. package/src/lib/scaffold/wizards/cms.js +2 -8
  485. package/src/lib/scaffold/wizards/worker-api.js +2 -8
  486. package/src/lib/slash-commands.js +10 -2
  487. package/src/local/migrations.js +109 -1
  488. package/src/local/runtime-store.js +31 -5
  489. package/src/local/sqlite.js +36 -1
  490. package/src/local-fs/capability.js +121 -0
  491. package/src/local-fs/freshness.js +75 -0
  492. package/src/local-fs/index.js +385 -0
  493. package/src/local-fs/paths.js +100 -0
  494. package/src/local-pty/server.js +295 -19
  495. package/src/mcp/authority.js +348 -0
  496. package/src/mcp/client-adapters.js +431 -0
  497. package/src/mcp/client.js +172 -0
  498. package/src/mcp/index.js +47 -0
  499. package/src/mcp/telemetry.js +103 -0
  500. package/src/models/ai-access-onboarding.js +112 -0
  501. package/src/models/catalog.js +329 -51
  502. package/src/models/discovery.js +34 -6
  503. package/src/models/index.js +2 -0
  504. package/src/models/inventory-core.js +190 -0
  505. package/src/models/policy.js +20 -0
  506. package/src/plugins/cloudflare.js +103 -0
  507. package/src/plugins/completeful.js +69 -0
  508. package/src/plugins/contracts.js +86 -0
  509. package/src/plugins/index.js +11 -0
  510. package/src/plugins/registry.js +207 -0
  511. package/src/plugins/resource-scope.js +45 -0
  512. package/src/plugins/runtime.js +118 -0
  513. package/src/plugins/vectorize.js +31 -0
  514. package/src/progression/engine.js +171 -0
  515. package/src/progression/index.js +1 -0
  516. package/src/providers/cloudflare-chat.js +1 -1
  517. package/src/providers/gemini-generate-content.js +2 -1
  518. package/src/providers/openai-responses.js +45 -16
  519. package/src/providers/tool-schema.js +85 -0
  520. package/src/repository/index.js +29 -0
  521. package/src/rpc/generated/errors_pb.js +961 -1
  522. package/src/sam/activity/index.js +183 -0
  523. package/src/sam/client.js +252 -0
  524. package/src/sam/decision/calibration.js +109 -0
  525. package/src/sam/decision/confidence.js +126 -0
  526. package/src/sam/decision/evaluate.js +157 -0
  527. package/src/sam/decision/evaluators/deterministic.js +341 -0
  528. package/src/sam/decision/evaluators/heuristic.js +61 -0
  529. package/src/sam/decision/evaluators/select.js +50 -0
  530. package/src/sam/decision/evaluators/semantic.js +149 -0
  531. package/src/sam/decision/hierarchical.js +61 -0
  532. package/src/sam/decision/index.js +53 -0
  533. package/src/sam/decision/policy.js +86 -0
  534. package/src/sam/decision/questions.js +120 -0
  535. package/src/sam/decision/receipt.js +148 -0
  536. package/src/sam/decision/state.js +117 -0
  537. package/src/sam/decision/types.js +22 -0
  538. package/src/sam/decision/validate.js +200 -0
  539. package/src/sam/define.js +51 -0
  540. package/src/sam/index.js +65 -0
  541. package/src/sam/operations/brand-scan.js +62 -0
  542. package/src/sam/operations/cad-blender-inspect.js +36 -0
  543. package/src/sam/operations/codebaseindex-ingest.js +49 -0
  544. package/src/sam/operations/decision-evaluate.js +59 -0
  545. package/src/sam/operations/planning-astar.js +77 -0
  546. package/src/sam/operations/planning-goap.js +60 -0
  547. package/src/sam/operations/repository-inspect.js +72 -0
  548. package/src/sam/operations/security-scan.js +33 -0
  549. package/src/sam/operations/terminal-exec.js +29 -0
  550. package/src/sam/planning/astar.js +311 -0
  551. package/src/sam/planning/goap.js +177 -0
  552. package/src/sam/planning/index.js +21 -0
  553. package/src/sam/planning/state.js +84 -0
  554. package/src/sam/registry.js +48 -0
  555. package/src/sam/result.js +77 -0
  556. package/src/sam/seed.js +44 -0
  557. package/src/sam/types.js +91 -0
  558. package/src/security/local-vault.js +415 -0
  559. package/src/security/process.js +20 -4
  560. package/src/skills/catalog.js +64 -0
  561. package/src/skills/content-resolver.js +124 -0
  562. package/src/skills/hosted-store.js +37 -0
  563. package/src/skills/index.js +29 -64
  564. package/src/skills/interaction.js +102 -0
  565. package/src/skills/local-store.js +228 -0
  566. package/src/skills/manifest.js +104 -0
  567. package/src/skills/metrics.js +31 -0
  568. package/src/skills/registry.js +184 -0
  569. package/src/skills/runtime.js +287 -0
  570. package/src/skills/slash.js +44 -0
  571. package/src/status/actions.js +192 -0
  572. package/src/tools/hydrate.js +5 -1
  573. package/src/tools/index.js +7 -0
  574. package/src/tools/redact.js +64 -0
  575. package/src/tools/registry.js +83 -0
  576. package/src/tools/runtime.js +257 -0
  577. package/src/tools/search.js +21 -8
  578. package/src/ui/ansi.js +117 -3
  579. package/src/ui/cli/activity.js +76 -7
  580. package/src/ui/cli/footer.js +110 -9
  581. package/src/ui/cli/help.js +96 -96
  582. package/src/ui/wireframes.js +166 -0
  583. package/test/account-session.test.mjs +28 -0
  584. package/test/apps-scaffold-contract.test.mjs +16 -1
  585. package/test/capabilities.test.mjs +1 -1
  586. package/test/cli/api-key-env-whoami.test.mjs +129 -0
  587. package/test/cli/codebaseindex-plan-ux.test.mjs +37 -0
  588. package/test/cli/eval-live.test.mjs +219 -0
  589. package/test/cli/go.test.mjs +128 -0
  590. package/test/cli/local-vault-and-provider-setup.test.mjs +268 -0
  591. package/test/cli/mcp-client.test.mjs +245 -0
  592. package/test/cli/runtime-ui.test.mjs +69 -2
  593. package/test/cli/skill-npm-and-env.test.mjs +52 -0
  594. package/test/cli/status-actions.test.mjs +88 -0
  595. package/test/cli/wireframes-go-registry.test.mjs +139 -0
  596. package/test/cloudflare-connector.test.mjs +3 -6
  597. package/test/cloudflare-runtime.test.mjs +8 -1
  598. package/test/context.test.mjs +15 -0
  599. package/test/error-diagnostics.test.mjs +9 -0
  600. package/test/fixtures/cad/courtyard-house.json +208 -0
  601. package/test/go/build-source-identity.test.mjs +31 -0
  602. package/test/go/cloudflare-probe.test.mjs +317 -0
  603. package/test/go/distribution.test.mjs +28 -0
  604. package/test/integration/ai-access-onboarding.test.mjs +47 -0
  605. package/test/integration/app-command.test.mjs +55 -0
  606. package/test/integration/cad-discovery.test.mjs +158 -0
  607. package/test/integration/cad-docker-executor.test.mjs +249 -0
  608. package/test/integration/cad-execution.test.mjs +184 -0
  609. package/test/integration/cad-project-app.test.mjs +31 -0
  610. package/test/integration/cad-project-d1.test.mjs +25 -0
  611. package/test/integration/cad-project-native.test.mjs +24 -0
  612. package/test/integration/cad-project-workflow.test.mjs +9 -0
  613. package/test/integration/cad-project.test.mjs +82 -0
  614. package/test/integration/cli-help.test.mjs +5 -1
  615. package/test/integration/cms-site-tenancy-contract.test.mjs +256 -0
  616. package/test/integration/codebaseindex-ingest.test.mjs +166 -0
  617. package/test/integration/core-client.integration.test.mjs +55 -0
  618. package/test/integration/error-runtime-rpc.test.mjs +71 -0
  619. package/test/integration/features-resolve.test.mjs +128 -0
  620. package/test/integration/icon-registry.test.mjs +67 -0
  621. package/test/integration/ingest-discover-models.test.mjs +30 -0
  622. package/test/integration/install-script.test.mjs +110 -0
  623. package/test/integration/inventory-core.test.mjs +53 -0
  624. package/test/integration/local-fs.test.mjs +113 -0
  625. package/test/integration/plugins-cloudflare.integration.test.mjs +28 -0
  626. package/test/integration/provider-env-cli.test.mjs +3 -2
  627. package/test/integration/runtime-migrations.test.mjs +6 -1
  628. package/test/integration/runtime-status.integration.test.mjs +211 -0
  629. package/test/integration/sam-activity-recovery.test.mjs +147 -0
  630. package/test/integration/sam-decision.test.mjs +584 -0
  631. package/test/integration/sam-kernel.test.mjs +99 -0
  632. package/test/integration/sam-planning-astar.test.mjs +279 -0
  633. package/test/integration/scaffold-cloudflare.test.mjs +46 -0
  634. package/test/integration/skill-runtime.test.mjs +240 -0
  635. package/test/integration/storage-architecture.test.mjs +154 -0
  636. package/test/integration/store-discovery.test.mjs +44 -0
  637. package/test/integration/studio-fs-pty-e2e.test.mjs +294 -0
  638. package/test/integration/terminal-exec.integration.test.mjs +86 -0
  639. package/test/integration/tool-runtime.test.mjs +124 -0
  640. package/test/integration/tool-schema.test.mjs +59 -0
  641. package/test/knowledge-service.test.mjs +4 -0
  642. package/test/local-sessions.test.mjs +11 -2
  643. package/test/local-studio-deploy.test.mjs +1 -1
  644. package/test/model-catalog.test.mjs +28 -1
  645. package/test/models.test.mjs +172 -11
  646. package/test/openai-responses.test.mjs +60 -0
  647. package/test/provider-credentials.test.mjs +15 -5
  648. package/test/responses-runner.test.mjs +321 -6
  649. package/test/shell.test.mjs +151 -6
  650. package/test/smoke.mjs +2 -2
  651. package/test/tools-search.test.mjs +33 -0
  652. package/test/unit/website-assets-bindings.test.mjs +60 -0
  653. package/test/whoami-resume.test.mjs +82 -3
  654. package/examples/gorilla-shell/README.md +0 -15
  655. package/src/lib/gorilla-template.js +0 -54
  656. package/templates/gorilla-shell/App.tsx +0 -639
  657. package/templates/gorilla-shell/README.md +0 -34
  658. package/templates/gorilla-shell/index.html +0 -15
  659. package/templates/gorilla-shell/main.jsx +0 -9
  660. package/templates/gorilla-shell/package.json +0 -19
  661. package/templates/gorilla-shell/vite.config.js +0 -21
@@ -0,0 +1,181 @@
1
+ /**
2
+ * codebaseindex.job.graph.v1 — portable job graph for CLI / Gantt / Studio.
3
+ */
4
+
5
+ import { randomUUID } from 'node:crypto';
6
+
7
+ export const JOB_GRAPH_SCHEMA = 'codebaseindex.job.graph.v1';
8
+
9
+ const DEFAULT_NODES = [
10
+ 'material.stage',
11
+ 'repository.snapshot',
12
+ 'inventory.classify',
13
+ 'scope.resolve',
14
+ 'profile.resolve',
15
+ 'lane.resolve',
16
+ 'plan.dry_run',
17
+ 'ast.parse',
18
+ 'chunks.build',
19
+ 'embedding.generate',
20
+ 'storage.write',
21
+ 'generation.verify',
22
+ 'search.smoke',
23
+ ];
24
+
25
+ /**
26
+ * @param {object} [opts]
27
+ */
28
+ export function createCodebaseindexJobGraph(opts = {}) {
29
+ const id = opts.id || `cidxjob_${randomUUID().replace(/-/g, '').slice(0, 16)}`;
30
+ const now = new Date().toISOString();
31
+ const nodes = (opts.nodes || DEFAULT_NODES).map((nodeId, index) => ({
32
+ id: nodeId,
33
+ status: opts.completed?.includes(nodeId) ? 'done'
34
+ : opts.current === nodeId ? 'run'
35
+ : 'pending',
36
+ ordinal: index,
37
+ started_at: null,
38
+ completed_at: null,
39
+ inputs: {},
40
+ outputs: {},
41
+ errors: [],
42
+ }));
43
+ return {
44
+ schema: JOB_GRAPH_SCHEMA,
45
+ id,
46
+ pipeline: 'sam.codebaseindex.index.run',
47
+ operation: 'codebaseindex.ingest',
48
+ created_at: now,
49
+ updated_at: now,
50
+ status: opts.status || 'planned',
51
+ current: nodes.find((node) => node.status === 'run')?.id || null,
52
+ nodes,
53
+ work_items: nodes.map((n) => ({
54
+ id: n.id,
55
+ title: n.id,
56
+ status: n.status === 'done' ? 'completed' : n.status === 'run' ? 'in_progress' : 'pending',
57
+ start: null,
58
+ end: null,
59
+ })),
60
+ };
61
+ }
62
+
63
+ /**
64
+ * Mark nodes through `throughId` as done; set next as run (or complete).
65
+ * @param {ReturnType<typeof createCodebaseindexJobGraph>} graph
66
+ * @param {string} throughId
67
+ */
68
+ export function advanceJobGraph(graph, throughId) {
69
+ const next = structuredClone(graph);
70
+ next.updated_at = new Date().toISOString();
71
+ let found = false;
72
+ for (const node of next.nodes) {
73
+ if (!found) {
74
+ if (node.status !== 'skipped') {
75
+ node.status = 'done';
76
+ node.completed_at = next.updated_at;
77
+ }
78
+ if (node.id === throughId) found = true;
79
+ } else if (node.status === 'pending') {
80
+ node.status = 'run';
81
+ node.started_at = next.updated_at;
82
+ break;
83
+ }
84
+ }
85
+ syncWorkItems(next);
86
+ const allDone = next.nodes.every((n) => n.status === 'done' || n.status === 'skipped');
87
+ next.status = allDone ? 'completed' : 'running';
88
+ next.current = next.nodes.find((n) => n.status === 'run')?.id || null;
89
+ return next;
90
+ }
91
+
92
+ /**
93
+ * After a successful dry-run: freeze remaining nodes as planned (not "run").
94
+ * Prevents `→ ast.parse` looking like the CLI is waiting for another command.
95
+ *
96
+ * @param {ReturnType<typeof createCodebaseindexJobGraph>} graph
97
+ * @param {{ skipEmbedding?: boolean }} [opts]
98
+ */
99
+ export function freezePlanJobGraph(graph, opts = {}) {
100
+ const next = structuredClone(graph);
101
+ next.updated_at = new Date().toISOString();
102
+ next.status = 'planned';
103
+ for (const node of next.nodes) {
104
+ if (node.status === 'done') continue;
105
+ if (opts.skipEmbedding && node.id === 'embedding.generate') {
106
+ node.status = 'skipped';
107
+ node.completed_at = next.updated_at;
108
+ continue;
109
+ }
110
+ // Clear accidental "run" pointer from advanceJobGraph
111
+ node.status = 'planned';
112
+ node.started_at = null;
113
+ }
114
+ next.current = null;
115
+ syncWorkItems(next);
116
+ return next;
117
+ }
118
+
119
+ /**
120
+ * Mark a graph node as intentionally skipped while preserving graph truth.
121
+ */
122
+ export function skipJobGraphNode(graph, nodeId, reason = 'not_required') {
123
+ const next = structuredClone(graph);
124
+ next.updated_at = new Date().toISOString();
125
+
126
+ const node = next.nodes.find((candidate) => candidate.id === nodeId);
127
+ if (!node) throw new Error(`Unknown job graph node: ${nodeId}`);
128
+
129
+ node.status = 'skipped';
130
+ node.started_at = null;
131
+ node.completed_at = next.updated_at;
132
+ node.outputs = { ...(node.outputs || {}), skip_reason: reason };
133
+
134
+ syncWorkItems(next);
135
+
136
+ const allDone = next.nodes.every(
137
+ (candidate) => candidate.status === 'done' || candidate.status === 'skipped',
138
+ );
139
+
140
+ next.status = allDone ? 'completed' : 'running';
141
+ next.current = next.nodes.find((candidate) => candidate.status === 'run')?.id || null;
142
+
143
+ return next;
144
+ }
145
+
146
+ /**
147
+ * Human projection of the job graph for CLI notes.
148
+ * @param {ReturnType<typeof createCodebaseindexJobGraph>} graph
149
+ * @param {{ planOnly?: boolean }} [opts]
150
+ */
151
+ export function formatJobGraphHuman(graph, opts = {}) {
152
+ const lines = [];
153
+ const planned = [];
154
+ for (const n of graph.nodes || []) {
155
+ if (n.status === 'done') lines.push(`✓ ${n.id}`);
156
+ else if (n.status === 'skipped') lines.push(`⊘ ${n.id} skipped`);
157
+ else if (opts.planOnly || n.status === 'planned' || graph.status === 'planned') {
158
+ planned.push(n.id);
159
+ } else if (n.status === 'run') lines.push(`→ ${n.id}`);
160
+ else lines.push(`· ${n.id}`);
161
+ }
162
+ if (planned.length) {
163
+ lines.push('');
164
+ lines.push('PLANNED FOR RUN');
165
+ for (const id of planned) lines.push(`○ ${id}`);
166
+ }
167
+ return lines.join('\n');
168
+ }
169
+
170
+ function syncWorkItems(graph) {
171
+ graph.work_items = graph.nodes.map((n) => ({
172
+ id: n.id,
173
+ title: n.id,
174
+ status: n.status === 'done' || n.status === 'skipped' ? 'completed'
175
+ : n.status === 'run' ? 'in_progress'
176
+ : n.status === 'planned' ? 'planned'
177
+ : 'pending',
178
+ start: n.started_at,
179
+ end: n.completed_at,
180
+ }));
181
+ }
@@ -0,0 +1,210 @@
1
+ /**
2
+ * Material intake for codebaseindex.ingest — paths pasted/dropped into the CLI.
3
+ * Handles archives (tar/zip), sites/builds, HTML, images, GLB, and mixed trees.
4
+ */
5
+
6
+ import fs from 'node:fs';
7
+ import path from 'node:path';
8
+ import { createHash, randomUUID } from 'node:crypto';
9
+ import { execFileSync, spawnSync } from 'node:child_process';
10
+
11
+ const ARCHIVE_EXT = new Set(['.zip', '.tar', '.tgz', '.gz', '.tar.gz', '.tbz2', '.tar.bz2']);
12
+ const IMAGE_EXT = new Set(['.png', '.jpg', '.jpeg', '.gif', '.webp', '.svg', '.ico', '.bmp', '.avif']);
13
+ const MODEL_3D_EXT = new Set(['.glb', '.gltf', '.obj', '.fbx', '.stl', '.usdz']);
14
+ const DOC_EXT = new Set(['.html', '.htm', '.md', '.txt', '.css', '.scss', '.json', '.xml', '.csv']);
15
+ const CODE_EXT = new Set([
16
+ '.js', '.mjs', '.cjs', '.ts', '.tsx', '.jsx', '.py', '.go', '.rs', '.java', '.kt',
17
+ '.swift', '.c', '.h', '.cpp', '.cc', '.cs', '.rb', '.php', '.sql', '.sh', '.bash',
18
+ '.zsh', '.yaml', '.yml', '.toml', '.vue', '.svelte',
19
+ ]);
20
+
21
+ function clean(value) {
22
+ return value == null ? '' : String(value).trim();
23
+ }
24
+
25
+ function extOf(filePath) {
26
+ const lower = filePath.toLowerCase();
27
+ if (lower.endsWith('.tar.gz')) return '.tar.gz';
28
+ if (lower.endsWith('.tar.bz2')) return '.tar.bz2';
29
+ return path.extname(lower);
30
+ }
31
+
32
+ /**
33
+ * Parse pasted CLI text into filesystem paths (one per line / whitespace-separated quoted).
34
+ * Terminal drag-drop typically pastes absolute paths; multi-line paste is supported.
35
+ * @param {string} text
36
+ * @returns {string[]}
37
+ */
38
+ export function parsePastedPaths(text) {
39
+ const raw = clean(text);
40
+ if (!raw) return [];
41
+ const paths = [];
42
+ const re = /"([^"]+)"|'([^']+)'|(`([^`]+)`)|(\S+)/g;
43
+ let match;
44
+ while ((match = re.exec(raw))) {
45
+ const candidate = match[1] || match[2] || match[4] || match[5];
46
+ if (!candidate || candidate.startsWith('-')) continue;
47
+ paths.push(candidate.replace(/\\ /g, ' '));
48
+ }
49
+ return [...new Set(paths)];
50
+ }
51
+
52
+ /**
53
+ * @param {string} filePath
54
+ */
55
+ export function classifyMaterial(filePath) {
56
+ const resolved = path.resolve(filePath);
57
+ const ext = extOf(resolved);
58
+ const exists = fs.existsSync(resolved);
59
+ const stat = exists ? fs.statSync(resolved) : null;
60
+ let kind = 'unknown';
61
+ if (stat?.isDirectory()) kind = 'directory';
62
+ else if (ARCHIVE_EXT.has(ext) || resolved.toLowerCase().endsWith('.tar.gz')) kind = 'archive';
63
+ else if (IMAGE_EXT.has(ext)) kind = 'image';
64
+ else if (MODEL_3D_EXT.has(ext)) kind = 'model3d';
65
+ else if (DOC_EXT.has(ext)) kind = 'document';
66
+ else if (CODE_EXT.has(ext)) kind = 'code';
67
+ else if (stat?.isFile()) kind = 'file';
68
+ return {
69
+ path: resolved,
70
+ exists,
71
+ kind,
72
+ ext,
73
+ bytes: stat?.isFile() ? stat.size : null,
74
+ sha256: stat?.isFile() && stat.size <= 32 * 1024 * 1024 ? hashFile(resolved) : null,
75
+ };
76
+ }
77
+
78
+ function hashFile(filePath) {
79
+ try {
80
+ return createHash('sha256').update(fs.readFileSync(filePath)).digest('hex');
81
+ } catch {
82
+ return null;
83
+ }
84
+ }
85
+
86
+ function hasBin(name) {
87
+ const result = spawnSync(name, ['--help'], { stdio: 'ignore' });
88
+ // Some tools exit non-zero on --help; presence of spawn failure matters more.
89
+ return result.error == null;
90
+ }
91
+
92
+ /**
93
+ * Extract archive into destDir. Uses host tar/unzip (no extra npm deps).
94
+ * @param {string} archivePath
95
+ * @param {string} destDir
96
+ */
97
+ export function extractArchive(archivePath, destDir) {
98
+ fs.mkdirSync(destDir, { recursive: true });
99
+ const lower = archivePath.toLowerCase();
100
+ if (lower.endsWith('.zip')) {
101
+ if (!hasBin('unzip')) throw new Error('unzip_unavailable: install unzip to extract .zip materials');
102
+ execFileSync('unzip', ['-q', '-o', archivePath, '-d', destDir], { stdio: ['ignore', 'pipe', 'pipe'] });
103
+ return { tool: 'unzip', dest: destDir };
104
+ }
105
+ if (lower.endsWith('.tar') || lower.endsWith('.tar.gz') || lower.endsWith('.tgz')
106
+ || lower.endsWith('.tar.bz2') || lower.endsWith('.tbz2') || lower.endsWith('.gz')) {
107
+ if (!hasBin('tar')) throw new Error('tar_unavailable: install tar to extract archive materials');
108
+ execFileSync('tar', ['-xf', archivePath, '-C', destDir], { stdio: ['ignore', 'pipe', 'pipe'] });
109
+ return { tool: 'tar', dest: destDir };
110
+ }
111
+ throw new Error(`unsupported_archive:${path.basename(archivePath)}`);
112
+ }
113
+
114
+ /**
115
+ * Stage pasted/dropped materials under `.agentsam/ingest/<id>/`.
116
+ * Archives are extracted; files/dirs are copied or linked by relative include paths.
117
+ *
118
+ * @param {{ root: string, materials: string[], ingestId?: string }} opts
119
+ */
120
+ export function stageMaterials(opts) {
121
+ const root = path.resolve(opts.root);
122
+ const ingestId = opts.ingestId || `ing_${randomUUID().replace(/-/g, '').slice(0, 12)}`;
123
+ const stageRoot = path.join(root, '.agentsam', 'ingest', ingestId);
124
+ fs.mkdirSync(stageRoot, { recursive: true });
125
+
126
+ /** @type {object[]} */
127
+ const items = [];
128
+ /** @type {string[]} */
129
+ const include = [];
130
+ /** @type {object[]} */
131
+ const assets = [];
132
+
133
+ for (const raw of opts.materials) {
134
+ const classified = classifyMaterial(raw);
135
+ if (!classified.exists) {
136
+ items.push({ ...classified, status: 'missing' });
137
+ continue;
138
+ }
139
+
140
+ if (classified.kind === 'archive') {
141
+ const dest = path.join(stageRoot, 'archives', path.basename(classified.path, classified.ext) || 'archive');
142
+ fs.mkdirSync(dest, { recursive: true });
143
+ const extracted = extractArchive(classified.path, dest);
144
+ const rel = path.relative(root, dest);
145
+ include.push(rel);
146
+ items.push({ ...classified, status: 'extracted', stage: dest, extract: extracted });
147
+ continue;
148
+ }
149
+
150
+ if (classified.kind === 'directory') {
151
+ const relInside = classified.path.startsWith(`${root}${path.sep}`) || classified.path === root
152
+ ? path.relative(root, classified.path) || '.'
153
+ : null;
154
+ if (relInside != null) {
155
+ include.push(relInside === '' ? '.' : relInside);
156
+ items.push({ ...classified, status: 'included', include: relInside || '.' });
157
+ } else {
158
+ const dest = path.join(stageRoot, 'trees', path.basename(classified.path) || 'tree');
159
+ copyTree(classified.path, dest);
160
+ const rel = path.relative(root, dest);
161
+ include.push(rel);
162
+ items.push({ ...classified, status: 'copied', stage: dest });
163
+ }
164
+ continue;
165
+ }
166
+
167
+ // Single file
168
+ const destDir = path.join(stageRoot, classified.kind === 'image' ? 'images'
169
+ : classified.kind === 'model3d' ? 'models3d'
170
+ : classified.kind === 'document' ? 'documents'
171
+ : 'files');
172
+ fs.mkdirSync(destDir, { recursive: true });
173
+ const dest = path.join(destDir, path.basename(classified.path));
174
+ fs.copyFileSync(classified.path, dest);
175
+ const rel = path.relative(root, dest);
176
+ include.push(path.dirname(rel));
177
+ assets.push({
178
+ kind: classified.kind,
179
+ path: rel,
180
+ bytes: classified.bytes,
181
+ sha256: classified.sha256,
182
+ ext: classified.ext,
183
+ });
184
+ items.push({ ...classified, status: 'staged', stage: dest, include: path.dirname(rel) });
185
+ }
186
+
187
+ const uniqueInclude = [...new Set(include.map((p) => p.replace(/\\/g, '/').replace(/\/$/, '') || '.'))].sort();
188
+ const manifest = {
189
+ schema: 'agentsam.ingest.materials.v1',
190
+ ingest_id: ingestId,
191
+ staged_at: new Date().toISOString(),
192
+ stage_root: path.relative(root, stageRoot),
193
+ items,
194
+ assets,
195
+ include: uniqueInclude,
196
+ };
197
+ fs.writeFileSync(path.join(stageRoot, 'manifest.json'), `${JSON.stringify(manifest, null, 2)}\n`);
198
+ return manifest;
199
+ }
200
+
201
+ function copyTree(src, dest) {
202
+ fs.mkdirSync(dest, { recursive: true });
203
+ for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
204
+ if (entry.name === '.git' || entry.name === 'node_modules' || entry.name === '.agentsam') continue;
205
+ const from = path.join(src, entry.name);
206
+ const to = path.join(dest, entry.name);
207
+ if (entry.isDirectory()) copyTree(from, to);
208
+ else if (entry.isFile()) fs.copyFileSync(from, to);
209
+ }
210
+ }
@@ -31,31 +31,39 @@ export function validateConfig(input) {
31
31
  if (!object || typeof object !== 'object' || Array.isArray(object)) throw new Error(`${label} must be an object.`);
32
32
  for (const key of Object.keys(object)) if (!keys.includes(key)) throw new Error(`Unknown ${label} field: ${key}`);
33
33
  };
34
- allowed(c, ['version', 'repository_id', 'workspace_id', 'scope', 'chunking', 'embedding', 'storage'], 'configuration');
34
+ allowed(c, ['version', 'repository_id', 'project_key', 'workspace_id', 'scope', 'chunking', 'embedding', 'storage', 'lane'], 'configuration');
35
35
  allowed(c.scope, ['name', 'include', 'exclude'], 'scope');
36
36
  allowed(c.chunking, ['max_chars'], 'chunking');
37
37
  allowed(c.embedding, ['provider', 'model', 'revision', 'dimensions', 'parameters'], 'embedding');
38
38
  allowed(c.storage, ['driver', 'connection_env'], 'storage');
39
- if (c.version !== 1) throw new Error('Unsupported knowledge configuration version.');
39
+ if (c.lane != null) allowed(c.lane, ['id', 'backend', 'resource', 'binding', 'index', 'metric'], 'lane');
40
+ if (![1, 2].includes(c.version)) throw new Error('Unsupported knowledge configuration version.');
40
41
  if (typeof c.repository_id !== 'string' || !c.repository_id.trim()) throw new Error('repository_id is required.');
42
+ if (c.project_key != null && (typeof c.project_key !== 'string' || !c.project_key.trim())) throw new Error('project_key must be a non-empty string when present.');
41
43
  if (c.workspace_id != null && (typeof c.workspace_id !== 'string' || !c.workspace_id.trim())) throw new Error('workspace_id must be a non-empty string when present.');
42
44
  if (typeof c.scope?.name !== 'string' || !c.scope.name.trim() || !Array.isArray(c.scope.include) || !c.scope.include.length) throw new Error('A named scope with at least one include path is required.');
43
45
  c.scope.include = [...new Set(c.scope.include.map(relativeSelection))].sort();
44
46
  c.scope.exclude = [...new Set((c.scope.exclude || []).map(relativeSelection))].sort();
45
47
  if (!Number.isInteger(c.chunking?.max_chars) || c.chunking.max_chars < 256 || c.chunking.max_chars > 12000) throw new Error('chunking.max_chars must be 256..12000.');
46
48
  const e = c.embedding;
47
- if (!e || ['provider', 'model', 'revision'].some(k => typeof e[k] !== 'string' || !e[k].trim()) || !Number.isInteger(e.dimensions) || e.dimensions < 1 || e.dimensions > 3072) throw new Error('Embedding provider, model, revision and dimensions (1..3072) are required.');
49
+ const disabledEmbedding = e?.provider === 'none' && e?.model === 'none' && e?.dimensions === 0;
50
+ if (!e || ['provider', 'model', 'revision'].some(k => typeof e[k] !== 'string' || !e[k].trim()) || !Number.isInteger(e.dimensions) || (!disabledEmbedding && (e.dimensions < 1 || e.dimensions > 3072))) throw new Error('Embedding provider, model, revision and dimensions (1..3072, or explicit none/0) are required.');
48
51
  if (!e.parameters || typeof e.parameters !== 'object' || Array.isArray(e.parameters)) throw new Error('Embedding parameters must be an object.');
49
52
  if (!['sqlite', 'postgres'].includes(c.storage?.driver)) throw new Error('storage.driver must be sqlite or postgres.');
50
53
  if (c.storage.driver === 'postgres' && !/^[A-Z_][A-Z0-9_]*$/.test(c.storage.connection_env || '')) throw new Error('Postgres requires a connection_env name, never a connection string in config.');
54
+ if (c.lane) {
55
+ if (typeof c.lane.id !== 'string' || !c.lane.id.trim() || !['local_exact', 'postgres_pgvector', 'supabase_pgvector', 'cloudflare_vectorize'].includes(c.lane.backend)) throw new Error('Knowledge lane requires an explicit supported backend.');
56
+ if (c.lane.backend === 'cloudflare_vectorize' && (!c.lane.binding || !c.lane.index)) throw new Error('Cloudflare Vectorize lanes require explicit binding and index.');
57
+ }
51
58
  return c;
52
59
  }
53
60
  export function defaultConfig({ include = ['.'], exclude = [], scope = 'default', target = 'local', dimensions = 768, repositoryId = '' } = {}) {
54
61
  if (!['local', 'production'].includes(target)) throw new Error('target must be local or production.');
55
- return validateConfig({ version: 1, repository_id: String(repositoryId || '').trim() || randomUUID(),
62
+ return validateConfig({ version: 2, repository_id: String(repositoryId || '').trim() || randomUUID(), project_key: String(repositoryId || '').trim() || undefined,
56
63
  scope: { name: scope, include, exclude }, chunking: { max_chars: 4000 },
57
64
  embedding: { provider: 'gemini', model: 'gemini-embedding-2', revision: '1', dimensions, parameters: { task: 'code retrieval' } },
58
- storage: target === 'local' ? { driver: 'sqlite' } : { driver: 'postgres', connection_env: 'AGENTSAM_DATABASE_URL' } });
65
+ storage: target === 'local' ? { driver: 'sqlite' } : { driver: 'postgres', connection_env: 'AGENTSAM_DATABASE_URL' },
66
+ lane: { id: `${scope}-default`, backend: target === 'local' ? 'local_exact' : 'postgres_pgvector', resource: null, binding: null, index: null, metric: 'cosine' } });
59
67
  }
60
68
  export function readConfig(root) { return validateConfig(JSON.parse(fs.readFileSync(path.join(root, CONFIG_PATH), 'utf8'))); }
61
69
  export function initRepository(root, options = {}) {
@@ -3,6 +3,7 @@ import { validateConfig, fingerprint, scopeKey, cacheNamespace, gitEvidence } fr
3
3
  import { PARSER, inventory, readSource, parseSource } from './source.js';
4
4
  import { createContextPack } from './context-pack.js';
5
5
  import { normalizeResultPolicy } from '../context/result-policy.js';
6
+ import { buildMerkleTree } from '../../packages/agentsam-repository/src/merkle/index.js';
6
7
 
7
8
  export const embeddingProfileId = profile => fingerprint({ ...profile, input_format: 'agentsam-code-content:1' });
8
9
  export function validateVector(vector, dimensions) {
@@ -14,20 +15,27 @@ function changes(before = [], after = []) {
14
15
  return { added: after.filter(f => !old.has(f.path)).map(f => f.path), changed: after.filter(f => old.has(f.path) && old.get(f.path) !== f.hash).map(f => f.path), removed: before.filter(f => !now.has(f.path)).map(f => f.path) };
15
16
  }
16
17
  /** Planning never persists, calls an embedding provider, or changes active state. */
17
- export async function planIndex({ root, config: input, store, embed = false }) {
18
+ export async function planIndex({ root, config: input, store, embed = false, limits = null }) {
18
19
  const config = validateConfig(input), scope = scopeKey(config), namespace = cacheNamespace(config);
20
+ if (embed && config.embedding.provider === 'none') throw new Error('Embedding is explicitly disabled for this knowledge profile. Configure a provider before --embed.');
21
+ const maxFiles = limits?.maxFiles == null ? Infinity : Number(limits.maxFiles);
22
+ const maxChunks = limits?.maxChunks == null ? Infinity : Number(limits.maxChunks);
23
+ if ((maxFiles !== Infinity && (!Number.isInteger(maxFiles) || maxFiles < 1)) || (maxChunks !== Infinity && (!Number.isInteger(maxChunks) || maxChunks < 1))) throw new Error('Index limits must be positive integers.');
19
24
  const previous = await store?.active(scope), profileId = embed ? embeddingProfileId(config.embedding) : null;
20
25
  const files = [], chunks = [], symbols = [], edges = [], parseWrites = [], skipped = [];
21
26
  const parseProfile = fingerprint([PARSER, config.chunking]);
22
27
  let parsedFiles = 0;
23
- for (const file of inventory(root, config.scope)) {
28
+ for (const file of inventory(root, config.scope).slice(0, maxFiles)) {
24
29
  const source = readSource(root, file);
25
30
  if (!source) { skipped.push(file); continue; }
26
31
  const key = `${namespace}:parse:${fingerprint([source.hash, file.split('.').pop(), parseProfile])}`;
27
32
  let parsed = await store?.cacheGet(key);
28
33
  if (!parsed) { parsed = parseSource(file, source.content, config.chunking.max_chars); parseWrites.push([key, parsed]); parsedFiles++; }
29
34
  files.push({ path: file, hash: source.hash, bytes: source.bytes, parser: parsed.parser });
30
- for (const [ordinal, c] of parsed.chunks.entries()) chunks.push({ ...c, path: file, ordinal, id: fingerprint([file, ordinal, c.content_hash]), embedding_key: embed ? `${namespace}:vector:${profileId}:${c.content_hash}` : null });
35
+ for (const [ordinal, c] of parsed.chunks.entries()) {
36
+ if (chunks.length >= maxChunks) break;
37
+ chunks.push({ ...c, path: file, ordinal, id: fingerprint([file, ordinal, c.content_hash]), embedding_key: embed ? `${namespace}:vector:${profileId}:${c.content_hash}` : null });
38
+ }
31
39
  symbols.push(...parsed.symbols.map(s => ({ ...s, path: file })));
32
40
  edges.push(...parsed.edges.map(e => ({ ...e, path: file })));
33
41
  }
@@ -36,19 +44,25 @@ export async function planIndex({ root, config: input, store, embed = false }) {
36
44
  if (!missing.has(chunk.embedding_key) && !(await store?.cacheGet(chunk.embedding_key))) missing.set(chunk.embedding_key, chunk.content);
37
45
  }
38
46
  const sourceHash = fingerprint(files.map(f => [f.path, f.hash]));
39
- const configHash = fingerprint([config.scope, config.chunking, PARSER, profileId]);
47
+ const configHash = fingerprint([config.scope, config.chunking, PARSER, profileId, Number.isFinite(maxFiles) ? maxFiles : null, Number.isFinite(maxChunks) ? maxChunks : null]);
48
+ let merkle = null;
49
+ try { merkle = await buildMerkleTree(root, { semantic: true }); } catch { merkle = null; }
50
+ const previousMerkle = previous?.receipt?.merkle_root || null;
51
+ const changedMerklePaths = merkle && previousMerkle !== merkle.rootHash ? files.filter(file => !previous?.files?.some(before => before.path === file.path && before.hash === file.hash)).map(file => file.path) : [];
40
52
  const noChange = previous?.source_hash === sourceHash && previous?.config_hash === configHash && !missing.size;
41
53
  return { root, config, previous, files, chunks, symbols, edges, parseWrites, missing,
42
54
  receipt: { scope: config.scope, files: files.length, chunks: chunks.length, symbols: symbols.length, edges: edges.length,
43
55
  parsed_files: parsedFiles, embedding_inputs: missing.size, embedding_characters: [...missing.values()].reduce((n, s) => n + s.length, 0),
44
56
  estimated_tokens: Math.ceil([...missing.values()].reduce((n, s) => n + s.length + 24, 0) / 4), token_estimate_method: 'characters / 4; not billable usage',
45
- profile_id: profileId, skipped, changes: changes(previous?.files, files), no_change: Boolean(noChange), source_hash: sourceHash, config_hash: configHash } };
57
+ profile_id: profileId, skipped, changes: changes(previous?.files, files), no_change: Boolean(noChange), source_hash: sourceHash, config_hash: configHash,
58
+ merkle_root: merkle?.rootHash || null, semantic_metadata_root: merkle?.semantic?.rootHash || null, merkle_changed_paths: changedMerklePaths,
59
+ limits: Number.isFinite(maxFiles) || Number.isFinite(maxChunks) ? { max_files: maxFiles, max_chunks: maxChunks } : null } };
46
60
  }
47
61
 
48
- export async function runIndex({ root, config, store, embedder, embed = false, maxInputs = 100, maxCharacters = 200000 }) {
62
+ export async function runIndex({ root, config, store, embedder, embed = false, maxInputs = 100, maxCharacters = 200000, limits = null }) {
49
63
  if (!store) throw new Error('A writable knowledge store is required.');
50
64
  if (!Number.isInteger(maxInputs) || maxInputs < 0 || !Number.isInteger(maxCharacters) || maxCharacters < 0) throw new Error('Embedding budgets must be nonnegative integers.');
51
- const plan = await planIndex({ root, config, store, embed });
65
+ const plan = await planIndex({ root, config, store, embed, limits });
52
66
  const { receipt } = plan;
53
67
  if (receipt.no_change) return { ...receipt, generation_id: plan.previous.id, published: false };
54
68
  if (receipt.embedding_inputs > maxInputs || receipt.embedding_characters > maxCharacters) throw new Error(`Embedding budget exceeded: ${receipt.embedding_inputs} unique inputs / ${receipt.embedding_characters} characters. Review index plan before raising limits.`);
@@ -64,7 +78,8 @@ export async function runIndex({ root, config, store, embedder, embed = false, m
64
78
  }
65
79
  // A generation describes one coherent source snapshot. Never publish after a mid-run edit.
66
80
  const check = [];
67
- for (const file of inventory(root, plan.config.scope)) { const source = readSource(root, file); if (source) check.push([file, source.hash]); }
81
+ const checkFiles = inventory(root, plan.config.scope).slice(0, limits?.maxFiles == null ? Infinity : limits.maxFiles);
82
+ for (const file of checkFiles) { const source = readSource(root, file); if (source) check.push([file, source.hash]); }
68
83
  if (fingerprint(check) !== receipt.source_hash) throw new Error('Repository changed while indexing; cached work retained, active generation unchanged. Rerun.');
69
84
  const generation = { id: randomUUID(), scope_key: scopeKey(plan.config), created_at: new Date().toISOString(),
70
85
  source_hash: receipt.source_hash, config_hash: receipt.config_hash, config: plan.config, profile_id: receipt.profile_id,
@@ -8,3 +8,4 @@ export { openSqliteStore } from './stores/sqlite.js';
8
8
  export { createPostgresStore, openPostgresStore, postgresSchema } from './stores/postgres.js';
9
9
  export { createGeminiEmbedder } from './providers/gemini.js';
10
10
  export { compareObservations } from './evolution.js';
11
+ export { normalizeRetrievalLane, selectProjectRetrievalLanes, loadProjectRetrievalLanes } from './lane-registry.js';
@@ -0,0 +1,46 @@
1
+ function clean(value) { return value == null ? '' : String(value).trim(); }
2
+ function json(value, fallback = {}) { try { return JSON.parse(String(value || '')); } catch { return fallback; } }
3
+
4
+ export function normalizeRetrievalLane(row = {}) {
5
+ return Object.freeze({
6
+ id: clean(row.id),
7
+ account_id: clean(row.account_id) || null,
8
+ repository_id: clean(row.repository_id) || null,
9
+ database_id: clean(row.database_id) || null,
10
+ backend_kind: clean(row.backend_kind || 'pgvector'),
11
+ provider_key: clean(row.provider_key) || null,
12
+ resource_id: clean(row.resource_id) || null,
13
+ binding_name: clean(row.binding_name) || null,
14
+ index_name: clean(row.index_name) || null,
15
+ // Namespace is provider/project-owned. Never silently force the shared
16
+ // `agentsam` schema onto a new application's retrieval lane.
17
+ schema_name: clean(row.schema_name) || null,
18
+ table_name: clean(row.table_name),
19
+ purpose: clean(row.purpose),
20
+ dimensions: Number(row.dimensions) || null,
21
+ metric: clean(row.metric || 'cosine'),
22
+ embedding_model: clean(row.embedding_model) || null,
23
+ metadata: json(row.metadata_json, {}),
24
+ is_active: Number(row.is_active) === 1,
25
+ });
26
+ }
27
+
28
+ /** Project selection is explicit; no global preferred vector store exists. */
29
+ export function selectProjectRetrievalLanes(rows, { accountId, repositoryId, purpose } = {}) {
30
+ const account = clean(accountId);
31
+ const repository = clean(repositoryId);
32
+ if (!account || !repository) throw new Error('project_retrieval_identity_required');
33
+ return (Array.isArray(rows) ? rows : [])
34
+ .map(normalizeRetrievalLane)
35
+ .filter((lane) => lane.is_active && lane.account_id === account && lane.repository_id === repository && (!purpose || lane.purpose === purpose));
36
+ }
37
+
38
+ export async function loadProjectRetrievalLanes(db, identity = {}) {
39
+ if (!db?.prepare) throw new TypeError('database_required');
40
+ const result = await db.prepare(`
41
+ SELECT * FROM agentsam_pgvector_lane_registry
42
+ WHERE account_id = ? AND repository_id = ? AND is_active = 1
43
+ ORDER BY purpose, id
44
+ `).bind(clean(identity.accountId), clean(identity.repositoryId)).all();
45
+ return selectProjectRetrievalLanes(result?.results || [], identity);
46
+ }
@@ -1,12 +1,20 @@
1
+ import { AgentSamError, classifyGeminiFailure } from '../../errors/index.js';
2
+
1
3
  /** Gemini Embedding 2 adapter; profile is supplied per job, never read globally. */
2
4
  export function createGeminiEmbedder({ apiKey, fetchImpl = globalThis.fetch, sleep = ms => new Promise(r => setTimeout(r, ms)), maxAttempts = 3, timeoutMs = 30000 } = {}) {
3
- if (!apiKey) throw new Error('GEMINI_API_KEY is required only for embedding/search with --semantic.');
4
- if (!Number.isInteger(maxAttempts) || maxAttempts < 1 || maxAttempts > 5) throw new Error('maxAttempts must be 1..5.');
5
+ if (!apiKey) throw new AgentSamError(classifyGeminiFailure({
6
+ credential_state: 'missing',
7
+ message: 'GEMINI_API_KEY is required only for embedding/search with --semantic.',
8
+ }, { domain: 'knowledge', tool: 'gemini', stage: 'embedding' }));
9
+ if (!Number.isInteger(maxAttempts) || maxAttempts < 1 || maxAttempts > 5) throw new AgentSamError(classifyGeminiFailure({
10
+ status: 400,
11
+ message: 'maxAttempts must be 1..5.',
12
+ }, { domain: 'knowledge', tool: 'gemini', stage: 'configuration', request_origin: 'user' }));
5
13
  return {
6
14
  validate(profile) {
7
- if (profile.provider !== 'gemini' || profile.model !== 'gemini-embedding-2') throw new Error('This adapter supports gemini-embedding-2; inject a different adapter for other models.');
8
- if (profile.dimensions < 128 || profile.dimensions > 3072) throw new Error('Gemini Embedding 2 dimensions must be 128..3072.');
9
- if (Object.keys(profile.parameters).some(k => k !== 'task') || !['code retrieval', 'search result', 'question answering'].includes(profile.parameters.task)) throw new Error('Unsupported Gemini embedding parameters.');
15
+ if (profile.provider !== 'gemini' || profile.model !== 'gemini-embedding-2') throw new AgentSamError(classifyGeminiFailure({ status: 400, message: 'This adapter supports gemini-embedding-2; inject a different adapter for other models.' }, { domain: 'knowledge', tool: 'gemini', stage: 'configuration', request_origin: 'user' }));
16
+ if (profile.dimensions < 128 || profile.dimensions > 3072) throw new AgentSamError(classifyGeminiFailure({ status: 400, message: 'Gemini Embedding 2 dimensions must be 128..3072.' }, { domain: 'knowledge', tool: 'gemini', stage: 'configuration', request_origin: 'user' }));
17
+ if (Object.keys(profile.parameters).some(k => k !== 'task') || !['code retrieval', 'search result', 'question answering'].includes(profile.parameters.task)) throw new AgentSamError(classifyGeminiFailure({ status: 400, message: 'Unsupported Gemini embedding parameters.' }, { domain: 'knowledge', tool: 'gemini', stage: 'configuration', request_origin: 'user' }));
10
18
  },
11
19
  async embed(text, profile, { kind = 'document' } = {}) {
12
20
  this.validate(profile);
@@ -19,10 +27,42 @@ export function createGeminiEmbedder({ apiKey, fetchImpl = globalThis.fetch, sle
19
27
  method: 'POST', headers: { 'Content-Type': 'application/json', 'x-goog-api-key': apiKey }, signal: AbortSignal.timeout(timeoutMs),
20
28
  body: JSON.stringify({ model: `models/${profile.model}`, content: { parts: [{ text: input }] }, outputDimensionality: profile.dimensions }),
21
29
  });
22
- } catch { if (attempt + 1 === maxAttempts) throw new Error('Gemini embedding request failed or timed out.'); }
30
+ } catch (cause) {
31
+ if (attempt + 1 === maxAttempts) {
32
+ throw new AgentSamError(classifyGeminiFailure({
33
+ status: 504,
34
+ status_name: 'UNAVAILABLE',
35
+ message: 'Gemini embedding request failed or timed out.',
36
+ exception_type: cause?.name,
37
+ stack: cause?.stack,
38
+ }, { domain: 'knowledge', tool: 'gemini', stage: 'embedding', reason: 'transport_timeout' }), { cause });
39
+ }
40
+ }
23
41
  if (response?.ok) return (await response.json()).embedding?.values;
24
- if (response && ![408, 429, 500, 502, 503, 504].includes(response.status)) throw new Error(`Gemini embedding failed (HTTP ${response.status}).`);
25
- if (attempt + 1 === maxAttempts) throw new Error(`Gemini embedding retry limit reached${response ? ` (HTTP ${response.status})` : ''}.`);
42
+ let providerBody = null;
43
+ if (response) {
44
+ try { providerBody = await response.clone().json(); } catch { providerBody = null; }
45
+ }
46
+ if (response && ![408, 429, 500, 502, 503, 504].includes(response.status)) {
47
+ throw new AgentSamError(classifyGeminiFailure({
48
+ status: response.status,
49
+ status_name: providerBody?.error?.status,
50
+ code: providerBody?.error?.code,
51
+ message: providerBody?.error?.message || `Gemini embedding failed (HTTP ${response.status}).`,
52
+ headers: response.headers,
53
+ body: providerBody,
54
+ }, { domain: 'knowledge', tool: 'gemini', stage: 'embedding', request_origin: 'agentsam' }));
55
+ }
56
+ if (attempt + 1 === maxAttempts) {
57
+ throw new AgentSamError(classifyGeminiFailure({
58
+ status: response?.status || 503,
59
+ status_name: providerBody?.error?.status,
60
+ code: providerBody?.error?.code,
61
+ message: providerBody?.error?.message || `Gemini embedding retry limit reached${response ? ` (HTTP ${response.status})` : ''}.`,
62
+ headers: response?.headers,
63
+ body: providerBody,
64
+ }, { domain: 'knowledge', tool: 'gemini', stage: 'embedding' }));
65
+ }
26
66
  await response?.body?.cancel();
27
67
  await sleep(Math.min(10000, 500 * 2 ** attempt + Math.floor(Math.random() * 250)));
28
68
  }