@inneranimalmedia/agentsam-sdk 2.6.5 → 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 (400) hide show
  1. package/AGENTSAM.md +29 -0
  2. package/README.md +37 -0
  3. package/apps/README.md +5 -0
  4. package/apps/cad-creator/README.md +4 -4
  5. package/apps/cad-creator/shared/cad/package.json +1 -1
  6. package/apps/client-cms-editor/AGENTS.md +12 -7
  7. package/apps/client-cms-editor/README.md +76 -48
  8. package/apps/client-cms-editor/agentsam.app.json +26 -9
  9. package/apps/client-cms-editor/backend/package.json +20 -3
  10. package/apps/client-cms-editor/backend/src/api/client.ts +134 -101
  11. package/apps/client-cms-editor/backend/src/index.ts +1 -1
  12. package/apps/client-cms-editor/backend/src/model.ts +11 -115
  13. package/apps/client-cms-editor/backend/src/preview/bridge.ts +1 -1
  14. package/apps/client-cms-editor/backend/tsconfig.json +6 -1
  15. package/apps/client-cms-editor/bin/agentsam-cms.js +262 -0
  16. package/apps/client-cms-editor/bin/agentsam-cms.mjs +2 -228
  17. package/apps/client-cms-editor/frontend/package.json +16 -7
  18. package/apps/client-cms-editor/frontend/src/AgentSamDrawer.tsx +9 -41
  19. package/apps/client-cms-editor/frontend/src/CmsAgentSurface.tsx +19 -174
  20. package/apps/client-cms-editor/frontend/src/adapters/heuristic.ts +29 -0
  21. package/apps/client-cms-editor/frontend/src/adapters/http.ts +628 -0
  22. package/apps/client-cms-editor/frontend/src/adapters/memory.ts +510 -0
  23. package/apps/client-cms-editor/frontend/src/editor/CmsEditor.tsx +213 -0
  24. package/apps/client-cms-editor/frontend/src/editor/CmsEditorProvider.tsx +20 -0
  25. package/apps/client-cms-editor/frontend/src/editor/canvas/PreviewCanvas.tsx +53 -0
  26. package/apps/client-cms-editor/frontend/src/{CmsEditor.tsx → editor/legacy/CmsEditorPrototype.tsx} +52 -23
  27. package/apps/client-cms-editor/frontend/src/editor/useCmsEditorController.ts +218 -0
  28. package/apps/client-cms-editor/frontend/src/index.ts +19 -5
  29. package/apps/client-cms-editor/frontend/src/lib/agent-host.ts +24 -0
  30. package/apps/client-cms-editor/frontend/src/main.tsx +82 -8
  31. package/apps/client-cms-editor/frontend/src/mount.tsx +92 -30
  32. package/apps/client-cms-editor/frontend/src/styles/agentsam-drawer.css +1 -1
  33. package/apps/client-cms-editor/frontend/src/styles/cmsShell.css +8 -8
  34. package/apps/client-cms-editor/frontend/src/styles/studio.css +55 -3
  35. package/apps/client-cms-editor/frontend/tsconfig.json +12 -1
  36. package/apps/client-cms-editor/frontend/vite.config.ts +12 -0
  37. package/apps/client-cms-editor/package-lock.json +973 -134
  38. package/apps/client-cms-editor/package.json +118 -6
  39. package/apps/client-cms-editor/reference/harvest/HARVEST_RECEIPT.json +201 -0
  40. package/apps/client-cms-editor/reference/harvest/PROVENANCE_HISTORY.txt +10 -0
  41. package/apps/client-cms-editor/reference/harvest/README.md +8 -0
  42. package/apps/client-cms-editor/reference/harvest/plans/ARCHIVE-INTAKE.md +135 -0
  43. package/apps/client-cms-editor/reference/harvest/plans/CHATGPT-IDENTITY-HARVEST.md +83 -0
  44. package/apps/client-cms-editor/reference/harvest/plans/CMS-EDITOR-HARVEST.md +166 -0
  45. package/apps/client-cms-editor/reference/harvest/plans/HARVEST-INDEX.md +196 -0
  46. package/apps/client-cms-editor/reference/harvest/plans/INNERANIMALS-CONTENT-001.md +137 -0
  47. package/apps/client-cms-editor/reference/harvest/plans/NO-IMPLICIT-SIDE-EFFECTS.md +87 -0
  48. package/apps/client-cms-editor/reference/harvest/plans/STOREFRONT-SURFACE-MAP.md +140 -0
  49. package/apps/client-cms-editor/reference/harvest/plans/THEME-INNERANIMALS-HARVEST.md +137 -0
  50. package/apps/client-cms-editor/reference/harvest/plans/TOOLING-LAB.md +63 -0
  51. package/apps/client-cms-editor/reference/harvest/plans/harvest-manifest.json +97 -0
  52. package/apps/client-cms-editor/reference/harvest/plans/local-cms-harvest-schema.sql +328 -0
  53. package/apps/client-cms-editor/shared/cms/package.json +17 -7
  54. package/apps/client-cms-editor/shared/cms/src/adapter.ts +204 -0
  55. package/apps/client-cms-editor/shared/cms/src/agent-context.ts +7 -5
  56. package/apps/client-cms-editor/shared/cms/src/editor-types.ts +32 -0
  57. package/apps/client-cms-editor/shared/cms/src/host.ts +82 -0
  58. package/apps/client-cms-editor/shared/cms/src/index.ts +4 -0
  59. package/apps/client-cms-editor/shared/cms/src/map.ts +115 -0
  60. package/apps/client-cms-editor/shared/cms/src/starter-pack.ts +158 -0
  61. package/contracts/source-types.v1.json +353 -0
  62. package/docs/CMS_CONTEXTUAL_COMPOSER.md +1 -1
  63. package/docs/PRODUCT_LIFECYCLE.md +566 -0
  64. package/docs/REPO_FILE_MAP.txt +132 -0
  65. package/docs/THEME_REFINERY.md +2 -2
  66. package/docs/architecture/AGENTSAM_RUNTIME_PROTOCOL.md +40 -20
  67. package/docs/content-studio/REVISION_GATE_2026-09-27.md +1 -1
  68. package/docs/plans/LOCAL_STUDIO_DESKTOP_RELEASE_2026-09-29.md +150 -0
  69. package/migrations/d1/0017_identity_native_oauth.sql +21 -0
  70. package/migrations/d1/0018_goap_control_plane_remaster.sql +40 -0
  71. package/migrations/d1/0019_agentsam_agent_run_plan_todo.sql +14 -0
  72. package/migrations/d1/README_PORTABLE_CONTROL_PLANE.md +20 -9
  73. package/migrations/runtime/0002_goap_blackboard_v1.sql +15 -0
  74. package/migrations/runtime/0004_agent_run_plan_linkage.sql +8 -0
  75. package/native/agentsam-machine/Cargo.lock +426 -0
  76. package/native/agentsam-machine/Cargo.toml +9 -0
  77. package/native/agentsam-machine/cli/Cargo.toml +21 -0
  78. package/native/agentsam-machine/cli/README.md +21 -0
  79. package/native/agentsam-machine/cli/src/main.rs +77 -0
  80. package/native/agentsam-machine/core/Cargo.toml +22 -0
  81. package/native/agentsam-machine/core/README.md +14 -0
  82. package/native/agentsam-machine/core/build.rs +33 -0
  83. package/native/agentsam-machine/core/contracts/source-types.v1.json +353 -0
  84. package/native/agentsam-machine/core/src/assets.rs +790 -0
  85. package/native/agentsam-machine/core/src/bound.rs +298 -0
  86. package/native/agentsam-machine/core/src/enrich.rs +706 -0
  87. package/native/agentsam-machine/core/src/frontend.rs +442 -0
  88. package/native/agentsam-machine/core/src/lib.rs +1092 -0
  89. package/native/agentsam-machine/core/src/liquid.rs +528 -0
  90. package/native/agentsam-machine/core/src/source_types.rs +78 -0
  91. package/package.json +64 -24
  92. package/packages/agentsam-brand/README.md +1 -1
  93. package/packages/agentsam-brand/package.json +4 -4
  94. package/packages/agentsam-brand/src/index.js +1 -1
  95. package/packages/agentsam-contracts/package.json +13 -3
  96. package/packages/agentsam-contracts/src/tools.ts +22 -0
  97. package/packages/agentsam-errors/package.json +13 -3
  98. package/packages/agentsam-errors/src/index.js +1 -0
  99. package/packages/agentsam-errors/src/tool.js +56 -0
  100. package/packages/agentsam-errors/test/tool.test.mjs +58 -0
  101. package/packages/agentsam-goap/README.md +52 -0
  102. package/packages/agentsam-goap/package.json +37 -0
  103. package/packages/agentsam-goap/src/adapters/d1-sqlite.js +570 -0
  104. package/packages/agentsam-goap/src/adapters/memory.js +199 -0
  105. package/packages/agentsam-goap/src/contracts.js +226 -0
  106. package/packages/agentsam-goap/src/control-plane.js +112 -0
  107. package/packages/agentsam-goap/src/errors.js +157 -0
  108. package/packages/agentsam-goap/src/index.js +5 -0
  109. package/packages/agentsam-goap/src/world.js +202 -0
  110. package/packages/agentsam-goap/test/goap-control-plane.test.mjs +245 -0
  111. package/packages/agentsam-goap/test/world.test.mjs +79 -0
  112. package/packages/agentsam-knowledge/package.json +18 -4
  113. package/packages/agentsam-knowledge/src/autorag/index.js +10 -3
  114. package/packages/agentsam-knowledge/src/backends/index.js +33 -1
  115. package/packages/agentsam-knowledge/test/autorag.test.mjs +60 -1
  116. package/packages/agentsam-nav/dist/browser.global.js +21 -18
  117. package/packages/agentsam-nav/dist/browser.js +6807 -130
  118. package/packages/agentsam-nav/dist/index.js +6799 -122
  119. package/packages/agentsam-nav/package.json +24 -6
  120. package/packages/agentsam-queue-control/README.md +1 -1
  121. package/packages/agentsam-queue-control/package.json +7 -2
  122. package/packages/agentsam-rapid-rust/src/main.rs +1 -1
  123. package/packages/agentsam-repository/package.json +13 -3
  124. package/packages/agentsam-repository/src/goap.js +13 -14
  125. package/packages/agentsam-repository/src/source-types.js +8 -0
  126. package/packages/agentsam-repository/src/tickets.js +15 -22
  127. package/packages/agentsam-repository/test/goap-tickets-workspace-state.test.mjs +19 -8
  128. package/packages/agentsam-vault/package.json +14 -4
  129. package/packages/agentsam-workbench/package.json +15 -4
  130. package/packages/agentsam-workbench/src/agent/ToolPermissionRequest.tsx +94 -0
  131. package/packages/agentsam-workbench/src/agent/index.ts +2 -0
  132. package/packages/agentsam-workbench/src/agent/tool-permission.css +134 -0
  133. package/packages/connectors/cloudflare/package.json +15 -3
  134. package/packages/connectors/cloudflare/src/api-client.js +3 -2
  135. package/packages/connectors/cloudflare/src/families/vectorize.js +127 -0
  136. package/packages/connectors/cloudflare/src/index.js +1 -0
  137. package/packages/heuristic-theme/README.md +2 -2
  138. package/packages/heuristic-theme/package.json +8 -3
  139. package/packages/heuristic-theme/src/registry.js +2 -2
  140. package/packages/heuristic-theme/src/theme.js +1 -1
  141. package/packages/heuristic-theme/test/theme.test.mjs +1 -1
  142. package/packages/identity/.agentsam/features/oauth-login-portal/agentsam.feature.json +1 -1
  143. package/packages/identity/.agentsam/features/oauth-login-portal/providers.json +27 -7
  144. package/packages/identity/README.md +2 -2
  145. package/packages/identity/migrations/D1_SCHEMA_MAPPING.md +18 -15
  146. package/packages/identity/migrations/apply-portable.js +109 -0
  147. package/packages/identity/migrations/sqlite/004_identity_oauth_consent_catalog.sql +1 -1
  148. package/packages/identity/migrations/sqlite/005_identity_company_native.sql +52 -0
  149. package/packages/identity/package.json +27 -6
  150. package/packages/identity/schema/agentsam.identity/manifest.json +101 -0
  151. package/packages/identity/scripts/local-identity-bridge.mjs +13 -7
  152. package/packages/identity/scripts/preview-auth-portal.mjs +6 -6
  153. package/packages/identity/src/adapters/cloudflare-d1/index.js +8 -401
  154. package/packages/identity/src/adapters/iam-compat/index.js +540 -0
  155. package/packages/identity/src/adapters/portable-d1/index.js +18 -0
  156. package/packages/identity/src/adapters/portable-store.js +479 -0
  157. package/packages/identity/src/adapters/sqlite/index.js +13 -312
  158. package/packages/identity/src/contracts/auth-config.js +0 -1
  159. package/packages/identity/src/contracts/identity-store.js +56 -5
  160. package/packages/identity/src/contracts/provider.js +1 -0
  161. package/packages/identity/src/contracts/sign-in-options.js +104 -0
  162. package/packages/identity/src/core/constants.js +1 -1
  163. package/packages/identity/src/core/session-policy.js +31 -0
  164. package/packages/identity/src/frontend/auth-portal/pages/login.html +6 -6
  165. package/packages/identity/src/frontend/auth-portal/pages/reset.html +5 -5
  166. package/packages/identity/src/frontend/auth-portal/pages/signup.html +5 -5
  167. package/packages/identity/src/frontend/auth-portal/shared/company-branding.js +1 -1
  168. package/packages/identity/src/frontend/auth-portal/shared/desktop-identity-bridge.js +6 -37
  169. package/packages/identity/src/index.js +28 -1
  170. package/packages/identity/src/migrations/README.md +23 -23
  171. package/packages/identity/src/oauth/README.md +1 -1
  172. package/packages/identity/src/oauth/credentials.js +10 -11
  173. package/packages/identity/src/oauth/google-desktop-exchange.js +195 -27
  174. package/packages/identity/src/oauth/iam-platform.js +21 -9
  175. package/packages/identity/src/oauth/native-handoff.js +136 -0
  176. package/packages/identity/src/providers/chatgpt/headers.js +65 -0
  177. package/packages/identity/src/providers/chatgpt/index.js +86 -0
  178. package/packages/identity/src/providers/chatgpt/mapper.js +43 -0
  179. package/packages/identity/src/providers/chatgpt/paths.js +45 -0
  180. package/packages/identity/src/providers/github/oauth.js +1 -2
  181. package/packages/identity/src/providers/github/profile.js +16 -2
  182. package/packages/identity/src/providers/index.js +11 -3
  183. package/packages/identity/src/server/identity-service.js +2 -1
  184. package/packages/identity/src/server/worker-router.js +71 -18
  185. package/packages/identity/tests/chatgpt-provider.test.mjs +75 -0
  186. package/packages/identity/tests/google-desktop-identity-login.test.mjs +210 -0
  187. package/packages/identity/tests/identity-init-scaffold.test.mjs +15 -4
  188. package/packages/identity/tests/lane1-identity-store-parity.test.mjs +527 -0
  189. package/packages/identity/tests/lane1-packed-consumer.test.mjs +175 -0
  190. package/packages/identity/tests/native-oauth-handoff.test.mjs +292 -0
  191. package/packages/identity/tests/oauth-credentials.test.mjs +4 -4
  192. package/packages/identity/tests/preview-auth-portal.test.mjs +4 -2
  193. package/packages/identity/tests/session-routes-policy.test.mjs +13 -1
  194. package/packages/identity/tests/worker-runtime-boundary.test.mjs +11 -0
  195. package/packages/providers/completeful/package.json +7 -2
  196. package/packages/theme-church-site/package.json +17 -6
  197. package/packages/theme-church-site/src/harvest.json +4 -2
  198. package/packages/theme-church-site/src/index.js +7 -3
  199. package/packages/theme-church-site/test/theme.test.mjs +4 -2
  200. package/packages/theme-companions-site/package.json +17 -6
  201. package/packages/theme-companions-site/src/harvest.json +4 -2
  202. package/packages/theme-companions-site/src/index.js +7 -3
  203. package/packages/theme-companions-site/test/theme.test.mjs +4 -2
  204. package/packages/theme-floors-site/package.json +17 -6
  205. package/packages/theme-floors-site/src/harvest.json +4 -2
  206. package/packages/theme-floors-site/src/index.js +7 -3
  207. package/packages/theme-floors-site/test/theme.test.mjs +4 -2
  208. package/packages/theme-fuelnfree-site/package.json +17 -6
  209. package/packages/theme-fuelnfree-site/src/harvest.json +4 -2
  210. package/packages/theme-fuelnfree-site/src/index.js +7 -3
  211. package/packages/theme-fuelnfree-site/test/theme.test.mjs +4 -2
  212. package/packages/theme-handyman-site/package.json +17 -6
  213. package/packages/theme-handyman-site/src/harvest.json +4 -2
  214. package/packages/theme-handyman-site/src/index.js +7 -3
  215. package/packages/theme-handyman-site/test/theme.test.mjs +4 -2
  216. package/packages/theme-insurance-site/package.json +17 -6
  217. package/packages/theme-insurance-site/src/harvest.json +4 -2
  218. package/packages/theme-insurance-site/src/index.js +7 -3
  219. package/packages/theme-insurance-site/test/theme.test.mjs +4 -2
  220. package/packages/theme-scenes/README.md +1 -1
  221. package/packages/theme-scenes/package.json +4 -3
  222. package/packages/theme-scenes/src/registry.js +187 -0
  223. package/packages/theme-shinshu-site/package.json +17 -6
  224. package/packages/theme-shinshu-site/src/harvest.json +4 -2
  225. package/packages/theme-shinshu-site/src/index.js +7 -3
  226. package/packages/theme-shinshu-site/test/theme.test.mjs +4 -2
  227. package/packages/work-graph/package.json +14 -4
  228. package/protocol/FILEMETA_V1.md +2 -2
  229. package/protocol/capabilities/manifest.json +1 -1
  230. package/protocol/database/agentsam.schema-pack.v1.schema.json +72 -0
  231. package/protocol/presets/catalog.json +2 -2
  232. package/protocol/theme-refinery/lineage-registry.json +105 -0
  233. package/protocol/theme-refinery/product-metadata.schema.json +21 -1
  234. package/python/agentsam_sdk/repository/intelligence/discovery.py +27 -2
  235. package/python/agentsam_sdk/repository/intelligence/git.py +4 -0
  236. package/python/tests/test_repository_intelligence.py +30 -0
  237. package/src/cli/command-catalog.js +48 -5
  238. package/src/cli/dispatch.js +1 -0
  239. package/src/cli.js +20 -1
  240. package/src/cloudflare/runtime-status.js +2 -1
  241. package/src/commands/autorag.js +67 -13
  242. package/src/commands/cheat-sheet.js +29 -4
  243. package/src/commands/codebaseindex.js +45 -2
  244. package/src/commands/goap-world.js +134 -0
  245. package/src/commands/goap.js +11 -4
  246. package/src/commands/knowledge.js +59 -2
  247. package/src/commands/machine-binary.js +109 -0
  248. package/src/commands/machine-runtime.js +266 -0
  249. package/src/commands/machine.js +208 -0
  250. package/src/commands/package.js +530 -0
  251. package/src/commands/plan-ledger.js +370 -0
  252. package/src/commands/plan.js +183 -0
  253. package/src/commands/security.js +67 -4
  254. package/src/commands/setup.js +33 -16
  255. package/src/commands/skill.js +78 -17
  256. package/src/commands/status.js +8 -1
  257. package/src/features/resolve.js +1 -0
  258. package/src/knowledge/engine.js +21 -2
  259. package/src/knowledge/runtime-discovery.js +127 -0
  260. package/src/knowledge/source.js +1 -1
  261. package/src/lib/identity-scaffold.js +53 -13
  262. package/src/lib/setup/recipes.js +1 -1
  263. package/src/lib/slash-commands.js +1 -1
  264. package/src/local/runtime-store.js +24 -2
  265. package/src/local/sqlite.js +17 -0
  266. package/src/models/discovery.js +40 -22
  267. package/src/models/inventory-core.d.ts +105 -0
  268. package/src/models/inventory-core.js +54 -6
  269. package/src/sam/operations/package-audit.js +41 -0
  270. package/src/sam/seed.js +2 -0
  271. package/src/security/logs.js +3 -0
  272. package/src/ui/cli/help.js +41 -0
  273. package/apps/client-cms-editor/backend/src/demo-bootstrap.ts +0 -145
  274. package/test/account-session.test.mjs +0 -101
  275. package/test/agent-capabilities.test.mjs +0 -67
  276. package/test/app-authority-context.test.mjs +0 -32
  277. package/test/app-building-skills.test.mjs +0 -61
  278. package/test/apps-scaffold-contract.test.mjs +0 -114
  279. package/test/blender-cad.test.mjs +0 -146
  280. package/test/cad-docker.test.mjs +0 -96
  281. package/test/capabilities.test.mjs +0 -133
  282. package/test/cli/api-key-env-whoami.test.mjs +0 -129
  283. package/test/cli/codebaseindex-plan-ux.test.mjs +0 -37
  284. package/test/cli/eval-live.test.mjs +0 -219
  285. package/test/cli/go.test.mjs +0 -128
  286. package/test/cli/local-vault-and-provider-setup.test.mjs +0 -268
  287. package/test/cli/mcp-client.test.mjs +0 -256
  288. package/test/cli/preferences-runtime.test.mjs +0 -11
  289. package/test/cli/runtime-persist.test.mjs +0 -56
  290. package/test/cli/runtime-ui.test.mjs +0 -141
  291. package/test/cli/rust-command.test.mjs +0 -21
  292. package/test/cli/skill-npm-and-env.test.mjs +0 -52
  293. package/test/cli/status-actions.test.mjs +0 -88
  294. package/test/cli/wireframes-go-registry.test.mjs +0 -139
  295. package/test/cli-preferences.test.mjs +0 -46
  296. package/test/cloudflare-connector.test.mjs +0 -93
  297. package/test/cloudflare-runtime.test.mjs +0 -82
  298. package/test/context.test.mjs +0 -159
  299. package/test/credentials-audit.test.mjs +0 -113
  300. package/test/deploy-health-scan.test.mjs +0 -95
  301. package/test/deploy-receipt.test.mjs +0 -91
  302. package/test/dockerize.test.mjs +0 -93
  303. package/test/error-diagnostics.test.mjs +0 -124
  304. package/test/eval-context.test.mjs +0 -37
  305. package/test/execution-approvals.test.mjs +0 -27
  306. package/test/fixtures/cad/courtyard-house.json +0 -208
  307. package/test/fixtures/knowledge-rpc-worker.mjs +0 -16
  308. package/test/gcloud-auth.test.mjs +0 -111
  309. package/test/go/build-source-identity.test.mjs +0 -31
  310. package/test/go/cloudflare-probe.test.mjs +0 -317
  311. package/test/go/distribution.test.mjs +0 -28
  312. package/test/google-cloud-connection.test.mjs +0 -83
  313. package/test/google-cloud-inventory.test.mjs +0 -64
  314. package/test/indexing-provider.test.mjs +0 -29
  315. package/test/init-options.test.mjs +0 -35
  316. package/test/integration/ai-access-onboarding.test.mjs +0 -47
  317. package/test/integration/app-command.test.mjs +0 -85
  318. package/test/integration/cad-discovery.test.mjs +0 -158
  319. package/test/integration/cad-docker-executor.test.mjs +0 -249
  320. package/test/integration/cad-execution.test.mjs +0 -184
  321. package/test/integration/cad-project-app.test.mjs +0 -31
  322. package/test/integration/cad-project-d1.test.mjs +0 -25
  323. package/test/integration/cad-project-native.test.mjs +0 -24
  324. package/test/integration/cad-project-workflow.test.mjs +0 -9
  325. package/test/integration/cad-project.test.mjs +0 -85
  326. package/test/integration/cli-help.test.mjs +0 -41
  327. package/test/integration/cms-app-scaffold.test.mjs +0 -71
  328. package/test/integration/cms-site-tenancy-contract.test.mjs +0 -257
  329. package/test/integration/codebaseindex-ingest.test.mjs +0 -214
  330. package/test/integration/core-client.integration.test.mjs +0 -55
  331. package/test/integration/error-runtime-rpc.test.mjs +0 -71
  332. package/test/integration/features-resolve.test.mjs +0 -147
  333. package/test/integration/icon-registry.test.mjs +0 -67
  334. package/test/integration/ingest-discover-models.test.mjs +0 -30
  335. package/test/integration/inspect-path-cli.test.mjs +0 -46
  336. package/test/integration/install-script.test.mjs +0 -110
  337. package/test/integration/inventory-core.test.mjs +0 -53
  338. package/test/integration/inventory-evidence.test.mjs +0 -125
  339. package/test/integration/knowledge-rpc.test.mjs +0 -112
  340. package/test/integration/local-fs.test.mjs +0 -113
  341. package/test/integration/merkle-cli.test.mjs +0 -61
  342. package/test/integration/merkle-persistence-identity.test.mjs +0 -48
  343. package/test/integration/plugins-cloudflare.integration.test.mjs +0 -28
  344. package/test/integration/provider-env-cli.test.mjs +0 -50
  345. package/test/integration/provider-factory.test.mjs +0 -197
  346. package/test/integration/repository-company-graph.test.mjs +0 -90
  347. package/test/integration/runtime-migrations.test.mjs +0 -87
  348. package/test/integration/runtime-status.integration.test.mjs +0 -212
  349. package/test/integration/sam-activity-recovery.test.mjs +0 -147
  350. package/test/integration/sam-decision.test.mjs +0 -584
  351. package/test/integration/sam-kernel.test.mjs +0 -99
  352. package/test/integration/sam-planning-astar.test.mjs +0 -279
  353. package/test/integration/scaffold-cloudflare.test.mjs +0 -46
  354. package/test/integration/skill-runtime.test.mjs +0 -240
  355. package/test/integration/storage-architecture.test.mjs +0 -154
  356. package/test/integration/store-discovery.test.mjs +0 -44
  357. package/test/integration/studio-fs-pty-e2e.test.mjs +0 -294
  358. package/test/integration/terminal-exec.integration.test.mjs +0 -86
  359. package/test/integration/tool-runtime.test.mjs +0 -124
  360. package/test/integration/tool-schema.test.mjs +0 -59
  361. package/test/jr-dev-skill.test.mjs +0 -26
  362. package/test/knowledge-context-pack.test.mjs +0 -19
  363. package/test/knowledge-postgres.test.mjs +0 -40
  364. package/test/knowledge-service.test.mjs +0 -110
  365. package/test/knowledge.test.mjs +0 -206
  366. package/test/live/terminal-transport.live.test.mjs +0 -24
  367. package/test/local-sessions.test.mjs +0 -57
  368. package/test/local-studio-deploy.test.mjs +0 -83
  369. package/test/loopback-oauth.test.mjs +0 -53
  370. package/test/merkle-render.test.mjs +0 -31
  371. package/test/mini.test.mjs +0 -140
  372. package/test/model-catalog.test.mjs +0 -70
  373. package/test/models.test.mjs +0 -309
  374. package/test/npm10-lock.test.mjs +0 -29
  375. package/test/ollama.test.mjs +0 -137
  376. package/test/open-url.test.mjs +0 -64
  377. package/test/openai-responses.test.mjs +0 -155
  378. package/test/portable-context.test.mjs +0 -94
  379. package/test/project-config.test.mjs +0 -81
  380. package/test/project-rules.test.mjs +0 -44
  381. package/test/provider-credentials.test.mjs +0 -106
  382. package/test/rehydrate.test.mjs +0 -25
  383. package/test/release-hygiene.test.mjs +0 -42
  384. package/test/repository-snapshot-view.test.mjs +0 -112
  385. package/test/responses-runner.test.mjs +0 -465
  386. package/test/runtime-activity.test.mjs +0 -98
  387. package/test/sdk-worker-contract.test.mjs +0 -72
  388. package/test/security.test.mjs +0 -252
  389. package/test/setup-planner.test.mjs +0 -74
  390. package/test/setup-runtime.test.mjs +0 -51
  391. package/test/shell.test.mjs +0 -281
  392. package/test/skills.test.mjs +0 -22
  393. package/test/smoke.mjs +0 -122
  394. package/test/telemetry.test.mjs +0 -79
  395. package/test/terminal/local-pty.mock.test.mjs +0 -153
  396. package/test/terminal-machine-identity.test.mjs +0 -88
  397. package/test/theme-portability.test.mjs +0 -14
  398. package/test/tools-search.test.mjs +0 -73
  399. package/test/unit/website-assets-bindings.test.mjs +0 -60
  400. package/test/whoami-resume.test.mjs +0 -157
@@ -1,154 +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 { spawnSync } from 'node:child_process';
6
- import test from 'node:test';
7
- import { dispatchShellLine } from '../../src/commands/shell.js';
8
- import { createLocalSession, listLocalSessions, loadLocalSession, saveLocalSession } from '../../src/lib/local-sessions.js';
9
- import { createLocalSqliteDatabaseSync } from '../../src/local/sqlite.js';
10
- import { applyRuntimeMigrationsSync } from '../../src/local/migrations.js';
11
- import { finishRuntimeRun, pruneExpiredRuntimeState, runtimeDatabasePath, startRuntimeRun } from '../../src/local/runtime-store.js';
12
-
13
- const repoRoot = path.resolve(new URL('../..', import.meta.url).pathname);
14
-
15
- function fixture(t) {
16
- const base = fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-storage-'));
17
- t.after(() => fs.rmSync(base, { recursive: true, force: true }));
18
- const home = path.join(base, 'home');
19
- const projectA = path.join(base, 'project-a');
20
- const projectB = path.join(base, 'project-b');
21
- for (const root of [projectA, projectB]) {
22
- fs.mkdirSync(path.join(root, '.agentsam'), { recursive: true });
23
- fs.writeFileSync(path.join(root, '.agentsam', 'config.json'), '{"schema_version":2}\n');
24
- }
25
- fs.mkdirSync(home);
26
- return { base, home, projectA, projectB };
27
- }
28
-
29
- test('S1: a local shell boots and migrates SQLite without cloud configuration', (t) => {
30
- const { home, projectA } = fixture(t);
31
- const env = { ...process.env, HOME: home };
32
- for (const key of ['CLOUDFLARE_API_TOKEN', 'AGENTSAM_API_KEY', 'SUPABASE_URL', 'DATABASE_URL']) delete env[key];
33
- const result = spawnSync(process.execPath, [path.join(repoRoot, 'src/cli.js'), 'shell'], {
34
- cwd: projectA, env, input: '/exit\n', encoding: 'utf8', timeout: 10_000,
35
- });
36
- assert.equal(result.status, 0, result.stderr);
37
- assert.match(result.stdout, /Interactive shell ready/);
38
- assert.equal(fs.existsSync(runtimeDatabasePath(projectA)), true);
39
- assert.equal(fs.existsSync(path.join(home, '.agentsam', 'sessions')), false);
40
- });
41
-
42
- test('S2-S4: cwd and model changes preserve project state; repository switch selects a new authority', async (t) => {
43
- const { home, projectA, projectB } = fixture(t);
44
- const child = path.join(projectA, 'src', 'agent');
45
- fs.mkdirSync(child, { recursive: true });
46
- assert.equal(runtimeDatabasePath(child), runtimeDatabasePath(projectA));
47
-
48
- const session = createLocalSession({ cwd: child, title: 'Project A' }, { home });
49
- const changedModel = saveLocalSession({ ...session, model_key: 'gemini:example' }, { home });
50
- assert.equal(changedModel.id, session.id);
51
- assert.equal(changedModel.project_root, projectA);
52
- assert.equal(loadLocalSession(session.id, { home, cwd: projectA }).model_key, 'gemini:example');
53
- assert.equal(loadLocalSession(session.id, { home, cwd: projectB }), null);
54
-
55
- const runId = await startRuntimeRun({ projectRoot: projectA, model_key: 'test:model' });
56
- let output = '';
57
- const state = { cwd: child, projectRoot: projectA, home, session: changedModel, interactive: false, write(value) { output += value; } };
58
- await dispatchShellLine('/logs', state);
59
- assert.match(output, new RegExp(runId));
60
- await dispatchShellLine(`/cd ${projectB}`, state);
61
- assert.equal(state.cwd, projectB);
62
- assert.equal(state.projectRoot, projectB);
63
- assert.notEqual(state.session.id, session.id);
64
- assert.equal(listLocalSessions({ home, cwd: projectA })[0].id, session.id);
65
- assert.equal(listLocalSessions({ home, cwd: projectB })[0].id, state.session.id);
66
- assert.equal(fs.existsSync(path.join(child, '.agentsam', 'data', 'agentsam.sqlite')), false);
67
- });
68
-
69
- test('S5: expiry cleanup removes transient digests and retains completed run receipts', async (t) => {
70
- const { projectA } = fixture(t);
71
- const runId = await startRuntimeRun({ cwd: projectA, model_key: 'test:model' });
72
- await finishRuntimeRun({ cwd: projectA, id: runId, status: 'completed' });
73
- const db = createLocalSqliteDatabaseSync(runtimeDatabasePath(projectA));
74
- db.prepare(`INSERT INTO agentsam_context_digest
75
- (id, digest_type, agent_run_id, source_hash, digest_hash, digest_text, expires_at_unix)
76
- VALUES (?, 'session', ?, 'source', 'digest', 'expired', 1)`).run('ctx_expired', runId);
77
- db.prepare('INSERT INTO agentsam_compaction_events (id, agent_run_id, expires_at_epoch) VALUES (?, ?, 1)').run('cmp_expired', runId);
78
- db.close();
79
-
80
- const pruned = await pruneExpiredRuntimeState({ cwd: projectA, nowUnix: 2 });
81
- assert.deepEqual(pruned, { digests: 1, compactions: 1, approvals_expired: 0 });
82
- const verified = createLocalSqliteDatabaseSync(runtimeDatabasePath(projectA));
83
- assert.equal(verified.prepare('SELECT status FROM agentsam_agent_run WHERE id = ?').get(runId).status, 'completed');
84
- assert.equal(verified.prepare('SELECT COUNT(*) AS n FROM agentsam_context_digest').get().n, 0);
85
- verified.close();
86
- });
87
-
88
- test('S6-S7: connected Worker bindings do not move sessions or store credential values', (t) => {
89
- const { home, projectA } = fixture(t);
90
- const workerConfig = fs.readFileSync(path.join(repoRoot, 'apps/local-studio/backend/wrangler.jsonc'), 'utf8');
91
- for (const binding of ['"d1_databases"', '"hyperdrive"', '"r2_buckets"', '"services"']) assert.match(workerConfig, new RegExp(binding));
92
- assert.doesNotMatch(workerConfig, /"durable_objects"/);
93
-
94
- const secret = 'storage_secret_do_not_persist_123';
95
- const session = createLocalSession({
96
- cwd: projectA, title: 'Safe project session', last_input: secret,
97
- provider_state: { provider: 'openai', previous_response_id: 'resp_safe', api_key: secret, messages: [{ content: secret }] },
98
- usage_snapshot: { current_context: { input_tokens: 20 }, credential: secret },
99
- last_error: { code: 'failed', message: secret },
100
- }, { home });
101
- assert.equal(session.storage.runtime, 'sqlite');
102
- assert.equal(session.storage.remote, null);
103
- assert.equal(session.storage.capabilities.remote_shared_state, false);
104
- assert.equal(session.storage.capabilities.distributed_actor_semantics, false);
105
- assert.equal(session.last_input, null);
106
- assert.equal(session.provider_state.api_key, undefined);
107
- assert.doesNotMatch(fs.readFileSync(runtimeDatabasePath(projectA), 'utf8'), new RegExp(secret));
108
- assert.equal(fs.statSync(runtimeDatabasePath(projectA)).mode & 0o777, 0o600);
109
- });
110
-
111
- test('S8: canonical migrations upgrade an older runtime database for project sessions', (t) => {
112
- const { base, home, projectA } = fixture(t);
113
- const oldMigrations = path.join(base, 'old-migrations');
114
- fs.mkdirSync(oldMigrations);
115
- fs.copyFileSync(path.join(repoRoot, 'migrations/runtime/0001_cli_runtime.sql'), path.join(oldMigrations, '0001_cli_runtime.sql'));
116
- const db = createLocalSqliteDatabaseSync(runtimeDatabasePath(projectA));
117
- assert.equal(applyRuntimeMigrationsSync(db, { migrationsDir: oldMigrations }).applied, 1);
118
- assert.equal(db.prepare("SELECT name FROM sqlite_master WHERE name = 'agentsam_project_sessions'").get(), undefined);
119
- db.close();
120
-
121
- createLocalSession({ cwd: projectA }, { home });
122
- const upgraded = createLocalSqliteDatabaseSync(runtimeDatabasePath(projectA));
123
- const migrationCount = fs.readdirSync(path.join(repoRoot, 'migrations', 'runtime'))
124
- .filter((name) => /^\d+.*\.sql$/i.test(name)).length;
125
- assert.equal(upgraded.prepare("SELECT COUNT(*) AS n FROM agentsam_schema_migrations").get().n, migrationCount);
126
- assert.ok(upgraded.prepare("SELECT name FROM sqlite_master WHERE name = 'agentsam_project_sessions'").get());
127
- upgraded.close();
128
- });
129
-
130
- test('legacy home-level JSON sessions import only into their matching project SQLite', (t) => {
131
- const { home, projectA, projectB } = fixture(t);
132
- const id = 'asess_00000000-0000-4000-8000-000000000099';
133
- const legacyDir = path.join(home, '.agentsam', 'sessions');
134
- fs.mkdirSync(legacyDir, { recursive: true });
135
- const filename = path.join(legacyDir, `${id}.json`);
136
- fs.writeFileSync(filename, JSON.stringify({
137
- schema_version: 'agentsam-local-session-v1', id, cwd: projectA,
138
- title: 'Prior work', provider_state: { provider: 'openai', api_key: 'legacy_secret' },
139
- }));
140
- assert.equal(loadLocalSession(id, { home, cwd: projectB }), null);
141
- assert.equal(fs.existsSync(runtimeDatabasePath(projectB)), false);
142
- const imported = loadLocalSession(id, { home, cwd: projectA });
143
- assert.equal(imported.project_root, projectA);
144
- assert.equal(imported.provider_state.api_key, undefined);
145
- assert.equal(fs.existsSync(filename), true);
146
- assert.doesNotMatch(fs.readFileSync(runtimeDatabasePath(projectA), 'utf8'), /legacy_secret/);
147
- });
148
-
149
- test('S9: default runtime has no Durable Object binding or dependency', () => {
150
- const pkg = JSON.parse(fs.readFileSync(path.join(repoRoot, 'package.json'), 'utf8'));
151
- assert.equal(Object.keys(pkg.dependencies || {}).some((name) => /durable.?object/i.test(name)), false);
152
- const shell = fs.readFileSync(path.join(repoRoot, 'src/commands/shell.js'), 'utf8');
153
- assert.doesNotMatch(shell, /\bDurableObject\b|\bdurable_objects\b|\bidFromName\s*\(/);
154
- });
@@ -1,44 +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 { discoverProjectStores, selectKnowledgeStore } from '../../src/knowledge/store-discovery.js';
7
- import { initRepository, readConfig } from '../../src/knowledge/config.js';
8
- import { dispatchShellLine } from '../../src/commands/shell.js';
9
-
10
- test('store discovery reads JSONC bindings without leaking credentials or selecting application storage', async () => {
11
- const root = fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-store-discovery-'));
12
- fs.writeFileSync(path.join(root, 'package.json'), '{"name":"stores"}');
13
- fs.writeFileSync(path.join(root, 'wrangler.jsonc'), `{
14
- // Existing application authority
15
- "vars": {"PASSWORD":"do-not-emit"},
16
- "d1_databases": [{"binding":"DB","database_name":"existing-app"}],
17
- "hyperdrive": [{"binding":"HYPERDRIVE","id":"existing-pool"}],
18
- "env": {"preview":{"d1_databases":[{"binding":"DB","database_name":"preview-app"}]}}
19
- }`);
20
- const result = await discoverProjectStores(root, { DATABASE_URL: 'postgres://secret:password@private/db' });
21
- assert.equal(result.candidates.find(c => c.driver === 'd1').name, 'existing-app');
22
- assert.equal(result.candidates.find(c => c.environment === 'preview').name, 'preview-app');
23
- assert.ok(result.candidates.filter(c => c.role === 'application').every(c => c.selectable === false));
24
- assert.equal(result.candidates.find(c => c.driver === 'postgres').connection_env, 'DATABASE_URL');
25
- assert.doesNotMatch(JSON.stringify(result), /password|secret|do-not-emit/);
26
- assert.equal(fs.existsSync(path.join(root, '.agentsam')), false);
27
- let output = '';
28
- await dispatchShellLine('/db sources', { cwd: root, write: s => { output += s; }, interactive: false });
29
- assert.match(output, /existing-app/);
30
- });
31
-
32
- test('knowledge selection edits existing portable config without overwriting scope or moving runtime data', () => {
33
- const root = fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-store-selection-'));
34
- fs.writeFileSync(path.join(root, 'package.json'), '{"name":"stores"}');
35
- initRepository(root, { repositoryId: 'repo:test', include: ['src'] });
36
- selectKnowledgeStore(root, 'postgres', 'MY_DATABASE_URL');
37
- assert.deepEqual(readConfig(root).scope.include, ['src']);
38
- assert.equal(readConfig(root).storage.connection_env, 'MY_DATABASE_URL');
39
- assert.equal(fs.existsSync(path.join(root, '.agentsam/data/agentsam.sqlite')), false);
40
- assert.throws(() => selectKnowledgeStore(root, 'postgres', 'postgres://password@host/db'), /connection_env/);
41
- assert.throws(() => selectKnowledgeStore(root, 'd1'), /adapter_unavailable/);
42
- selectKnowledgeStore(root, 'sqlite');
43
- assert.deepEqual(readConfig(root).storage, { driver: 'sqlite' });
44
- });
@@ -1,294 +0,0 @@
1
- /**
2
- * Product-path filesystem ↔ PTY proof.
3
- *
4
- * Exercises the same RuntimeFilesystemAdapter contract Monaco uses, plus a
5
- * real node-pty session on the SAME authorized root, with git diff evidence.
6
- *
7
- * This is not a raw /v1/fs unit test substitute for browser Monaco chrome —
8
- * it is the Monaco adapter + real PTY identity path. Browser UI automation
9
- * is layered on top when Studio is running (see receipt).
10
- */
11
-
12
- import assert from 'node:assert/strict';
13
- import { spawnSync } from 'node:child_process';
14
- import fs from 'node:fs';
15
- import os from 'node:os';
16
- import path from 'node:path';
17
- import { after, before, describe, it } from 'node:test';
18
- import { WebSocket } from 'ws';
19
- import { startLocalPtyServer } from '../../src/local-pty/server.js';
20
- import { getRepositoryFreshness } from '../../src/local-fs/freshness.js';
21
-
22
- /**
23
- * Minimal JS twin of RuntimeFilesystemAdapter (Studio Monaco path).
24
- */
25
- class RuntimeFilesystemAdapter {
26
- constructor(baseUrl, capability) {
27
- this.baseUrl = String(baseUrl).replace(/\/$/, '');
28
- this.capability = capability;
29
- }
30
-
31
- headers(json = false) {
32
- const h = {};
33
- if (json) h['Content-Type'] = 'application/json';
34
- if (this.capability) {
35
- h.Authorization = `Bearer ${this.capability}`;
36
- h['x-agentsam-workspace-capability'] = this.capability;
37
- }
38
- return h;
39
- }
40
-
41
- async read(filePath) {
42
- const u = new URL(`${this.baseUrl}/v1/fs/read`);
43
- u.searchParams.set('path', filePath);
44
- const res = await fetch(u, { headers: this.headers() });
45
- return res.json();
46
- }
47
-
48
- async write(filePath, content, expectedVersion, overwrite = false) {
49
- const res = await fetch(`${this.baseUrl}/v1/fs/write`, {
50
- method: 'POST',
51
- headers: this.headers(true),
52
- body: JSON.stringify({ path: filePath, content, expectedVersion, overwrite }),
53
- });
54
- return res.json();
55
- }
56
- }
57
-
58
- function runGit(cwd, args) {
59
- return spawnSync('git', args, { cwd, encoding: 'utf8' });
60
- }
61
-
62
- function wait(ms) {
63
- return new Promise((r) => setTimeout(r, ms));
64
- }
65
-
66
- /**
67
- * Drive a real PTY over the local WS wire: send a command, collect output.
68
- */
69
- async function ptyExec({ url, capability, cwd, command, timeoutMs = 8000 }) {
70
- const wsUrl = `${url}/?cwd=${encodeURIComponent(cwd)}&cols=100&rows=30&capability=${encodeURIComponent(capability)}`;
71
- const ws = new WebSocket(wsUrl);
72
- let buf = '';
73
- let sessionId = null;
74
- let identity = null;
75
-
76
- ws.on('message', (data) => {
77
- const text = Buffer.isBuffer(data) ? data.toString('utf8') : String(data);
78
- if (text.startsWith('{')) {
79
- try {
80
- const msg = JSON.parse(text);
81
- if (msg.type === 'session_id') sessionId = msg.session_id;
82
- if (msg.type === 'workspace_identity') {
83
- identity = msg;
84
- sessionId = msg.session_id || sessionId;
85
- }
86
- if (msg.type === 'error') buf += `\nPTY_ERROR:${msg.code}:${msg.message}\n`;
87
- return;
88
- } catch {
89
- /* fall through */
90
- }
91
- }
92
- buf += text;
93
- });
94
-
95
- await new Promise((resolve, reject) => {
96
- const t = setTimeout(() => reject(new Error('pty_connect_timeout')), 5000);
97
- ws.on('open', () => {
98
- clearTimeout(t);
99
- resolve();
100
- });
101
- ws.on('error', (err) => {
102
- clearTimeout(t);
103
- reject(err);
104
- });
105
- });
106
-
107
- // Wait for bash prompt
108
- const promptDeadline = Date.now() + 3000;
109
- while (Date.now() < promptDeadline) {
110
- if (/[$#]\s*$/.test(buf.replace(/\x1b\[[0-9;?]*[a-zA-Z]/g, '').trimEnd()) || buf.includes('bash')) break;
111
- await wait(50);
112
- }
113
- await wait(100);
114
- ws.send(`${command}\r`);
115
- const deadline = Date.now() + timeoutMs;
116
- while (Date.now() < deadline) {
117
- await wait(150);
118
- const plain = buf.replace(/\x1b\[[0-9;?]*[a-zA-Z]/g, '');
119
- if (plain.includes('MONACO_MARK_DONE') || plain.includes('diff --git') || plain.includes('+##')) {
120
- break;
121
- }
122
- }
123
- await wait(400);
124
- ws.close();
125
- return { output: buf, sessionId, identity };
126
- }
127
-
128
- describe('Studio filesystem ↔ real PTY product proof', () => {
129
- /** @type {string} */
130
- let root;
131
- /** @type {Awaited<ReturnType<typeof startLocalPtyServer>>} */
132
- let server;
133
- /** @type {RuntimeFilesystemAdapter} */
134
- let adapter;
135
- const monacoMarker = `MONACO_MARK_${Date.now()}`;
136
- const ptyMarker = `PTY_MARK_${Date.now()}`;
137
-
138
- before(async () => {
139
- root = fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-fs-e2e-'));
140
- runGit(root, ['init']);
141
- runGit(root, ['config', 'user.email', 'agentsam-e2e@local']);
142
- runGit(root, ['config', 'user.name', 'AgentSam E2E']);
143
- fs.writeFileSync(path.join(root, 'README.md'), '# disposable\n');
144
- fs.writeFileSync(path.join(root, 'NOTES.md'), 'stable\n');
145
- runGit(root, ['add', '.']);
146
- runGit(root, ['commit', '-m', 'init']);
147
-
148
- server = await startLocalPtyServer({
149
- cwd: root,
150
- port: 0,
151
- host: '127.0.0.1',
152
- shell: '/bin/bash',
153
- });
154
- assert.ok(server.capability?.capability);
155
- assert.equal(server.cwd, path.resolve(root));
156
-
157
- // Bootstrap as Studio would
158
- const boot = await fetch(server.bootstrapUrl);
159
- const claim = await boot.json();
160
- assert.equal(claim.ok, true);
161
- assert.equal(claim.root, path.resolve(root));
162
- assert.equal(claim.capability, server.capability.capability);
163
-
164
- adapter = new RuntimeFilesystemAdapter(
165
- `http://${server.host}:${server.port}`,
166
- claim.capability,
167
- );
168
- });
169
-
170
- after(async () => {
171
- if (server) await server.close().catch(() => {});
172
- fs.rmSync(root, { recursive: true, force: true });
173
- });
174
-
175
- it('rejects FS without capability', async () => {
176
- const res = await fetch(`http://${server.host}:${server.port}/v1/fs/read?path=README.md`);
177
- const body = await res.json();
178
- assert.equal(body.ok, false);
179
- assert.equal(body.code, 'WORKSPACE_CAPABILITY_REQUIRED');
180
- });
181
-
182
- it('rejects arbitrary root claim', async () => {
183
- const outside = os.tmpdir();
184
- const res = await fetch(
185
- `${server.bootstrapUrl}?root=${encodeURIComponent(outside)}`,
186
- );
187
- const body = await res.json();
188
- assert.equal(body.ok, false);
189
- assert.equal(body.code, 'WORKSPACE_ROOT_MISMATCH');
190
- });
191
-
192
- it('Monaco adapter write → real PTY git diff sees the edit', async () => {
193
- const before = await adapter.read('README.md');
194
- assert.equal(before.ok, true);
195
- const next = `${before.content}\n## ${monacoMarker}\n`;
196
- const wrote = await adapter.write('README.md', next, before.version);
197
- assert.equal(wrote.ok, true, JSON.stringify(wrote));
198
-
199
- // Disk truth
200
- const disk = fs.readFileSync(path.join(root, 'README.md'), 'utf8');
201
- assert.ok(disk.includes(monacoMarker));
202
-
203
- // Same-root PTY git diff
204
- const pty = await ptyExec({
205
- url: server.url,
206
- capability: server.capability.capability,
207
- cwd: root,
208
- command: 'git diff -- README.md; echo MONACO_MARK_DONE',
209
- });
210
- assert.ok(pty.identity, 'workspace_identity required');
211
- assert.equal(pty.identity.root, path.resolve(root));
212
- assert.equal(pty.identity.workspace_id, server.workspace_id);
213
- assert.ok(pty.sessionId || pty.identity.session_id);
214
- assert.ok(
215
- pty.output.includes(monacoMarker) || pty.output.includes('+##'),
216
- `git diff missing Monaco edit.\nOUTPUT:\n${pty.output}`,
217
- );
218
-
219
- // Persist receipt fields on the test for the final report
220
- globalThis.__AGENTSAM_FS_E2E__ = {
221
- root,
222
- workspace_id: server.workspace_id,
223
- runtimeBaseUrl: `http://${server.host}:${server.port}`,
224
- pty_session_id: pty.sessionId || pty.identity.session_id,
225
- monaco_path: 'README.md',
226
- monaco_marker: monacoMarker,
227
- git_diff_snippet: pty.output.slice(0, 1200),
228
- identity: pty.identity,
229
- };
230
- });
231
-
232
- it('PTY disk edit → adapter detects version change → stale Monaco save conflicts', async () => {
233
- const read1 = await adapter.read('NOTES.md');
234
- assert.equal(read1.ok, true);
235
- const staleVersion = read1.version;
236
-
237
- // External change (simulates PTY echo >> NOTES.md)
238
- fs.appendFileSync(path.join(root, 'NOTES.md'), `\n${ptyMarker}\n`);
239
-
240
- const read2 = await adapter.read('NOTES.md');
241
- assert.equal(read2.ok, true);
242
- assert.notEqual(read2.version, staleVersion);
243
- assert.ok(read2.content.includes(ptyMarker));
244
-
245
- // Stale Monaco save must conflict
246
- const conflict = await adapter.write('NOTES.md', 'should not land\n', staleVersion, false);
247
- assert.equal(conflict.ok, false);
248
- assert.equal(conflict.code, 'version_conflict');
249
-
250
- // Intentional overwrite still works
251
- const force = await adapter.write('NOTES.md', `${read2.content}\nforced\n`, null, true);
252
- assert.equal(force.ok, true);
253
-
254
- globalThis.__AGENTSAM_FS_E2E__ = globalThis.__AGENTSAM_FS_E2E__ || {};
255
- globalThis.__AGENTSAM_FS_E2E__.pty_path = 'NOTES.md';
256
- globalThis.__AGENTSAM_FS_E2E__.pty_marker = ptyMarker;
257
- globalThis.__AGENTSAM_FS_E2E__.stale_conflict = conflict;
258
- globalThis.__AGENTSAM_FS_E2E__.external_version_before = staleVersion;
259
- globalThis.__AGENTSAM_FS_E2E__.external_version_after = read2.version;
260
- });
261
-
262
- it('filesystem write marks repository freshness stale (path-scoped)', () => {
263
- const fresh = getRepositoryFreshness(path.resolve(root));
264
- assert.equal(fresh.ok, true);
265
- assert.ok(fresh.generation >= 1);
266
- assert.ok(fresh.stale_paths.includes('README.md') || fresh.stale_paths.includes('NOTES.md'));
267
- });
268
-
269
- it('records final proof receipt JSON', () => {
270
- const receipt = {
271
- schema: 'agentsam.fs-e2e-receipt.v1',
272
- complete: true,
273
- ...globalThis.__AGENTSAM_FS_E2E__,
274
- authorization: {
275
- binding: '127.0.0.1',
276
- capability_required: true,
277
- cors: 'studio-origin-allowlist',
278
- arbitrary_root_claim: 'rejected',
279
- },
280
- scratch_vs_filesystem: {
281
- filesystem: 'real FS + real PTY',
282
- scratch: 'virtual files + virtual shell',
283
- silent_fallback: false,
284
- },
285
- };
286
- const out = path.join(root, '.agentsam-fs-e2e-receipt.json');
287
- // root may be deleted after — write to tmp as well
288
- const durable = path.join(os.tmpdir(), `agentsam-fs-e2e-receipt-${Date.now()}.json`);
289
- fs.writeFileSync(durable, `${JSON.stringify(receipt, null, 2)}\n`);
290
- assert.ok(fs.existsSync(durable));
291
- console.log(`\nFS_E2E_RECEIPT=${durable}\n`);
292
- globalThis.__AGENTSAM_FS_E2E_RECEIPT_PATH__ = durable;
293
- });
294
- });
@@ -1,86 +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 { terminalExec } from '../../src/capabilities/terminal-exec.js';
7
- import { createCapabilityAdapter } from '../../src/agent/capability-adapter.js';
8
- import { toolApprovalKey } from '../../src/lib/execution-approvals.js';
9
-
10
- function root(t) {
11
- const value = fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-terminal-exec-'));
12
- t.after(() => fs.rmSync(value, { recursive: true, force: true }));
13
- return value;
14
- }
15
-
16
- test('terminal.exec runs a real argv process inside the runtime-owned project', async t => {
17
- const cwd = root(t);
18
- fs.mkdirSync(path.join(cwd, 'src'));
19
- const seen = [];
20
- const result = await terminalExec({
21
- cwd,
22
- relative_cwd: 'src',
23
- command: 'node',
24
- args: ['--version'],
25
- }, {
26
- env: { PATH: process.env.PATH, OPENAI_API_KEY: 'must-not-reach-child' },
27
- run: async (command, args, options) => {
28
- seen.push({ command, args, options });
29
- return { code: 0, signal: null, stdout: 'v24.0.0\n', stderr: '' };
30
- },
31
- });
32
- assert.equal(result.ok, true);
33
- assert.equal(result.cwd, path.join(cwd, 'src'));
34
- assert.equal(seen[0].options.env.OPENAI_API_KEY, undefined);
35
- assert.equal(seen[0].options.env.PATH, process.env.PATH);
36
- });
37
-
38
- test('terminal.exec expands a leading ~ in argv and cwd override (spawn never invokes a shell)', async t => {
39
- const home = os.homedir();
40
- const seen = [];
41
- const result = await terminalExec({
42
- cwd: process.cwd(),
43
- command: 'git',
44
- args: ['-C', '~/agentsam-sdk', 'status'],
45
- }, {
46
- env: { PATH: process.env.PATH },
47
- run: async (command, args, options) => {
48
- seen.push({ command, args, options });
49
- return { code: 0, signal: null, stdout: '', stderr: '' };
50
- },
51
- });
52
- assert.equal(result.ok, true);
53
- assert.equal(seen[0].args[1], path.join(home, 'agentsam-sdk'));
54
- assert.equal(seen[0].args[1].startsWith('~'), false);
55
- });
56
-
57
- test('terminal.exec leaves non-leading tildes and bare relative args untouched', async t => {
58
- const seen = [];
59
- await terminalExec({
60
- cwd: process.cwd(),
61
- command: 'echo',
62
- args: ['user~name', 'plain-arg'],
63
- }, {
64
- env: { PATH: process.env.PATH },
65
- run: async (command, args, options) => {
66
- seen.push({ command, args, options });
67
- return { code: 0, signal: null, stdout: '', stderr: '' };
68
- },
69
- });
70
- assert.deepEqual(seen[0].args, ['user~name', 'plain-arg']);
71
- });
72
-
73
- test('terminal.exec rejects shell strings and working-directory escape', async t => {
74
- const cwd = root(t);
75
- await assert.rejects(terminalExec({ cwd, command: 'git status', args: [] }), /pathless_executable/);
76
- await assert.rejects(terminalExec({ cwd, relative_cwd: '..', command: 'git', args: ['status'] }), /outside_project/);
77
- });
78
-
79
- test('terminal.exec is model-callable and approvals are command-specific', () => {
80
- const adapter = createCapabilityAdapter();
81
- const descriptor = adapter.toolDescriptors().find((row) => row.name === 'terminal.exec');
82
- assert.ok(descriptor);
83
- assert.equal(descriptor.risk, 'write');
84
- assert.equal(toolApprovalKey('terminal.exec', { command: 'git' }), 'terminal.exec:git');
85
- assert.equal(toolApprovalKey('terminal.exec', { command: 'npm' }), 'terminal.exec:npm');
86
- });