@inneranimalmedia/agentsam-sdk 2.6.7 → 2.6.8

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 (318) hide show
  1. package/README.md +37 -0
  2. package/docs/REPO_FILE_MAP.txt +132 -0
  3. package/migrations/d1/0018_goap_control_plane_remaster.sql +40 -0
  4. package/migrations/d1/0019_agentsam_agent_run_plan_todo.sql +14 -0
  5. package/migrations/d1/README_PORTABLE_CONTROL_PLANE.md +20 -9
  6. package/migrations/runtime/0002_goap_blackboard_v1.sql +15 -0
  7. package/migrations/runtime/0004_agent_run_plan_linkage.sql +8 -0
  8. package/native/agentsam-machine/cli/Cargo.toml +8 -1
  9. package/native/agentsam-machine/cli/README.md +21 -0
  10. package/native/agentsam-machine/core/Cargo.toml +7 -0
  11. package/native/agentsam-machine/core/README.md +14 -0
  12. package/native/agentsam-machine/core/build.rs +33 -0
  13. package/native/agentsam-machine/core/contracts/source-types.v1.json +353 -0
  14. package/native/agentsam-machine/core/src/lib.rs +6 -0
  15. package/native/agentsam-machine/core/src/source_types.rs +2 -2
  16. package/package.json +16 -6
  17. package/packages/agentsam-errors/package.json +1 -1
  18. package/packages/agentsam-errors/src/index.js +1 -0
  19. package/packages/agentsam-errors/src/tool.js +56 -0
  20. package/packages/agentsam-errors/test/tool.test.mjs +58 -0
  21. package/packages/agentsam-goap/README.md +52 -0
  22. package/packages/agentsam-goap/package.json +37 -0
  23. package/packages/agentsam-goap/src/adapters/d1-sqlite.js +570 -0
  24. package/packages/agentsam-goap/src/adapters/memory.js +199 -0
  25. package/packages/agentsam-goap/src/contracts.js +226 -0
  26. package/packages/agentsam-goap/src/control-plane.js +112 -0
  27. package/packages/agentsam-goap/src/errors.js +157 -0
  28. package/packages/agentsam-goap/src/index.js +5 -0
  29. package/packages/agentsam-goap/src/world.js +202 -0
  30. package/packages/agentsam-goap/test/goap-control-plane.test.mjs +245 -0
  31. package/packages/agentsam-goap/test/world.test.mjs +79 -0
  32. package/packages/agentsam-nav/dist/Nav.d.ts +43 -0
  33. package/packages/agentsam-nav/dist/NavCollapsible.d.ts +10 -0
  34. package/packages/agentsam-nav/dist/NavContent.d.ts +2 -0
  35. package/packages/agentsam-nav/dist/NavFooter.d.ts +2 -0
  36. package/packages/agentsam-nav/dist/NavGroup.d.ts +3 -0
  37. package/packages/agentsam-nav/dist/NavHeader.d.ts +2 -0
  38. package/packages/agentsam-nav/dist/NavMenu.d.ts +22 -0
  39. package/packages/agentsam-nav/dist/NavProvider.d.ts +35 -0
  40. package/packages/agentsam-nav/dist/NavTrigger.d.ts +2 -0
  41. package/packages/agentsam-nav/dist/Surfaces.d.ts +41 -0
  42. package/packages/agentsam-nav/dist/browser.d.ts +11 -0
  43. package/packages/agentsam-nav/dist/browser.global.js +135 -0
  44. package/packages/agentsam-nav/dist/browser.js +7290 -0
  45. package/packages/agentsam-nav/dist/contracts.d.ts +76 -0
  46. package/packages/agentsam-nav/dist/index.d.ts +11 -0
  47. package/packages/agentsam-nav/dist/index.js +7291 -0
  48. package/packages/agentsam-nav/dist/legacy.css +83 -0
  49. package/packages/agentsam-nav/dist/shell.css +113 -0
  50. package/packages/agentsam-nav/dist/theme.css +113 -0
  51. package/packages/agentsam-nav/dist/utils.d.ts +1 -0
  52. package/packages/agentsam-repository/src/goap.js +13 -14
  53. package/packages/agentsam-repository/src/goap.js.bak-20260922011251 +670 -0
  54. package/packages/agentsam-repository/src/tickets.js +15 -22
  55. package/packages/agentsam-repository/test/goap-tickets-workspace-state.test.mjs +19 -8
  56. package/packages/connectors/cloudflare/package.json +3 -1
  57. package/packages/identity/tests/lane1-packed-consumer.test.mjs +1 -1
  58. package/python/agentsam_sdk/repository/intelligence/discovery.py +27 -2
  59. package/python/agentsam_sdk/repository/intelligence/git.py +4 -0
  60. package/python/tests/test_repository_intelligence.py +30 -0
  61. package/src/cli/command-catalog.js +2 -1
  62. package/src/cli.js +10 -1
  63. package/src/commands/goap-world.js +134 -0
  64. package/src/commands/goap.js +11 -4
  65. package/src/commands/machine-binary.js +33 -27
  66. package/src/commands/machine-runtime.js +266 -0
  67. package/src/commands/machine.js +122 -51
  68. package/src/commands/package.js +530 -0
  69. package/src/commands/plan-ledger.js +370 -0
  70. package/src/commands/plan.js +183 -0
  71. package/src/commands/skill.js +78 -17
  72. package/src/knowledge/source.js +1 -1
  73. package/src/lib/slash-commands.js +1 -1
  74. package/src/local/runtime-store.js +24 -2
  75. package/src/local/sqlite.js +17 -0
  76. package/src/sam/operations/package-audit.js +41 -0
  77. package/src/sam/seed.js +2 -0
  78. package/skills/grok-auth/SKILL.md +0 -110
  79. package/skills/grok-auth/agentsam.skill.json +0 -25
  80. package/skills/grok-auth/references/grok-identity.md +0 -64
  81. package/skills/grok-auth/references/per-user-data.md +0 -49
  82. package/skills/grok-auth/references/prewired-and-env.md +0 -54
  83. package/skills/grok-auth/references/session-ui.md +0 -133
  84. package/skills/grok-auth/references/sign-in-methods.md +0 -55
  85. package/skills/grok-auth/references/wiring.md +0 -71
  86. package/skills/grok-building-games/SKILL.md +0 -213
  87. package/skills/grok-building-games/agentsam.skill.json +0 -25
  88. package/skills/grok-building-games/references/3d-libs.md +0 -64
  89. package/skills/grok-building-games/references/ai-pathfinding.md +0 -122
  90. package/skills/grok-building-games/references/audio.md +0 -129
  91. package/skills/grok-building-games/references/babylon.md +0 -202
  92. package/skills/grok-building-games/references/collision-physics.md +0 -122
  93. package/skills/grok-building-games/references/ecs-architecture.md +0 -111
  94. package/skills/grok-building-games/references/game-feel-juice.md +0 -110
  95. package/skills/grok-building-games/references/genres/board-card-chess.md +0 -89
  96. package/skills/grok-building-games/references/genres/endless-runner.md +0 -83
  97. package/skills/grok-building-games/references/genres/fps.md +0 -105
  98. package/skills/grok-building-games/references/genres/platformer-2d.md +0 -97
  99. package/skills/grok-building-games/references/genres/puzzle-match3-tetris.md +0 -131
  100. package/skills/grok-building-games/references/genres/racing-kart.md +0 -106
  101. package/skills/grok-building-games/references/genres/topdown-twin-stick.md +0 -97
  102. package/skills/grok-building-games/references/genres/tower-defense.md +0 -84
  103. package/skills/grok-building-games/references/genres/voxel-minecraft.md +0 -89
  104. package/skills/grok-building-games/references/input.md +0 -139
  105. package/skills/grok-building-games/references/phaser.md +0 -277
  106. package/skills/grok-building-games/references/procedural-generation.md +0 -141
  107. package/skills/grok-building-games/references/save-persistence.md +0 -108
  108. package/skills/grok-building-games/references/threejs-foundational.md +0 -148
  109. package/skills/grok-controls/SKILL.md +0 -274
  110. package/skills/grok-controls/agentsam.skill.json +0 -25
  111. package/skills/grok-design-ui/SKILL.md +0 -122
  112. package/skills/grok-design-ui/agentsam.skill.json +0 -25
  113. package/skills/grok-design-ui/references/animations.md +0 -379
  114. package/skills/grok-design-ui/references/performance.md +0 -88
  115. package/skills/grok-design-ui/references/refined-ui.md +0 -384
  116. package/skills/grok-design-ui/references/surfaces.md +0 -247
  117. package/skills/grok-design-ui/references/typography.md +0 -123
  118. package/skills/grok-game-animation-frames/SKILL.md +0 -84
  119. package/skills/grok-game-animation-frames/agentsam.skill.json +0 -25
  120. package/skills/grok-game-asset-core/SKILL.md +0 -69
  121. package/skills/grok-game-asset-core/agentsam.skill.json +0 -25
  122. package/skills/grok-game-character-consistency/SKILL.md +0 -69
  123. package/skills/grok-game-character-consistency/agentsam.skill.json +0 -25
  124. package/skills/grok-game-tilesets/SKILL.md +0 -65
  125. package/skills/grok-game-tilesets/agentsam.skill.json +0 -25
  126. package/skills/grok-game-ui-icons/SKILL.md +0 -56
  127. package/skills/grok-game-ui-icons/agentsam.skill.json +0 -25
  128. package/skills/grok-generate2dmap/LICENSE +0 -21
  129. package/skills/grok-generate2dmap/SKILL.md +0 -120
  130. package/skills/grok-generate2dmap/SOURCE.md +0 -6
  131. package/skills/grok-generate2dmap/agentsam.skill.json +0 -25
  132. package/skills/grok-generate2dmap/references/deliverables.md +0 -101
  133. package/skills/grok-generate2dmap/references/layered-map-contract.md +0 -209
  134. package/skills/grok-generate2dmap/references/map-strategies.md +0 -341
  135. package/skills/grok-generate2dmap/references/object-production-gate.md +0 -24
  136. package/skills/grok-generate2dmap/references/pipeline.md +0 -149
  137. package/skills/grok-generate2dmap/references/prop-pack-contract.md +0 -174
  138. package/skills/grok-generate2dmap/references/side-scroll-stages.md +0 -29
  139. package/skills/grok-generate2dmap/scripts/compose_layered_preview.py +0 -157
  140. package/skills/grok-generate2dmap/scripts/extract_prop_pack.py +0 -369
  141. package/skills/grok-generate2dsprite/LICENSE +0 -21
  142. package/skills/grok-generate2dsprite/SKILL.md +0 -313
  143. package/skills/grok-generate2dsprite/SOURCE.md +0 -6
  144. package/skills/grok-generate2dsprite/agentsam.skill.json +0 -25
  145. package/skills/grok-generate2dsprite/references/modes.md +0 -124
  146. package/skills/grok-generate2dsprite/references/prompt-rules.md +0 -315
  147. package/skills/grok-generate2dsprite/scripts/generate2dsprite.py +0 -1031
  148. package/skills/grok-generate2dsprite/scripts/make_layout_guide.py +0 -109
  149. package/skills/grok-imagine/SKILL.md +0 -201
  150. package/skills/grok-imagine/agentsam.skill.json +0 -25
  151. package/skills/grok-multiplayer-p2p/SKILL.md +0 -111
  152. package/skills/grok-multiplayer-p2p/agentsam.skill.json +0 -25
  153. package/skills/grok-multiplayer-p2p/references/react-binding.md +0 -144
  154. package/skills/grok-multiplayer-p2p/references/signaling-relay.md +0 -269
  155. package/skills/grok-neon/SKILL.md +0 -157
  156. package/skills/grok-neon/agentsam.skill.json +0 -25
  157. package/skills/grok-og/SKILL.md +0 -102
  158. package/skills/grok-og/agentsam.skill.json +0 -25
  159. package/skills/grok-og/references/brand-pass.md +0 -53
  160. package/skills/grok-og/references/custom-card.md +0 -107
  161. package/skills/grok-og/references/favicon-and-icons.md +0 -48
  162. package/skills/grok-og/references/og-type-contract.md +0 -18
  163. package/skills/grok-og/references/placeholder-card.md +0 -21
  164. package/skills/grok-og/references/x-banner.md +0 -41
  165. package/skills/grok-threejs/SKILL.md +0 -67
  166. package/skills/grok-threejs/agentsam.skill.json +0 -25
  167. package/skills/grok-threejs/references/llms-full.txt +0 -2780
  168. package/skills/grok-video2dsprite/LICENSE +0 -21
  169. package/skills/grok-video2dsprite/SKILL.md +0 -236
  170. package/skills/grok-video2dsprite/SOURCE.md +0 -6
  171. package/skills/grok-video2dsprite/agentsam.skill.json +0 -25
  172. package/skills/grok-video2dsprite/references/pipeline.md +0 -90
  173. package/skills/grok-video2dsprite/references/prompt-rules.md +0 -63
  174. package/skills/grok-video2dsprite/scripts/video2dsprite.py +0 -490
  175. package/skills/grok-xai-api/SKILL.md +0 -152
  176. package/skills/grok-xai-api/agentsam.skill.json +0 -25
  177. package/test/account-session.test.mjs +0 -101
  178. package/test/agent-capabilities.test.mjs +0 -67
  179. package/test/app-authority-context.test.mjs +0 -32
  180. package/test/app-building-skills.test.mjs +0 -61
  181. package/test/apps-scaffold-contract.test.mjs +0 -115
  182. package/test/blender-cad.test.mjs +0 -146
  183. package/test/cad-docker.test.mjs +0 -96
  184. package/test/capabilities.test.mjs +0 -133
  185. package/test/cli/api-key-env-whoami.test.mjs +0 -129
  186. package/test/cli/catalog-authority.test.mjs +0 -64
  187. package/test/cli/codebaseindex-plan-ux.test.mjs +0 -37
  188. package/test/cli/eval-live.test.mjs +0 -219
  189. package/test/cli/go.test.mjs +0 -128
  190. package/test/cli/local-vault-and-provider-setup.test.mjs +0 -268
  191. package/test/cli/machine-command.test.mjs +0 -34
  192. package/test/cli/mcp-client.test.mjs +0 -256
  193. package/test/cli/preferences-runtime.test.mjs +0 -11
  194. package/test/cli/runtime-persist.test.mjs +0 -56
  195. package/test/cli/runtime-ui.test.mjs +0 -141
  196. package/test/cli/rust-command.test.mjs +0 -21
  197. package/test/cli/skill-npm-and-env.test.mjs +0 -52
  198. package/test/cli/status-actions.test.mjs +0 -88
  199. package/test/cli/wireframes-go-registry.test.mjs +0 -139
  200. package/test/cli-preferences.test.mjs +0 -46
  201. package/test/cloudflare-connector.test.mjs +0 -93
  202. package/test/cloudflare-runtime.test.mjs +0 -82
  203. package/test/context.test.mjs +0 -159
  204. package/test/credentials-audit.test.mjs +0 -113
  205. package/test/deploy-health-scan.test.mjs +0 -95
  206. package/test/deploy-receipt.test.mjs +0 -91
  207. package/test/dockerize.test.mjs +0 -93
  208. package/test/error-diagnostics.test.mjs +0 -124
  209. package/test/eval-context.test.mjs +0 -37
  210. package/test/execution-approvals.test.mjs +0 -27
  211. package/test/fixtures/cad/courtyard-house.json +0 -208
  212. package/test/fixtures/knowledge-rpc-worker.mjs +0 -16
  213. package/test/fixtures/project-authority/customer-app/.agentsam/app.json +0 -5
  214. package/test/fixtures/project-authority/customer-app/apps/my-product/index.ts +0 -1
  215. package/test/fixtures/project-authority/customer-app/wrangler.toml +0 -17
  216. package/test/gcloud-auth.test.mjs +0 -111
  217. package/test/go/build-source-identity.test.mjs +0 -31
  218. package/test/go/cloudflare-probe.test.mjs +0 -317
  219. package/test/go/distribution.test.mjs +0 -28
  220. package/test/google-cloud-connection.test.mjs +0 -83
  221. package/test/google-cloud-inventory.test.mjs +0 -64
  222. package/test/indexing-provider.test.mjs +0 -29
  223. package/test/init-options.test.mjs +0 -35
  224. package/test/integration/ai-access-onboarding.test.mjs +0 -47
  225. package/test/integration/app-command.test.mjs +0 -85
  226. package/test/integration/autorag-project-authority.integration.test.mjs +0 -51
  227. package/test/integration/autorag-runtime-discovery.test.mjs +0 -107
  228. package/test/integration/cad-discovery.test.mjs +0 -158
  229. package/test/integration/cad-docker-executor.test.mjs +0 -249
  230. package/test/integration/cad-execution.test.mjs +0 -184
  231. package/test/integration/cad-project-app.test.mjs +0 -31
  232. package/test/integration/cad-project-d1.test.mjs +0 -25
  233. package/test/integration/cad-project-native.test.mjs +0 -24
  234. package/test/integration/cad-project-workflow.test.mjs +0 -9
  235. package/test/integration/cad-project.test.mjs +0 -85
  236. package/test/integration/cli-help.test.mjs +0 -41
  237. package/test/integration/cms-app-scaffold.test.mjs +0 -77
  238. package/test/integration/cms-site-tenancy-contract.test.mjs +0 -268
  239. package/test/integration/codebaseindex-ingest.test.mjs +0 -255
  240. package/test/integration/core-client.integration.test.mjs +0 -55
  241. package/test/integration/database-hosted-honesty.test.mjs +0 -49
  242. package/test/integration/desktop-keychain-boundary.test.mjs +0 -45
  243. package/test/integration/error-runtime-rpc.test.mjs +0 -71
  244. package/test/integration/features-resolve.test.mjs +0 -147
  245. package/test/integration/hosted-work-host-authority.test.mjs +0 -47
  246. package/test/integration/icon-registry.test.mjs +0 -67
  247. package/test/integration/ingest-discover-models.test.mjs +0 -30
  248. package/test/integration/inspect-path-cli.test.mjs +0 -46
  249. package/test/integration/install-script.test.mjs +0 -110
  250. package/test/integration/inventory-core.test.mjs +0 -53
  251. package/test/integration/inventory-eligibility.test.mjs +0 -59
  252. package/test/integration/inventory-evidence.test.mjs +0 -125
  253. package/test/integration/knowledge-rpc.test.mjs +0 -112
  254. package/test/integration/local-fs.test.mjs +0 -113
  255. package/test/integration/local-provider-bridge.test.mjs +0 -65
  256. package/test/integration/local-studio-settings-production.test.mjs +0 -40
  257. package/test/integration/lockfile-sync.test.mjs +0 -26
  258. package/test/integration/merkle-cli.test.mjs +0 -61
  259. package/test/integration/merkle-persistence-identity.test.mjs +0 -48
  260. package/test/integration/plugins-cloudflare.integration.test.mjs +0 -28
  261. package/test/integration/provider-env-cli.test.mjs +0 -60
  262. package/test/integration/provider-factory.test.mjs +0 -197
  263. package/test/integration/repository-company-graph.test.mjs +0 -90
  264. package/test/integration/runtime-migrations.test.mjs +0 -87
  265. package/test/integration/runtime-status.integration.test.mjs +0 -227
  266. package/test/integration/sam-activity-recovery.test.mjs +0 -147
  267. package/test/integration/sam-decision.test.mjs +0 -584
  268. package/test/integration/sam-kernel.test.mjs +0 -99
  269. package/test/integration/sam-planning-astar.test.mjs +0 -279
  270. package/test/integration/scaffold-cloudflare.test.mjs +0 -46
  271. package/test/integration/skill-runtime.test.mjs +0 -240
  272. package/test/integration/storage-architecture.test.mjs +0 -154
  273. package/test/integration/store-discovery.test.mjs +0 -44
  274. package/test/integration/studio-fs-pty-e2e.test.mjs +0 -294
  275. package/test/integration/terminal-exec.integration.test.mjs +0 -86
  276. package/test/integration/theme-package-registry.test.mjs +0 -31
  277. package/test/integration/tool-runtime.test.mjs +0 -124
  278. package/test/integration/tool-schema.test.mjs +0 -59
  279. package/test/jr-dev-skill.test.mjs +0 -26
  280. package/test/knowledge-context-pack.test.mjs +0 -19
  281. package/test/knowledge-postgres.test.mjs +0 -40
  282. package/test/knowledge-service.test.mjs +0 -110
  283. package/test/knowledge.test.mjs +0 -206
  284. package/test/live/terminal-transport.live.test.mjs +0 -24
  285. package/test/local-sessions.test.mjs +0 -57
  286. package/test/local-studio-deploy.test.mjs +0 -83
  287. package/test/loopback-oauth.test.mjs +0 -53
  288. package/test/merkle-render.test.mjs +0 -31
  289. package/test/mini.test.mjs +0 -140
  290. package/test/model-catalog.test.mjs +0 -70
  291. package/test/models.test.mjs +0 -309
  292. package/test/npm10-lock.test.mjs +0 -29
  293. package/test/ollama.test.mjs +0 -137
  294. package/test/open-url.test.mjs +0 -64
  295. package/test/openai-responses.test.mjs +0 -155
  296. package/test/portable-context.test.mjs +0 -94
  297. package/test/project-config.test.mjs +0 -81
  298. package/test/project-rules.test.mjs +0 -44
  299. package/test/provider-credentials.test.mjs +0 -106
  300. package/test/rehydrate.test.mjs +0 -25
  301. package/test/release-hygiene.test.mjs +0 -42
  302. package/test/repository-snapshot-view.test.mjs +0 -112
  303. package/test/responses-runner.test.mjs +0 -465
  304. package/test/runtime-activity.test.mjs +0 -98
  305. package/test/sdk-worker-contract.test.mjs +0 -72
  306. package/test/security.test.mjs +0 -266
  307. package/test/setup-planner.test.mjs +0 -74
  308. package/test/setup-runtime.test.mjs +0 -51
  309. package/test/shell.test.mjs +0 -281
  310. package/test/skills.test.mjs +0 -22
  311. package/test/smoke.mjs +0 -122
  312. package/test/telemetry.test.mjs +0 -79
  313. package/test/terminal/local-pty.mock.test.mjs +0 -153
  314. package/test/terminal-machine-identity.test.mjs +0 -88
  315. package/test/theme-portability.test.mjs +0 -14
  316. package/test/tools-search.test.mjs +0 -73
  317. package/test/unit/website-assets-bindings.test.mjs +0 -60
  318. package/test/whoami-resume.test.mjs +0 -157
@@ -1,124 +0,0 @@
1
- import assert from 'node:assert/strict';
2
- import test from 'node:test';
3
-
4
- import {
5
- createToolExecutor,
6
- createToolRegistry,
7
- } from '../../src/tools/index.js';
8
- import {
9
- COMPLETEFUL_TOOL_DEFINITIONS,
10
- createCompletefulClient,
11
- createCompletefulProviderAdapter,
12
- } from '../../packages/providers/completeful/src/index.js';
13
-
14
- test('tool runtime owns idempotency, redacts durable receipts, and emits safe events', async () => {
15
- let captured = null;
16
- const client = createCompletefulClient({
17
- apiKey: 'capp_test_example',
18
- fetchImpl: async (url, init) => {
19
- captured = { url, init };
20
- return new Response(
21
- JSON.stringify({
22
- id: 'ord_1',
23
- email: 'customer@example.com',
24
- shipping_address: { line1: 'private street' },
25
- notes: 'private note',
26
- }),
27
- { status: 201, headers: { 'x-request-id': 'req_order_1' } },
28
- );
29
- },
30
- });
31
-
32
- const registry = createToolRegistry({
33
- tools: COMPLETEFUL_TOOL_DEFINITIONS,
34
- adapters: [createCompletefulProviderAdapter(client)],
35
- });
36
-
37
- const recorded = [];
38
- const observed = [];
39
- let sequence = 0;
40
- const executor = createToolExecutor({
41
- registry,
42
- makeId: (prefix) => `${prefix}_test_${++sequence}`,
43
- now: (() => {
44
- let value = 1_800_000_000_000;
45
- return () => ++value;
46
- })(),
47
- recordReceipt: (receipt) => recorded.push(receipt),
48
- onEvent: (event) => observed.push(event),
49
- });
50
-
51
- const result = await executor.execute({
52
- toolKey: 'completeful.order.create',
53
- accountId: 'acct_1',
54
- correlationId: 'corr_1',
55
- input: {
56
- shop_id: 'shop_1',
57
- body: {
58
- shipping_address: { line1: 'private street' },
59
- email: 'customer@example.com',
60
- notes: 'private note',
61
- line_items: [{ product_id: 'prod_1', quantity: 1 }],
62
- },
63
- },
64
- });
65
-
66
- assert.equal(result.ok, true);
67
- assert.equal(result.output.email, 'customer@example.com');
68
- assert.equal(captured.init.headers.get('Idempotency-Key'), result.invocation.id);
69
- assert.equal(result.receipt.input.body.email, '[REDACTED]');
70
- assert.equal(result.receipt.input.body.shipping_address, '[REDACTED]');
71
- assert.equal(result.receipt.output.email, '[REDACTED]');
72
- assert.equal(result.receipt.output.shipping_address, '[REDACTED]');
73
- assert.equal(recorded.length, 1);
74
- assert.equal(observed.length, 1);
75
- assert.equal(observed[0].eventKey, 'completeful.order.created');
76
- assert.equal(observed[0].payload.output.email, '[REDACTED]');
77
- assert.equal(observed[0].causationId, result.invocation.id);
78
- assert.equal(observed[0].correlationId, 'corr_1');
79
- });
80
-
81
- test('tool runtime converts provider errors into the canonical AgentSam envelope', async () => {
82
- const client = createCompletefulClient({
83
- apiKey: 'capp_test_example',
84
- fetchImpl: async () =>
85
- new Response(
86
- JSON.stringify({
87
- error: 'too many requests',
88
- code: 'rate_limited',
89
- request_id: 'req_rate',
90
- }),
91
- { status: 429 },
92
- ),
93
- });
94
-
95
- const registry = createToolRegistry({
96
- tools: COMPLETEFUL_TOOL_DEFINITIONS,
97
- adapters: [createCompletefulProviderAdapter(client)],
98
- });
99
- const executor = createToolExecutor({
100
- registry,
101
- makeId: (prefix) => `${prefix}_failure`,
102
- });
103
-
104
- const result = await executor.execute({
105
- toolKey: 'completeful.catalog.list',
106
- input: { limit: 1 },
107
- });
108
-
109
- assert.equal(result.ok, false);
110
- assert.equal(result.error.reason, 'provider_rate_limited');
111
- assert.equal(result.error.code, 'RESOURCE_EXHAUSTED');
112
- assert.equal(result.error.provider, 'completeful');
113
- assert.equal(result.error.provider_code, 'rate_limited');
114
- assert.equal(result.error.request_id, 'req_rate');
115
- assert.equal(result.receipt.status, 'failed');
116
- });
117
-
118
- test('registry rejects duplicate tool keys instead of silently shadowing definitions', () => {
119
- const definition = COMPLETEFUL_TOOL_DEFINITIONS[0];
120
- assert.throws(
121
- () => createToolRegistry({ tools: [definition, definition] }),
122
- /duplicate tool definition/,
123
- );
124
- });
@@ -1,59 +0,0 @@
1
- import test from 'node:test';
2
- import assert from 'node:assert/strict';
3
- import { compileToolSchema, restoreOptionalArguments } from '../../src/providers/tool-schema.js';
4
- import { createCapabilityAdapter } from '../../src/agent/capability-adapter.js';
5
- import { createOpenAIResponsesAdapter } from '../../src/providers/openai-responses.js';
6
- import { createGeminiGenerateContentAdapter } from '../../src/providers/gemini-generate-content.js';
7
-
8
- const canonical = { $schema: 'https://json-schema.org/draft/2020-12/schema', $id: 'sample', type: 'object', properties: {
9
- text: { type: 'string' }, rows: { type: 'array', items: { type: 'object', properties: { label: { type: 'string', enum: ['x'] } } } },
10
- additionalProperties: { type: 'string' },
11
- }, required: ['text'] };
12
-
13
- test('strict compiler recursively closes objects and makes omitted fields nullable without mutating canonical input', () => {
14
- const original = structuredClone(canonical);
15
- const { providerSchema: s } = compileToolSchema({ provider: 'openai', canonicalSchema: canonical });
16
- assert.equal(s.additionalProperties, false);
17
- assert.deepEqual(s.required, ['text', 'rows', 'additionalProperties']);
18
- assert.equal(s.properties.rows.anyOf[0].items.additionalProperties, false);
19
- assert.deepEqual(s.properties.rows.anyOf[0].items.required, ['label']);
20
- assert.deepEqual(s.properties.rows.anyOf[0].items.properties.label.anyOf, [{ type: 'string', enum: ['x'] }, { type: 'null' }]);
21
- assert.deepEqual(canonical, original);
22
- assert.deepEqual(restoreOptionalArguments({ text: 'x', rows: [{ label: null }], additionalProperties: null }, canonical), { text: 'x', rows: [{}] });
23
- });
24
-
25
- test('all executable capability schemas compile for both providers, including actual knowledge.search arguments', () => {
26
- for (const descriptor of createCapabilityAdapter().toolDescriptors()) {
27
- for (const provider of ['openai', 'gemini']) assert.ok(compileToolSchema({ provider, canonicalSchema: descriptor.input_schema, strict: descriptor.strict !== false, name: descriptor.name }).hash);
28
- if (descriptor.name === 'knowledge.search') assert.equal(descriptor.input_schema.properties.text.type, 'string');
29
- }
30
- });
31
-
32
- test('bad schemas fail before provider fetch, with actionable paths', async () => {
33
- for (const schema of [
34
- { type: 'object', properties: {}, required: ['missing'] },
35
- { type: 'object', properties: { x: { $ref: 'https://remote/schema' } } },
36
- { type: 'object', properties: { x: { type: 'array' } } },
37
- { type: 'object', properties: { x: { type: 'invalid' } } },
38
- ]) {
39
- let requests = 0;
40
- const adapter = createOpenAIResponsesAdapter({ apiKey: 'test', fetchImpl: async () => { requests++; } });
41
- await assert.rejects(adapter.create({ model: 'gpt-6-astra', input: 'test', tools: [{ type: 'function', name: 'broken', parameters: schema }] }), /tool_schema_invalid:openai:broken:/);
42
- assert.equal(requests, 0);
43
- }
44
- });
45
-
46
- test('Gemini uses JSON Schema declaration field and preserves canonical optionality', async () => {
47
- let body;
48
- const adapter = createGeminiGenerateContentAdapter({ apiKey: 'test', fetchImpl: async (_, init) => {
49
- body = JSON.parse(init.body);
50
- return { ok: true, json: async () => ({ candidates: [{ content: { role: 'model', parts: [{ text: 'ok' }] } }] }) };
51
- } });
52
- await adapter.create({ modelRecord: { provider: 'gemini', provider_model_id: 'fixture' }, input: 'test', tools: [{ name: 'sample', parameters: canonical }] });
53
- const declaration = body.tools[0].functionDeclarations[0];
54
- assert.equal(declaration.parameters, undefined);
55
- assert.equal(declaration.parametersJsonSchema.$schema, undefined);
56
- assert.equal(declaration.parametersJsonSchema.$id, undefined);
57
- assert.deepEqual(declaration.parametersJsonSchema.required, ['text']);
58
- assert.equal(declaration.parametersJsonSchema.properties.additionalProperties.type, 'string');
59
- });
@@ -1,26 +0,0 @@
1
- import assert from 'node:assert/strict';
2
- import fs from 'node:fs';
3
- import path from 'node:path';
4
- import test from 'node:test';
5
-
6
- const root = path.resolve(import.meta.dirname, '..');
7
- const skill = path.join(root, 'skills', 'agentsam-jr-dev', 'SKILL.md');
8
- const fundamentals = path.join(root, 'skills', 'agentsam-jr-dev', 'references', 'web-application-fundamentals.md');
9
- const logic = path.join(root, 'skills', 'agentsam-jr-dev', 'references', 'real-application-logic.md');
10
-
11
- test('agentsam-jr-dev ships as a portable skill with depth references', () => {
12
- for (const file of [skill, fundamentals, logic]) {
13
- assert.equal(fs.existsSync(file), true, `${file} must exist`);
14
- }
15
-
16
- const text = fs.readFileSync(skill, 'utf8');
17
- assert.match(text, /name: agentsam-jr-dev/);
18
- assert.match(text, /Inspect before teaching repo-specific facts/);
19
- assert.match(text, /Real application logic is the standard/);
20
- assert.match(text, /Never invent a repo architecture/);
21
- assert.match(text, /frontend owns presentation/);
22
- assert.match(text, /backend owns trusted execution/);
23
-
24
- const pkg = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8'));
25
- assert.ok(pkg.files.includes('skills'), 'root npm package must include portable skills');
26
- });
@@ -1,19 +0,0 @@
1
- import assert from 'node:assert/strict';
2
- import test from 'node:test';
3
- import { createContextPack } from '../src/knowledge/context-pack.js';
4
-
5
- test('knowledge ContextPack includes a measurable selection receipt', () => {
6
- const pack = createContextPack({
7
- queryId: 'q1',
8
- query: { text: 'where is auth?', top_k: 2, token_budget: 2000 },
9
- hits: [{ ref: 'file:a', content: 'abcd' }, { ref: 'file:b', content: '12345678' }],
10
- diagnostics: { sources_considered: 7, sources_deferred: 5 },
11
- });
12
- assert.deepEqual(pack.receipt, {
13
- chars: 12,
14
- estimated_tokens: 3,
15
- sources_considered: 7,
16
- sources_included: 2,
17
- sources_deferred: 5,
18
- });
19
- });
@@ -1,40 +0,0 @@
1
- import test from 'node:test';
2
- import assert from 'node:assert/strict';
3
- import fs from 'node:fs';
4
- import os from 'node:os';
5
- import path from 'node:path';
6
- import { PGlite } from '@electric-sql/pglite';
7
- import { vector } from '@electric-sql/pglite-pgvector';
8
- import { createPostgresStore, defaultConfig, runIndex, retrieve, scopeKey } from '../src/knowledge/index.js';
9
-
10
- test('real Postgres/pgvector schema, exact retrieval, profile isolation and publication rollback', async t => {
11
- const db = new PGlite({ extensions: { vector } });
12
- // PGlite exposes the same parameterized SQL execution; exec supports DDL batches.
13
- const store = createPostgresStore({ query: (sql, params) => params ? db.query(sql, params) : db.exec(sql).then(results => results.at(-1)), end: () => db.close() });
14
- const root = fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-pg-'));
15
- t.after(async () => { await store.close(); fs.rmSync(root, { recursive: true, force: true }); });
16
- await store.setup(); await store.setup();
17
- fs.writeFileSync(path.join(root, 'math.ts'), 'export function add(a: number, b: number) { return a + b; }\nexport const name = "math";');
18
- const config = defaultConfig();
19
- config.embedding = { provider: 'fixture', model: 'vector-test', revision: '1', dimensions: 3, parameters: {} };
20
- const embedder = { async embed(text) { return text.includes('add') ? [1, 0, 0] : [0, 1, 0]; } };
21
- const first = await runIndex({ root, config, store, embedder, embed: true });
22
- const result = await retrieve({ config, store, embedder, text: 'add', semantic: true });
23
- assert.equal(result.hits[0].metadata.symbol, 'add'); assert.equal(result.hits[0].score, 1);
24
- assert.equal((await db.query('SELECT count(*)::int AS n FROM agentsam_knowledge.cache WHERE embedding IS NOT NULL')).rows[0].n, 2);
25
- assert.equal((await runIndex({ root, config, store, embedder, embed: true })).embedding_inputs, 0);
26
- // A different-dimensional profile in the same table must not break retrieval.
27
- await store.cachePut('foreign:vector:other', [1, 0, 0, 0]);
28
- assert.equal((await retrieve({ config, store, embedder, text: 'add', semantic: true })).hits[0].score, 1);
29
- const generation = await store.active(scopeKey(config));
30
- await assert.rejects(store.publish({ ...generation, id: 'bad-cas' }, 'wrong-parent'), /concurrently/);
31
- assert.equal((await store.active(scopeKey(config))).id, first.generation_id);
32
- // Force SQL failure after the CAS check; the old generation remains visible.
33
- await assert.rejects(store.publish(generation, generation.id), /duplicate key/);
34
- assert.equal((await store.active(scopeKey(config))).id, first.generation_id);
35
- assert.equal((await store.history(scopeKey(config))).length, 1);
36
- const observation = { id: 'obs-1', created_at: new Date().toISOString(), data: { files: 1 } };
37
- await store.observe('customer', observation);
38
- assert.deepEqual(await store.observations('customer'), [observation]);
39
- assert.deepEqual(await store.observations('another-customer'), []);
40
- });
@@ -1,110 +0,0 @@
1
- import { test } from 'node:test';
2
- import assert from 'node:assert/strict';
3
- import fs from 'node:fs';
4
- import os from 'node:os';
5
- import path from 'node:path';
6
- import { DatabaseSync } from 'node:sqlite';
7
- import { defaultConfig } from '../src/knowledge/config.js';
8
- import { startKnowledgeService } from '../src/knowledge/service/server.js';
9
- import { createKnowledgeServiceClient } from '../src/knowledge/service/client.js';
10
- import { dockerize } from '../src/lib/dockerize.js';
11
-
12
- async function completed(client, id) {
13
- for (let i = 0; i < 200; i++) {
14
- const job = await client.job(id);
15
- if (['completed', 'failed'].includes(job.status)) { assert.equal(job.status, 'completed', job.error); return job; }
16
- await new Promise(resolve => setTimeout(resolve, 25));
17
- }
18
- throw new Error('Job did not complete.');
19
- }
20
-
21
- test('service isolates scopes, authenticates, deduplicates, indexes, searches, and preserves restart state', async () => {
22
- const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-service-'));
23
- const root = path.join(tmp, 'repo'), stateDir = path.join(tmp, 'state');
24
- fs.mkdirSync(path.join(root, 'src'), { recursive: true });
25
- fs.writeFileSync(path.join(root, 'src/math.ts'), 'export function add(a: number,b: number) { return a+b; }\n');
26
- fs.writeFileSync(path.join(root, '.env.json'), '{"password":"must-not-index"}');
27
- const before = fs.readFileSync(path.join(root, 'src/math.ts'), 'utf8');
28
- const token = 't'.repeat(64), repositories = { sample: { root, config: defaultConfig({ include: ['src'] }) } };
29
- let service;
30
- try {
31
- service = await startKnowledgeService({ stateDir, repositories, token, port: 0, maxFiles: 1 });
32
- let baseUrl = `http://127.0.0.1:${service.address.port}`;
33
- let client = createKnowledgeServiceClient({ baseUrl, token });
34
- assert.equal((await fetch(baseUrl + '/healthz')).status, 200);
35
- assert.equal((await fetch(baseUrl + '/v1/repositories')).status, 401);
36
- await assert.rejects(client.submit({ repository: 'missing', operation: 'index' }), e => e.status === 404);
37
- await assert.rejects(client.submit({ repository: 'sample', operation: 'index', include: ['.'] }), e => e.status === 403);
38
- await assert.rejects(client.submit({ repository: 'sample', operation: 'index', include: ['../'] }), e => e.status === 400);
39
- await assert.rejects(client.submit({ repository: 'sample', operation: 'index', embed: true }), e => e.status === 403);
40
- const request = { repository: 'sample', operation: 'index' };
41
- const submitted = await client.submit(request, 'first');
42
- assert.equal((await client.submit(request, 'first')).id, submitted.id);
43
- await assert.rejects(client.submit({ ...request, scope: 'other' }, 'first'), e => e.status === 409);
44
- const first = await completed(client, submitted.id);
45
- assert.equal(first.result.files, 1); assert.equal(first.result.embedding_inputs, 0);
46
- assert.equal(first.result.published, true);
47
- const second = await completed(client, (await client.submit(request)).id);
48
- assert.equal(second.result.no_change, true); assert.equal(second.result.parsed_files, 0);
49
- assert.equal(second.result.generation_id, first.result.generation_id);
50
- fs.writeFileSync(path.join(root, 'src/unindexed.ts'), 'export const later = true;');
51
- const search = await completed(client, (await client.submit({ repository: 'sample', operation: 'search', query: 'add' })).id);
52
- assert.match(JSON.stringify(search.result), /src\/math.ts/);
53
- const narrow = await client.submit({ repository: 'sample', operation: 'search', query: 'add', include: ['src/unindexed.ts'] });
54
- for (let i = 0; i < 200; i++) {
55
- const job = await client.job(narrow.id);
56
- if (job.status === 'failed') { assert.match(job.error, /exceeds the requested scope/); break; }
57
- if (i === 199) assert.fail('Narrowed scope should fail without leaking broader snapshot contents.');
58
- await new Promise(resolve => setTimeout(resolve, 25));
59
- }
60
- fs.unlinkSync(path.join(root, 'src/unindexed.ts'));
61
- const plan = await completed(client, (await client.submit({ repository: 'sample', operation: 'plan', embed: true })).id);
62
- assert.ok(plan.result.embedding_inputs > 0); // Costs can be estimated without credentials.
63
- await service.close(); service = null;
64
- // Simulate an interrupted persisted job, as happens on SIGKILL/power loss.
65
- const db = new DatabaseSync(path.join(stateDir, 'jobs.sqlite'));
66
- db.prepare("UPDATE jobs SET status='running',result=NULL,attempts=1 WHERE id=?").run(second.id); db.close();
67
- service = await startKnowledgeService({ stateDir, repositories, token, port: 0 });
68
- baseUrl = `http://127.0.0.1:${service.address.port}`;
69
- client = createKnowledgeServiceClient({ baseUrl, token });
70
- assert.equal((await client.job(first.id)).result.generation_id, first.result.generation_id);
71
- const recovered = await completed(client, second.id);
72
- assert.equal(recovered.attempts, 2); assert.equal(recovered.result.no_change, true);
73
- assert.equal(fs.readFileSync(path.join(root, 'src/math.ts'), 'utf8'), before);
74
- assert.equal(fs.existsSync(path.join(root, '.agentsam')), false);
75
- } finally { await service?.close(); fs.rmSync(tmp, { recursive: true, force: true }); }
76
- });
77
-
78
- test('portable dockerize stages only SDK runtime, preserves identities/tokens, and generates persistent loopback config', async () => {
79
- const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-service-docker-'));
80
- const root = path.join(tmp, 'customer'); fs.mkdirSync(root);
81
- fs.writeFileSync(path.join(root, 'customer-secret.js'), 'must not enter build context');
82
- try {
83
- const options = { appSlug: 'knowledge-test', repositories: [`customer=${root}`], writeOnly: true };
84
- const result = await dockerize(tmp, 'knowledge_service', options);
85
- assert.match(result.plan.files.compose, /127\.0\.0\.1:8792:8792/);
86
- assert.match(result.plan.files.compose, /unless-stopped/);
87
- assert.match(result.plan.files.compose, /"read_only":true/);
88
- const context = path.join(result.written.versionDir, 'context');
89
- assert.equal(fs.existsSync(path.join(context, 'customer-secret.js')), false);
90
- assert.equal(fs.existsSync(path.join(context, 'src/knowledge/service/server.js')), true);
91
- assert.equal(fs.existsSync(path.join(context, 'src/knowledge/service/grpc-server.js')), true);
92
- assert.equal(fs.existsSync(path.join(context, 'src/rpc/generated/knowledge_pb.js')), true);
93
- assert.equal(fs.existsSync(path.join(context, 'src/rpc/generated/knowledge_grpc_pb.js')), true);
94
- assert.equal(fs.existsSync(path.join(context, 'src/rpc/generated/package.json')), true);
95
- assert.equal(fs.existsSync(path.join(context, 'src/errors/contract.js')), true);
96
- assert.equal(fs.existsSync(path.join(context, 'packages/agentsam-errors/src/index.js')), true);
97
- assert.equal(fs.existsSync(path.join(context, 'packages/agentsam-errors/package.json')), true);
98
- assert.equal(fs.existsSync(path.join(context, 'packages/agentsam-repository/src/merkle/hash.js')), true);
99
- assert.match(result.plan.files.dockerfile, /COPY packages \.\/packages/);
100
- assert.equal(fs.existsSync(path.join(context, 'package-lock.json')), true);
101
- const token = fs.readFileSync(result.tokenFile, 'utf8');
102
- assert.equal(fs.statSync(result.tokenFile).mode & 0o777, 0o600);
103
- assert.ok(!JSON.stringify(result.plan).includes(token.trim()));
104
- const registry = fs.readFileSync(path.join(result.configurationDir, 'repositories.json'), 'utf8');
105
- await dockerize(tmp, 'knowledge_service', options);
106
- assert.equal(fs.readFileSync(result.tokenFile, 'utf8'), token);
107
- assert.equal(fs.readFileSync(path.join(result.configurationDir, 'repositories.json'), 'utf8'), registry);
108
- await assert.rejects(dockerize(tmp, 'knowledge_service', { ...options, timeoutSeconds: 2 }), /persistent/);
109
- } finally { fs.rmSync(tmp, { recursive: true, force: true }); }
110
- });
@@ -1,206 +0,0 @@
1
- import test from 'node:test';
2
- import assert from 'node:assert/strict';
3
- import fs from 'node:fs';
4
- import os from 'node:os';
5
- import path from 'node:path';
6
- import { execFileSync } from 'node:child_process';
7
- import { fileURLToPath } from 'node:url';
8
- import { defaultConfig, initRepository, readConfig, scopeKey, embeddingProfileId, openSqliteStore, runIndex, planIndex, retrieve, createGeminiEmbedder, KnowledgeClient } from '../src/knowledge/index.js';
9
- import { inventory, parseSource } from '../src/knowledge/source.js';
10
-
11
- const cli = fileURLToPath(new URL('../src/cli.js', import.meta.url));
12
- const write = (root, name, content) => { fs.mkdirSync(path.dirname(path.join(root, name)), { recursive: true }); fs.writeFileSync(path.join(root, name), content); };
13
- async function fixture(t) {
14
- const root = fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-knowledge-'));
15
- execFileSync('git', ['init', '-q'], { cwd: root });
16
- write(root, 'src/a.ts', 'export function alpha() { return 1; }\nexport function beta() { return 2; }\n');
17
- write(root, 'other/b.js', 'export const gamma = 3;\n');
18
- const config = defaultConfig({ include: ['src'] });
19
- config.embedding = { provider: 'fixture', model: 'deterministic', revision: '1', dimensions: 3, parameters: {} };
20
- const store = await openSqliteStore(path.join(root, '.agentsam/knowledge/index.sqlite'));
21
- let calls = 0;
22
- const embedder = { async embed(text) { calls++; return [1, text.includes('alpha') ? 1 : 0, text.length / 100]; } };
23
- t.after(async () => { await store.close(); fs.rmSync(root, { recursive: true, force: true }); });
24
- return { root, config, store, embedder, count: () => calls };
25
- }
26
-
27
- test('AST parser observes real syntax, spans and unresolved edges; text is labeled separately', () => {
28
- const code = `import { read } from './io';\nexport class Reader { value() { return read(); } }\n`;
29
- const parsed = parseSource('reader.ts', code);
30
- assert.ok(parsed.symbols.some(s => s.name === 'Reader.value'));
31
- assert.ok(parsed.edges.some(e => e.kind === 'calls' && e.target === 'read' && e.resolved === false));
32
- assert.equal(parsed.chunks.map(c => c.content).join(''), code.trimEnd());
33
- assert.equal(parseSource('schema.sql', 'select 1;').parser, 'text:1');
34
- assert.throws(() => parseSource('bad.ts', 'export function {'), /bad.ts/);
35
- });
36
-
37
- test('Rust sources survive knowledge inventory and persist in the active SQLite generation', async t => {
38
- const root = fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-knowledge-rust-'));
39
- execFileSync('git', ['init', '-q'], { cwd: root });
40
- write(root, 'core/src/lib.rs', 'pub fn core_value() -> u32 { 7 }\n');
41
- write(root, 'worker/src/lib.rs', 'pub fn worker_value() -> u32 { 8 }\n');
42
- write(root, 'docs/MACHINE-PIPELINE.md', '# Machine pipeline\n');
43
- write(root, 'target/generated.rs', 'pub fn generated() {}\n');
44
-
45
- const config = defaultConfig({ include: ['core', 'worker', 'docs'], exclude: ['target'] });
46
- const store = await openSqliteStore(path.join(root, '.agentsam/knowledge/index.sqlite'));
47
- t.after(async () => {
48
- await store.close();
49
- fs.rmSync(root, { recursive: true, force: true });
50
- });
51
-
52
- const files = inventory(root, config.scope);
53
- assert.ok(files.includes('core/src/lib.rs'));
54
- assert.ok(files.includes('worker/src/lib.rs'));
55
- assert.ok(files.includes('docs/MACHINE-PIPELINE.md'));
56
- assert.equal(files.includes('target/generated.rs'), false);
57
-
58
- const result = await runIndex({ root, config, store, embed: false });
59
- assert.equal(result.published, true);
60
- assert.ok(result.changes.added.includes('core/src/lib.rs'));
61
- assert.ok(result.changes.added.includes('worker/src/lib.rs'));
62
-
63
- const generation = await store.getGeneration(scopeKey(config), result.generation_id);
64
- const persisted = generation.files.map(file => file.path);
65
- assert.ok(persisted.includes('core/src/lib.rs'));
66
- assert.ok(persisted.includes('worker/src/lib.rs'));
67
- assert.ok(persisted.includes('docs/MACHINE-PIPELINE.md'));
68
- assert.equal(generation.files.find(file => file.path === 'core/src/lib.rs')?.parser, 'text:1');
69
- });
70
-
71
- test('incremental indexing reuses unchanged functions, moves and deletions; old knowledge remains retrievable', async t => {
72
- const f = await fixture(t), args = { ...f, embed: true };
73
- const plan = await planIndex(args);
74
- assert.equal(f.count(), 0); assert.equal(await f.store.active(scopeKey(f.config)), null);
75
- assert.equal(plan.receipt.embedding_inputs, 2);
76
- const first = await runIndex(args);
77
- assert.equal(f.count(), 2);
78
- const again = await runIndex(args);
79
- assert.equal(again.published, false); assert.equal(again.parsed_files, 0); assert.equal(f.count(), 2);
80
- fs.renameSync(path.join(f.root, 'src/a.ts'), path.join(f.root, 'src/moved.ts'));
81
- const moved = await runIndex(args);
82
- assert.equal(moved.embedding_inputs, 0); assert.equal(moved.parsed_files, 0); assert.equal(f.count(), 2);
83
- write(f.root, 'src/moved.ts', 'export function alpha() { return 100; }\nexport function beta() { return 2; }\n');
84
- assert.equal((await runIndex(args)).embedding_inputs, 1); assert.equal(f.count(), 3);
85
- const old = await retrieve({ ...f, text: 'alpha', generationId: first.generation_id });
86
- assert.ok(old.hits.some(h => h.content.includes('return 1;') && h.path === 'src/a.ts' && h.stale));
87
- fs.unlinkSync(path.join(f.root, 'src/moved.ts'));
88
- assert.deepEqual((await runIndex(args)).changes.removed, ['src/moved.ts']);
89
- assert.equal((await retrieve({ ...f, text: 'alpha' })).hits.length, 0);
90
- assert.equal((await f.store.history(scopeKey(f.config))).length, 4);
91
- });
92
-
93
- test('scope and repository isolation; profile changes cannot silently reuse vectors', async t => {
94
- const f = await fixture(t);
95
- await runIndex({ ...f, embed: true });
96
- const other = structuredClone(f.config); other.scope = { name: 'other', include: ['other'], exclude: [] };
97
- await runIndex({ ...f, config: other, embed: true });
98
- assert.equal((await f.store.active(scopeKey(f.config))).files[0].path, 'src/a.ts');
99
- const changed = structuredClone(f.config); changed.embedding.revision = '2';
100
- assert.notEqual(embeddingProfileId(changed.embedding), embeddingProfileId(f.config.embedding));
101
- assert.equal((await planIndex({ ...f, config: changed, embed: true })).receipt.embedding_inputs, 2);
102
- await assert.rejects(retrieve({ ...f, config: changed, text: 'alpha', semantic: true }), /different embedding profile/);
103
- const foreign = structuredClone(f.config); foreign.repository_id = 'another-repo';
104
- assert.equal((await planIndex({ ...f, config: foreign, embed: true })).receipt.embedding_inputs, 2);
105
- const wider = structuredClone(f.config); wider.scope.include.push('other');
106
- assert.equal((await planIndex({ ...f, config: wider, embed: true })).receipt.files, 2);
107
- assert.equal((await planIndex({ ...f, config: wider, embed: true })).receipt.embedding_inputs, 0);
108
- });
109
-
110
- test('budgets, invalid vectors and concurrent changes preserve the active generation and useful cached work', async t => {
111
- const f = await fixture(t);
112
- const initial = await runIndex(f);
113
- await assert.rejects(runIndex({ ...f, embed: true, maxInputs: 0 }), /budget/);
114
- assert.equal(f.count(), 0);
115
- let requests = 0;
116
- await assert.rejects(runIndex({ ...f, embed: true, embedder: { async embed() { if (++requests === 2) throw new Error('503'); return [1, 0, 0]; } } }), /503/);
117
- assert.equal((await f.store.active(scopeKey(f.config))).id, initial.generation_id);
118
- assert.equal((await planIndex({ ...f, embed: true })).receipt.embedding_inputs, 1);
119
- await assert.rejects(runIndex({ ...f, embed: true, embedder: { async embed() { return [NaN]; } } }), /finite values/);
120
- assert.equal((await f.store.active(scopeKey(f.config))).id, initial.generation_id);
121
- const resumed = await runIndex({ ...f, embed: true }); assert.equal(resumed.embedding_inputs, 1);
122
- write(f.root, 'src/a.ts', 'export function alpha() { return 33; }');
123
- await assert.rejects(runIndex({ ...f, embed: true, embedder: { async embed() { write(f.root, 'src/a.ts', 'export function alpha() { return 44; }'); return [1, 0, 0]; } } }), /Repository changed/);
124
- assert.equal((await f.store.active(scopeKey(f.config))).id, resumed.generation_id);
125
- const current = await f.store.active(scopeKey(f.config));
126
- await assert.rejects(f.store.publish({ ...current, id: 'race' }, initial.generation_id), /concurrently/);
127
- assert.equal((await f.store.active(scopeKey(f.config))).id, resumed.generation_id);
128
- });
129
-
130
- test('source safety and setup preserve repository files; read-only plan creates no database', async t => {
131
- const root = fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-adopt-'));
132
- t.after(() => fs.rmSync(root, { recursive: true, force: true }));
133
- execFileSync('git', ['init', '-q'], { cwd: root });
134
- write(root, 'package.json', '{"name":"keep-this"}\n');
135
- write(root, '.env.js', 'SECRET'); write(root, 'src/real.ts', 'export const real = 1;');
136
- write(root, '.gitignore', 'ignored/\n'); write(root, 'ignored/hidden.ts', 'export const hidden = 1;');
137
- fs.symlinkSync(path.join(root, '.env.js'), path.join(root, 'src/link.ts'));
138
- const initial = fs.readFileSync(path.join(root, 'package.json'), 'utf8');
139
- const output = execFileSync(process.execPath, [cli, 'init', '--yes', '--include', 'src'], { cwd: root, encoding: 'utf8' });
140
- assert.equal(JSON.parse(output).storage, 'sqlite');
141
- assert.equal(fs.readFileSync(path.join(root, 'package.json'), 'utf8'), initial);
142
- assert.throws(() => initRepository(root), /EEXIST/);
143
- const plan = JSON.parse(execFileSync(process.execPath, [cli, 'index', 'plan'], { cwd: root, encoding: 'utf8' }));
144
- assert.equal(plan.files, 1); assert.deepEqual(plan.skipped, ['src/link.ts']);
145
- assert.equal(fs.existsSync(path.join(root, '.agentsam/knowledge/index.sqlite')), false);
146
- const all = readConfig(root); all.scope.include = ['.'];
147
- const paths = (await planIndex({ root, config: all })).files.map(f => f.path);
148
- assert.ok(!paths.includes('.env.js')); assert.ok(!paths.includes('ignored/hidden.ts'));
149
- });
150
-
151
- test('index and search derive safe local defaults when knowledge.json is absent', async t => {
152
- const root = fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-configless-'));
153
- t.after(() => fs.rmSync(root, { recursive: true, force: true }));
154
- execFileSync('git', ['init', '-q'], { cwd: root });
155
- execFileSync('git', ['remote', 'add', 'origin', 'git@github.com:ExampleOrg/ConfiglessRepo.git'], { cwd: root });
156
- write(root, 'src/real.ts', 'export function configlessSymbol() { return 7; }\n');
157
- const run = args => JSON.parse(execFileSync(process.execPath, [cli, ...args], { cwd: root, encoding: 'utf8' }));
158
- assert.equal(fs.existsSync(path.join(root, '.agentsam/knowledge.json')), false);
159
- const plan = run(['index', 'plan']);
160
- assert.ok(plan.files >= 1); assert.equal(plan.embedding_inputs, 0);
161
- assert.equal(fs.existsSync(path.join(root, '.agentsam/knowledge.json')), false);
162
- assert.equal(run(['index', 'run']).published, true);
163
- assert.equal(fs.existsSync(path.join(root, '.agentsam/knowledge.json')), false);
164
- assert.equal(run(['search', 'configlessSymbol']).hits[0].path, 'src/real.ts');
165
- });
166
-
167
- test('two independent repositories work through the same CLI and exported package', async t => {
168
- for (const name of ['customer-a', 'customer-b']) {
169
- const root = fs.mkdtempSync(path.join(os.tmpdir(), name));
170
- t.after(() => fs.rmSync(root, { recursive: true, force: true }));
171
- write(root, 'lib/tool.js', `export function ${name.replace('-', '_')}() { return 1; }`);
172
- const run = args => JSON.parse(execFileSync(process.execPath, [cli, ...args], { cwd: root, encoding: 'utf8' }));
173
- run(['init', '.', '--yes', '--include', 'lib']);
174
- assert.equal(run(['index', 'run']).published, true);
175
- assert.equal(run(['index', 'run']).no_change, true);
176
- assert.equal(run(['search', name.replace('-', '_')]).hits[0].path, 'lib/tool.js');
177
- }
178
- });
179
-
180
- test('Gemini sends task prefixes and configured dimensions, retries transient responses, and rejects unsupported profiles', async () => {
181
- const requests = [], sleeps = [];
182
- const adapter = createGeminiEmbedder({ apiKey: 'fixture-key', sleep: async ms => sleeps.push(ms), fetchImpl: async (_url, request) => {
183
- requests.push(JSON.parse(request.body));
184
- if (requests.length === 1) return new Response('', { status: 503 });
185
- return Response.json({ embedding: { values: Array(128).fill(0.1) } });
186
- } });
187
- const profile = defaultConfig({ dimensions: 128 }).embedding;
188
- await adapter.embed('function useful() {}', profile);
189
- await adapter.embed('find useful', profile, { kind: 'query' });
190
- assert.equal(requests[1].outputDimensionality, 128);
191
- assert.equal(requests[1].content.parts[0].text, 'title: none | text: function useful() {}');
192
- assert.equal(requests[2].content.parts[0].text, 'task: code retrieval | query: find useful');
193
- assert.equal(requests[1].taskType, undefined); assert.equal(sleeps.length, 1);
194
- await assert.rejects(adapter.embed('x', { ...profile, parameters: { taskType: 'CODE_RETRIEVAL' } }), /Unsupported/);
195
- let tries = 0;
196
- const denied = createGeminiEmbedder({ apiKey: 'fixture-key', fetchImpl: async () => { tries++; return new Response('', { status: 403 }); } });
197
- await assert.rejects(denied.embed('x', profile), /403/); assert.equal(tries, 1);
198
- });
199
-
200
- test('recovered KnowledgeClient contracts remain usable with injected transports', async () => {
201
- const operations = [];
202
- const client = new KnowledgeClient({ transport: { async request(op, payload) { operations.push([op, payload]); return { query_id: 'test', hits: [] }; } } });
203
- await client.retrieve({ text: 'find parser', workspace_id: 'customer' });
204
- await client.index('repository');
205
- assert.equal(operations[0][1].top_k, 8); assert.equal(operations[0][1].token_budget, 6000); assert.equal(operations[0][1].result_policy.max_items, 8); assert.equal(operations[1][0], 'knowledge.index');
206
- });
@@ -1,24 +0,0 @@
1
- import assert from 'node:assert/strict';
2
- import test from 'node:test';
3
- import { WebSocket } from 'ws';
4
-
5
- const liveUrl = String(process.env.AGENTSAM_LIVE_TERMINAL_WS_URL || '').trim();
6
-
7
- test('live terminal transport accepts a websocket connection', { skip: !liveUrl }, async (t) => {
8
- const ws = new WebSocket(liveUrl, {
9
- headers: process.env.AGENTSAM_LIVE_TERMINAL_AUTH
10
- ? { authorization: process.env.AGENTSAM_LIVE_TERMINAL_AUTH }
11
- : undefined,
12
- });
13
- t.after(() => { try { ws.close(); } catch {} });
14
-
15
- await Promise.race([
16
- new Promise((resolve, reject) => {
17
- ws.once('open', resolve);
18
- ws.once('error', reject);
19
- }),
20
- new Promise((_, reject) => setTimeout(() => reject(new Error('live terminal websocket open timed out')), 8000)),
21
- ]);
22
-
23
- assert.equal(ws.readyState, WebSocket.OPEN);
24
- });