@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,59 +0,0 @@
1
- import test from 'node:test';
2
- import assert from 'node:assert/strict';
3
-
4
- import { discoverOpenAIModels, discoverGeminiModels, discoverCursorModels } from '../../src/models/discovery.js';
5
- import { sanitizeInventoryForClient } from '../../src/models/inventory-core.js';
6
-
7
- function json(body) {
8
- return new Response(JSON.stringify(body), { status: 200, headers: { 'content-type': 'application/json' } });
9
- }
10
-
11
- function sanitized(models) {
12
- return sanitizeInventoryForClient({
13
- providers: [],
14
- discovery: {},
15
- availableModels: models,
16
- }).availableModels;
17
- }
18
-
19
- test('known OpenAI Responses reference is selectable while unknown live models stay visible', async () => {
20
- const result = await discoverOpenAIModels('user-key', async () => json({
21
- data: [{ id: 'gpt-5.6-sol' }, { id: 'brand-new-unclassified-model' }],
22
- }));
23
- const rows = sanitized(result.models);
24
- assert.equal(rows.length, 2);
25
- assert.equal(rows.find((row) => row.model_id === 'gpt-5.6-sol')?.chat_eligible, true);
26
- const unknown = rows.find((row) => row.model_id === 'brand-new-unclassified-model');
27
- assert.equal(unknown?.chat_eligible, false);
28
- assert.equal(unknown?.eligibility_reason, 'capability_unknown');
29
- });
30
-
31
- test('Cursor inventory is preserved but reports adapter unavailability', async () => {
32
- const result = await discoverCursorModels('cursor-key', async () => json({
33
- items: [{ id: 'gpt-5.6-sol', displayName: 'GPT-5.6 Sol', parameters: [] }],
34
- }));
35
- const [row] = sanitized(result.models);
36
- assert.equal(row.provider, 'cursor');
37
- assert.equal(row.model_id, 'gpt-5.6-sol');
38
- assert.equal(row.chat_eligible, false);
39
- assert.equal(row.eligibility_reason, 'provider_adapter_unavailable');
40
- });
41
-
42
- test('Gemini provider description keeps TTS visible outside the chat picker', async () => {
43
- const result = await discoverGeminiModels('gemini-key', async () => json({
44
- models: [{
45
- name: 'models/gemini-tts-fixture',
46
- baseModelId: 'gemini-tts-fixture',
47
- displayName: 'Voice fixture',
48
- description: 'Preview Text-to-Speech model',
49
- supportedGenerationMethods: ['generateContent'],
50
- inputTokenLimit: 8192,
51
- outputTokenLimit: 8192,
52
- }],
53
- }));
54
- const [row] = sanitized(result.models);
55
- assert.equal(row.model_id, 'gemini-tts-fixture');
56
- assert.equal(row.chat_eligible, false);
57
- assert.equal(row.eligibility_reason, 'specialized_output_model');
58
- assert.equal(row.eligibility_source, 'provider_api');
59
- });
@@ -1,125 +0,0 @@
1
- import { describe, it } 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 { buildInventory } from '../../src/indexing/ingest/inventory.js';
8
- import {
9
- extractStyleEvidence,
10
- finalizeStyleEvidence,
11
- mergeStyleEvidence,
12
- } from '../../src/indexing/ingest/style-evidence.js';
13
- import { inventory as knowledgeInventory } from '../../src/knowledge/source.js';
14
-
15
- function write(root, rel, text = '') {
16
- const abs = path.join(root, rel);
17
- fs.mkdirSync(path.dirname(abs), { recursive: true });
18
- fs.writeFileSync(abs, text);
19
- }
20
-
21
- describe('inventory classifies by evidence', () => {
22
- it('uses dominant evidence, root files, tooling LOC, and git ignore state', () => {
23
- const root = fs.mkdtempSync(path.join(os.tmpdir(), 'inv-evidence-'));
24
- try {
25
- execFileSync('git', ['init', '-q'], { cwd: root });
26
- write(root, '.gitignore', '.sites-runtime/\n');
27
-
28
- write(root, 'app/page.tsx', Array.from({ length: 30 }, (_, i) => `export const x${i} = ${i};`).join('\n'));
29
- write(root, 'db/schema.sql', 'create table t (id integer);\n');
30
- write(root, 'drizzle/meta/_journal.json', '{"version":"1"}\n');
31
- for (let i = 1; i <= 9; i += 1) write(root, `plans/p${i}.md`, `# plan ${i}\ntext\n`);
32
- write(root, 'plans/schema.sql', 'create table plan (id integer);\n');
33
- write(root, 'public/logo.png', 'x');
34
- write(root, 'scripts/harvest.py', Array.from({ length: 80 }, (_, i) => `x_${i} = ${i}`).join('\n'));
35
- write(root, '.sites-runtime/cache/blob.bin', 'x'.repeat(2048));
36
-
37
- write(root, 'package.json', '{"name":"fixture"}\n');
38
- write(root, 'wrangler.jsonc', '{}\n');
39
- write(root, 'drizzle.config.ts', 'export default {};\n');
40
- write(root, 'README.md', '# Fixture\n');
41
- write(root, 'entry.ts', 'export const root = true;\n');
42
- write(root, 'package-lock.json', '{"lockfileVersion":3}\n');
43
- write(root, '.env', 'SECRET=do-not-index\n');
44
- write(root, '.dev.vars', 'TOKEN=do-not-index\n');
45
- write(root, 'tls.pem', 'private material\n');
46
-
47
- execFileSync('git', ['add', '.'], { cwd: root });
48
-
49
- const inventory = buildInventory({ root });
50
- const categories = inventory.categories;
51
-
52
- assert.ok(categories.source.includes('app'));
53
- assert.ok(categories.source.includes('db'));
54
- assert.ok(categories.docs.includes('plans'), '9 markdown + 1 SQL is dominantly docs');
55
- assert.ok(categories.data.includes('drizzle'), 'JSON-only drizzle metadata is data');
56
- assert.ok(categories.assets.includes('public'));
57
- assert.ok(categories.operational.includes('.sites-runtime'));
58
- assert.ok(categories.tooling.includes('scripts'));
59
- assert.deepEqual(categories.unknown, []);
60
-
61
- assert.ok(inventory.suggested.include.includes('scripts'), 'tracked top-2 language tooling is promoted');
62
- assert.ok(inventory.top_level_details.scripts.loc >= 80);
63
- assert.equal(inventory.top_level_details.scripts.dominant_language, 'Python');
64
-
65
- assert.ok(inventory.root_files.manifest.includes('package.json'));
66
- assert.ok(inventory.root_files.manifest.includes('wrangler.jsonc'));
67
- assert.ok(inventory.root_files.manifest.includes('drizzle.config.ts'));
68
- assert.ok(inventory.root_files.docs.includes('README.md'));
69
- assert.ok(inventory.root_files.source.includes('entry.ts'));
70
- assert.ok(inventory.root_files.lockfile.includes('package-lock.json'));
71
- assert.ok(inventory.root_files.secret.includes('.env'));
72
- assert.ok(inventory.root_files.secret.includes('.dev.vars'));
73
- assert.ok(inventory.root_files.secret.includes('tls.pem'));
74
-
75
- for (const wanted of ['package.json', 'wrangler.jsonc', 'drizzle.config.ts', 'README.md', 'entry.ts']) {
76
- assert.ok(inventory.suggested.include_files.includes(wanted), wanted);
77
- }
78
- for (const forbidden of ['package-lock.json', '.env', '.dev.vars', 'tls.pem']) {
79
- assert.ok(!inventory.suggested.include_files.includes(forbidden), forbidden);
80
- }
81
-
82
- const files = knowledgeInventory(root, { include: ['.'], exclude: [] });
83
- assert.ok(files.includes('entry.ts'));
84
- assert.ok(!files.includes('.env'));
85
- assert.ok(!files.includes('.dev.vars'));
86
- assert.ok(!files.includes('tls.pem'));
87
- assert.ok(!files.includes('package-lock.json'));
88
- } finally {
89
- fs.rmSync(root, { recursive: true, force: true });
90
- }
91
- });
92
-
93
- it('detects coherent theme signatures from markup and CSS evidence', () => {
94
- const evidence = extractStyleEvidence(`
95
- <html data-theme-preset="fuel-free-time" data-header-preset="adaptive-bar">
96
- <link rel="stylesheet" href="/css/heuristic-theme.css">
97
- <body>
98
- <header class="fnf-header fnf-header--adaptive-bar">
99
- <a class="fnf-logo"></a>
100
- <nav class="fnf-primary"></nav>
101
- </header>
102
- </body>
103
- </html>
104
- <style>
105
- :root { --fnf-accent: #ff4d00; --fnf-logo-height: 58px; }
106
- .fnf-header { color: var(--fnf-accent); }
107
- .fnf-logo { height: var(--fnf-logo-height); }
108
- </style>
109
- `);
110
-
111
- assert.equal(evidence.theme_presets['fuel-free-time'], 1);
112
- assert.equal(evidence.header_presets['adaptive-bar'], 1);
113
- assert.equal(evidence.stylesheets['/css/heuristic-theme.css'], 1);
114
- const fnf = evidence.namespaces.find((row) => row.prefix === 'fnf');
115
- assert.ok(fnf);
116
- assert.ok(fnf.signal_kinds >= 2);
117
- assert.ok(fnf.signals.class_tokens >= 3);
118
- assert.ok(fnf.signals.custom_properties >= 2);
119
-
120
- const final = finalizeStyleEvidence(mergeStyleEvidence(null, evidence));
121
- const finalFnf = final.namespaces.find((row) => row.prefix === 'fnf');
122
- assert.equal(final.theme_candidate, true);
123
- assert.equal(finalFnf?.candidate, true);
124
- });
125
- });
@@ -1,112 +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 { fileURLToPath } from 'node:url';
7
- import { defaultConfig } from '../../src/knowledge/config.js';
8
- import { createKnowledgeJobEngine } from '../../src/knowledge/service/job-engine.js';
9
- import { startKnowledgeHttpServer } from '../../src/knowledge/service/server.js';
10
- import { startKnowledgeGrpcServer } from '../../src/knowledge/service/grpc-server.js';
11
- import { createKnowledgeServiceClient } from '../../src/knowledge/service/client.js';
12
- import { createKnowledgeGrpcClient } from '../../src/knowledge/service/grpc-client.js';
13
- import { grpc } from '../../src/knowledge/service/grpc-codec.js';
14
-
15
- const fixtureWorker = fileURLToPath(new URL('../fixtures/knowledge-rpc-worker.mjs', import.meta.url));
16
- const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
17
-
18
- async function waitFor(client, id, wanted = new Set(['completed', 'failed'])) {
19
- for (let i = 0; i < 200; i++) {
20
- const job = await client.job(id);
21
- if (wanted.has(job.status)) return job;
22
- await sleep(10);
23
- }
24
- throw new Error(`Job ${id} did not reach ${[...wanted].join('/')}.`);
25
- }
26
-
27
- async function collect(stream) {
28
- const events = [];
29
- for await (const event of stream) events.push(event);
30
- return events;
31
- }
32
-
33
- test('knowledge HTTP and gRPC adapters share auth, validation, idempotency, lifecycle, cancellation, and durable jobs', async t => {
34
- const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-rpc-'));
35
- t.after(() => fs.rmSync(tmp, { recursive: true, force: true }));
36
- const root = path.join(tmp, 'repo');
37
- const stateDir = path.join(tmp, 'state');
38
- fs.mkdirSync(path.join(root, 'src'), { recursive: true });
39
- fs.writeFileSync(path.join(root, 'src', 'sample.js'), 'export const sample = true;\n');
40
- const config = defaultConfig({ include: ['src'] });
41
- const repositories = { sample: { root, config } };
42
- const token = 'r'.repeat(64);
43
- const engine = createKnowledgeJobEngine({ stateDir, repositories, workerPath: fixtureWorker, jobTimeoutMs: 2_000 });
44
- const http = await startKnowledgeHttpServer({ engine, token, port: 0 });
45
- const rpcServer = await startKnowledgeGrpcServer({ engine, token, port: 0 });
46
- const httpClient = createKnowledgeServiceClient({ baseUrl: `http://127.0.0.1:${http.address.port}`, token });
47
- const rpc = createKnowledgeGrpcClient({ target: rpcServer.target, token });
48
- const unauthorized = createKnowledgeGrpcClient({ target: rpcServer.target, token: 'x'.repeat(64) });
49
- t.after(async () => {
50
- unauthorized.close();
51
- rpc.close();
52
- await rpcServer.close();
53
- await http.close();
54
- await engine.close();
55
- });
56
-
57
- const repos = await rpc.repositories();
58
- assert.deepEqual(repos.repositories, ['sample']);
59
- assert.equal(repos.repository_details[0].repository_id, config.repository_id);
60
- assert.equal(repos.embeddings_enabled, false);
61
- await assert.rejects(unauthorized.repositories(), error => error.status === 401 && error.grpcCode === grpc.status.UNAUTHENTICATED);
62
- await assert.rejects(
63
- rpc.submit({ repository: 'sample', operation: 'bogus' }),
64
- error => error.status === 400 && error.grpcCode === grpc.status.INVALID_ARGUMENT,
65
- );
66
-
67
- const request = { repository: 'sample', operation: 'index', generation_id: 'equivalent' };
68
- const fromHttp = await httpClient.submit(request, 'cross-transport');
69
- const fromGrpc = await rpc.submit(request, 'cross-transport');
70
- assert.equal(fromGrpc.id, fromHttp.id);
71
- await assert.rejects(
72
- rpc.submit({ ...request, scope: 'different' }, 'cross-transport'),
73
- error => error.status === 409 && error.grpcCode === grpc.status.ABORTED,
74
- );
75
- const completed = await waitFor(rpc, fromGrpc.id);
76
- assert.equal(completed.status, 'completed');
77
- assert.equal((await httpClient.job(fromGrpc.id)).result.repository_id, completed.result.repository_id);
78
-
79
- const blocker = await rpc.submit({ repository: 'sample', operation: 'index', generation_id: 'slow' }, 'blocker');
80
- await waitFor(rpc, blocker.id, new Set(['running']));
81
- const watched = await rpc.submit({ repository: 'sample', operation: 'index', generation_id: 'watch' }, 'watched');
82
- const lifecycle = await collect(rpc.watch(watched.id));
83
- assert.deepEqual(lifecycle.map(event => event.job.status), ['queued', 'running', 'completed']);
84
- assert.deepEqual(lifecycle.map(event => event.sequence), [1, 2, 3]);
85
-
86
- const failed = await rpc.submit({ repository: 'sample', operation: 'index', generation_id: 'fail' }, 'failed');
87
- const failureEvents = await collect(rpc.watch(failed.id));
88
- assert.equal(failureEvents.at(-1).job.status, 'failed');
89
- assert.match(failureEvents.at(-1).job.error, /fixture knowledge failure/);
90
-
91
- const cancellable = await rpc.submit({ repository: 'sample', operation: 'index', generation_id: 'slow' }, 'cancel-watch');
92
- const controller = new AbortController();
93
- const iterator = rpc.watch(cancellable.id, { signal: controller.signal })[Symbol.asyncIterator]();
94
- const first = await iterator.next();
95
- assert.equal(first.done, false);
96
- controller.abort();
97
- const afterAbort = await iterator.next();
98
- assert.equal(afterAbort.done, true);
99
- assert.equal((await waitFor(rpc, cancellable.id)).status, 'completed');
100
-
101
- const deadlineJob = await rpc.submit({ repository: 'sample', operation: 'index', generation_id: 'slow' }, 'deadline-watch');
102
- let deadlineError = null;
103
- try {
104
- await collect(rpc.watch(deadlineJob.id, { timeoutMs: 15 }));
105
- } catch (error) {
106
- deadlineError = error;
107
- }
108
- assert.ok(deadlineError);
109
- assert.equal(deadlineError.grpcCode, grpc.status.DEADLINE_EXCEEDED);
110
- assert.equal(deadlineError.status, 504);
111
- assert.equal((await waitFor(rpc, deadlineJob.id)).status, 'completed');
112
- });
@@ -1,113 +0,0 @@
1
- import assert from 'node:assert/strict';
2
- import fs from 'node:fs';
3
- import path from 'node:path';
4
- import { describe, it, before, after } from 'node:test';
5
- import {
6
- createLocalFilesystem,
7
- createTempWorkspaceRoot,
8
- LOCAL_FS_ENGINE,
9
- } from '../../src/local-fs/index.js';
10
- import { resolveContainedPath } from '../../src/local-fs/paths.js';
11
-
12
- describe('local-fs path containment', () => {
13
- /** @type {string} */
14
- let root;
15
- before(() => {
16
- root = createTempWorkspaceRoot();
17
- fs.writeFileSync(path.join(root, 'ok.txt'), 'hello\n');
18
- fs.mkdirSync(path.join(root, 'sub'));
19
- });
20
- after(() => {
21
- fs.rmSync(root, { recursive: true, force: true });
22
- });
23
-
24
- it('resolves relative paths inside root', () => {
25
- const r = resolveContainedPath(root, 'ok.txt');
26
- assert.equal(r.ok, true);
27
- assert.equal(r.rel, 'ok.txt');
28
- });
29
-
30
- it('rejects traversal', () => {
31
- const r = resolveContainedPath(root, '../outside.txt');
32
- assert.equal(r.ok, false);
33
- assert.equal(r.code, 'path_escape');
34
- });
35
-
36
- it('rejects NUL', () => {
37
- const r = resolveContainedPath(root, 'a\0b.txt');
38
- assert.equal(r.ok, false);
39
- assert.equal(r.code, 'invalid_path');
40
- });
41
-
42
- it('rejects symlink escape when possible', () => {
43
- const outside = createTempWorkspaceRoot('agentsam-fs-out-');
44
- try {
45
- fs.writeFileSync(path.join(outside, 'secret.txt'), 'nope');
46
- const link = path.join(root, 'escape-link');
47
- try {
48
- fs.symlinkSync(path.join(outside, 'secret.txt'), link);
49
- } catch {
50
- // Windows may lack symlink privilege — skip
51
- return;
52
- }
53
- const r = resolveContainedPath(root, 'escape-link');
54
- assert.equal(r.ok, false);
55
- assert.equal(r.code, 'path_escape');
56
- } finally {
57
- fs.rmSync(outside, { recursive: true, force: true });
58
- }
59
- });
60
- });
61
-
62
- describe('local-fs operations', () => {
63
- /** @type {string} */
64
- let root;
65
- /** @type {ReturnType<typeof createLocalFilesystem>} */
66
- let fsApi;
67
-
68
- before(() => {
69
- root = createTempWorkspaceRoot();
70
- fsApi = createLocalFilesystem(root);
71
- });
72
- after(() => {
73
- fs.rmSync(root, { recursive: true, force: true });
74
- });
75
-
76
- it('create / read / write with version conflict detection', () => {
77
- assert.equal(fsApi.engine, LOCAL_FS_ENGINE);
78
- const created = fsApi.create('README.md', '# one\n');
79
- assert.equal(created.ok, true);
80
- const v1 = created.version;
81
-
82
- const read1 = fsApi.read('README.md');
83
- assert.equal(read1.ok, true);
84
- assert.equal(read1.content, '# one\n');
85
- assert.equal(read1.version, v1);
86
-
87
- const conflict = fsApi.write('README.md', '# stale\n', { expectedVersion: 'sha256:dead' });
88
- assert.equal(conflict.ok, false);
89
- assert.equal(conflict.code, 'version_conflict');
90
-
91
- const wrote = fsApi.write('README.md', '# two\n', { expectedVersion: v1 });
92
- assert.equal(wrote.ok, true);
93
- assert.notEqual(wrote.version, v1);
94
- assert.equal(fs.readFileSync(path.join(root, 'README.md'), 'utf8'), '# two\n');
95
- });
96
-
97
- it('list / rename / remove', () => {
98
- fsApi.create('a.txt', 'a');
99
- fsApi.mkdir('dir');
100
- const listed = fsApi.list('.');
101
- assert.equal(listed.ok, true);
102
- assert.ok(listed.entries.some((e) => e.path === 'a.txt'));
103
-
104
- const renamed = fsApi.rename('a.txt', 'b.txt');
105
- assert.equal(renamed.ok, true);
106
- assert.ok(fs.existsSync(path.join(root, 'b.txt')));
107
- assert.equal(fs.existsSync(path.join(root, 'a.txt')), false);
108
-
109
- const removed = fsApi.remove('b.txt');
110
- assert.equal(removed.ok, true);
111
- assert.equal(fs.existsSync(path.join(root, 'b.txt')), false);
112
- });
113
- });
@@ -1,65 +0,0 @@
1
- import test from 'node:test';
2
- import assert from 'node:assert/strict';
3
- import { executeLocalProviderBridge } from '../../packages/agentsam-desktop-shell/scripts/local-provider-bridge.mjs';
4
-
5
- const CANARY = 'sk-test-CANARY-123456';
6
-
7
- function json(body, status = 200) {
8
- return new Response(JSON.stringify(body), { status, headers: { 'content-type': 'application/json' } });
9
- }
10
-
11
- function openAiFetch(url, init = {}) {
12
- assert.equal(init.headers?.authorization, `Bearer ${CANARY}`);
13
- if (String(url).endsWith('/v1/models')) {
14
- return Promise.resolve(json({ data: [{ id: 'gpt-5.6-sol', object: 'model' }] }));
15
- }
16
- if (String(url).endsWith('/v1/responses')) {
17
- return Promise.resolve(json({
18
- id: 'resp_local_fixture',
19
- status: 'completed',
20
- output_text: 'offline bridge works',
21
- output: [],
22
- usage: { input_tokens: 3, output_tokens: 4 },
23
- }));
24
- }
25
- throw new Error(`unexpected_url:${url}`);
26
- }
27
-
28
- test('device OpenAI credential discovers live inventory without leaking the key', async () => {
29
- const result = await executeLocalProviderBridge({
30
- operation: 'inventory',
31
- credentials: { openai: CANARY },
32
- }, { fetchImpl: openAiFetch });
33
- assert.equal(result.ok, true);
34
- assert.equal(result.credential_plane, 'device_keychain');
35
- assert.equal(result.providers.find((row) => row.id === 'openai')?.configured, true);
36
- assert.equal(result.availableModels.some((row) => row.provider === 'openai' && row.model_id === 'gpt-5.6-sol'), true);
37
- assert.equal(JSON.stringify(result).includes(CANARY), false);
38
- });
39
-
40
- test('device OpenAI credential chats through canonical Responses adapter without leaking the key', async () => {
41
- const result = await executeLocalProviderBridge({
42
- operation: 'chat',
43
- provider: 'openai',
44
- model_id: 'gpt-5.6-sol',
45
- messages: [{ role: 'user', content: 'hello' }],
46
- credentials: { openai: CANARY },
47
- }, { fetchImpl: openAiFetch });
48
- assert.deepEqual(result, {
49
- ok: true,
50
- provider: 'openai',
51
- model_id: 'gpt-5.6-sol',
52
- text: 'offline bridge works',
53
- });
54
- assert.equal(JSON.stringify(result).includes(CANARY), false);
55
- });
56
-
57
- test('provider rejection is sanitized and never echoes credential material', async () => {
58
- const result = await executeLocalProviderBridge({
59
- operation: 'inventory',
60
- credentials: { openai: CANARY },
61
- }, {
62
- fetchImpl: async () => json({ error: { message: `bad ${CANARY}` } }, 401),
63
- });
64
- assert.equal(JSON.stringify(result).includes(CANARY), false);
65
- });
@@ -1,40 +0,0 @@
1
- import test from 'node:test';
2
- import assert from 'node:assert/strict';
3
- import { readFileSync } from 'node:fs';
4
-
5
- function read(path) {
6
- return readFileSync(new URL(`../../${path}`, import.meta.url), 'utf8');
7
- }
8
-
9
- const settingsPage = read('apps/local-studio/frontend/src/components/settings/LocalStudioSettingsPage.tsx');
10
- const settingsHost = read('apps/local-studio/frontend/src/components/settings/localStudioSettingsHost.ts');
11
- const shell = read('apps/local-studio/frontend/agentsam/AgentSamShell.tsx');
12
- const keysPage = read('apps/local-studio/frontend/src/components/settings/LiveKeysSettingsPage.tsx');
13
- const apiKeys = read('apps/local-studio/frontend/src/components/settings/ApiKeysTable.tsx');
14
- const settingsFrontend = read('packages/agentsam-settings/src/frontend/index.tsx');
15
-
16
- test('production Settings never mounts fixture data', () => {
17
- assert.doesNotMatch(settingsPage, /createFixtureSettingsHost|getSettingsFixture|SettingsFixtureName/);
18
- assert.doesNotMatch(settingsHost, /demo-app|Demo Org|health:\s*["']healthy["']/i);
19
- assert.match(settingsHost, /repositoryLabel:\s*["']Not connected["']/);
20
- assert.match(settingsHost, /browser:\s*["']Not checked["']/);
21
- assert.match(settingsHost, /health:\s*["']unknown["']/);
22
- assert.doesNotMatch(settingsFrontend, /demo-app|Demo Org/);
23
- });
24
-
25
- test('Settings route suppresses the outer application sidenav', () => {
26
- assert.match(shell, /const isSettings = pathname === ['"]\/settings['"] \|\| pathname\.startsWith\(['"]\/settings\/['"]\)/);
27
- assert.match(shell, /!isSettings \? <Nav\.Sidenav \/> : null/);
28
- });
29
-
30
- test('Keys page has a visible explicit AgentSam key trigger', () => {
31
- assert.match(keysPage, /variant="secondary"/);
32
- assert.match(keysPage, /Create AgentSam key/);
33
- });
34
-
35
- test('account provider rows show live discovery trust status', () => {
36
- assert.match(apiKeys, /accountInventoryRequest/);
37
- assert.match(apiKeys, /Connected · \$\{count\} model/);
38
- assert.match(apiKeys, /rejected this key/);
39
- assert.match(apiKeys, /Not selected/);
40
- });
@@ -1,26 +0,0 @@
1
- import { test } from 'node:test';
2
- import assert from 'node:assert/strict';
3
- import fs from 'node:fs';
4
- import path from 'node:path';
5
- import { fileURLToPath } from 'node:url';
6
-
7
- const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');
8
-
9
- test('every workspace and link path in package-lock.json exists on disk', () => {
10
- const lock = JSON.parse(fs.readFileSync(path.join(root, 'package-lock.json'), 'utf8'));
11
- const paths = new Set();
12
- for (const [key, value] of Object.entries(lock.packages)) {
13
- if (key && !key.includes('node_modules/')) paths.add(key);
14
- if (value.link && value.resolved) paths.add(value.resolved);
15
- }
16
- const missing = [...paths].filter((p) => !fs.existsSync(path.join(root, p)));
17
- assert.deepEqual(missing, []);
18
- });
19
-
20
- test('package.json bin map matches package-lock packages[""].bin', () => {
21
- const pkg = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8'));
22
- const lock = JSON.parse(fs.readFileSync(path.join(root, 'package-lock.json'), 'utf8'));
23
- const pkgBin = pkg.bin || {};
24
- const lockBin = (lock.packages && lock.packages[''] && lock.packages[''].bin) || {};
25
- assert.deepEqual(lockBin, pkgBin);
26
- });
@@ -1,61 +0,0 @@
1
- import assert from 'node:assert/strict';
2
- import { test } from 'node:test';
3
- import fs from 'node:fs/promises';
4
- import os from 'node:os';
5
- import path from 'node:path';
6
- import { spawnSync } from 'node:child_process';
7
- import { fileURLToPath } from 'node:url';
8
-
9
- const cli = fileURLToPath(new URL('../../src/cli.js', import.meta.url));
10
-
11
- async function fixture(t) {
12
- const root = await fs.mkdtemp(path.join(os.tmpdir(), 'agentsam-merkle-cli-test-'));
13
- t.after(() => fs.rm(root, { recursive: true, force: true }));
14
- return root;
15
- }
16
-
17
- async function write(root, name, content = name) {
18
- await fs.mkdir(path.dirname(path.join(root, name)), { recursive: true });
19
- await fs.writeFile(path.join(root, name), content);
20
- }
21
-
22
- function run(args, cwd) {
23
- return spawnSync(process.execPath, [cli, 'merkle', ...args], {
24
- cwd,
25
- encoding: 'utf8',
26
- timeout: 15000,
27
- });
28
- }
29
-
30
- test('CLI snapshot/verify/diff supports JSON, moved roots, and distinct mismatch/error exit codes', async (t) => {
31
- const root = await fixture(t), moved = await fixture(t);
32
- await write(root, 'a.txt', 'hello');
33
- await write(moved, 'a.txt', 'hello');
34
-
35
- const saved = run(['snapshot', '.', '--json'], root);
36
- assert.equal(saved.status, 0, saved.stderr);
37
- const manifest = JSON.parse(saved.stdout);
38
- assert.ok(manifest.output.endsWith('merkle.json'));
39
-
40
- const matching = run(['verify', manifest.output, '--root', moved, '--json'], root);
41
- assert.equal(matching.status, 0, matching.stderr);
42
- assert.equal(JSON.parse(matching.stdout).equal, true);
43
-
44
- await write(moved, 'a.txt', 'changed');
45
- await write(moved, 'b.txt', 'new');
46
- const changed = run(['verify', manifest.output, '--root', moved, '--json'], root);
47
- assert.equal(changed.status, 1, changed.stderr);
48
- assert.deepEqual(JSON.parse(changed.stdout).stats, { unchanged: 0, modified: 1, added: 1, removed: 0 });
49
-
50
- const diff = run(['diff', root, moved, '--json'], root);
51
- assert.equal(diff.status, 1, diff.stderr);
52
-
53
- const invalid = run(['root', '.', '--typo', '--json'], root);
54
- assert.equal(invalid.status, 2);
55
- assert.equal(invalid.stdout, '');
56
- assert.match(JSON.parse(invalid.stderr).error, /Unknown option/);
57
-
58
- const piped = run(['inspect', '.', '--tui'], root);
59
- assert.equal(piped.status, 0, piped.stderr);
60
- assert.ok(!piped.stdout.includes('\x1b'));
61
- });
@@ -1,48 +0,0 @@
1
- import assert from 'node:assert/strict';
2
- import fs from 'node:fs/promises';
3
- import os from 'node:os';
4
- import path from 'node:path';
5
- import { execFileSync } from 'node:child_process';
6
- import { test } from 'node:test';
7
- import { resolveMerklePersistenceIdentity } from '../../src/commands/merkle-persist.js';
8
-
9
- async function gitFixture(t, remote = null) {
10
- const root = await fs.mkdtemp(path.join(os.tmpdir(), 'agentsam-merkle-identity-'));
11
- t.after(() => fs.rm(root, { recursive: true, force: true }));
12
- execFileSync('git', ['init', '-q', root]);
13
- if (remote) execFileSync('git', ['-C', root, 'remote', 'add', 'origin', remote]);
14
- return root;
15
- }
16
-
17
- test('Merkle persistence identity uses authenticated session + Git provider identity', async (t) => {
18
- const root = await gitFixture(t, 'git@github.com:SamPrimeaux/agentsam-sdk.git');
19
- const identity = resolveMerklePersistenceIdentity(root, {
20
- session: { account_id: 'au_test' },
21
- projectConfig: { repository: { id: 'local:should-not-win' } },
22
- });
23
- assert.deepEqual(identity, {
24
- accountId: 'au_test',
25
- repositoryId: 'github:samprimeaux/agentsam-sdk',
26
- repositoryIdentitySource: 'git',
27
- });
28
- });
29
-
30
- test('local repositories fall back to committed project identity', async (t) => {
31
- const root = await gitFixture(t);
32
- const identity = resolveMerklePersistenceIdentity(root, {
33
- session: { account_id: 'au_test' },
34
- projectConfig: { repository: { id: 'local:fixture-repository' } },
35
- });
36
- assert.equal(identity.repositoryId, 'local:fixture-repository');
37
- assert.equal(identity.repositoryIdentitySource, 'project_manifest');
38
- });
39
-
40
- test('Merkle persistence refuses unauthenticated ownership', async (t) => {
41
- const root = await gitFixture(t, 'https://github.com/SamPrimeaux/agentsam-sdk.git');
42
- assert.throws(() => resolveMerklePersistenceIdentity(root, { session: null }), /agentsam_login_required_for_merkle_persistence/);
43
- });
44
-
45
- test('Merkle persistence CLI has no account/repository ownership env shortcuts', async () => {
46
- const source = await fs.readFile(new URL('../../src/commands/merkle-persist.js', import.meta.url), 'utf8');
47
- assert.doesNotMatch(source, /AGENTSAM_ACCOUNT_ID|AGENTSAM_REPOSITORY_ID|--account-id|--repository-id/);
48
- });