@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,184 +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 {
7
- openScadCompile,
8
- validateOpenScadSource,
9
- freeCadBuild,
10
- freeCadInspect,
11
- blenderBuild,
12
- blenderInspect,
13
- blenderExport,
14
- discoverAllCadTools,
15
- } from '../../src/lib/cad/index.js';
16
-
17
- // These tests exercise real local CAD/3D engine binaries (OpenSCAD, FreeCAD,
18
- // Blender). They are not installed on the generic CI runner and are heavy
19
- // desktop applications — deliberately not force-installed there (matches
20
- // the local-first storage/tooling stance elsewhere in this repo). Each
21
- // execution test below skips itself with a clear reason when its engine
22
- // isn't present, rather than failing CI for an environment gap. On a
23
- // machine that has the tool installed (e.g. local dev), the test runs for
24
- // real with the full original assertions, unchanged.
25
- const cadReport = await discoverAllCadTools();
26
- const toolAvailable = (name) => cadReport.tools.find((t) => t.tool === name)?.available === true;
27
-
28
- test('CAD Tool Discovery identifies local engines on the machine (schema is always validated; per-tool availability is informational)', async () => {
29
- const report = await discoverAllCadTools();
30
- assert.equal(report.schema_version, 1);
31
- assert.ok(report.total_tools >= 5);
32
-
33
- for (const toolName of ['openscad', 'freecad', 'blender']) {
34
- const tool = report.tools.find((t) => t.tool === toolName);
35
- assert.ok(tool, `${toolName} entry missing from discovery report`);
36
- assert.equal(typeof tool.available, 'boolean');
37
- if (tool.available) {
38
- assert.ok(tool.binary, `${toolName} reported available but has no binary path`);
39
- assert.ok(tool.version, `${toolName} reported available but has no version`);
40
- } else {
41
- assert.ok(tool.install_guidance, `${toolName} reported unavailable but has no install_guidance`);
42
- }
43
- }
44
- });
45
-
46
- test('OpenSCAD execution rejects security-violating scripts', async () => {
47
- assert.throws(
48
- () => validateOpenScadSource('use <child_process>;'),
49
- /Security Violation/
50
- );
51
- assert.throws(
52
- () => validateOpenScadSource('exec("cat /etc/passwd");'),
53
- /Security Violation/
54
- );
55
- assert.throws(
56
- () => validateOpenScadSource('import("../../secret.scad");'),
57
- /Security Violation/
58
- );
59
- });
60
-
61
- test('OpenSCAD real compilation produces watertight geometry and returns typed receipt', { skip: !toolAvailable('openscad') && 'openscad binary not available on this machine' }, async (t) => {
62
- const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-openscad-test-'));
63
- t.after(() => fs.rmSync(tmpDir, { recursive: true, force: true }));
64
-
65
- const source = `
66
- difference() {
67
- cube([width, depth, height], center=true);
68
- cylinder(h=height + 2, r=holeRadius, center=true, $fn=24);
69
- }
70
- `;
71
-
72
- const result = await openScadCompile({
73
- source,
74
- outputFormat: 'stl',
75
- parameters: {
76
- width: 30,
77
- depth: 20,
78
- height: 10,
79
- holeRadius: 4,
80
- },
81
- filename: 'flange.stl',
82
- });
83
-
84
- assert.equal(result.success, true);
85
- assert.equal(result.engine, 'openscad-native');
86
- assert.equal(result.filename, 'flange.stl');
87
- assert.equal(result.outputFormat, 'stl');
88
- assert.equal(result.mimeType, 'model/stl');
89
- assert.ok(result.sizeBytes > 0);
90
- assert.ok(result.artifactContent.includes('solid OpenSCAD_Model'));
91
- assert.ok(result.artifactContent.includes('facet normal'));
92
- assert.ok(result.artifactContent.includes('outer loop'));
93
- assert.ok(result.logs.some(l => l.includes('[KERNEL] OpenSCAD Native Compiler')));
94
- });
95
-
96
- test('FreeCAD solid kernel executes precision B-Rep operations and exports valid ISO STEP', { skip: !toolAvailable('freecad') && 'freecad binary not available on this machine' }, async (t) => {
97
- const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-freecad-test-'));
98
- t.after(() => fs.rmSync(tmpDir, { recursive: true, force: true }));
99
-
100
- const stepOutput = path.join(tmpDir, 'bracket.step');
101
-
102
- const recipe = {
103
- operations: [
104
- { op: 'box', name: 'main_block', length: 40.0, width: 25.0, height: 12.0 },
105
- { op: 'cylinder', name: 'bore', radius: 5.0, height: 14.0, translate: [20.0, 12.5, -1.0] },
106
- { op: 'cut', base: 'main_block', tool: 'bore' },
107
- ],
108
- };
109
-
110
- const buildResult = await freeCadBuild({
111
- recipe,
112
- output: stepOutput,
113
- format: 'step',
114
- });
115
-
116
- assert.equal(buildResult.ok, true);
117
- assert.equal(buildResult.capability, 'freecad.build');
118
- assert.equal(buildResult.format, 'step');
119
- assert.ok(buildResult.sizeBytes > 0);
120
- assert.ok(fs.existsSync(stepOutput));
121
-
122
- // Verify solid shape metrics
123
- const expectedSolidVolume = 40.0 * 25.0 * 12.0 - Math.PI * 25.0 * 12.0;
124
- assert.ok(Math.abs(buildResult.metrics.volume - expectedSolidVolume) < 1.0, 'Volume matches geometry');
125
- assert.equal(buildResult.metrics.faces_count, 7);
126
-
127
- // Read raw STEP content to verify ISO-10303 signature
128
- const stepText = fs.readFileSync(stepOutput, 'utf8');
129
- assert.ok(stepText.includes('ISO-10303-21;'));
130
- assert.ok(stepText.includes('Open CASCADE STEP processor'));
131
-
132
- // Inspect the exported STEP file using FreeCAD inspection
133
- const inspectResult = await freeCadInspect({ input: stepOutput });
134
- assert.equal(inspectResult.ok, true);
135
- assert.equal(inspectResult.capability, 'freecad.inspect');
136
- assert.ok(Math.abs(inspectResult.metrics.volume - expectedSolidVolume) < 1.0);
137
- assert.equal(inspectResult.metrics.faces_count, 7);
138
- });
139
-
140
- test('Blender real execution builds, inspects, and exports production 3D assets', { skip: !toolAvailable('blender') && 'blender binary not available on this machine' }, async (t) => {
141
- const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-blender-test-'));
142
- t.after(() => fs.rmSync(tmpDir, { recursive: true, force: true }));
143
-
144
- const blendPath = path.join(tmpDir, 'scene.blend');
145
- const glbPath = path.join(tmpDir, 'scene.glb');
146
-
147
- const recipe = {
148
- schema_version: 1,
149
- operations: [
150
- { op: 'clear_scene' },
151
- { op: 'add', primitive: 'cylinder', name: 'Pillar', radius: 1.5, depth: 4.0 },
152
- { op: 'add_light', light_type: 'SUN', energy: 2.5 },
153
- ],
154
- };
155
-
156
- // 1. Build .blend file
157
- const buildResult = await blenderBuild({
158
- recipe,
159
- output: blendPath,
160
- });
161
-
162
- assert.equal(buildResult.ok, true);
163
- assert.equal(buildResult.capability, 'blender.build');
164
- assert.ok(fs.existsSync(blendPath));
165
- assert.ok(buildResult.objects.includes('Pillar'));
166
-
167
- // 2. Inspect built scene
168
- const inspectResult = await blenderInspect({ input: blendPath });
169
- assert.equal(inspectResult.ok, true);
170
- assert.equal(inspectResult.capability, 'blender.inspect');
171
- assert.ok(inspectResult.scene.objects.some(o => o.name === 'Pillar'));
172
-
173
- // 3. Export to GLB
174
- const exportResult = await blenderExport({
175
- input: blendPath,
176
- output: glbPath,
177
- format: 'glb',
178
- });
179
-
180
- assert.equal(exportResult.ok, true);
181
- assert.equal(exportResult.capability, 'blender.export');
182
- assert.ok(fs.existsSync(glbPath));
183
- assert.ok(fs.statSync(glbPath).size > 0);
184
- });
@@ -1,31 +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 {spawn} from 'node:child_process';
7
- import {localProjectRuntime} from '../../src/lib/cad/project-cli.js';
8
- test('packaged app API shares CLI revisions, emits events and rejects stale writes',{skip:process.env.AGENTSAM_TEST_CAD_APP!=='1'},async t=>{
9
- const root=fs.mkdtempSync(path.join(os.tmpdir(),'cad-app-proof-')),port=31987;
10
- const app=new URL('../../apps/cad-creator/backend/',import.meta.url);
11
- const child=spawn(process.execPath,['dist/server.mjs'],{cwd:app,env:{...process.env,NODE_ENV:'production',PORT:String(port),HOST:'127.0.0.1',AGENTSAM_CAD_PROJECT_ROOT:root},stdio:['ignore','pipe','pipe']});
12
- let log='';child.stdout.on('data',d=>log+=d);child.stderr.on('data',d=>log+=d);
13
- t.after(()=>{child.kill();fs.rmSync(root,{recursive:true,force:true});});
14
- const base='http://127.0.0.1:'+port;
15
- let ready=false;
16
- for(let i=0;i<80;i++){try{const r=await fetch(base);if(r.ok){ready=true;break;}}catch{}await new Promise(r=>setTimeout(r,100));}
17
- assert.ok(ready,log);
18
- async function call(name,input){const res=await fetch(base+'/api/cad/project/tools/'+name,{method:'POST',headers:{'content-type':'application/json'},body:JSON.stringify(input)});return {status:res.status,body:await res.json()};}
19
- const project=JSON.parse(fs.readFileSync(new URL('../fixtures/cad/courtyard-house.json',import.meta.url),'utf8'));
20
- const saved=await call('design_project_save',{project,expected_revision:0});assert.equal(saved.status,200);
21
- const runtime=localProjectRuntime(root);assert.equal((await runtime.execute('design_project_get',{project_id:project.id})).content_hash,saved.body.result.content_hash);
22
- const abort=new AbortController();t.after(()=>abort.abort());
23
- const events=await fetch(base+'/api/cad/project/events',{signal:abort.signal});const reader=events.body.getReader();
24
- const edited=await runtime.execute('design_apply_operation',{project_id:project.id,expected_revision:1,operation:{type:'update_wall',wallId:'wall-0',updates:{height3D:132}}});
25
- const event=await Promise.race([reader.read(),new Promise((_,reject)=>setTimeout(()=>reject(new Error('event timeout')),5000))]);
26
- assert.match(new TextDecoder().decode(event.value),/"revision":2/);
27
- const reopened=await call('design_project_get',{project_id:project.id,expected_content_hash:edited.content_hash});assert.equal(reopened.body.result.revision,2);
28
- assert.equal((await call('design_project_save',{project,expected_revision:1})).status,409);
29
- const denied=await fetch(base+'/api/cad/project/tools/design_project_get',{method:'POST',headers:{'content-type':'application/json',origin:'https://other.example'},body:JSON.stringify({project_id:project.id})});assert.equal(denied.status,403);
30
- abort.abort();
31
- });
@@ -1,25 +0,0 @@
1
- import test from 'node:test';
2
- import assert from 'node:assert/strict';
3
- import fs from 'node:fs';
4
- import {DatabaseSync} from 'node:sqlite';
5
- import {D1ProjectStore} from '../../src/lib/cad/d1-project-store.js';
6
- const schema="CREATE TABLE designstudio_design_blueprints (\n id TEXT PRIMARY KEY DEFAULT ('dsb_' || lower(hex(randomblob(8)))),\n\n tenant_id TEXT NOT NULL DEFAULT 'tenant_inneranimalmedia',\n workspace_id TEXT NOT NULL DEFAULT 'ws_inneranimalmedia',\n project_id TEXT,\n\n title TEXT NOT NULL,\n description TEXT,\n original_prompt TEXT,\n\n intent_json TEXT NOT NULL DEFAULT '{}',\n\n cad_script TEXT,\n cad_engine TEXT DEFAULT 'openscad',\n\n sketch_json TEXT DEFAULT '{}',\n preview_image_url TEXT,\n\n generation_config_json TEXT DEFAULT '{}',\n\n latest_asset_id TEXT,\n latest_run_id TEXT,\n\n status TEXT NOT NULL DEFAULT 'draft'\n CHECK (status IN (\n 'draft',\n 'structured',\n 'generated',\n 'validated',\n 'exported',\n 'failed'\n )),\n\n quality_score REAL DEFAULT 0,\n success_rate REAL DEFAULT 0,\n\n tags TEXT DEFAULT '[]',\n notes TEXT,\n\n total_tokens INTEGER DEFAULT 0,\n total_cost_usd REAL DEFAULT 0,\n avg_latency_ms REAL DEFAULT 0,\n\n created_at TEXT NOT NULL DEFAULT (datetime('now')),\n updated_at TEXT NOT NULL DEFAULT (datetime('now'))\n, preview_svg_url TEXT);\nCREATE TABLE \"scene_snapshots\" (\n id TEXT PRIMARY KEY DEFAULT ('scene_' || lower(hex(randomblob(8)))),\n workspace_id TEXT NOT NULL,\n user_id TEXT NOT NULL,\n tenant_id TEXT NOT NULL DEFAULT 'tenant_sam_primeaux',\n name TEXT NOT NULL DEFAULT 'Untitled Scene',\n project_type TEXT NOT NULL DEFAULT 'SANDBOX',\n entity_count INTEGER NOT NULL DEFAULT 0,\n r2_key TEXT NOT NULL,\n r2_bucket TEXT NOT NULL DEFAULT 'inneranimalmedia',\n public_url TEXT,\n thumbnail_r2_key TEXT,\n thumbnail_url TEXT,\n tags TEXT DEFAULT '[]',\n description TEXT,\n is_autosave INTEGER NOT NULL DEFAULT 0,\n version INTEGER NOT NULL DEFAULT 1,\n created_at INTEGER NOT NULL DEFAULT (unixepoch()),\n updated_at INTEGER NOT NULL DEFAULT (unixepoch())\n, project_id TEXT, glb_r2_key TEXT, style_preset TEXT, voxel_count INTEGER, cad_job_id TEXT);";
7
- const project=JSON.parse(fs.readFileSync(new URL('../fixtures/cad/courtyard-house.json',import.meta.url),'utf8'));
8
- test('existing D1 tables support scoped immutable revisions and optimistic concurrency',async t=>{
9
- const sqlite=new DatabaseSync(':memory:');t.after(()=>sqlite.close());sqlite.exec(schema);
10
- const db={prepare(sql){return {bind(...params){return {sql,params,async first(){return sqlite.prepare(sql).get(...params)||null;}};}};},
11
- async batch(statements){sqlite.exec('BEGIN');try{const results=statements.map(s=>({meta:{changes:Number(sqlite.prepare(s.sql).run(...s.params).changes)}}));sqlite.exec('COMMIT');return results;}catch(e){sqlite.exec('ROLLBACK');throw e;}}};
12
- const blobs=new Map(),objects={async put(k,v){blobs.set(k,v);},async get(k){return blobs.has(k)?{async text(){return blobs.get(k);}}:null;}};
13
- const scope={account_id:'test-owner',workspace_id:'test-workspace',tenant_id:'test-tenant'};
14
- const store=new D1ProjectStore({db,objects,bucket:'test-bucket',scope});
15
- await store.save(project,0);
16
- await store.save({...project,name:'Revision two'},1);
17
- await assert.rejects(store.save(project,1),/revision_conflict/);
18
- assert.equal(sqlite.prepare('SELECT count(*) n FROM scene_snapshots').get().n,2);
19
- assert.equal((await store.read(project.id,1)).project.name,project.name);
20
- assert.equal((await store.restore(project.id,1,2)).revision,3);
21
- const other=new D1ProjectStore({db,objects,bucket:'test-bucket',scope:{...scope,account_id:'other'}});
22
- await assert.rejects(other.read(project.id),/project_not_found/);
23
- await assert.rejects(other.save(project,3),/revision_conflict/);
24
- assert.equal((await store.read(project.id)).revision,3);
25
- });
@@ -1,24 +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 {localProjectRuntime} from '../../src/lib/cad/project-cli.js';
7
- const enabled=process.env.AGENTSAM_TEST_NATIVE_CAD==='1';
8
- test('courtyard real build inspect export render and restored revision rebuild',{skip:!enabled&&'Set AGENTSAM_TEST_NATIVE_CAD=1; enabled runs must find Blender'},async t=>{
9
- const root=process.env.AGENTSAM_CAD_TEST_OUTPUT||fs.mkdtempSync(path.join(os.tmpdir(),'cad-house-native-'));
10
- if(!process.env.AGENTSAM_CAD_TEST_OUTPUT)t.after(()=>fs.rmSync(root,{recursive:true,force:true}));
11
- const p=JSON.parse(fs.readFileSync(new URL('../fixtures/cad/courtyard-house.json',import.meta.url),'utf8'));
12
- p.id='courtyard-'+Date.now();
13
- const run=localProjectRuntime(root),saved=await run.execute('design_project_save',{project:p,expected_revision:0});
14
- const input={project_id:p.id,revision:saved.revision};
15
- const build=await run.execute('design_model_build',input);assert.ok(build.artifact.size_bytes>0);
16
- const inspection=await run.execute('design_model_inspect',input);assert.ok(inspection.ok);
17
- const glb=await run.execute('design_model_export',{...input,format:'glb'});assert.equal(fs.readFileSync(glb.artifact.path).subarray(0,4).toString(),'glTF');
18
- const png=await run.execute('design_model_render',input);assert.equal(fs.readFileSync(png.artifact.path).subarray(1,4).toString(),'PNG');
19
- const edited=await run.execute('design_apply_operation',{project_id:p.id,expected_revision:1,operation:{type:'update_wall',wallId:'wall-0',updates:{height3D:132}}});
20
- assert.equal(edited.revision,2);
21
- const restored=await run.execute('design_project_restore',{project_id:p.id,revision:1,expected_revision:2});assert.equal(restored.project.walls[0].height3D,120);
22
- await run.execute('design_model_build',{project_id:p.id,revision:3});
23
- console.log(JSON.stringify({root,project_id:p.id,build:build.artifact,glb:glb.artifact,png:png.artifact,restored_revision:3}));
24
- });
@@ -1,9 +0,0 @@
1
- import test from 'node:test';
2
- import assert from 'node:assert/strict';
3
- import {runProjectWorkflow} from '../../src/lib/cad/project-workflows.js';
4
- test('workflow halts on invalid validation and records no claimed effects',async()=>{
5
- let calls=0;await assert.rejects(runProjectWorkflow({execute:async()=>{calls++;return {valid:false,errors:['bad wall']};}},'cad.house_baseline',{project:{}}),/project_invalid/);assert.equal(calls,1);
6
- });
7
- test('edit workflow refuses stale expected revision before edit',async()=>{
8
- const calls=[];await assert.rejects(runProjectWorkflow({execute:async(name)=>{calls.push(name);return {revision:2,project:{id:'p'}};}},'cad.edit_preview',{project_id:'p',expected_revision:1,operation:{}}),/revision_conflict/);assert.deepEqual(calls,['design_project_get']);
9
- });
@@ -1,85 +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 {validateProject,applyProjectOperation} from '../../src/lib/cad/project-contract.js';
7
- import {FileProjectStore} from '../../src/lib/cad/project-store.js';
8
- import {createProjectRuntime} from '../../src/lib/cad/project-runtime.js';
9
- import {localProjectRuntime} from '../../src/lib/cad/project-cli.js';
10
- import {projectToBlenderRecipe} from '../../src/lib/cad/project-recipe.js';
11
- import {createCapabilityAdapter} from '../../src/agent/capability-adapter.js';
12
- const project=JSON.parse(fs.readFileSync(new URL('../fixtures/cad/courtyard-house.json',import.meta.url),'utf8'));
13
- test('invalid references and non-finite geometry fail before mutation',()=>{
14
- const p=structuredClone(project);p.walls[0].x1=Infinity;assert.equal(validateProject(p).valid,false);
15
- p.walls[0].x1=0;p.doors[0].wallId='missing';assert.equal(validateProject(p).valid,false);
16
- assert.equal(validateProject({...p,walls:{}}).valid,false);
17
- });
18
- test('batch is atomic, absent targets fail, and host deletion cascades',()=>{
19
- const before=JSON.stringify(project);
20
- assert.throws(()=>applyProjectOperation(project,{type:'batch_operations',operations:[{type:'delete_wall',wallId:'wall-4'},{type:'update_wall',wallId:'absent',updates:{height3D:96}}]}),/element_not_found/);
21
- assert.equal(JSON.stringify(project),before);
22
- assert.equal(applyProjectOperation(project,{type:'delete_wall',wallId:'wall-4'}).doors.length,0);
23
- });
24
- test('save reopen restore and stale revision checks preserve immutable snapshots',async t=>{
25
- const dir=fs.mkdtempSync(path.join(os.tmpdir(),'cad-project-'));t.after(()=>fs.rmSync(dir,{recursive:true,force:true}));
26
- const store=new FileProjectStore(dir);
27
- await store.save(project,0);
28
- const next=applyProjectOperation(project,{type:'update_wall',wallId:'wall-0',updates:{height3D:132}});
29
- await store.save(next,1);
30
- await assert.rejects(store.save(project,1),/revision_conflict/);
31
- const restored=await new FileProjectStore(dir).restore(project.id,1,2);
32
- assert.equal(restored.revision,3);assert.equal(restored.project.walls[0].height3D,120);assert.equal((await store.read(project.id,2)).project.walls[0].height3D,132);
33
- });
34
- test('native recipe converts inches to metres and preserves a real door gap',()=>{
35
- const recipe=projectToBlenderRecipe(project);
36
- assert.equal(recipe.operations.find(o=>o.name==='wall-0:0').scale[0],864*0.0254);
37
- const pieces=recipe.operations.filter(o=>o.name?.startsWith('wall-4:'));
38
- assert.equal(pieces.length,3);
39
- assert.throws(()=>projectToBlenderRecipe({...project,roofType:'gable'}),/roof_geometry_not_supported/);
40
- });
41
- test('agent and runtime share executable CAD handlers',async t=>{
42
- const root=fs.mkdtempSync(path.join(os.tmpdir(),'cad-agent-'));t.after(()=>fs.rmSync(root,{recursive:true,force:true}));
43
- const adapter=createCapabilityAdapter({projectRoot:root});
44
- assert.ok(adapter.toolDescriptors().some(t=>t.name==='design_project_save'));
45
- await adapter.invoke('design_project_save',{project,expected_revision:0});
46
- const result=await adapter.invoke('design_apply_operation',{project_id:project.id,expected_revision:1,operation:{type:'update_wall',wallId:'wall-0',updates:{height3D:132}}});
47
- assert.equal(result.result.revision,2);
48
- });
49
-
50
-
51
- test('CAD registry projects the app into tools workflows and CLI graph relationships',()=>{
52
- const manifest=JSON.parse(fs.readFileSync(new URL('../../registry/cad-project/manifest.json',import.meta.url),'utf8'));
53
- const migration=fs.readFileSync(new URL('../../registry/cad-project/migration.sql',import.meta.url),'utf8');
54
- assert.equal(manifest.product.app_id,'cad-creator');
55
- assert.equal(manifest.product.slug,'cad-creator');
56
- assert.deepEqual(manifest.product.capability_keys,['design.read','design.write','design.export']);
57
- assert.equal(manifest.product.cli_commands[0].id,'agentsam:cad:project');
58
- assert.equal(manifest.tools.length,9);
59
- assert.equal(manifest.workflows.length,2);
60
- assert.match(migration,/WHERE slug='cad-creator'/);
61
- assert.match(migration,/WHERE slug='agentsam-cad-creator'/);
62
- assert.match(migration,/legacy_slug','agentsam-cad-creator/);
63
- assert.equal((migration.match(/'exposes_tool'/g)||[]).length,9);
64
- assert.equal((migration.match(/'provides_workflow'/g)||[]).length,2);
65
- assert.equal((migration.match(/'exposes_command'/g)||[]).length,1);
66
- assert.match(migration,/'cli_command','agentsam:cad:project'/);
67
- assert.match(migration,/ON CONFLICT\(id\) DO UPDATE SET tool_name=excluded\.tool_name/);
68
- assert.doesNotMatch(migration,/DO UPDATE SET[^;]*is_active=excluded\.is_active/);
69
- assert.doesNotMatch(migration,/DO UPDATE SET[^;]*lifecycle=excluded\.lifecycle/);
70
-
71
- });
72
-
73
-
74
- test('CAD validate requires project or project_id and model-facing CAD tools declare non-strict rich payloads',async()=>{
75
- const root=fs.mkdtempSync(path.join(os.tmpdir(),'cad-validate-source-'));
76
- const runtime=localProjectRuntime(root);
77
- await assert.rejects(()=>runtime.execute('design_project_validate',{}),/argument_required:project_or_project_id/);
78
- const adapter=createCapabilityAdapter({projectRoot:root});
79
- const save=adapter.toolDescriptors().find(t=>t.name==='design_project_save');
80
- const edit=adapter.toolDescriptors().find(t=>t.name==='design_apply_operation');
81
- assert.equal(save.strict,false);
82
- assert.equal(edit.strict,false);
83
- assert.equal(save.input_schema.properties.project.additionalProperties,true);
84
- assert.equal(edit.input_schema.properties.operation.additionalProperties,true);
85
- });
@@ -1,41 +0,0 @@
1
- import assert from 'node:assert/strict';
2
- import path from 'node:path';
3
- import { spawnSync } from 'node:child_process';
4
- import test from 'node:test';
5
-
6
- const repoRoot = path.resolve(new URL('../..', import.meta.url).pathname);
7
-
8
- function run(...args) {
9
- return spawnSync(process.execPath, ['src/cli.js', ...args], { cwd: repoRoot, encoding: 'utf8' });
10
- }
11
-
12
- test('agentsam help is concise, topic-aware, and deterministic outside a TTY', () => {
13
- const help = run('help');
14
- assert.equal(help.status, 0, help.stderr);
15
- assert.doesNotMatch(help.stderr, /Unknown command/);
16
- assert.match(help.stdout, /Agent Sam/);
17
- assert.match(help.stdout, /SAM = Systematic Autonomous Machinery/);
18
- assert.match(help.stdout, /agentsam help <topic>/);
19
- assert.match(help.stdout, /press \/ for the command picker/i);
20
- assert.doesNotMatch(help.stdout, /Inspect options:/);
21
-
22
- const topic = run('help', 'runtime');
23
- assert.equal(topic.status, 0, topic.stderr);
24
- assert.match(topic.stdout, /Runtime \/ terminal/);
25
- assert.match(topic.stdout, /agentsam connections/);
26
- assert.match(topic.stdout, /agentsam deploy/);
27
-
28
- const all = run('help', '--all');
29
- assert.equal(all.status, 0, all.stderr);
30
- assert.match(all.stdout, /Build \/ inspect/);
31
- assert.match(all.stdout, /Create \/ extend/);
32
-
33
- const allAlias = run('help', 'all');
34
- assert.equal(allAlias.status, 0, allAlias.stderr);
35
- assert.equal(allAlias.stdout, all.stdout);
36
-
37
- const flag = run('--help');
38
- assert.equal(flag.status, 0, flag.stderr);
39
- assert.match(flag.stdout, /agentsam help <topic>/);
40
- assert.doesNotMatch(flag.stdout, /Inspect options:/);
41
- });
@@ -1,77 +0,0 @@
1
- import assert from 'node:assert/strict';
2
- import fs from 'node:fs';
3
- import os from 'node:os';
4
- import path from 'node:path';
5
- import test from 'node:test';
6
- import { execFileSync } from 'node:child_process';
7
- import { fileURLToPath } from 'node:url';
8
-
9
- const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');
10
- const cmsBin = path.join(root, 'apps/client-cms-editor/bin/agentsam-cms.mjs');
11
-
12
- function scaffold(persistence, extraArgs = []) {
13
- const temp = fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-cms-scaffold-'));
14
- const target = path.join(temp, 'editor');
15
- execFileSync(process.execPath, [
16
- cmsBin,
17
- 'scaffold',
18
- target,
19
- '--persistence',
20
- persistence,
21
- ...extraArgs,
22
- ], { cwd: root, stdio: 'pipe' });
23
- return { temp, target };
24
- }
25
-
26
- test('CMS editor scaffold is self-contained and records SQLite authority', () => {
27
- const { temp, target } = scaffold('sqlite');
28
- try {
29
- assert.equal(fs.existsSync(path.join(target, 'agentsam.app.json')), true);
30
- assert.equal(fs.existsSync(path.join(target, 'cms.config.json')), true);
31
- assert.equal(fs.existsSync(path.join(target, '.agentsam/cms.sqlite')), true);
32
- assert.equal(fs.existsSync(path.join(target, '.agentsam/assets')), true);
33
- assert.equal(fs.existsSync(path.join(target, 'public')), true);
34
-
35
- const cfg = JSON.parse(fs.readFileSync(path.join(target, 'cms.config.json'), 'utf8'));
36
- assert.equal(cfg.schema, 'agentsam.cms.project.v1');
37
- assert.equal(cfg.persistence, 'sqlite');
38
- assert.equal(cfg.dbPath, '.agentsam/cms.sqlite');
39
- assert.equal(cfg.cmsBase, '/cms');
40
- assert.equal(cfg.auth?.mode, 'local-dev-principal');
41
-
42
- const app = JSON.parse(fs.readFileSync(path.join(target, 'agentsam.app.json'), 'utf8'));
43
- assert.equal(app.schema, 'agentsam.app.v1');
44
- assert.equal(app.product_id, 'cms');
45
- assert.equal(app.package, '@inneranimalmedia/client-cms-editor');
46
-
47
- // Lean project shell — no monorepo package vendoring / file: escapes.
48
- assert.equal(fs.existsSync(path.join(target, 'packages')), false);
49
- assert.equal(fs.existsSync(path.join(target, 'frontend/package.json')), false);
50
- } finally {
51
- fs.rmSync(temp, { recursive: true, force: true });
52
- }
53
- });
54
-
55
- test('CMS editor rejects localStorage as persistence authority', () => {
56
- const temp = fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-cms-scaffold-'));
57
- const target = path.join(temp, 'editor');
58
- try {
59
- assert.throws(
60
- () => execFileSync(process.execPath, [
61
- cmsBin,
62
- 'scaffold',
63
- target,
64
- '--persistence',
65
- 'localStorage',
66
- ], { cwd: root, stdio: 'pipe', encoding: 'utf8' }),
67
- (error) => {
68
- const message = String(error?.stderr || error?.message || error);
69
- return /unsupported persistence "localStorage"/i.test(message)
70
- && /choose sqlite or d1/i.test(message);
71
- },
72
- );
73
- assert.equal(fs.existsSync(target), false);
74
- } finally {
75
- fs.rmSync(temp, { recursive: true, force: true });
76
- }
77
- });