@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,309 +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 { collectModelsStatus, renderModelsStatus } from '../src/commands/models.js';
7
-
8
- function response(body, status = 200) {
9
- return { ok: status >= 200 && status < 300, status, async json() { return body; } };
10
- }
11
-
12
- function tempHome(t) {
13
- const home = fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-model-home-'));
14
- t.after(() => fs.rmSync(home, { recursive: true, force: true }));
15
- return home;
16
- }
17
-
18
- test('model inventory reports configured API providers without exposing credentials', async t => {
19
- const home = tempHome(t);
20
- const status = await collectModelsStatus({
21
- home,
22
- discoverRemote: false,
23
- env: {
24
- OPENAI_API_KEY: 'secret-openai', GEMINI_API_KEY: '', XAI_API_KEY: 'secret-xai', ANTHROPIC_API_KEY: 'secret-anthropic', CLOUDFLARE_API_TOKEN: 'secret-cf', CLOUDFLARE_ACCOUNT_ID: '33333333333333333333333333333333',
25
- OLLAMA_BASE_URL: 'http://127.0.0.1:11434', OLLAMA_MODEL: 'qwen:test', OLLAMA_EMBED_MODEL: 'embed:test',
26
- },
27
- fetchImpl: async () => response({ models: [{ name: 'qwen:test' }, { name: 'embed:test' }] }),
28
- });
29
- assert.equal(status.providers.find((row) => row.id === 'openai').configured, true);
30
- assert.equal(status.providers.find((row) => row.id === 'gemini').configured, false);
31
- assert.equal(status.providers.find((row) => row.id === 'grok').configured, true);
32
- assert.equal(status.providers.find((row) => row.id === 'anthropic').configured, true);
33
- assert.equal(status.providers.find((row) => row.id === 'cloudflare').configured, true);
34
- assert.equal(status.local.online, true);
35
- assert.deepEqual(status.local.models.map((row) => row.name), ['qwen:test', 'embed:test']);
36
- const rendered = renderModelsStatus(status);
37
- assert.match(rendered, /OpenAI/);
38
- assert.match(rendered, /qwen:test/);
39
- assert.doesNotMatch(rendered, /secret-openai|secret-xai|secret-anthropic|secret-cf/);
40
- });
41
-
42
- test('static/reference metadata never invents hosted model availability', async t => {
43
- const home = tempHome(t);
44
- const status = await collectModelsStatus({
45
- home,
46
- env: { OPENAI_API_KEY: 'secret-openai', OLLAMA_BASE_URL: 'http://127.0.0.1:11434' },
47
- fetchImpl: async () => response({ models: [] }),
48
- providerFetchImpl: async () => response({ data: [{ id: 'some-other-model' }] }),
49
- });
50
-
51
- assert.deepEqual(status.availableModels.map((row) => row.provider_model_id), ['some-other-model']);
52
- const referenceOnly = status.catalogModels.find((row) => row.provider_model_id === 'gpt-6-astra');
53
- assert.equal(referenceOnly?.availability, 'unverified');
54
- assert.equal(referenceOnly?.availability_source, 'sdk_reference');
55
- });
56
-
57
- test('exact hosted model availability is verified against the provider inventory', async t => {
58
- const home = tempHome(t);
59
- const status = await collectModelsStatus({
60
- home,
61
- env: { OPENAI_API_KEY: 'secret-openai', OLLAMA_BASE_URL: 'http://127.0.0.1:11434' },
62
- fetchImpl: async () => response({ models: [] }),
63
- providerFetchImpl: async () => response({ data: [{ id: 'gpt-6-astra' }, { id: 'some-other-model' }] }),
64
- });
65
- assert.equal(status.discovery.openai.ok, true);
66
- assert.equal(status.discovery.openai.returnedModelCount, 2);
67
- assert.deepEqual(status.availableModels.map((row) => row.provider_model_id), ['gpt-6-astra', 'some-other-model']);
68
- assert.equal(status.availableModels[0].availability_source, 'provider_api');
69
- assert.equal(status.availableModels[0].context_window_source, 'sdk_reference');
70
- });
71
-
72
-
73
-
74
-
75
- test('Gemini and xAI discovery keep per-key limits from provider metadata', async t => {
76
- const home = tempHome(t);
77
- const seen = [];
78
- const status = await collectModelsStatus({
79
- home,
80
- env: {
81
- GEMINI_API_KEY: 'gem-key',
82
- XAI_API_KEY: 'xai-key',
83
- OLLAMA_BASE_URL: 'http://127.0.0.1:11434',
84
- },
85
- fetchImpl: async () => response({ models: [] }),
86
- providerFetchImpl: async (url, options) => {
87
- seen.push(url);
88
- if (url.includes('generativelanguage.googleapis.com')) {
89
- return response({ models: [{
90
- name: 'models/gemini-test',
91
- baseModelId: 'gemini-test',
92
- displayName: 'Gemini Test',
93
- inputTokenLimit: 123456,
94
- outputTokenLimit: 8192,
95
- supportedGenerationMethods: ['generateContent'],
96
- thinking: true,
97
- }] });
98
- }
99
- if (url.includes('api.x.ai')) {
100
- return response({ data: [{
101
- id: 'grok-test',
102
- context_length: 256000,
103
- prompt_text_token_price: 1000,
104
- cached_prompt_text_token_price: 500,
105
- completion_text_token_price: 4000,
106
- }] });
107
- }
108
- throw new Error('unexpected URL ' + url);
109
- },
110
- });
111
-
112
- const gemini = status.providerModels.gemini[0];
113
- assert.equal(gemini.provider_model_id, 'gemini-test');
114
- assert.equal(gemini.context_window, 123456);
115
- assert.equal(gemini.context_window_source, 'provider_api');
116
- assert.deepEqual(gemini.reasoning_efforts, ['auto', 'low', 'medium', 'high']);
117
-
118
- const grok = status.providerModels.grok[0];
119
- assert.equal(grok.provider_model_id, 'grok-test');
120
- assert.equal(grok.context_window, 256000);
121
- assert.equal(grok.pricing.input, 1);
122
- assert.equal(grok.pricing.output, 4);
123
- assert.equal(seen.some((url) => url.includes('generativelanguage.googleapis.com')), true);
124
- assert.equal(seen.some((url) => url.includes('api.x.ai')), true);
125
- });
126
-
127
-
128
- test('Cloudflare discovery is scoped to the loaded account and surfaces text-generation + embeddings', async t => {
129
- const seen = [];
130
- const home = tempHome(t);
131
- const status = await collectModelsStatus({
132
- home,
133
- curateWorkersAi: false,
134
- env: { CLOUDFLARE_API_TOKEN: 'secret-cf', CLOUDFLARE_ACCOUNT_ID: '44444444444444444444444444444444', OLLAMA_BASE_URL: 'http://127.0.0.1:11434' },
135
- fetchImpl: async () => response({ models: [] }),
136
- providerFetchImpl: async (url, options) => {
137
- seen.push({ url, auth: options.headers.authorization });
138
- return response({ success: true, result: [
139
- { name: '@cf/qwen/code', task: { name: 'Text Generation' }, description: 'coding' },
140
- { name: '@cf/baai/embed', task: { name: 'Text Embeddings' }, description: 'embeddings' },
141
- ] });
142
- },
143
- });
144
- assert.equal(seen.length, 1);
145
- assert.match(seen[0].url, /accounts\/44444444444444444444444444444444\/ai\/models\/search$/);
146
- assert.equal(status.discovery.cloudflare.ok, true);
147
- assert.equal(status.discovery.cloudflare.returnedModelCount, 2);
148
- assert.deepEqual(
149
- status.providerModels.cloudflare.map((row) => row.provider_model_id).sort(),
150
- ['@cf/baai/embed', '@cf/qwen/code'],
151
- );
152
- const embed = status.providerModels.cloudflare.find((row) => row.provider_model_id === '@cf/baai/embed');
153
- const qwen = status.providerModels.cloudflare.find((row) => row.provider_model_id === '@cf/qwen/code');
154
- assert.equal(qwen.availability_source, 'provider_api');
155
- assert.equal(qwen.context_window_source, 'unknown');
156
- const rendered = renderModelsStatus(status);
157
- assert.match(rendered, /@cf\/qwen\/code/);
158
- assert.match(rendered, /@cf\/baai\/embed/);
159
- assert.doesNotMatch(rendered, /secret-cf/);
160
- });
161
-
162
- test('Cursor participates in machine inventory when CURSOR_API_KEY is configured', async t => {
163
- const home = tempHome(t);
164
- const seen = [];
165
- const status = await collectModelsStatus({
166
- home,
167
- env: {
168
- CURSOR_API_KEY: 'cursor-secret-key',
169
- OLLAMA_BASE_URL: 'http://127.0.0.1:11434',
170
- },
171
- fetchImpl: async () => response({ models: [] }),
172
- providerFetchImpl: async (url, options) => {
173
- seen.push({ url, auth: options?.headers?.authorization });
174
- if (String(url).includes('api.cursor.com')) {
175
- return response({
176
- items: [
177
- { id: 'composer-2.5', displayName: 'Composer 2.5', parameters: [] },
178
- { id: 'gpt-5.6-sol', displayName: 'GPT-5.6 Sol', parameters: [{ id: 'reasoning', values: [{ value: 'high' }] }] },
179
- ],
180
- });
181
- }
182
- throw new Error('unexpected URL ' + url);
183
- },
184
- });
185
-
186
- const cursor = status.providers.find((row) => row.id === 'cursor');
187
- assert.equal(cursor?.configured, true);
188
- assert.equal(status.discovery.cursor.ok, true);
189
- assert.equal(status.discovery.cursor.returnedModelCount, 2);
190
- assert.equal(seen.length, 1);
191
- assert.match(seen[0].url, /api\.cursor\.com\/v1\/models/);
192
- assert.match(seen[0].auth, /Bearer cursor-secret-key/);
193
- assert.deepEqual(
194
- status.availableModels.filter((row) => row.provider === 'cursor').map((row) => row.provider_model_id),
195
- ['composer-2.5', 'gpt-5.6-sol'],
196
- );
197
- const rendered = renderModelsStatus(status);
198
- assert.match(rendered, /Cursor/);
199
- assert.match(rendered, /composer-2\.5/);
200
- assert.doesNotMatch(rendered, /cursor-secret-key/);
201
- });
202
-
203
- test('missing Cursor credential skips discovery and does not fall back to another provider', async t => {
204
- const home = tempHome(t);
205
- const seen = [];
206
- const status = await collectModelsStatus({
207
- home,
208
- env: {
209
- OPENAI_API_KEY: 'secret-openai',
210
- OLLAMA_BASE_URL: 'http://127.0.0.1:11434',
211
- },
212
- fetchImpl: async () => response({ models: [] }),
213
- providerFetchImpl: async (url) => {
214
- seen.push(url);
215
- if (String(url).includes('api.openai.com')) return response({ data: [{ id: 'gpt-test' }] });
216
- if (String(url).includes('api.cursor.com')) throw new Error('cursor must not be called');
217
- return response({ data: [] });
218
- },
219
- });
220
- assert.equal(status.providers.find((row) => row.id === 'cursor')?.configured, false);
221
- assert.equal(status.discovery.cursor.attempted, false);
222
- assert.equal(seen.some((url) => String(url).includes('api.cursor.com')), false);
223
- assert.equal(status.availableModels.some((row) => row.provider === 'cursor'), false);
224
- assert.equal(status.availableModels.some((row) => row.provider === 'openai'), true);
225
- });
226
-
227
- test('Cursor discovery failure stays attached to Cursor and does not invent OpenAI models', async t => {
228
- const home = tempHome(t);
229
- const status = await collectModelsStatus({
230
- home,
231
- env: {
232
- CURSOR_API_KEY: 'bad-cursor-key',
233
- OLLAMA_BASE_URL: 'http://127.0.0.1:11434',
234
- },
235
- fetchImpl: async () => response({ models: [] }),
236
- providerFetchImpl: async (url) => {
237
- if (String(url).includes('api.cursor.com')) {
238
- return { ok: false, status: 401, async json() { return { error: 'unauthorized' }; } };
239
- }
240
- throw new Error('unexpected URL ' + url);
241
- },
242
- });
243
- assert.equal(status.providers.find((row) => row.id === 'cursor')?.configured, true);
244
- assert.equal(status.discovery.cursor.ok, false);
245
- assert.ok(status.discovery.cursor.error);
246
- assert.equal((status.providerModels.cursor || []).length, 0);
247
- assert.equal(status.availableModels.some((row) => row.provider === 'openai'), false);
248
- });
249
-
250
- test('Workers AI curated allowlist intersects live Cloudflare discovery', async t => {
251
- const home = tempHome(t);
252
- const status = await collectModelsStatus({
253
- home,
254
- curateWorkersAi: true,
255
- env: { CLOUDFLARE_API_TOKEN: 'secret-cf', CLOUDFLARE_ACCOUNT_ID: '44444444444444444444444444444444', OLLAMA_BASE_URL: 'http://127.0.0.1:11434' },
256
- fetchImpl: async () => response({ models: [] }),
257
- providerFetchImpl: async () => response({
258
- success: true,
259
- result: [
260
- { name: '@cf/qwen/qwen2.5-coder-32b-instruct', task: { name: 'Text Generation' } },
261
- { name: '@cf/meta/llama-3.2-1b-instruct', task: { name: 'Text Generation' } },
262
- { name: '@cf/openai/gpt-oss-120b', task: { name: 'Text Generation' } },
263
- { name: '@cf/baai/bge-base-en-v1.5', task: { name: 'Text Embeddings' } },
264
- ],
265
- }),
266
- });
267
- // Chat allowlist applies to Text Generation; Text Embeddings always pass (Vectorize lane).
268
- assert.deepEqual(
269
- status.providerModels.cloudflare.map((row) => row.provider_model_id).sort(),
270
- ['@cf/baai/bge-base-en-v1.5', '@cf/openai/gpt-oss-120b', '@cf/qwen/qwen2.5-coder-32b-instruct'],
271
- );
272
- assert.equal(status.discovery.cloudflare.curation, 'agentsam_workers_ai_allowlist');
273
- });
274
-
275
- test('studio vault credential plane never reads machine env when resolver is injected', async t => {
276
- const home = tempHome(t);
277
- const status = await collectModelsStatus({
278
- home,
279
- credentialPlane: 'studio_vault',
280
- includeLocal: false,
281
- env: { OPENAI_API_KEY: 'machine-must-not-be-used', CURSOR_API_KEY: 'machine-cursor' },
282
- resolveCredential: async (providerId) => {
283
- if (providerId === 'gemini') {
284
- return { configured: true, value: 'vault-gemini', source: 'user_vault', env: 'GEMINI_API_KEY' };
285
- }
286
- return { configured: false, value: '', source: null, error: null };
287
- },
288
- fetchImpl: async () => response({ models: [] }),
289
- providerFetchImpl: async (url) => {
290
- if (String(url).includes('generativelanguage.googleapis.com') && String(url).includes('vault-gemini')) {
291
- return response({
292
- models: [{
293
- name: 'models/gemini-vault',
294
- baseModelId: 'gemini-vault',
295
- displayName: 'Vault Gemini',
296
- inputTokenLimit: 1000,
297
- supportedGenerationMethods: ['generateContent'],
298
- }],
299
- });
300
- }
301
- throw new Error('machine providers must not be discovered: ' + url);
302
- },
303
- });
304
- assert.equal(status.credential_plane, 'studio_vault');
305
- assert.equal(status.providers.find((row) => row.id === 'openai')?.configured, false);
306
- assert.equal(status.providers.find((row) => row.id === 'gemini')?.configured, true);
307
- assert.equal(status.providers.find((row) => row.id === 'gemini')?.source, 'user_vault');
308
- assert.deepEqual(status.availableModels.map((row) => row.provider_model_id), ['gemini-vault']);
309
- });
@@ -1,29 +0,0 @@
1
- import assert from 'node:assert/strict';
2
- import fs from 'node:fs';
3
- import path from 'node:path';
4
- import { describe, it } from 'node:test';
5
- import { spawnSync } from 'node:child_process';
6
- import { fileURLToPath } from 'node:url';
7
-
8
- const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
9
- const lockPath = path.join(root, 'apps/local-studio/package-lock.json');
10
-
11
- describe('local-studio npm 10 lockfile', () => {
12
- it('pins lru-cache@11.5.2 so Cloudflare npm ci can resolve it', () => {
13
- const lock = JSON.parse(fs.readFileSync(lockPath, 'utf8'));
14
- assert.equal(lock.lockfileVersion, 3);
15
- const pkgs = lock.packages || {};
16
- const hits = Object.entries(pkgs).filter(([key, meta]) => key.includes('lru-cache') && meta.version === '11.5.2');
17
- assert.ok(hits.length >= 1, 'Missing: lru-cache@11.5.2 from lock file');
18
- const [, meta] = hits[0];
19
- assert.match(meta.resolved || '', /lru-cache-11\.5\.2\.tgz/);
20
- assert.ok(meta.integrity);
21
- });
22
-
23
- it('verify-npm10-lock script exits 0 against the current lock', () => {
24
- const script = path.join(root, 'apps/local-studio/scripts/verify-npm10-lock.mjs');
25
- const r = spawnSync(process.execPath, [script], { encoding: 'utf8' });
26
- assert.equal(r.status, 0, r.stderr || r.stdout);
27
- assert.match(r.stdout, /lru-cache@11\.5\.2/);
28
- });
29
- });
@@ -1,137 +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 {
7
- OLLAMA_DEFAULTS,
8
- ollamaInstallPlan,
9
- parseOllamaArgs,
10
- probeOllama,
11
- probeOllamaModel,
12
- resolveOllamaConfig,
13
- updateProjectOllamaConfig,
14
- upsertOllamaEnvFile,
15
- } from '../src/commands/ollama.js';
16
- import { createProjectManifest } from '../src/lib/project-config.js';
17
-
18
- test('Ollama defaults are local-only and match the SDK local-dev contract', () => {
19
- assert.deepEqual(OLLAMA_DEFAULTS, {
20
- baseUrl: 'http://127.0.0.1:11434',
21
- model: 'qwen2.5-coder',
22
- embedModel: 'mxbai-embed-large',
23
- });
24
- assert.deepEqual(resolveOllamaConfig({}, {}), OLLAMA_DEFAULTS);
25
- });
26
-
27
- test('Ollama endpoints normalize host-only values and honor AgentSam precedence', () => {
28
- assert.equal(resolveOllamaConfig({}, { OLLAMA_HOST: '0.0.0.0:11434' }).baseUrl, 'http://127.0.0.1:11434');
29
- assert.equal(resolveOllamaConfig({}, { OLLAMA_HOST: '127.0.0.1:11434' }).baseUrl, 'http://127.0.0.1:11434');
30
- assert.equal(resolveOllamaConfig({}, { OLLAMA_HOST: 'localhost:11434' }).baseUrl, 'http://localhost:11434');
31
- assert.equal(resolveOllamaConfig({}, { OLLAMA_HOST: 'http://localhost:11434' }).baseUrl, 'http://localhost:11434');
32
-
33
- assert.equal(resolveOllamaConfig({}, {
34
- AGENTSAM_OLLAMA_ENDPOINT: '127.0.0.1:2244',
35
- OLLAMA_BASE_URL: 'localhost:3344',
36
- OLLAMA_HOST: '0.0.0.0:4444',
37
- }).baseUrl, 'http://127.0.0.1:2244');
38
-
39
- assert.equal(resolveOllamaConfig({}, {
40
- OLLAMA_BASE_URL: 'localhost:3344',
41
- OLLAMA_HOST: '0.0.0.0:4444',
42
- }).baseUrl, 'http://localhost:3344');
43
-
44
- assert.equal(resolveOllamaConfig({}, {
45
- OLLAMA_HOST: '0.0.0.0:4444',
46
- }).baseUrl, 'http://127.0.0.1:4444');
47
- });
48
-
49
- test('Ollama setup args require explicit install/pull/start opt-ins', () => {
50
- assert.deepEqual(parseOllamaArgs(['setup']), {
51
- command: 'setup',
52
- cwd: process.cwd(),
53
- envFile: '',
54
- baseUrl: '',
55
- model: '',
56
- embedModel: '',
57
- install: false,
58
- start: false,
59
- pull: false,
60
- json: false,
61
- });
62
- const opted = parseOllamaArgs(['setup', '--install', '--start', '--pull', '--json']);
63
- assert.equal(opted.install, true);
64
- assert.equal(opted.start, true);
65
- assert.equal(opted.pull, true);
66
- assert.equal(opted.json, true);
67
- });
68
-
69
- test('setup env writer updates only canonical OLLAMA keys and preserves other config', () => {
70
- const root = fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-ollama-'));
71
- const envFile = path.join(root, '.env');
72
- fs.writeFileSync(envFile, 'EXISTING=value\nOLLAMA_MODEL=old\n');
73
- upsertOllamaEnvFile(envFile, OLLAMA_DEFAULTS);
74
- const text = fs.readFileSync(envFile, 'utf8');
75
- assert.match(text, /^EXISTING=value$/m);
76
- assert.match(text, /^OLLAMA_BASE_URL=http:\/\/127\.0\.0\.1:11434$/m);
77
- assert.match(text, /^OLLAMA_MODEL=qwen2\.5-coder$/m);
78
- assert.match(text, /^OLLAMA_EMBED_MODEL=mxbai-embed-large$/m);
79
- assert.equal((text.match(/^OLLAMA_MODEL=/gm) || []).length, 1);
80
- });
81
-
82
- test('project config records only portable Ollama capability metadata', () => {
83
- const root = fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-ollama-config-'));
84
- fs.mkdirSync(path.join(root, '.agentsam'));
85
- fs.writeFileSync(path.join(root, '.agentsam', 'config.json'), `${JSON.stringify(createProjectManifest({ projectName: 'demo', repositoryId: 'local:demo' }), null, 2)}\n`);
86
- const filename = updateProjectOllamaConfig(root, OLLAMA_DEFAULTS);
87
- const config = JSON.parse(fs.readFileSync(filename, 'utf8'));
88
- assert.equal(config.models.local.provider, 'ollama');
89
- assert.equal(config.models.local.base_url_env, 'OLLAMA_BASE_URL');
90
- assert.equal(config.models.local.model_env, 'OLLAMA_MODEL');
91
- assert.equal(config.models.local.embed_model_env, 'OLLAMA_EMBED_MODEL');
92
- assert.equal(JSON.stringify(config).includes('127.0.0.1'), false);
93
- assert.equal(JSON.stringify(config).includes('qwen2.5-coder'), false);
94
- assert.equal(JSON.stringify(config).includes('token'), false);
95
- });
96
-
97
- test('status probe recognizes configured chat and embedding models', async () => {
98
- const fakeFetch = async () => new Response(JSON.stringify({ models: [
99
- { name: 'qwen2.5-coder:latest' },
100
- { name: 'mxbai-embed-large:latest' },
101
- ] }), { status: 200, headers: { 'content-type': 'application/json' } });
102
- const status = await probeOllama(OLLAMA_DEFAULTS, fakeFetch);
103
- assert.equal(status.online, true);
104
- assert.equal(status.chat_ready, true);
105
- assert.equal(status.embed_ready, true);
106
- });
107
-
108
- test('local model metadata is accepted only after Ollama itself verifies the model', async () => {
109
- let seenBody = null;
110
- const fakeFetch = async (url, init) => {
111
- assert.match(url, /\/api\/show$/);
112
- seenBody = JSON.parse(init.body);
113
- return new Response(JSON.stringify({
114
- model_info: { 'qwen2.context_length': 32768 },
115
- capabilities: ['completion', 'tools'],
116
- details: { family: 'qwen2' },
117
- }), { status: 200, headers: { 'content-type': 'application/json' } });
118
- };
119
-
120
- const result = await probeOllamaModel('qwen2.5-coder', OLLAMA_DEFAULTS, fakeFetch);
121
- assert.equal(seenBody.model, 'qwen2.5-coder');
122
- assert.equal(result.ok, true);
123
- assert.equal(result.context_window, 32768);
124
- assert.equal(result.context_window_source, 'local_runtime');
125
- assert.deepEqual(result.capabilities, ['completion', 'tools']);
126
- });
127
-
128
- test('automatic install plans use local package managers, never a remote shell script', () => {
129
- assert.deepEqual(ollamaInstallPlan('darwin', { brew: true }), {
130
- command: 'brew', args: ['install', 'ollama'], manager: 'homebrew',
131
- });
132
- assert.equal(ollamaInstallPlan('linux', { brew: false }), null);
133
- assert.equal(ollamaInstallPlan('darwin', { brew: false }), null);
134
- const win = ollamaInstallPlan('win32', { winget: true });
135
- assert.equal(win.command, 'winget');
136
- assert.equal(win.args.includes('Ollama.Ollama'), true);
137
- });
@@ -1,64 +0,0 @@
1
- import test from 'node:test';
2
- import assert from 'node:assert/strict';
3
- import { PassThrough } from 'node:stream';
4
- import { browserCommand, promptToOpenUrl } from '../src/lib/open-url.js';
5
-
6
- test('browserCommand uses argv-safe platform launchers', () => {
7
- assert.deepEqual(browserCommand('https://inneranimalmedia.com/auth', 'darwin'), {
8
- command: 'open',
9
- args: ['https://inneranimalmedia.com/auth'],
10
- });
11
- assert.deepEqual(browserCommand('https://inneranimalmedia.com/auth', 'linux'), {
12
- command: 'xdg-open',
13
- args: ['https://inneranimalmedia.com/auth'],
14
- });
15
- assert.deepEqual(browserCommand('https://inneranimalmedia.com/auth', 'win32'), {
16
- command: 'cmd',
17
- args: ['/c', 'start', '', 'https://inneranimalmedia.com/auth'],
18
- });
19
- });
20
-
21
- test('browserCommand rejects non-http protocols', () => {
22
- assert.throws(() => browserCommand('file:///tmp/example', 'darwin'), /Unsupported URL protocol/);
23
- assert.throws(() => browserCommand('javascript:alert(1)', 'darwin'), /Unsupported URL protocol/);
24
- });
25
-
26
- test('promptToOpenUrl stays non-interactive when stdin is not a TTY', async () => {
27
- const input = new PassThrough();
28
- const output = new PassThrough();
29
- let text = '';
30
- output.on('data', chunk => { text += chunk.toString(); });
31
- let opened = false;
32
- const result = await promptToOpenUrl('https://www.blender.org/download/', {
33
- input,
34
- output,
35
- openImpl: () => { opened = true; },
36
- });
37
- assert.equal(result.interactive, false);
38
- assert.equal(result.opened, false);
39
- assert.equal(opened, false);
40
- assert.match(text, /https:\/\/www\.blender\.org\/download\//);
41
- assert.match(text, /Open the URL above in a browser/);
42
- });
43
-
44
- test('promptToOpenUrl waits for Enter before opening in a TTY', async () => {
45
- const input = new PassThrough();
46
- const output = new PassThrough();
47
- input.isTTY = true;
48
- output.isTTY = true;
49
- let text = '';
50
- output.on('data', chunk => { text += chunk.toString(); });
51
- let openedUrl = null;
52
- const pending = promptToOpenUrl('https://inneranimalmedia.com/dashboard', {
53
- input,
54
- output,
55
- openImpl: url => { openedUrl = url; },
56
- });
57
- input.write('\n');
58
- const result = await pending;
59
- assert.equal(result.interactive, true);
60
- assert.equal(result.opened, true);
61
- assert.equal(openedUrl, 'https://inneranimalmedia.com/dashboard');
62
- assert.match(text, /Press ENTER to open/);
63
- assert.match(text, /Browser opened/);
64
- });