@inneranimalmedia/agentsam-sdk 2.6.7 → 2.6.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (318) hide show
  1. package/README.md +37 -0
  2. package/docs/REPO_FILE_MAP.txt +132 -0
  3. package/migrations/d1/0018_goap_control_plane_remaster.sql +40 -0
  4. package/migrations/d1/0019_agentsam_agent_run_plan_todo.sql +14 -0
  5. package/migrations/d1/README_PORTABLE_CONTROL_PLANE.md +20 -9
  6. package/migrations/runtime/0002_goap_blackboard_v1.sql +15 -0
  7. package/migrations/runtime/0004_agent_run_plan_linkage.sql +8 -0
  8. package/native/agentsam-machine/cli/Cargo.toml +8 -1
  9. package/native/agentsam-machine/cli/README.md +21 -0
  10. package/native/agentsam-machine/core/Cargo.toml +7 -0
  11. package/native/agentsam-machine/core/README.md +14 -0
  12. package/native/agentsam-machine/core/build.rs +33 -0
  13. package/native/agentsam-machine/core/contracts/source-types.v1.json +353 -0
  14. package/native/agentsam-machine/core/src/lib.rs +6 -0
  15. package/native/agentsam-machine/core/src/source_types.rs +2 -2
  16. package/package.json +16 -6
  17. package/packages/agentsam-errors/package.json +1 -1
  18. package/packages/agentsam-errors/src/index.js +1 -0
  19. package/packages/agentsam-errors/src/tool.js +56 -0
  20. package/packages/agentsam-errors/test/tool.test.mjs +58 -0
  21. package/packages/agentsam-goap/README.md +52 -0
  22. package/packages/agentsam-goap/package.json +37 -0
  23. package/packages/agentsam-goap/src/adapters/d1-sqlite.js +570 -0
  24. package/packages/agentsam-goap/src/adapters/memory.js +199 -0
  25. package/packages/agentsam-goap/src/contracts.js +226 -0
  26. package/packages/agentsam-goap/src/control-plane.js +112 -0
  27. package/packages/agentsam-goap/src/errors.js +157 -0
  28. package/packages/agentsam-goap/src/index.js +5 -0
  29. package/packages/agentsam-goap/src/world.js +202 -0
  30. package/packages/agentsam-goap/test/goap-control-plane.test.mjs +245 -0
  31. package/packages/agentsam-goap/test/world.test.mjs +79 -0
  32. package/packages/agentsam-nav/dist/Nav.d.ts +43 -0
  33. package/packages/agentsam-nav/dist/NavCollapsible.d.ts +10 -0
  34. package/packages/agentsam-nav/dist/NavContent.d.ts +2 -0
  35. package/packages/agentsam-nav/dist/NavFooter.d.ts +2 -0
  36. package/packages/agentsam-nav/dist/NavGroup.d.ts +3 -0
  37. package/packages/agentsam-nav/dist/NavHeader.d.ts +2 -0
  38. package/packages/agentsam-nav/dist/NavMenu.d.ts +22 -0
  39. package/packages/agentsam-nav/dist/NavProvider.d.ts +35 -0
  40. package/packages/agentsam-nav/dist/NavTrigger.d.ts +2 -0
  41. package/packages/agentsam-nav/dist/Surfaces.d.ts +41 -0
  42. package/packages/agentsam-nav/dist/browser.d.ts +11 -0
  43. package/packages/agentsam-nav/dist/browser.global.js +135 -0
  44. package/packages/agentsam-nav/dist/browser.js +7290 -0
  45. package/packages/agentsam-nav/dist/contracts.d.ts +76 -0
  46. package/packages/agentsam-nav/dist/index.d.ts +11 -0
  47. package/packages/agentsam-nav/dist/index.js +7291 -0
  48. package/packages/agentsam-nav/dist/legacy.css +83 -0
  49. package/packages/agentsam-nav/dist/shell.css +113 -0
  50. package/packages/agentsam-nav/dist/theme.css +113 -0
  51. package/packages/agentsam-nav/dist/utils.d.ts +1 -0
  52. package/packages/agentsam-repository/src/goap.js +13 -14
  53. package/packages/agentsam-repository/src/goap.js.bak-20260922011251 +670 -0
  54. package/packages/agentsam-repository/src/tickets.js +15 -22
  55. package/packages/agentsam-repository/test/goap-tickets-workspace-state.test.mjs +19 -8
  56. package/packages/connectors/cloudflare/package.json +3 -1
  57. package/packages/identity/tests/lane1-packed-consumer.test.mjs +1 -1
  58. package/python/agentsam_sdk/repository/intelligence/discovery.py +27 -2
  59. package/python/agentsam_sdk/repository/intelligence/git.py +4 -0
  60. package/python/tests/test_repository_intelligence.py +30 -0
  61. package/src/cli/command-catalog.js +2 -1
  62. package/src/cli.js +10 -1
  63. package/src/commands/goap-world.js +134 -0
  64. package/src/commands/goap.js +11 -4
  65. package/src/commands/machine-binary.js +33 -27
  66. package/src/commands/machine-runtime.js +266 -0
  67. package/src/commands/machine.js +122 -51
  68. package/src/commands/package.js +530 -0
  69. package/src/commands/plan-ledger.js +370 -0
  70. package/src/commands/plan.js +183 -0
  71. package/src/commands/skill.js +78 -17
  72. package/src/knowledge/source.js +1 -1
  73. package/src/lib/slash-commands.js +1 -1
  74. package/src/local/runtime-store.js +24 -2
  75. package/src/local/sqlite.js +17 -0
  76. package/src/sam/operations/package-audit.js +41 -0
  77. package/src/sam/seed.js +2 -0
  78. package/skills/grok-auth/SKILL.md +0 -110
  79. package/skills/grok-auth/agentsam.skill.json +0 -25
  80. package/skills/grok-auth/references/grok-identity.md +0 -64
  81. package/skills/grok-auth/references/per-user-data.md +0 -49
  82. package/skills/grok-auth/references/prewired-and-env.md +0 -54
  83. package/skills/grok-auth/references/session-ui.md +0 -133
  84. package/skills/grok-auth/references/sign-in-methods.md +0 -55
  85. package/skills/grok-auth/references/wiring.md +0 -71
  86. package/skills/grok-building-games/SKILL.md +0 -213
  87. package/skills/grok-building-games/agentsam.skill.json +0 -25
  88. package/skills/grok-building-games/references/3d-libs.md +0 -64
  89. package/skills/grok-building-games/references/ai-pathfinding.md +0 -122
  90. package/skills/grok-building-games/references/audio.md +0 -129
  91. package/skills/grok-building-games/references/babylon.md +0 -202
  92. package/skills/grok-building-games/references/collision-physics.md +0 -122
  93. package/skills/grok-building-games/references/ecs-architecture.md +0 -111
  94. package/skills/grok-building-games/references/game-feel-juice.md +0 -110
  95. package/skills/grok-building-games/references/genres/board-card-chess.md +0 -89
  96. package/skills/grok-building-games/references/genres/endless-runner.md +0 -83
  97. package/skills/grok-building-games/references/genres/fps.md +0 -105
  98. package/skills/grok-building-games/references/genres/platformer-2d.md +0 -97
  99. package/skills/grok-building-games/references/genres/puzzle-match3-tetris.md +0 -131
  100. package/skills/grok-building-games/references/genres/racing-kart.md +0 -106
  101. package/skills/grok-building-games/references/genres/topdown-twin-stick.md +0 -97
  102. package/skills/grok-building-games/references/genres/tower-defense.md +0 -84
  103. package/skills/grok-building-games/references/genres/voxel-minecraft.md +0 -89
  104. package/skills/grok-building-games/references/input.md +0 -139
  105. package/skills/grok-building-games/references/phaser.md +0 -277
  106. package/skills/grok-building-games/references/procedural-generation.md +0 -141
  107. package/skills/grok-building-games/references/save-persistence.md +0 -108
  108. package/skills/grok-building-games/references/threejs-foundational.md +0 -148
  109. package/skills/grok-controls/SKILL.md +0 -274
  110. package/skills/grok-controls/agentsam.skill.json +0 -25
  111. package/skills/grok-design-ui/SKILL.md +0 -122
  112. package/skills/grok-design-ui/agentsam.skill.json +0 -25
  113. package/skills/grok-design-ui/references/animations.md +0 -379
  114. package/skills/grok-design-ui/references/performance.md +0 -88
  115. package/skills/grok-design-ui/references/refined-ui.md +0 -384
  116. package/skills/grok-design-ui/references/surfaces.md +0 -247
  117. package/skills/grok-design-ui/references/typography.md +0 -123
  118. package/skills/grok-game-animation-frames/SKILL.md +0 -84
  119. package/skills/grok-game-animation-frames/agentsam.skill.json +0 -25
  120. package/skills/grok-game-asset-core/SKILL.md +0 -69
  121. package/skills/grok-game-asset-core/agentsam.skill.json +0 -25
  122. package/skills/grok-game-character-consistency/SKILL.md +0 -69
  123. package/skills/grok-game-character-consistency/agentsam.skill.json +0 -25
  124. package/skills/grok-game-tilesets/SKILL.md +0 -65
  125. package/skills/grok-game-tilesets/agentsam.skill.json +0 -25
  126. package/skills/grok-game-ui-icons/SKILL.md +0 -56
  127. package/skills/grok-game-ui-icons/agentsam.skill.json +0 -25
  128. package/skills/grok-generate2dmap/LICENSE +0 -21
  129. package/skills/grok-generate2dmap/SKILL.md +0 -120
  130. package/skills/grok-generate2dmap/SOURCE.md +0 -6
  131. package/skills/grok-generate2dmap/agentsam.skill.json +0 -25
  132. package/skills/grok-generate2dmap/references/deliverables.md +0 -101
  133. package/skills/grok-generate2dmap/references/layered-map-contract.md +0 -209
  134. package/skills/grok-generate2dmap/references/map-strategies.md +0 -341
  135. package/skills/grok-generate2dmap/references/object-production-gate.md +0 -24
  136. package/skills/grok-generate2dmap/references/pipeline.md +0 -149
  137. package/skills/grok-generate2dmap/references/prop-pack-contract.md +0 -174
  138. package/skills/grok-generate2dmap/references/side-scroll-stages.md +0 -29
  139. package/skills/grok-generate2dmap/scripts/compose_layered_preview.py +0 -157
  140. package/skills/grok-generate2dmap/scripts/extract_prop_pack.py +0 -369
  141. package/skills/grok-generate2dsprite/LICENSE +0 -21
  142. package/skills/grok-generate2dsprite/SKILL.md +0 -313
  143. package/skills/grok-generate2dsprite/SOURCE.md +0 -6
  144. package/skills/grok-generate2dsprite/agentsam.skill.json +0 -25
  145. package/skills/grok-generate2dsprite/references/modes.md +0 -124
  146. package/skills/grok-generate2dsprite/references/prompt-rules.md +0 -315
  147. package/skills/grok-generate2dsprite/scripts/generate2dsprite.py +0 -1031
  148. package/skills/grok-generate2dsprite/scripts/make_layout_guide.py +0 -109
  149. package/skills/grok-imagine/SKILL.md +0 -201
  150. package/skills/grok-imagine/agentsam.skill.json +0 -25
  151. package/skills/grok-multiplayer-p2p/SKILL.md +0 -111
  152. package/skills/grok-multiplayer-p2p/agentsam.skill.json +0 -25
  153. package/skills/grok-multiplayer-p2p/references/react-binding.md +0 -144
  154. package/skills/grok-multiplayer-p2p/references/signaling-relay.md +0 -269
  155. package/skills/grok-neon/SKILL.md +0 -157
  156. package/skills/grok-neon/agentsam.skill.json +0 -25
  157. package/skills/grok-og/SKILL.md +0 -102
  158. package/skills/grok-og/agentsam.skill.json +0 -25
  159. package/skills/grok-og/references/brand-pass.md +0 -53
  160. package/skills/grok-og/references/custom-card.md +0 -107
  161. package/skills/grok-og/references/favicon-and-icons.md +0 -48
  162. package/skills/grok-og/references/og-type-contract.md +0 -18
  163. package/skills/grok-og/references/placeholder-card.md +0 -21
  164. package/skills/grok-og/references/x-banner.md +0 -41
  165. package/skills/grok-threejs/SKILL.md +0 -67
  166. package/skills/grok-threejs/agentsam.skill.json +0 -25
  167. package/skills/grok-threejs/references/llms-full.txt +0 -2780
  168. package/skills/grok-video2dsprite/LICENSE +0 -21
  169. package/skills/grok-video2dsprite/SKILL.md +0 -236
  170. package/skills/grok-video2dsprite/SOURCE.md +0 -6
  171. package/skills/grok-video2dsprite/agentsam.skill.json +0 -25
  172. package/skills/grok-video2dsprite/references/pipeline.md +0 -90
  173. package/skills/grok-video2dsprite/references/prompt-rules.md +0 -63
  174. package/skills/grok-video2dsprite/scripts/video2dsprite.py +0 -490
  175. package/skills/grok-xai-api/SKILL.md +0 -152
  176. package/skills/grok-xai-api/agentsam.skill.json +0 -25
  177. package/test/account-session.test.mjs +0 -101
  178. package/test/agent-capabilities.test.mjs +0 -67
  179. package/test/app-authority-context.test.mjs +0 -32
  180. package/test/app-building-skills.test.mjs +0 -61
  181. package/test/apps-scaffold-contract.test.mjs +0 -115
  182. package/test/blender-cad.test.mjs +0 -146
  183. package/test/cad-docker.test.mjs +0 -96
  184. package/test/capabilities.test.mjs +0 -133
  185. package/test/cli/api-key-env-whoami.test.mjs +0 -129
  186. package/test/cli/catalog-authority.test.mjs +0 -64
  187. package/test/cli/codebaseindex-plan-ux.test.mjs +0 -37
  188. package/test/cli/eval-live.test.mjs +0 -219
  189. package/test/cli/go.test.mjs +0 -128
  190. package/test/cli/local-vault-and-provider-setup.test.mjs +0 -268
  191. package/test/cli/machine-command.test.mjs +0 -34
  192. package/test/cli/mcp-client.test.mjs +0 -256
  193. package/test/cli/preferences-runtime.test.mjs +0 -11
  194. package/test/cli/runtime-persist.test.mjs +0 -56
  195. package/test/cli/runtime-ui.test.mjs +0 -141
  196. package/test/cli/rust-command.test.mjs +0 -21
  197. package/test/cli/skill-npm-and-env.test.mjs +0 -52
  198. package/test/cli/status-actions.test.mjs +0 -88
  199. package/test/cli/wireframes-go-registry.test.mjs +0 -139
  200. package/test/cli-preferences.test.mjs +0 -46
  201. package/test/cloudflare-connector.test.mjs +0 -93
  202. package/test/cloudflare-runtime.test.mjs +0 -82
  203. package/test/context.test.mjs +0 -159
  204. package/test/credentials-audit.test.mjs +0 -113
  205. package/test/deploy-health-scan.test.mjs +0 -95
  206. package/test/deploy-receipt.test.mjs +0 -91
  207. package/test/dockerize.test.mjs +0 -93
  208. package/test/error-diagnostics.test.mjs +0 -124
  209. package/test/eval-context.test.mjs +0 -37
  210. package/test/execution-approvals.test.mjs +0 -27
  211. package/test/fixtures/cad/courtyard-house.json +0 -208
  212. package/test/fixtures/knowledge-rpc-worker.mjs +0 -16
  213. package/test/fixtures/project-authority/customer-app/.agentsam/app.json +0 -5
  214. package/test/fixtures/project-authority/customer-app/apps/my-product/index.ts +0 -1
  215. package/test/fixtures/project-authority/customer-app/wrangler.toml +0 -17
  216. package/test/gcloud-auth.test.mjs +0 -111
  217. package/test/go/build-source-identity.test.mjs +0 -31
  218. package/test/go/cloudflare-probe.test.mjs +0 -317
  219. package/test/go/distribution.test.mjs +0 -28
  220. package/test/google-cloud-connection.test.mjs +0 -83
  221. package/test/google-cloud-inventory.test.mjs +0 -64
  222. package/test/indexing-provider.test.mjs +0 -29
  223. package/test/init-options.test.mjs +0 -35
  224. package/test/integration/ai-access-onboarding.test.mjs +0 -47
  225. package/test/integration/app-command.test.mjs +0 -85
  226. package/test/integration/autorag-project-authority.integration.test.mjs +0 -51
  227. package/test/integration/autorag-runtime-discovery.test.mjs +0 -107
  228. package/test/integration/cad-discovery.test.mjs +0 -158
  229. package/test/integration/cad-docker-executor.test.mjs +0 -249
  230. package/test/integration/cad-execution.test.mjs +0 -184
  231. package/test/integration/cad-project-app.test.mjs +0 -31
  232. package/test/integration/cad-project-d1.test.mjs +0 -25
  233. package/test/integration/cad-project-native.test.mjs +0 -24
  234. package/test/integration/cad-project-workflow.test.mjs +0 -9
  235. package/test/integration/cad-project.test.mjs +0 -85
  236. package/test/integration/cli-help.test.mjs +0 -41
  237. package/test/integration/cms-app-scaffold.test.mjs +0 -77
  238. package/test/integration/cms-site-tenancy-contract.test.mjs +0 -268
  239. package/test/integration/codebaseindex-ingest.test.mjs +0 -255
  240. package/test/integration/core-client.integration.test.mjs +0 -55
  241. package/test/integration/database-hosted-honesty.test.mjs +0 -49
  242. package/test/integration/desktop-keychain-boundary.test.mjs +0 -45
  243. package/test/integration/error-runtime-rpc.test.mjs +0 -71
  244. package/test/integration/features-resolve.test.mjs +0 -147
  245. package/test/integration/hosted-work-host-authority.test.mjs +0 -47
  246. package/test/integration/icon-registry.test.mjs +0 -67
  247. package/test/integration/ingest-discover-models.test.mjs +0 -30
  248. package/test/integration/inspect-path-cli.test.mjs +0 -46
  249. package/test/integration/install-script.test.mjs +0 -110
  250. package/test/integration/inventory-core.test.mjs +0 -53
  251. package/test/integration/inventory-eligibility.test.mjs +0 -59
  252. package/test/integration/inventory-evidence.test.mjs +0 -125
  253. package/test/integration/knowledge-rpc.test.mjs +0 -112
  254. package/test/integration/local-fs.test.mjs +0 -113
  255. package/test/integration/local-provider-bridge.test.mjs +0 -65
  256. package/test/integration/local-studio-settings-production.test.mjs +0 -40
  257. package/test/integration/lockfile-sync.test.mjs +0 -26
  258. package/test/integration/merkle-cli.test.mjs +0 -61
  259. package/test/integration/merkle-persistence-identity.test.mjs +0 -48
  260. package/test/integration/plugins-cloudflare.integration.test.mjs +0 -28
  261. package/test/integration/provider-env-cli.test.mjs +0 -60
  262. package/test/integration/provider-factory.test.mjs +0 -197
  263. package/test/integration/repository-company-graph.test.mjs +0 -90
  264. package/test/integration/runtime-migrations.test.mjs +0 -87
  265. package/test/integration/runtime-status.integration.test.mjs +0 -227
  266. package/test/integration/sam-activity-recovery.test.mjs +0 -147
  267. package/test/integration/sam-decision.test.mjs +0 -584
  268. package/test/integration/sam-kernel.test.mjs +0 -99
  269. package/test/integration/sam-planning-astar.test.mjs +0 -279
  270. package/test/integration/scaffold-cloudflare.test.mjs +0 -46
  271. package/test/integration/skill-runtime.test.mjs +0 -240
  272. package/test/integration/storage-architecture.test.mjs +0 -154
  273. package/test/integration/store-discovery.test.mjs +0 -44
  274. package/test/integration/studio-fs-pty-e2e.test.mjs +0 -294
  275. package/test/integration/terminal-exec.integration.test.mjs +0 -86
  276. package/test/integration/theme-package-registry.test.mjs +0 -31
  277. package/test/integration/tool-runtime.test.mjs +0 -124
  278. package/test/integration/tool-schema.test.mjs +0 -59
  279. package/test/jr-dev-skill.test.mjs +0 -26
  280. package/test/knowledge-context-pack.test.mjs +0 -19
  281. package/test/knowledge-postgres.test.mjs +0 -40
  282. package/test/knowledge-service.test.mjs +0 -110
  283. package/test/knowledge.test.mjs +0 -206
  284. package/test/live/terminal-transport.live.test.mjs +0 -24
  285. package/test/local-sessions.test.mjs +0 -57
  286. package/test/local-studio-deploy.test.mjs +0 -83
  287. package/test/loopback-oauth.test.mjs +0 -53
  288. package/test/merkle-render.test.mjs +0 -31
  289. package/test/mini.test.mjs +0 -140
  290. package/test/model-catalog.test.mjs +0 -70
  291. package/test/models.test.mjs +0 -309
  292. package/test/npm10-lock.test.mjs +0 -29
  293. package/test/ollama.test.mjs +0 -137
  294. package/test/open-url.test.mjs +0 -64
  295. package/test/openai-responses.test.mjs +0 -155
  296. package/test/portable-context.test.mjs +0 -94
  297. package/test/project-config.test.mjs +0 -81
  298. package/test/project-rules.test.mjs +0 -44
  299. package/test/provider-credentials.test.mjs +0 -106
  300. package/test/rehydrate.test.mjs +0 -25
  301. package/test/release-hygiene.test.mjs +0 -42
  302. package/test/repository-snapshot-view.test.mjs +0 -112
  303. package/test/responses-runner.test.mjs +0 -465
  304. package/test/runtime-activity.test.mjs +0 -98
  305. package/test/sdk-worker-contract.test.mjs +0 -72
  306. package/test/security.test.mjs +0 -266
  307. package/test/setup-planner.test.mjs +0 -74
  308. package/test/setup-runtime.test.mjs +0 -51
  309. package/test/shell.test.mjs +0 -281
  310. package/test/skills.test.mjs +0 -22
  311. package/test/smoke.mjs +0 -122
  312. package/test/telemetry.test.mjs +0 -79
  313. package/test/terminal/local-pty.mock.test.mjs +0 -153
  314. package/test/terminal-machine-identity.test.mjs +0 -88
  315. package/test/theme-portability.test.mjs +0 -14
  316. package/test/tools-search.test.mjs +0 -73
  317. package/test/unit/website-assets-bindings.test.mjs +0 -60
  318. package/test/whoami-resume.test.mjs +0 -157
@@ -1,128 +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 { fileURLToPath } from 'node:url';
7
- import { discoverGoRuntime, resolveProductRoot, ensureProductContract, buildGoProduct } from '../../src/go/index.js';
8
- import { runGo } from '../../src/commands/go.js';
9
-
10
- const SDK_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');
11
-
12
-
13
- function tempStateRoot() {
14
- return fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-go-test-state-'));
15
- }
16
-
17
- test('discoverGoRuntime finds agentsam-go-worker without inventing a sibling', () => {
18
- const discovery = discoverGoRuntime(SDK_ROOT);
19
- assert.equal(discovery.go.ok, true);
20
- assert.ok(discovery.runtime, 'expected Go runtime');
21
- assert.match(discovery.runtime.module, /agentsam-go-worker/);
22
- assert.equal(path.basename(discovery.runtime.productRoot), 'agentsam-go-worker');
23
- const productRoot = resolveProductRoot(discovery, 'agentsam-go-worker');
24
- const contract = ensureProductContract(productRoot);
25
- assert.equal(contract.product, 'agentsam-go-worker');
26
- assert.equal(contract.existing, true);
27
- assert.deepEqual(contract.created, []);
28
- });
29
-
30
- test('ensureProductContract refuses missing product roots instead of scaffolding siblings', () => {
31
- const missing = path.join(os.tmpdir(), `agentsam-go-missing-${Date.now()}`);
32
- assert.throws(() => ensureProductContract(missing), /product_root_missing/);
33
- });
34
-
35
- test('buildGoProduct emits build receipt after go test/vet/build', () => {
36
- const discovery = discoverGoRuntime(SDK_ROOT);
37
- const productRoot = resolveProductRoot(discovery);
38
- const stateRoot = tempStateRoot();
39
- const result = buildGoProduct({
40
- productRoot,
41
- runtimeRoot: discovery.runtime.runtimeRoot,
42
- repositoryRoot: discovery.repository_root,
43
- stateRoot,
44
- });
45
- assert.equal(result.receipt.schema, 'agentsam.go-build-receipt.v1');
46
- assert.equal(result.tests.ok, true);
47
- assert.equal(result.vet.ok, true);
48
- assert.ok(result.build.binary);
49
- assert.match(result.receipt.artifact.digest, /^sha256:[a-f0-9]{64}$/);
50
- assert.equal(result.receipt.tests.runtime_probe, true);
51
- assert.match(result.receipt.source.identity, /^git:[a-f0-9]{40}$/);
52
- assert.equal(result.probe.checks.source_identity, true);
53
- assert.equal(result.probe.checks.source_commit, true);
54
- assert.equal(result.probe.checks.error_envelope, true);
55
- assert.equal(result.probe.checks.clean_shutdown, true);
56
- assert.ok(fs.existsSync(result.receiptPath));
57
- });
58
-
59
- test('agentsam go build --json exposes only portable build paths', async () => {
60
- const stateRoot = tempStateRoot();
61
- const chunks = [];
62
-
63
- const result = await runGo(
64
- ['build', '--json'],
65
- {
66
- write: (value) => chunks.push(String(value)),
67
- stateRoot,
68
- },
69
- );
70
-
71
- assert.ok(path.isAbsolute(result.receiptPath), 'internal execution keeps absolute receipt path');
72
- assert.ok(path.isAbsolute(result.build.binary), 'internal execution keeps absolute binary path');
73
-
74
- const output = chunks.join('');
75
- const parsed = JSON.parse(output);
76
-
77
- assert.equal(path.isAbsolute(parsed.receiptPath), false);
78
- assert.equal(path.isAbsolute(parsed.build.binary), false);
79
- assert.equal(path.isAbsolute(parsed.receipt.runtime.module_root), false);
80
- assert.equal(Object.hasOwn(parsed.probe || {}, 'origin'), false);
81
- assert.equal(Object.hasOwn(parsed.receipt?.probe || {}, 'origin'), false);
82
- assert.equal(output.includes(SDK_ROOT), false);
83
- });
84
-
85
- test('agentsam go --cloudflare agentsam-go-worker --skip-deploy is idempotent', async () => {
86
- const stateRoot = tempStateRoot();
87
- const chunks = [];
88
- const write = (v) => chunks.push(String(v));
89
- const first = await runGo(
90
- ['--cloudflare', 'agentsam-go-worker', '--skip-deploy', '--json'],
91
- { write, stateRoot },
92
- );
93
- assert.equal(first.ok, true);
94
- assert.equal(first.product, 'agentsam-go-worker');
95
- assert.equal(first.scaffold_changes_required, false);
96
- assert.equal(first.mode, 'self_host');
97
- assert.equal(first.deploy.registry.reason, 'self_host_registry_isolated');
98
-
99
- const chunks2 = [];
100
- const second = await runGo(
101
- ['--cloudflare', 'agentsam-go-worker', '--skip-deploy', '--json'],
102
- {
103
- write: (v) => chunks2.push(String(v)),
104
- stateRoot,
105
- },
106
- );
107
- assert.equal(second.ok, true);
108
- assert.equal(second.existing_product, true);
109
- assert.equal(second.scaffold_changes_required, false);
110
- assert.ok(second.deploy.receiptPath);
111
- assert.ok(fs.existsSync(second.deploy.productPath));
112
- });
113
-
114
- test('agentsam go status --json reports discovery', async () => {
115
- const stateRoot = tempStateRoot();
116
- const chunks = [];
117
- const result = await runGo(
118
- ['status', '--json'],
119
- {
120
- write: (v) => chunks.push(String(v)),
121
- stateRoot,
122
- },
123
- );
124
- assert.equal(result.ok, true);
125
- assert.ok(result.discovery.go.ok);
126
- const parsed = JSON.parse(chunks.join(''));
127
- assert.equal(parsed.product, 'agentsam-go-worker');
128
- });
@@ -1,268 +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
-
7
- import {
8
- getSecureProviderKey,
9
- setSecureProviderKey,
10
- deleteSecureProviderKey,
11
- listSecureConfiguredProviders,
12
- hydrateSecureCredentials,
13
- localVaultPath,
14
- localVaultSaltPath,
15
- } from '../../src/security/local-vault.js';
16
- import { resolveExecutableCommand } from '../../src/security/process.js';
17
- import {
18
- resolveProviderCredential,
19
- setProviderCredential,
20
- removeProviderCredential,
21
- exportProviderEnvProfile,
22
- } from '../../src/lib/provider-credentials.js';
23
- import {
24
- validateAndSaveProviderCredential,
25
- providerChoices,
26
- runProviders,
27
- } from '../../src/commands/providers.js';
28
- import { renderModelsStatus } from '../../src/commands/models.js';
29
-
30
- // picocolors color-detection differs between local runs and CI runners (CI often
31
- // reports TTY-like support that enables ANSI output) - strip escape codes before
32
- // asserting on rendered text content so this test checks content, not incidental
33
- // terminal color state.
34
- // eslint-disable-next-line no-control-regex
35
- const ANSI_PATTERN = /\x1B\[[0-9;]*m/g;
36
- const stripAnsi = (s) => String(s).replace(ANSI_PATTERN, '');
37
-
38
- function createTempHome(t) {
39
- const home = fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-vault-test-'));
40
- t.after(() => fs.rmSync(home, { recursive: true, force: true }));
41
- return home;
42
- }
43
-
44
- test('resolveExecutableCommand resolves Windows .cmd shims with shell: true on win32', () => {
45
- const npxWin = resolveExecutableCommand('npx', 'win32');
46
- assert.equal(npxWin.command, 'npx.cmd');
47
- assert.equal(npxWin.shell, true);
48
-
49
- const npmWin = resolveExecutableCommand('npm', 'win32');
50
- assert.equal(npmWin.command, 'npm.cmd');
51
- assert.equal(npmWin.shell, true);
52
-
53
- const wranglerWin = resolveExecutableCommand('wrangler', 'win32');
54
- assert.equal(wranglerWin.command, 'wrangler.cmd');
55
- assert.equal(wranglerWin.shell, true);
56
-
57
- const scriptWin = resolveExecutableCommand('build.bat', 'win32');
58
- assert.equal(scriptWin.command, 'build.bat');
59
- assert.equal(scriptWin.shell, true);
60
-
61
- // Linux and macOS are untouched
62
- const npxMac = resolveExecutableCommand('npx', 'darwin');
63
- assert.equal(npxMac.command, 'npx');
64
- assert.equal(npxMac.shell, false);
65
-
66
- const npmLinux = resolveExecutableCommand('npm', 'linux');
67
- assert.equal(npmLinux.command, 'npm');
68
- assert.equal(npmLinux.shell, false);
69
- });
70
-
71
- test('local vault encrypts with AES-256-GCM and never writes plaintext secrets to disk', (t) => {
72
- const home = createTempHome(t);
73
- const opts = { home, disableOsStore: true };
74
-
75
- const secret = 'sk-proj-testsecret1234567890abcdef';
76
- setSecureProviderKey('openai', secret, opts);
77
-
78
- const retrieved = getSecureProviderKey('openai', opts);
79
- assert.equal(retrieved.value, secret);
80
- assert.equal(retrieved.source, 'local_vault');
81
-
82
- // Verify disk contents
83
- const encFile = localVaultPath(opts);
84
- assert.equal(fs.existsSync(encFile), true);
85
- const rawText = fs.readFileSync(encFile, 'utf8');
86
-
87
- // Plaintext MUST NOT appear anywhere in the file
88
- assert.equal(rawText.includes(secret), false);
89
-
90
- // Must have JSON with iv, tag, and data
91
- const parsed = JSON.parse(rawText);
92
- assert.ok(parsed.secrets.openai.iv);
93
- assert.ok(parsed.secrets.openai.tag);
94
- assert.ok(parsed.secrets.openai.data);
95
-
96
- // Salt file must exist with restrictive permissions
97
- const saltFile = localVaultSaltPath(opts);
98
- assert.equal(fs.existsSync(saltFile), true);
99
- if (process.platform !== 'win32') {
100
- assert.equal(fs.statSync(saltFile).mode & 0o777, 0o600);
101
- assert.equal(fs.statSync(encFile).mode & 0o777, 0o600);
102
- }
103
- });
104
-
105
- test('local vault detects tampering of encrypted ciphertext', (t) => {
106
- const home = createTempHome(t);
107
- const opts = { home, disableOsStore: true };
108
-
109
- setSecureProviderKey('anthropic', 'sk-ant-test-key-12345', opts);
110
-
111
- // Tamper with the ciphertext
112
- const encFile = localVaultPath(opts);
113
- const parsed = JSON.parse(fs.readFileSync(encFile, 'utf8'));
114
- const originalData = parsed.secrets.anthropic.data;
115
- // Flip the last hex byte
116
- const tamperedData = originalData.slice(0, -2) + (originalData.slice(-2) === 'aa' ? 'bb' : 'aa');
117
- parsed.secrets.anthropic.data = tamperedData;
118
- fs.writeFileSync(encFile, JSON.stringify(parsed));
119
-
120
- // Decryption must fail and return null safely rather than corrupt data
121
- const retrieved = getSecureProviderKey('anthropic', opts);
122
- assert.equal(retrieved, null);
123
- });
124
-
125
- test('local vault stores and retrieves Cloudflare accountId alongside token', (t) => {
126
- const home = createTempHome(t);
127
- const opts = { home, disableOsStore: true };
128
-
129
- setSecureProviderKey('cloudflare', { value: 'cf-token-123', accountId: 'abcdef0123456789abcdef0123456789' }, opts);
130
- const retrieved = getSecureProviderKey('cloudflare', opts);
131
-
132
- assert.equal(retrieved.value, 'cf-token-123');
133
- assert.equal(retrieved.accountId, 'abcdef0123456789abcdef0123456789');
134
- });
135
-
136
- test('hydrateSecureCredentials populates process.env for unconfigured providers without overwriting', (t) => {
137
- const home = createTempHome(t);
138
- const opts = { home, disableOsStore: true };
139
-
140
- setSecureProviderKey('gemini', 'gemini-key-val-789', opts);
141
-
142
- const mockEnv = {
143
- EXISTING_KEY: 'pre-existing',
144
- };
145
-
146
- const hydrated = hydrateSecureCredentials(mockEnv, opts);
147
- assert.ok(hydrated.includes('gemini'));
148
- assert.equal(mockEnv.GEMINI_API_KEY, 'gemini-key-val-789');
149
-
150
- // Second run does not overwrite
151
- mockEnv.GEMINI_API_KEY = 'user-override';
152
- hydrateSecureCredentials(mockEnv, opts);
153
- assert.equal(mockEnv.GEMINI_API_KEY, 'user-override');
154
- });
155
-
156
- test('resolveProviderCredential resolves keys from local secure vault across any directory', (t) => {
157
- const home = createTempHome(t);
158
- const opts = { home, disableOsStore: true };
159
-
160
- setProviderCredential('cursor', 'cur-key-secret-456', opts);
161
-
162
- const resolved = resolveProviderCredential('cursor', { env: {}, home, disableOsStore: true });
163
- assert.equal(resolved.configured, true);
164
- assert.equal(resolved.value, 'cur-key-secret-456');
165
-
166
- // Deleting removes it
167
- removeProviderCredential('cursor', opts);
168
- const afterRemove = resolveProviderCredential('cursor', { env: {}, home, disableOsStore: true });
169
- assert.equal(afterRemove.configured, false);
170
- });
171
-
172
- test('validateAndSaveProviderCredential rejects invalid key and does NOT persist it', async (t) => {
173
- const home = createTempHome(t);
174
- const opts = {
175
- home,
176
- disableOsStore: true,
177
- fetchImpl: async () => ({
178
- ok: false,
179
- status: 401,
180
- json: async () => ({ error: { message: 'Incorrect API key provided' } }),
181
- }),
182
- };
183
-
184
- const result = await validateAndSaveProviderCredential('openai', 'sk-invalid-test-key', opts);
185
- assert.equal(result.ok, false);
186
- assert.equal(result.saved, false);
187
- assert.match(result.error, /Incorrect API key/i);
188
-
189
- // Verify it was NOT stored in the vault!
190
- const retrieved = getSecureProviderKey('openai', opts);
191
- assert.equal(retrieved, null);
192
- });
193
-
194
- test('validateAndSaveProviderCredential verifies valid key and saves ONLY to local vault without plaintext file', async (t) => {
195
- const home = createTempHome(t);
196
- const opts = {
197
- home,
198
- disableOsStore: true,
199
- fetchImpl: async () => ({
200
- ok: true,
201
- status: 200,
202
- json: async () => ({
203
- data: [{ id: 'gpt-4o' }, { id: 'gpt-4o-mini' }],
204
- }),
205
- }),
206
- };
207
-
208
- const result = await validateAndSaveProviderCredential('openai', 'sk-valid-key-xyz', opts);
209
- assert.equal(result.ok, true);
210
- assert.equal(result.saved, true);
211
- assert.equal(result.model_count, 2);
212
-
213
- // Verify it was saved to local vault
214
- const retrieved = getSecureProviderKey('openai', opts);
215
- assert.equal(retrieved.value, 'sk-valid-key-xyz');
216
-
217
- // CRITICAL: Plaintext .env profile file MUST NOT be created automatically!
218
- const plaintextFile = path.join(home, '.agentsam', 'env.d', 'openai.env');
219
- assert.equal(fs.existsSync(plaintextFile), false, 'Plaintext .env file must NOT exist after secure provider setup');
220
- });
221
-
222
- test('exportProviderEnvProfile and agentsam providers export create plaintext .env file ONLY on explicit opt-in', async (t) => {
223
- const home = createTempHome(t);
224
- const opts = { home, disableOsStore: true };
225
-
226
- // Set up provider key in secure vault
227
- setProviderCredential('anthropic', 'sk-ant-test-export-key', opts);
228
-
229
- // Confirm NO plaintext file exists yet
230
- const plaintextFile = path.join(home, '.agentsam', 'env.d', 'anthropic.env');
231
- assert.equal(fs.existsSync(plaintextFile), false);
232
-
233
- // Explicit opt-in export via CLI command
234
- let output = '';
235
- const exported = await runProviders(['export', 'anthropic'], {
236
- ...opts,
237
- write: (text) => { output += text; },
238
- });
239
-
240
- assert.equal(exported.provider, 'anthropic');
241
- assert.equal(fs.existsSync(plaintextFile), true);
242
- const content = fs.readFileSync(plaintextFile, 'utf8');
243
- assert.match(content, /ANTHROPIC_API_KEY="sk-ant-test-export-key"/);
244
- assert.match(output, /Exported anthropic profile/);
245
- });
246
-
247
- test('renderModelsStatus shows tip: Select your preferred provider when providers are unconfigured', () => {
248
- const status = {
249
- providers: [
250
- { id: 'openai', label: 'OpenAI', configured: false, credential: 'OPENAI_API_KEY' },
251
- { id: 'anthropic', label: 'Anthropic', configured: false, credential: 'ANTHROPIC_API_KEY' },
252
- ],
253
- discovery: {},
254
- providerModels: {},
255
- local: { online: false, models: [] },
256
- };
257
-
258
- const output = stripAnsi(renderModelsStatus(status));
259
- assert.match(output, /Tip:\s*Select your preferred provider/i);
260
- });
261
-
262
- test('providerChoices returns valid choice list for select picker', () => {
263
- const choices = providerChoices();
264
- assert.ok(choices.length >= 6);
265
- assert.ok(choices.some((c) => c.value === 'openai'));
266
- assert.ok(choices.some((c) => c.value === 'anthropic'));
267
- assert.ok(choices.some((c) => c.value === 'gemini'));
268
- });
@@ -1,34 +0,0 @@
1
- import test from 'node:test';
2
- import assert from 'node:assert/strict';
3
- import fs from 'node:fs';
4
- import path from 'node:path';
5
- import { fileURLToPath } from 'node:url';
6
- import { getCliCommand } from '../../src/cli/command-catalog.js';
7
- import { resolveMachineBinary } from '../../src/commands/machine-binary.js';
8
-
9
- const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');
10
-
11
- test('machine command is catalogued as machine.inspect', () => {
12
- const entry = getCliCommand('machine');
13
- assert.equal(entry?.id, 'machine');
14
- assert.equal(entry?.operation, 'machine.inspect');
15
- assert.equal(entry?.common, true);
16
- });
17
-
18
- test('machine crate + CLI sources exist for graduation', () => {
19
- assert.equal(fs.existsSync(path.join(root, 'native/agentsam-machine/Cargo.toml')), true);
20
- assert.equal(fs.existsSync(path.join(root, 'native/agentsam-machine/cli/src/main.rs')), true);
21
- assert.equal(fs.existsSync(path.join(root, 'src/commands/machine.js')), true);
22
- assert.equal(fs.existsSync(path.join(root, 'src/commands/machine-binary.js')), true);
23
- });
24
-
25
- test('resolveMachineBinary finds crate binary or cargo fallback in this repo', () => {
26
- const resolution = resolveMachineBinary();
27
- assert.notEqual(resolution.kind, 'missing');
28
- if (resolution.kind === 'binary') {
29
- assert.equal(fs.existsSync(resolution.path), true);
30
- } else {
31
- assert.equal(resolution.kind, 'cargo');
32
- assert.equal(fs.existsSync(resolution.manifest), true);
33
- }
34
- });
@@ -1,256 +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
-
7
- import {
8
- MCP_PRESETS,
9
- deleteMcpServer,
10
- fetchExternalClientRegistry,
11
- fetchMcpServerCatalog,
12
- getClientConfigPath,
13
- getClientRegistryCachePath,
14
- getServerCatalogCachePath,
15
- getSessionToolReceipts,
16
- inspectClientAdapter,
17
- isClientRegistered,
18
- listKnownServers,
19
- listMcpServers,
20
- listRegisteredClients,
21
- readMcpServer,
22
- recordToolReceipt,
23
- removeServerFromClient,
24
- resolveServerPreset,
25
- summarizeToolReceipts,
26
- syncServerToClient,
27
- writeMcpServer,
28
- } from '../../src/mcp/index.js';
29
- import { runMcp } from '../../src/commands/mcp.js';
30
-
31
- function tempHome() {
32
- return fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-mcp-test-'));
33
- }
34
-
35
- test('MCP authority store manages servers under ~/.agentsam/mcp with safe permissions', () => {
36
- const home = tempHome();
37
- const config = {
38
- url: 'https://mcp.inneranimalmedia.com/mcp',
39
- auth: { type: 'bearer', token: 'iam_token_abc' },
40
- clients: ['cursor', 'claude'],
41
- };
42
-
43
- const written = writeMcpServer('inneranimalmedia', config, { home });
44
- assert.equal(written.name, 'inneranimalmedia');
45
- assert.equal(written.url, 'https://mcp.inneranimalmedia.com/mcp');
46
-
47
- const read = readMcpServer('inneranimalmedia', { home });
48
- assert.equal(read.name, 'inneranimalmedia');
49
- assert.equal(read.auth.token, 'iam_token_abc');
50
- assert.deepEqual(read.clients, ['cursor', 'claude']);
51
-
52
- const list = listMcpServers({ home });
53
- assert.equal(list.length, 1);
54
- assert.equal(list[0].name, 'inneranimalmedia');
55
-
56
- const deleted = deleteMcpServer('inneranimalmedia', { home });
57
- assert.equal(deleted, true);
58
- assert.equal(readMcpServer('inneranimalmedia', { home }), null);
59
- });
60
-
61
- test('MCP external client registry recognizes chatgpt, claude, cursor — not CF portals', async () => {
62
- const home = tempHome();
63
-
64
- // Baseline seed / cached client list
65
- const clients = listRegisteredClients({ home });
66
- const keys = clients.map((c) => c.client_key);
67
- assert.ok(keys.includes('chatgpt'), 'ChatGPT is recognized in the external client registry');
68
- assert.ok(keys.includes('cursor'), 'Cursor is recognized in the external client registry');
69
- assert.ok(keys.includes('claude'), 'Claude is recognized in the external client registry');
70
- assert.ok(keys.includes('agentsam'), 'AgentSam is recognized in the external client registry');
71
- assert.equal(keys.some((k) => k.startsWith('cf_')), false, 'CF MCP portals are servers, not clients');
72
-
73
- assert.equal(isClientRegistered('chatgpt', { home }), true);
74
- assert.equal(isClientRegistered('cursor', { home }), true);
75
- assert.equal(isClientRegistered('cf_bindings_mcp', { home }), false);
76
- assert.equal(isClientRegistered('nonexistent_client_xyz', { home }), false);
77
-
78
- // Cache path is created upon writing
79
- const cachePath = getClientRegistryCachePath({ home });
80
- assert.equal(cachePath.endsWith('client-registry-cache.json'), true);
81
- });
82
-
83
- test('MCP client adapters materialize Cursor, Claude, and ChatGPT configurations cleanly', () => {
84
- const home = tempHome();
85
- const serverConfig = {
86
- url: 'https://mcp.inneranimalmedia.com/mcp',
87
- auth: { type: 'bearer', token: 'oauth_cursor_123' },
88
- };
89
-
90
- // Pre-seed an existing server in Cursor config to ensure no clobbering
91
- const cursorConfigPath = getClientConfigPath('cursor', { home });
92
- fs.mkdirSync(path.dirname(cursorConfigPath), { recursive: true });
93
- fs.writeFileSync(
94
- cursorConfigPath,
95
- JSON.stringify({ mcpServers: { other_server: { url: 'http://localhost:8080' } } })
96
- );
97
-
98
- // Sync to Cursor
99
- const cursorResult = syncServerToClient('cursor', 'inneranimalmedia', serverConfig, { home });
100
- assert.equal(cursorResult.synced, true);
101
-
102
- const cursorContent = JSON.parse(fs.readFileSync(cursorConfigPath, 'utf8'));
103
- assert.ok(cursorContent.mcpServers.other_server, 'Preserved other server in Cursor config');
104
- assert.equal(cursorContent.mcpServers.inneranimalmedia.url, 'https://mcp.inneranimalmedia.com/mcp');
105
- assert.equal(cursorContent.mcpServers.inneranimalmedia.headers.Authorization, 'Bearer oauth_cursor_123');
106
- assert.equal(cursorContent.mcpServers.inneranimalmedia.headers.Accept, 'application/json, text/event-stream');
107
-
108
- // Inspect Cursor adapter
109
- const inspection = inspectClientAdapter('cursor', 'inneranimalmedia', { home });
110
- assert.equal(inspection.configured, true);
111
- assert.equal(inspection.present, true);
112
-
113
- // Sync to Claude
114
- const claudeResult = syncServerToClient('claude', 'inneranimalmedia', serverConfig, { home });
115
- assert.equal(claudeResult.synced, true);
116
- const claudeConfigPath = getClientConfigPath('claude', { home });
117
- const claudeContent = JSON.parse(fs.readFileSync(claudeConfigPath, 'utf8'));
118
- assert.equal(claudeContent.mcpServers.inneranimalmedia.url, 'https://mcp.inneranimalmedia.com/mcp');
119
-
120
- // Sync to ChatGPT
121
- const chatgptResult = syncServerToClient('chatgpt', 'inneranimalmedia', serverConfig, { home });
122
- assert.equal(chatgptResult.synced, true);
123
- const chatgptConfigPath = getClientConfigPath('chatgpt', { home });
124
- assert.ok(fs.existsSync(chatgptConfigPath));
125
- const chatgptContent = JSON.parse(fs.readFileSync(chatgptConfigPath, 'utf8'));
126
- assert.equal(chatgptContent.name, 'inneranimalmedia');
127
- assert.equal(chatgptContent.server_url, 'https://mcp.inneranimalmedia.com/mcp');
128
- assert.equal(chatgptContent.schema, 'agentsam.mcp.client-adapter.chatgpt.v1');
129
-
130
- // Sync to AgentSam family adapter (~/.agentsam/mcp.json)
131
- const agentsamResult = syncServerToClient('agentsam', 'inneranimalmedia', serverConfig, { home });
132
- assert.equal(agentsamResult.synced, true);
133
- const agentsamConfigPath = getClientConfigPath('agentsam', { home });
134
- assert.equal(agentsamConfigPath, path.join(home, '.agentsam', 'mcp.json'));
135
- assert.ok(fs.existsSync(agentsamConfigPath));
136
- const agentsamContent = JSON.parse(fs.readFileSync(agentsamConfigPath, 'utf8'));
137
- assert.equal(agentsamContent.mcpServers.inneranimalmedia.url, 'https://mcp.inneranimalmedia.com/mcp');
138
- assert.equal(agentsamContent.mcpServers.inneranimalmedia.headers.Authorization, 'Bearer oauth_cursor_123');
139
-
140
- // Remove from Cursor
141
- const removeResult = removeServerFromClient('cursor', 'inneranimalmedia', { home });
142
- assert.equal(removeResult.removed, true);
143
- const postRemove = JSON.parse(fs.readFileSync(cursorConfigPath, 'utf8'));
144
- assert.equal(postRemove.mcpServers.inneranimalmedia, undefined);
145
- assert.ok(postRemove.mcpServers.other_server, 'Still preserved other server');
146
-
147
- // Remove from AgentSam family adapter
148
- const removeAgentsam = removeServerFromClient('agentsam', 'inneranimalmedia', { home });
149
- assert.equal(removeAgentsam.removed, true);
150
- const postRemoveAgentsam = JSON.parse(fs.readFileSync(agentsamConfigPath, 'utf8'));
151
- assert.equal(postRemoveAgentsam.mcpServers.inneranimalmedia, undefined);
152
-
153
- // Remove from ChatGPT
154
- const removeChatgpt = removeServerFromClient('chatgpt', 'inneranimalmedia', { home });
155
- assert.equal(removeChatgpt.removed, true);
156
- assert.equal(fs.existsSync(chatgptConfigPath), false);
157
- });
158
-
159
- test('MCP server catalog resolves CF portal bundles + IAM without fabricated health', () => {
160
- const home = tempHome();
161
- const catalog = listKnownServers({ home });
162
- assert.ok(catalog.length >= 8);
163
-
164
- const cfApi = resolveServerPreset('cloudflare-api', { home });
165
- assert.ok(cfApi);
166
- assert.equal(cfApi.url, 'https://mcp.cloudflare.com/mcp');
167
- assert.equal(cfApi.provider, 'cloudflare');
168
- assert.equal(cfApi.kind, 'mcp_portal_bundle');
169
- assert.ok(cfApi.portal_manage_scopes.includes('mcp-portals.read'));
170
-
171
- const bindings = resolveServerPreset('cloudflare-bindings', { home });
172
- assert.ok(bindings);
173
- assert.ok(bindings.feature_packs.includes('data'));
174
-
175
- const iam = resolveServerPreset('inneranimalmedia', { home });
176
- assert.ok(iam);
177
- assert.equal(iam.url, 'https://mcp.inneranimalmedia.com/mcp');
178
- });
179
-
180
- test('MCP telemetry logs tool receipts and computes accurate summaries', () => {
181
- const home = tempHome();
182
-
183
- recordToolReceipt({ tool_key: 'github_read', source_client: 'cursor', duration_ms: 120 }, { home });
184
- recordToolReceipt({ tool_key: 'mcp:d1_query', source_client: 'cursor_mcp', duration_ms: 45 }, { home });
185
- recordToolReceipt({ tool_key: 'terminal_exec', source_client: 'agentsam', duration_ms: 800 }, { home });
186
- recordToolReceipt({ tool_key: 'mcp:tool_broken', error_code: 'TIMEOUT', duration_ms: 5000 }, { home });
187
-
188
- const receipts = getSessionToolReceipts({ home });
189
- assert.equal(receipts.length, 4);
190
-
191
- const summary = summarizeToolReceipts(receipts);
192
- assert.equal(summary.tool_call_count, 4);
193
- assert.equal(summary.mcp_call_count, 2);
194
- assert.equal(summary.github_call_count, 1);
195
- assert.equal(summary.d1_call_count, 1);
196
- assert.equal(summary.terminal_call_count, 1);
197
- assert.equal(summary.failure_count, 1);
198
- assert.equal(summary.success_count, 3);
199
- });
200
-
201
- test('agentsam mcp CLI handles add, list, status, doctor, and remove end-to-end', async () => {
202
- const home = tempHome();
203
- const logs = [];
204
- const write = (str) => logs.push(str);
205
-
206
- // Test --help output surfaces chatgpt and known catalog servers
207
- await runMcp(['--help'], { home, write });
208
- const helpText = logs.join('\n');
209
- assert.ok(helpText.includes('chatgpt'), 'Help text displays ChatGPT as a recognized client');
210
- assert.ok(helpText.includes('cloudflare-api'), 'Help text displays cloudflare-api preset');
211
- assert.ok(helpText.includes('bindings.mcp.cloudflare.com') || helpText.includes('cloudflare-bindings'), 'CF portal hostnames remain offerable');
212
- logs.length = 0;
213
-
214
- // Add inneranimalmedia preset for chatgpt client
215
- const addRes = await runMcp(
216
- ['add', 'inneranimalmedia', '--client', 'chatgpt', '--token', 'test_tok_777', '--json'],
217
- { home, write }
218
- );
219
- assert.equal(addRes.ok, true);
220
- assert.equal(addRes.server.name, 'inneranimalmedia');
221
- assert.equal(addRes.server.auth.token, 'test_tok_777');
222
- assert.equal(addRes.syncedAdapters[0].client, 'chatgpt');
223
-
224
- // List
225
- const listRes = await runMcp(['list', '--json'], { home, write });
226
- assert.equal(listRes.length, 1);
227
- assert.equal(listRes[0].name, 'inneranimalmedia');
228
-
229
- // List catalog
230
- const catalogRes = await runMcp(['list', '--catalog', '--json'], { home, write });
231
- assert.ok(catalogRes.length >= 8);
232
-
233
- // Status
234
- const statusRes = await runMcp(['status', 'inneranimalmedia', '--json'], { home, write });
235
- assert.equal(statusRes.name, 'inneranimalmedia');
236
- assert.equal(statusRes.hasAuth, true);
237
-
238
- // Doctor includes catalog / CF pack metadata
239
- const doctorRes = await runMcp(['doctor', 'inneranimalmedia', '--json'], { home, write });
240
- assert.equal(doctorRes.name, 'inneranimalmedia');
241
- assert.equal(doctorRes.authConfigured, true);
242
- assert.equal(doctorRes.catalog?.auth_type, 'bearer');
243
-
244
- // Cloudflare bundle scopes are pack-scoped (includes mcp-portals.*)
245
- const scopeRes = await runMcp(['scopes', 'cloudflare-bindings', '--json'], { home, write });
246
- assert.ok(scopeRes.oauth_scopes.includes('mcp-portals.read'));
247
- assert.ok(scopeRes.oauth_scopes.includes('mcp-portals.write'));
248
- assert.ok(scopeRes.oauth_scopes.includes('d1.read'));
249
-
250
- // Remove
251
- const removeRes = await runMcp(['remove', 'inneranimalmedia', '--client', 'all', '--json'], { home, write });
252
- assert.equal(removeRes.deletedAuthority, true);
253
-
254
- const emptyList = await runMcp(['list', '--json'], { home, write });
255
- assert.equal(emptyList.length, 0);
256
- });