@inneranimalmedia/agentsam-sdk 2.6.4 → 2.6.5

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 (418) hide show
  1. package/AGENTSAM.md +11 -0
  2. package/README.md +15 -9
  3. package/apps/client-cms-editor/AGENTS.md +12 -0
  4. package/apps/client-cms-editor/IMPORT_PROVENANCE.json +8 -0
  5. package/apps/client-cms-editor/README.md +72 -0
  6. package/apps/client-cms-editor/agentsam.app.json +57 -0
  7. package/apps/client-cms-editor/backend/README.md +5 -0
  8. package/apps/client-cms-editor/backend/package.json +22 -0
  9. package/apps/client-cms-editor/backend/src/api/client.ts +200 -0
  10. package/apps/client-cms-editor/backend/src/demo-bootstrap.ts +145 -0
  11. package/apps/client-cms-editor/backend/src/index.ts +6 -0
  12. package/apps/client-cms-editor/backend/src/model.ts +115 -0
  13. package/apps/client-cms-editor/backend/src/preview/bridge.ts +79 -0
  14. package/apps/client-cms-editor/backend/src/preview/urls.ts +55 -0
  15. package/apps/client-cms-editor/backend/src/routing/cms-route.js +293 -0
  16. package/apps/client-cms-editor/backend/src/routing/index.js +10 -0
  17. package/apps/client-cms-editor/backend/src/storefront.ts +52 -0
  18. package/apps/client-cms-editor/backend/tsconfig.json +15 -0
  19. package/apps/client-cms-editor/backend/worker/index.js +34 -0
  20. package/apps/client-cms-editor/backend/wrangler.jsonc +11 -0
  21. package/apps/client-cms-editor/bin/agentsam-cms.mjs +229 -0
  22. package/apps/client-cms-editor/frontend/index.html +12 -0
  23. package/apps/client-cms-editor/frontend/package.json +33 -0
  24. package/apps/client-cms-editor/frontend/src/AgentSamDrawer.tsx +188 -0
  25. package/apps/client-cms-editor/frontend/src/CmsAgentSurface.tsx +191 -0
  26. package/apps/client-cms-editor/frontend/src/CmsEditor.tsx +1345 -0
  27. package/apps/client-cms-editor/frontend/src/env.d.ts +14 -0
  28. package/apps/client-cms-editor/frontend/src/index.ts +8 -0
  29. package/apps/client-cms-editor/frontend/src/lib/content-safety.ts +63 -0
  30. package/apps/client-cms-editor/frontend/src/main.tsx +17 -0
  31. package/apps/client-cms-editor/frontend/src/mount.tsx +51 -0
  32. package/apps/client-cms-editor/frontend/src/styles/agentsam-drawer.css +214 -0
  33. package/apps/client-cms-editor/frontend/src/styles/cmsShell.css +1739 -0
  34. package/apps/client-cms-editor/frontend/src/styles/studio.css +106 -0
  35. package/apps/client-cms-editor/frontend/src/surfaces/CmsDashboard.tsx +313 -0
  36. package/apps/client-cms-editor/frontend/src/surfaces/CmsGuidedChatHero.tsx +121 -0
  37. package/apps/client-cms-editor/frontend/src/surfaces/CmsHubPage.tsx +132 -0
  38. package/apps/client-cms-editor/frontend/src/surfaces/CmsSiteSwitcher.tsx +176 -0
  39. package/apps/client-cms-editor/frontend/src/surfaces/index.ts +5 -0
  40. package/apps/client-cms-editor/frontend/src/surfaces/types.ts +48 -0
  41. package/apps/client-cms-editor/frontend/tsconfig.json +25 -0
  42. package/apps/client-cms-editor/frontend/vite.config.ts +13 -0
  43. package/apps/client-cms-editor/package-lock.json +3832 -0
  44. package/apps/client-cms-editor/package.json +23 -0
  45. package/apps/client-cms-editor/reference/DONOR_README.md +52 -0
  46. package/apps/client-cms-editor/reference/DONOR_package-lock.json +1253 -0
  47. package/apps/client-cms-editor/reference/DONOR_tsconfig.json +15 -0
  48. package/apps/client-cms-editor/shared/cms/package.json +21 -0
  49. package/apps/client-cms-editor/shared/cms/src/agent-context.ts +35 -0
  50. package/apps/client-cms-editor/shared/cms/src/cloudflare-bindings.ts +51 -0
  51. package/apps/client-cms-editor/shared/cms/src/editor-types.ts +58 -0
  52. package/apps/client-cms-editor/shared/cms/src/index.ts +5 -0
  53. package/apps/client-cms-editor/shared/cms/src/publication.ts +24 -0
  54. package/apps/client-cms-editor/shared/cms/src/routes.ts +11 -0
  55. package/apps/client-cms-editor/shared/cms/tsconfig.json +12 -0
  56. package/bin/agentsam-rapid-rust +36 -0
  57. package/docs/AUTH_IDENTITY_CONTRACT.md +2 -0
  58. package/docs/MACHINE_INTELLIGENCE.md +120 -0
  59. package/docs/WINDOWS_RUNTIME_INSTALL.md +30 -0
  60. package/docs/architecture/AGENTSAM_APPLICATION_CONTRACT.md +188 -0
  61. package/docs/architecture/AGENTSAM_RUNTIME_PROTOCOL.md +151 -0
  62. package/docs/architecture/LOCAL_STUDIO_CLOUDFLARE_OAUTH.md +12 -4
  63. package/docs/architecture/R2_SLUG_NAMESPACE.md +20 -0
  64. package/docs/architecture/WORK_PRODUCT_EXTRACTION.md +97 -0
  65. package/docs/brand/AGENT_SAM_ICON_GRAMMAR.md +70 -0
  66. package/docs/content-studio/HOST_MOUNT_CHECKLIST.md +71 -0
  67. package/docs/content-studio/REVISION_GATE_2026-09-27.md +501 -0
  68. package/docs/contracts/capability-install-planner.md +67 -0
  69. package/docs/contracts/environment-vocabulary.md +195 -0
  70. package/docs/contracts/google-cloud-oauth-setup.md +199 -0
  71. package/docs/local-studio/WORKMODE_DONOR_NOTES.md +1 -1
  72. package/docs/plans/LOCAL-STUDIO-GRADUATION-2026-09-26.md +290 -0
  73. package/docs/plans/LOCAL-STUDIO-REAL-APP-CONTRACT-ADDENDUM-2026-09-27.md +394 -0
  74. package/docs/plans/MACHINE-FIRST-APPS-TUI-2026-09-24.md +227 -0
  75. package/docs/plans/TOMORROW-EXTENSIVE-TODO-2026-09-26.md +221 -0
  76. package/docs/plans/TOMORROW-MACHINE-FIRST-BRIEFING.md +145 -0
  77. package/docs/plans/UNIVERSAL-INGEST-MACHINE-FIRST-2026-09-24.md +215 -0
  78. package/docs/plugins.md +2 -2
  79. package/docs/product/AGENTSAM_PRODUCT_EXPERIENCE_STANDARD.md +280 -0
  80. package/docs/product/LOCAL_STUDIO_DESKTOP_EXPERIENCE.md +139 -0
  81. package/docs/product/README.md +8 -0
  82. package/docs/rapid-rust-wasm.md +35 -0
  83. package/migrations/d1/0016_cloudflare_oauth_user_oauth_tokens_ssot.sql +14 -0
  84. package/package.json +73 -14
  85. package/packages/agentsam-brand/README.md +106 -11
  86. package/packages/agentsam-brand/bin/agentsam-brand.mjs +9 -0
  87. package/packages/agentsam-brand/package.json +39 -7
  88. package/packages/agentsam-brand/src/adapters/cloudflare-images.js +453 -0
  89. package/packages/agentsam-brand/src/adapters/cloudflare-r2.js +74 -0
  90. package/packages/agentsam-brand/src/adapters/d1-registry.js +26 -0
  91. package/packages/agentsam-brand/src/adapters/filesystem.js +59 -0
  92. package/packages/agentsam-brand/src/adapters/memory.js +31 -0
  93. package/packages/agentsam-brand/src/cli/controller.js +503 -0
  94. package/packages/agentsam-brand/src/cli/wizard.js +526 -0
  95. package/packages/agentsam-brand/src/core/capabilities.js +201 -0
  96. package/packages/agentsam-brand/src/core/derivatives.js +211 -0
  97. package/packages/agentsam-brand/src/core/errors.js +12 -0
  98. package/packages/agentsam-brand/src/core/ingest.js +195 -0
  99. package/packages/agentsam-brand/src/core/inspect.js +109 -0
  100. package/packages/agentsam-brand/src/core/keys.js +83 -0
  101. package/packages/agentsam-brand/src/core/naming.js +142 -0
  102. package/packages/agentsam-brand/src/core/optimize.js +316 -0
  103. package/packages/agentsam-brand/src/core/pack.js +305 -0
  104. package/packages/agentsam-brand/src/core/plan.js +276 -0
  105. package/packages/agentsam-brand/src/core/preview.js +159 -0
  106. package/packages/agentsam-brand/src/core/processors/cloudflare.js +68 -0
  107. package/packages/agentsam-brand/src/core/processors/contract.js +203 -0
  108. package/packages/agentsam-brand/src/core/processors/index.js +148 -0
  109. package/packages/agentsam-brand/src/core/processors/native.js +82 -0
  110. package/packages/agentsam-brand/src/core/processors/sharp.js +113 -0
  111. package/packages/agentsam-brand/src/core/processors/squoosh-binary.js +195 -0
  112. package/packages/agentsam-brand/src/core/promote.js +288 -0
  113. package/packages/agentsam-brand/src/core/receipts.js +155 -0
  114. package/packages/agentsam-brand/src/core/v2/compile.js +280 -0
  115. package/packages/agentsam-brand/src/core/v2/derivatives-semantic.js +207 -0
  116. package/packages/agentsam-brand/src/core/v2/ingest-graph.js +387 -0
  117. package/packages/agentsam-brand/src/core/v2/roles.js +180 -0
  118. package/packages/agentsam-brand/src/core/v2/schema.js +209 -0
  119. package/packages/agentsam-brand/src/core/v2/templates.js +114 -0
  120. package/packages/agentsam-brand/src/index.js +193 -36
  121. package/packages/agentsam-brand/src/presets/app-icon.json +16 -0
  122. package/packages/agentsam-brand/src/presets/favicon.json +17 -0
  123. package/packages/agentsam-brand/src/presets/hero.json +12 -0
  124. package/packages/agentsam-brand/src/presets/index.js +40 -0
  125. package/packages/agentsam-brand/src/presets/logo.json +12 -0
  126. package/packages/agentsam-brand/src/presets/model.json +8 -0
  127. package/packages/agentsam-brand/src/presets/og-image.json +10 -0
  128. package/packages/agentsam-brand/src/presets/product-shot.json +11 -0
  129. package/packages/agentsam-brand/src/presets/social-image.json +10 -0
  130. package/packages/agentsam-brand/src/presets/web-image.json +10 -0
  131. package/packages/agentsam-contracts/src/artifacts.ts +41 -0
  132. package/packages/agentsam-knowledge/src/autorag/index.js +1 -1
  133. package/packages/agentsam-knowledge/src/providers/index.js +6 -4
  134. package/packages/agentsam-knowledge/src/providers/ollama-endpoint.js +31 -0
  135. package/packages/agentsam-knowledge/test/autorag.test.mjs +22 -1
  136. package/packages/agentsam-nav/package.json +2 -2
  137. package/packages/agentsam-rapid-rust/Cargo.lock +344 -0
  138. package/packages/agentsam-rapid-rust/Cargo.toml +18 -0
  139. package/packages/agentsam-rapid-rust/README.md +5 -0
  140. package/packages/agentsam-rapid-rust/src/main.rs +718 -0
  141. package/packages/agentsam-rapid-rust/templates/api/Cargo.toml.tmpl +18 -0
  142. package/packages/agentsam-rapid-rust/templates/api/src/lib.rs.tmpl +17 -0
  143. package/packages/agentsam-rapid-rust/templates/common/README.md.tmpl +22 -0
  144. package/packages/agentsam-rapid-rust/templates/common/package.json.tmpl +12 -0
  145. package/packages/agentsam-rapid-rust/templates/common/wrangler.toml.tmpl +6 -0
  146. package/packages/agentsam-rapid-rust/templates/crypto-auth/Cargo.toml.tmpl +21 -0
  147. package/packages/agentsam-rapid-rust/templates/crypto-auth/src/lib.rs.tmpl +32 -0
  148. package/packages/agentsam-rapid-rust/templates/data-processor/Cargo.toml.tmpl +18 -0
  149. package/packages/agentsam-rapid-rust/templates/data-processor/src/lib.rs.tmpl +41 -0
  150. package/packages/agentsam-rapid-rust/templates/shared-core/Cargo.toml.tmpl +9 -0
  151. package/packages/agentsam-rapid-rust/templates/shared-core/core/Cargo.toml.tmpl +7 -0
  152. package/packages/agentsam-rapid-rust/templates/shared-core/core/src/lib.rs.tmpl +23 -0
  153. package/packages/agentsam-rapid-rust/templates/shared-core/worker/Cargo.toml.tmpl +12 -0
  154. package/packages/agentsam-rapid-rust/templates/shared-core/worker/src/lib.rs.tmpl +16 -0
  155. package/packages/agentsam-rapid-rust/templates/shared-core/wrangler.toml.tmpl +6 -0
  156. package/packages/agentsam-repository/src/index.js +1 -0
  157. package/packages/agentsam-repository/src/merkle/semantic.js +3 -10
  158. package/packages/agentsam-repository/src/source-types.js +85 -0
  159. package/packages/agentsam-vault/README.md +96 -0
  160. package/packages/agentsam-vault/package.json +32 -0
  161. package/packages/agentsam-vault/src/contracts/credential.d.ts +78 -0
  162. package/packages/agentsam-vault/src/contracts/credential.js +132 -0
  163. package/packages/agentsam-vault/src/crypto/aes-gcm.d.ts +30 -0
  164. package/packages/agentsam-vault/src/crypto/aes-gcm.js +107 -0
  165. package/packages/agentsam-vault/src/crypto/oauth-envelope.js +150 -0
  166. package/packages/agentsam-vault/src/index.d.ts +9 -0
  167. package/packages/agentsam-vault/src/index.js +27 -0
  168. package/packages/agentsam-vault/src/providers/registry.js +90 -0
  169. package/packages/agentsam-vault/src/runtime/resolver.js +77 -0
  170. package/packages/agentsam-workbench/README.md +24 -0
  171. package/packages/agentsam-workbench/package.json +38 -0
  172. package/packages/agentsam-workbench/src/agent/AgentPanel.tsx +41 -0
  173. package/packages/agentsam-workbench/src/agent/ArtifactCard.tsx +9 -0
  174. package/packages/agentsam-workbench/src/agent/Composer.tsx +102 -0
  175. package/packages/agentsam-workbench/src/agent/ConnectedAgentPanel.tsx +194 -0
  176. package/packages/agentsam-workbench/src/agent/ContextualComposer.tsx +788 -0
  177. package/packages/agentsam-workbench/src/agent/GoalStatusStrip.tsx +38 -0
  178. package/packages/agentsam-workbench/src/agent/MiniAgentSam.tsx +86 -0
  179. package/packages/agentsam-workbench/src/agent/ModelSelect.tsx +19 -0
  180. package/packages/agentsam-workbench/src/agent/Thread.tsx +56 -0
  181. package/packages/agentsam-workbench/src/agent/ToolReceipt.tsx +11 -0
  182. package/packages/agentsam-workbench/src/agent/contextual-composer.css +611 -0
  183. package/packages/agentsam-workbench/src/agent/index.ts +10 -0
  184. package/packages/agentsam-workbench/src/agent/mini-agentsam.css +12 -0
  185. package/packages/agentsam-workbench/src/browser/BrowserFrame.tsx +37 -0
  186. package/packages/agentsam-workbench/src/browser/index.ts +1 -0
  187. package/packages/agentsam-workbench/src/index.ts +6 -0
  188. package/packages/agentsam-workbench/src/project-control.css +160 -0
  189. package/packages/agentsam-workbench/src/projects/ProjectsSurface.tsx +131 -0
  190. package/packages/agentsam-workbench/src/projects/index.ts +1 -0
  191. package/packages/agentsam-workbench/src/shell/Breadcrumb.tsx +35 -0
  192. package/packages/agentsam-workbench/src/shell/ResizableStage.tsx +99 -0
  193. package/packages/agentsam-workbench/src/shell/SidePanel.tsx +5 -0
  194. package/packages/agentsam-workbench/src/shell/index.ts +4 -0
  195. package/packages/agentsam-workbench/src/shell/surfaceRegistry.ts +29 -0
  196. package/packages/agentsam-workbench/src/terminal/TerminalSurface.tsx +5 -0
  197. package/packages/agentsam-workbench/src/terminal/index.ts +1 -0
  198. package/packages/agentsam-workbench/src/timeline/GanttBoard.tsx +258 -0
  199. package/packages/agentsam-workbench/src/timeline/index.ts +1 -0
  200. package/packages/agentsam-workbench/tsconfig.json +13 -0
  201. package/packages/connectors/cloudflare/OAUTH_STORAGE_AUDIT.md +53 -0
  202. package/packages/connectors/cloudflare/package.json +3 -1
  203. package/packages/connectors/cloudflare/src/api-client.js +279 -0
  204. package/packages/connectors/cloudflare/src/capabilities.js +585 -0
  205. package/packages/connectors/cloudflare/src/credential.js +318 -0
  206. package/packages/connectors/cloudflare/src/families/brand-protection.js +123 -0
  207. package/packages/connectors/cloudflare/src/families/keyless.js +114 -0
  208. package/packages/connectors/cloudflare/src/families/pages.js +151 -0
  209. package/packages/connectors/cloudflare/src/families/scanner.js +123 -0
  210. package/packages/connectors/cloudflare/src/families/snippets.js +207 -0
  211. package/packages/connectors/cloudflare/src/families/tag-gateway.js +46 -0
  212. package/packages/connectors/cloudflare/src/families/tags.js +124 -0
  213. package/packages/connectors/cloudflare/src/families/token-validation.js +95 -0
  214. package/packages/connectors/cloudflare/src/families/workflows.js +156 -0
  215. package/packages/connectors/cloudflare/src/index.js +102 -265
  216. package/packages/connectors/cloudflare/src/oauth-persist.js +336 -0
  217. package/packages/connectors/cloudflare/src/owner.js +42 -12
  218. package/packages/connectors/cloudflare/src/permission-options.js +1064 -0
  219. package/packages/connectors/cloudflare/src/routes.js +309 -144
  220. package/packages/connectors/cloudflare/src/scope-catalog.js +345 -0
  221. package/packages/connectors/cloudflare/src/vault.js +2 -2
  222. package/packages/connectors/cloudflare/tests/capabilities.test.mjs +276 -0
  223. package/packages/connectors/cloudflare/tests/connector.test.mjs +26 -30
  224. package/packages/connectors/cloudflare/tests/oauth-persist.test.mjs +125 -0
  225. package/packages/identity/.agentsam/features/oauth-login-portal/providers.json +22 -2
  226. package/packages/identity/.agentsam/features/oauth-login-portal/resources.json +10 -4
  227. package/packages/identity/.agentsam/features/oauth-login-portal/routes.json +20 -0
  228. package/packages/identity/README.md +1 -1
  229. package/packages/identity/backend/README.md +1 -1
  230. package/packages/identity/migrations/D1_SCHEMA_MAPPING.md +3 -2
  231. package/packages/identity/migrations/sqlite/004_identity_oauth_consent_catalog.sql +48 -0
  232. package/packages/identity/package.json +4 -3
  233. package/packages/identity/scripts/local-identity-bridge.mjs +184 -0
  234. package/packages/identity/scripts/preview-auth-portal.mjs +7 -7
  235. package/packages/identity/src/adapters/cloudflare-d1/index.js +31 -2
  236. package/packages/identity/src/adapters/sqlite/index.js +4 -1
  237. package/packages/identity/src/contracts/auth-config.js +28 -8
  238. package/packages/identity/src/contracts/external-identity.js +1 -1
  239. package/packages/identity/src/contracts/provider.js +1 -0
  240. package/packages/identity/src/frontend/auth-portal/README.md +2 -1
  241. package/packages/identity/src/frontend/auth-portal/pages/login.html +6 -5
  242. package/packages/identity/src/frontend/auth-portal/pages/reset.html +6 -5
  243. package/packages/identity/src/frontend/auth-portal/pages/signup.html +6 -5
  244. package/packages/identity/src/frontend/auth-portal/shared/company-branding.js +1 -1
  245. package/packages/identity/src/frontend/auth-portal/shared/desktop-identity-bridge.js +207 -0
  246. package/packages/identity/src/index.js +16 -0
  247. package/packages/identity/src/migrations/0001_identity_core.sql +19 -2
  248. package/packages/identity/src/migrations/0003_accounts_ssot.sql +20 -0
  249. package/packages/identity/src/migrations/README.md +5 -2
  250. package/packages/identity/src/oauth/README.md +10 -5
  251. package/packages/identity/src/oauth/consent-view.js +388 -0
  252. package/packages/identity/src/oauth/credentials.js +31 -11
  253. package/packages/identity/src/oauth/google-desktop-exchange.js +173 -0
  254. package/packages/identity/src/providers/cloudflare/oauth.js +3 -4
  255. package/packages/identity/src/providers/cloudflare/profile.js +49 -14
  256. package/packages/identity/src/providers/iam/index.js +27 -5
  257. package/packages/identity/src/server/identity-service.js +31 -2
  258. package/packages/identity/src/server/worker-router.js +111 -81
  259. package/packages/identity/tests/auth-config.test.mjs +3 -2
  260. package/packages/identity/tests/identity-init-scaffold.test.mjs +3 -0
  261. package/packages/identity/tests/identity-service.test.mjs +16 -0
  262. package/packages/identity/tests/native-session-worker.test.mjs +64 -0
  263. package/packages/identity/tests/oauth-consent-view.test.mjs +106 -0
  264. package/packages/identity/tests/oauth-credentials.test.mjs +17 -4
  265. package/packages/identity/tests/oauth-presets-accounts-ssot.test.mjs +58 -0
  266. package/packages/identity/tests/preview-auth-portal.test.mjs +3 -3
  267. package/packages/runtime-protocol/src/index.js +154 -0
  268. package/packages/theme-scenes/README.md +164 -0
  269. package/packages/theme-scenes/package.json +53 -0
  270. package/packages/theme-scenes/src/blocks/index.js +30 -0
  271. package/packages/theme-scenes/src/contracts/index.js +286 -0
  272. package/packages/theme-scenes/src/demos/index.js +65 -0
  273. package/packages/theme-scenes/src/index.js +75 -0
  274. package/packages/theme-scenes/src/presets/index.js +263 -0
  275. package/packages/theme-scenes/src/runtime/compile.js +119 -0
  276. package/packages/theme-scenes/src/scenes/index.js +146 -0
  277. package/packages/theme-scenes/src/shell/index.js +47 -0
  278. package/packages/theme-scenes/src/themes/index.js +129 -0
  279. package/packages/theme-scenes/src/visuals/index.js +41 -0
  280. package/packages/theme-scenes/test/theme-scenes.test.mjs +179 -0
  281. package/packages/work-graph/src/index.js +34 -1
  282. package/packages/work-graph/src/renderers/gantt-model.js +24 -0
  283. package/packages/work-graph/test/work-graph.test.mjs +27 -7
  284. package/protocol/README.md +15 -7
  285. package/protocol/apps/agentsam.app.v1.schema.json +89 -7
  286. package/protocol/apps/agentsam.host-install.v1.schema.json +36 -0
  287. package/protocol/assets/README.md +9 -0
  288. package/protocol/assets/asset-record.v1.schema.json +64 -0
  289. package/protocol/runtime/agentsam.runtime.v1.schema.json +75 -0
  290. package/protocol/scoring/README.md +10 -0
  291. package/protocol/scoring/scorecard.v1.schema.json +65 -0
  292. package/protocol/ui/icon-registry.mjs +1 -0
  293. package/registry/cms-rust-machine-20260928/installable-products.json +31 -0
  294. package/registry/cms-rust-machine-20260928/manifest.json +22 -0
  295. package/registry/cms-rust-machine-20260928/migration.sql +237 -0
  296. package/registry/cms-rust-machine-20260928/receipt.json +21 -0
  297. package/registry/cms-rust-machine-20260928/receipt.sql +27 -0
  298. package/scripts/build_rapid_rust_cli.py +83 -0
  299. package/src/attachments/index.js +6 -0
  300. package/src/attachments/intake.js +235 -0
  301. package/src/capabilities/repository-snapshot.js +19 -2
  302. package/src/cli/command-catalog.js +8 -0
  303. package/src/cli.js +182 -26
  304. package/src/commands/account-auth.js +94 -8
  305. package/src/commands/app.js +307 -3
  306. package/src/commands/billing.js +127 -0
  307. package/src/commands/brand.js +74 -60
  308. package/src/commands/cheat-sheet.js +154 -0
  309. package/src/commands/cloudflare-login.js +222 -0
  310. package/src/commands/cloudflare.js +453 -23
  311. package/src/commands/codebaseindex.js +6 -1
  312. package/src/commands/compute.js +4 -0
  313. package/src/commands/connections.js +11 -5
  314. package/src/commands/credentials.js +116 -0
  315. package/src/commands/gcloud-auth.js +427 -0
  316. package/src/commands/google-cloud.js +375 -0
  317. package/src/commands/identity-init.js +2 -2
  318. package/src/commands/mcp.js +226 -33
  319. package/src/commands/ollama.js +3 -2
  320. package/src/commands/plugins.js +7 -2
  321. package/src/commands/product.js +36 -0
  322. package/src/commands/runtime-status.js +28 -9
  323. package/src/commands/runtime.js +313 -0
  324. package/src/commands/rust.js +24 -0
  325. package/src/commands/setup.js +279 -0
  326. package/src/commands/shell.js +16 -3
  327. package/src/commands/start-local.js +2 -2
  328. package/src/commands/terminal.js +171 -0
  329. package/src/commands/update.js +140 -0
  330. package/src/commands/whoami.js +329 -65
  331. package/src/features/resolve.js +1 -0
  332. package/src/index.js +4 -0
  333. package/src/indexing/ingest/inventory.js +254 -19
  334. package/src/indexing/ingest/materials.js +3 -9
  335. package/src/indexing/ingest/style-evidence.js +181 -0
  336. package/src/knowledge/source.js +3 -3
  337. package/src/lib/account-session.js +11 -4
  338. package/src/lib/app-authority.js +172 -0
  339. package/src/lib/auth.js +94 -21
  340. package/src/lib/core-client.js +5 -6
  341. package/src/lib/credentials-audit.js +451 -0
  342. package/src/lib/deploy/health.js +24 -6
  343. package/src/lib/detect-context.js +7 -1
  344. package/src/lib/google-cloud-connection.js +270 -0
  345. package/src/lib/google-cloud-inventory.js +385 -0
  346. package/src/lib/google-desktop-oauth.js +372 -0
  347. package/src/lib/google-studio-brokered-oauth.js +158 -0
  348. package/src/lib/identity-scaffold.js +24 -6
  349. package/src/lib/init-options.js +192 -0
  350. package/src/lib/local-scaffold.js +48 -16
  351. package/src/lib/provider-command-remediation.js +308 -0
  352. package/src/lib/provider-credentials.js +8 -0
  353. package/src/lib/scaffold/index.js +8 -2
  354. package/src/lib/scaffold/mcp-server.js +43 -0
  355. package/src/lib/scaffold/templates/mcp-server/index.js +397 -0
  356. package/src/lib/scaffold/templates/mcp-server/presets.js +39 -0
  357. package/src/lib/scaffold/wizards/cms.js +93 -0
  358. package/src/lib/scaffold/wizards/mcp-server.js +61 -0
  359. package/src/lib/setup/contract.js +26 -0
  360. package/src/lib/setup/discover.js +116 -0
  361. package/src/lib/setup/execute.js +205 -0
  362. package/src/lib/setup/planner.js +134 -0
  363. package/src/lib/setup/recipes.js +235 -0
  364. package/src/lib/setup/runtime-persist.js +197 -0
  365. package/src/lib/setup/runtime.js +394 -0
  366. package/src/lib/slash-commands.js +2 -0
  367. package/src/lib/terminal/machine-identity.js +95 -0
  368. package/src/lib/terminal-local.js +164 -0
  369. package/src/lib/terminal-scopes.js +52 -0
  370. package/src/lib/whoami-capabilities.js +184 -0
  371. package/src/local-pty/server.js +34 -5
  372. package/src/mcp/authority.js +58 -108
  373. package/src/mcp/client-adapters.js +68 -144
  374. package/src/mcp/client.js +142 -122
  375. package/src/mcp/cloudflare-bundles.js +225 -0
  376. package/src/mcp/index.js +12 -0
  377. package/src/plugins/cloudflare.js +1 -1
  378. package/src/providers/ollama-chat.js +2 -1
  379. package/src/sam/types.js +27 -2
  380. package/src/security/inventory.js +12 -2
  381. package/src/security/local-vault.js +2 -0
  382. package/src/security/scan.js +1 -1
  383. package/test/account-session.test.mjs +3 -3
  384. package/test/app-authority-context.test.mjs +32 -0
  385. package/test/cli/codebaseindex-plan-ux.test.mjs +1 -1
  386. package/test/cli/mcp-client.test.mjs +21 -10
  387. package/test/cli/runtime-persist.test.mjs +56 -0
  388. package/test/cli/rust-command.test.mjs +21 -0
  389. package/test/credentials-audit.test.mjs +113 -0
  390. package/test/deploy-health-scan.test.mjs +29 -1
  391. package/test/gcloud-auth.test.mjs +111 -0
  392. package/test/google-cloud-connection.test.mjs +83 -0
  393. package/test/google-cloud-inventory.test.mjs +64 -0
  394. package/test/init-options.test.mjs +35 -0
  395. package/test/integration/app-command.test.mjs +30 -0
  396. package/test/integration/cad-project.test.mjs +4 -1
  397. package/test/integration/cms-app-scaffold.test.mjs +71 -0
  398. package/test/integration/cms-site-tenancy-contract.test.mjs +3 -2
  399. package/test/integration/codebaseindex-ingest.test.mjs +48 -0
  400. package/test/integration/features-resolve.test.mjs +30 -11
  401. package/test/integration/inspect-path-cli.test.mjs +46 -0
  402. package/test/integration/inventory-evidence.test.mjs +125 -0
  403. package/test/integration/runtime-status.integration.test.mjs +2 -1
  404. package/test/knowledge.test.mjs +35 -1
  405. package/test/loopback-oauth.test.mjs +53 -0
  406. package/test/ollama.test.mjs +22 -0
  407. package/test/security.test.mjs +23 -0
  408. package/test/setup-planner.test.mjs +74 -0
  409. package/test/setup-runtime.test.mjs +51 -0
  410. package/test/terminal/local-pty.mock.test.mjs +3 -1
  411. package/test/terminal-machine-identity.test.mjs +88 -0
  412. package/test/whoami-resume.test.mjs +27 -6
  413. package/packages/agentsam-brand/test/brand-scan.test.mjs +0 -106
  414. package/packages/work-graph/prototype/README.md +0 -32
  415. package/packages/work-graph/prototype/data/demo-workgraph.js +0 -47
  416. package/packages/work-graph/prototype/renderers/timeline-model.js +0 -21
  417. package/packages/work-graph/prototype/renderers/workgraph-runtime.js +0 -38
  418. package/packages/work-graph/prototype-gnantt.html +0 -655
@@ -120,7 +120,9 @@ function osStoreWriteDarwin(provider, secret) {
120
120
  try {
121
121
  const res = spawnSync('/usr/bin/security', ['add-generic-password', '-a', `agentsam:${provider}`, '-s', 'agentsam', '-w', secret, '-U'], {
122
122
  stdio: 'ignore',
123
+ timeout: 12_000,
123
124
  });
125
+ if (res.error?.code === 'ETIMEDOUT' || res.signal === 'SIGTERM') return false;
124
126
  return res.status === 0;
125
127
  } catch { return false; }
126
128
  }
@@ -4,7 +4,7 @@ import { triageLog, resolveLogFindings } from './logs.js';
4
4
  import { scanTrustBoundary } from './trust-boundary.js';
5
5
 
6
6
  export async function scanProjectSecurity(options = {}) {
7
- const inventory = collectNpmDependencies(options.projectRoot);
7
+ const inventory = collectNpmDependencies(options.projectRoot, { releaseCandidate: options.releaseCandidate });
8
8
  const results = options.offline
9
9
  ? inventory.dependencies.map(d => ({ ...d, checked: false, advisories: [] }))
10
10
  : await queryOsv(inventory.dependencies, options);
@@ -38,7 +38,7 @@ test('opaque browser login persists in machine-local storage and resolves indepe
38
38
  assert.equal(loaded.access_token, 'browser_session_machine_test');
39
39
  const browser = resolveBrowserSessionCredential({ env: {}, home });
40
40
  assert.equal(browser.source, 'agentsam_browser_oauth');
41
- assert.equal(browser.kind, 'browser_oauth');
41
+ assert.equal(browser.kind, 'agentsam_browser_oauth');
42
42
  assert.equal(browser.value, 'browser_session_machine_test');
43
43
  assert.equal(resolveAccountApiKey({ env: {}, home }).value, '');
44
44
  assert.equal(resolveAccountAuth({ env: {}, home }).value, 'browser_session_machine_test');
@@ -70,7 +70,7 @@ test('invalid environment API key cannot shadow a valid browser login', t => {
70
70
  saveAccountSession({ access_token: 'browser_session_machine_test' }, { home });
71
71
  const resolved = resolveAccountAuth({ env: { AGENTSAM_API_KEY: 'not-an-aak' }, home });
72
72
  assert.equal(resolved.value, 'browser_session_machine_test');
73
- assert.equal(resolved.kind, 'browser_oauth');
73
+ assert.equal(resolved.kind, 'agentsam_browser_oauth');
74
74
  assert.equal(resolved.fallback_error, 'invalid_api_key_prefix');
75
75
  });
76
76
 
@@ -79,7 +79,7 @@ test('async IAM authority also falls back from invalid environment key to browse
79
79
  saveAccountSession({ access_token: 'browser_session_machine_test' }, { home });
80
80
  const resolved = await resolveAccountAuthority({ env: { AGENTSAM_API_KEY: 'not-an-aak' }, home });
81
81
  assert.equal(resolved.value, 'browser_session_machine_test');
82
- assert.equal(resolved.kind, 'browser_oauth');
82
+ assert.equal(resolved.kind, 'agentsam_browser_oauth');
83
83
  assert.equal(resolved.fallback_error, 'invalid_api_key_prefix');
84
84
  });
85
85
 
@@ -0,0 +1,32 @@
1
+ import assert from 'node:assert/strict';
2
+ import path from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import test from 'node:test';
5
+ import { resolveCurrentAppContext } from '../src/lib/app-authority.js';
6
+
7
+ const HERE = path.dirname(fileURLToPath(import.meta.url));
8
+ const ROOT = path.resolve(HERE, '..');
9
+
10
+ test('generic repo root has no fabricated app identity', () => {
11
+ const context = resolveCurrentAppContext({ root: ROOT, cwd: ROOT });
12
+ assert.deepEqual(context, { app_id: null, host_origin: null, source: null });
13
+ });
14
+
15
+ test('Local Studio context resolves from nearest agentsam.app.json', () => {
16
+ const context = resolveCurrentAppContext({
17
+ root: ROOT,
18
+ cwd: path.join(ROOT, 'apps/local-studio/frontend'),
19
+ });
20
+ assert.equal(context.app_id, 'local-studio');
21
+ assert.equal(context.host_origin, null);
22
+ assert.match(context.source || '', /apps\/local-studio\/agentsam\.app\.json$/);
23
+ });
24
+
25
+ test('package app identity resolves from its own manifest without Local Studio leakage', () => {
26
+ const context = resolveCurrentAppContext({
27
+ root: ROOT,
28
+ cwd: path.join(ROOT, 'packages/agentsam-database-editor/src'),
29
+ });
30
+ assert.equal(context.app_id, 'database-editor');
31
+ assert.equal(context.host_origin, null);
32
+ });
@@ -32,6 +32,6 @@ describe('inventory path categories', () => {
32
32
  assert.equal(classifyTopLevel('node_modules'), 'dependencies');
33
33
  assert.equal(classifyTopLevel('dist'), 'dependencies');
34
34
  assert.equal(classifyTopLevel('generated'), 'generated');
35
- assert.equal(classifyTopLevel('.agentsam'), 'config');
35
+ assert.equal(classifyTopLevel('.agentsam'), 'operational');
36
36
  });
37
37
  });
@@ -58,7 +58,7 @@ test('MCP authority store manages servers under ~/.agentsam/mcp with safe permis
58
58
  assert.equal(readMcpServer('inneranimalmedia', { home }), null);
59
59
  });
60
60
 
61
- test('MCP external client registry recognizes chatgpt, claude, cursor and respects is_active', async () => {
61
+ test('MCP external client registry recognizes chatgpt, claude, cursor — not CF portals', async () => {
62
62
  const home = tempHome();
63
63
 
64
64
  // Baseline seed / cached client list
@@ -68,9 +68,11 @@ test('MCP external client registry recognizes chatgpt, claude, cursor and respec
68
68
  assert.ok(keys.includes('cursor'), 'Cursor is recognized in the external client registry');
69
69
  assert.ok(keys.includes('claude'), 'Claude is recognized in the external client registry');
70
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');
71
72
 
72
73
  assert.equal(isClientRegistered('chatgpt', { home }), true);
73
74
  assert.equal(isClientRegistered('cursor', { home }), true);
75
+ assert.equal(isClientRegistered('cf_bindings_mcp', { home }), false);
74
76
  assert.equal(isClientRegistered('nonexistent_client_xyz', { home }), false);
75
77
 
76
78
  // Cache path is created upon writing
@@ -154,23 +156,25 @@ test('MCP client adapters materialize Cursor, Claude, and ChatGPT configurations
154
156
  assert.equal(fs.existsSync(chatgptConfigPath), false);
155
157
  });
156
158
 
157
- test('MCP server catalog resolves real registered servers with live health metrics', () => {
159
+ test('MCP server catalog resolves CF portal bundles + IAM without fabricated health', () => {
158
160
  const home = tempHome();
159
161
  const catalog = listKnownServers({ home });
160
162
  assert.ok(catalog.length >= 8);
161
163
 
162
- // Cloudflare API server from D1
163
164
  const cfApi = resolveServerPreset('cloudflare-api', { home });
164
165
  assert.ok(cfApi);
165
166
  assert.equal(cfApi.url, 'https://mcp.cloudflare.com/mcp');
166
- assert.equal(cfApi.health_status, 'degraded');
167
- assert.equal(cfApi.avg_latency_ms, 9);
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'));
168
174
 
169
- // InnerAnimalMedia Main MCP from D1
170
175
  const iam = resolveServerPreset('inneranimalmedia', { home });
171
176
  assert.ok(iam);
172
- assert.equal(iam.health_status, 'healthy');
173
- assert.equal(iam.avg_latency_ms, 443);
177
+ assert.equal(iam.url, 'https://mcp.inneranimalmedia.com/mcp');
174
178
  });
175
179
 
176
180
  test('MCP telemetry logs tool receipts and computes accurate summaries', () => {
@@ -204,6 +208,7 @@ test('agentsam mcp CLI handles add, list, status, doctor, and remove end-to-end'
204
208
  const helpText = logs.join('\n');
205
209
  assert.ok(helpText.includes('chatgpt'), 'Help text displays ChatGPT as a recognized client');
206
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');
207
212
  logs.length = 0;
208
213
 
209
214
  // Add inneranimalmedia preset for chatgpt client
@@ -230,11 +235,17 @@ test('agentsam mcp CLI handles add, list, status, doctor, and remove end-to-end'
230
235
  assert.equal(statusRes.name, 'inneranimalmedia');
231
236
  assert.equal(statusRes.hasAuth, true);
232
237
 
233
- // Doctor includes catalog health data
238
+ // Doctor includes catalog / CF pack metadata
234
239
  const doctorRes = await runMcp(['doctor', 'inneranimalmedia', '--json'], { home, write });
235
240
  assert.equal(doctorRes.name, 'inneranimalmedia');
236
241
  assert.equal(doctorRes.authConfigured, true);
237
- assert.equal(doctorRes.catalogHealth?.health_status, 'healthy');
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'));
238
249
 
239
250
  // Remove
240
251
  const removeRes = await runMcp(['remove', 'inneranimalmedia', '--client', 'all', '--json'], { home, write });
@@ -0,0 +1,56 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import fs from 'node:fs';
4
+ import os from 'node:os';
5
+ import path from 'node:path';
6
+ import {
7
+ buildWindowsScheduledTaskXml,
8
+ buildLaunchAgentPlist,
9
+ writeWindowsScheduledTask,
10
+ WINDOWS_TASK_NAME,
11
+ } from '../../src/lib/setup/runtime-persist.js';
12
+
13
+ test('buildWindowsScheduledTaskXml includes binary, listen, logon trigger', () => {
14
+ const xml = buildWindowsScheduledTaskXml({
15
+ binary: 'C:\\Users\\sam\\.agentsam\\bin\\agentsamd.exe',
16
+ listen: '127.0.0.1:18765',
17
+ workingDirectory: 'C:\\Users\\sam\\.agentsam\\bin',
18
+ });
19
+ assert.match(xml, /agentsamd\.exe/);
20
+ assert.match(xml, /--listen 127\.0\.0\.1:18765/);
21
+ assert.match(xml, /LogonTrigger/);
22
+ assert.match(xml, /InteractiveToken/);
23
+ assert.match(xml, /RestartOnFailure/);
24
+ });
25
+
26
+ test('buildLaunchAgentPlist includes KeepAlive and listen', () => {
27
+ const plist = buildLaunchAgentPlist({
28
+ binary: '/Users/sam/.agentsam/bin/agentsamd',
29
+ listen: '127.0.0.1:18765',
30
+ stdoutLog: '/tmp/out.log',
31
+ stderrLog: '/tmp/err.log',
32
+ });
33
+ assert.match(plist, /com\.inneranimalmedia\.agentsamd/);
34
+ assert.match(plist, /KeepAlive/);
35
+ assert.match(plist, /127\.0\.0\.1:18765/);
36
+ });
37
+
38
+ test('writeWindowsScheduledTask writes XML without calling schtasks when skipRegister', async () => {
39
+ const home = fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-runtime-'));
40
+ try {
41
+ const result = await writeWindowsScheduledTask(
42
+ home,
43
+ path.join(home, '.agentsam', 'bin', 'agentsamd.exe'),
44
+ '127.0.0.1:18765',
45
+ { forcePlatform: 'win32', skipRegister: true },
46
+ );
47
+ assert.equal(result.kind, 'scheduled_task');
48
+ assert.equal(result.taskName, WINDOWS_TASK_NAME);
49
+ assert.equal(result.registered, false);
50
+ assert.ok(fs.existsSync(result.xmlPath));
51
+ const xml = fs.readFileSync(result.xmlPath, 'utf8');
52
+ assert.match(xml, /agentsamd\.exe/);
53
+ } finally {
54
+ fs.rmSync(home, { recursive: true, force: true });
55
+ }
56
+ });
@@ -0,0 +1,21 @@
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
+
8
+ const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');
9
+
10
+ test('rust/wasm command aliases resolve to one catalog authority', () => {
11
+ const rust = getCliCommand('rust');
12
+ assert.equal(rust?.id, 'rust');
13
+ assert.equal(getCliCommand('wasm')?.id, 'rust');
14
+ assert.equal(getCliCommand('rapid-rust')?.id, 'rust');
15
+ });
16
+
17
+ test('rapid rust root bin and native crate ship in source tree', () => {
18
+ assert.equal(fs.existsSync(path.join(root, 'bin/agentsam-rapid-rust')), true);
19
+ assert.equal(fs.existsSync(path.join(root, 'packages/agentsam-rapid-rust/Cargo.toml')), true);
20
+ assert.equal(fs.existsSync(path.join(root, 'scripts/build_rapid_rust_cli.py')), true);
21
+ });
@@ -0,0 +1,113 @@
1
+ import assert from 'node:assert/strict';
2
+ import test from 'node:test';
3
+ import {
4
+ remediateGcloudEdgeServiceAccountKey,
5
+ remediateGcloudPermissionDenied,
6
+ remediateGithubTokenShadow,
7
+ remediateProviderFailure,
8
+ renderRemediationCard,
9
+ recommendedCommand,
10
+ } from '../src/lib/provider-command-remediation.js';
11
+ import { runCredentials } from '../src/commands/credentials.js';
12
+ import { listCheatSheetGroups, renderCheatSheet } from '../src/commands/cheat-sheet.js';
13
+ import { collectCredentialsAudit } from '../src/lib/credentials-audit.js';
14
+
15
+ test('edge-cloud service-account key create remediates to IAM / compute intents', () => {
16
+ const card = remediateGcloudEdgeServiceAccountKey({
17
+ argv: ['gcloud', 'edge-cloud', 'service-accounts', 'keys', 'create'],
18
+ projectId: 'gen-lang-client-0684066529',
19
+ instance: 'iam-tunnel',
20
+ zone: 'us-central1-f',
21
+ });
22
+ assert.ok(card);
23
+ assert.equal(card.provider, 'google_cloud');
24
+ assert.equal(card.kind, 'command_incomplete_wrong_family');
25
+ assert.match(card.summary, /Distributed Cloud Edge/i);
26
+ assert.match(card.summary, /Compute Engine/i);
27
+ const commands = card.actions.map((row) => row.command).join('\n');
28
+ assert.match(commands, /gcloud compute instances describe iam-tunnel/);
29
+ assert.match(commands, /gcloud iam service-accounts list/);
30
+ assert.match(commands, /gcloud iam service-accounts keys create/);
31
+ assert.match(commands, /agentsam connections/);
32
+ const rendered = renderRemediationCard(card);
33
+ assert.match(rendered, /Command incomplete/);
34
+ assert.match(rendered, /\[enter\]/);
35
+ assert.equal(recommendedCommand(card), card.actions[0].command);
36
+ });
37
+
38
+ test('remediateProviderFailure matches edge-cloud argv fixture', () => {
39
+ const card = remediateProviderFailure({
40
+ argv: ['gcloud', 'edge-cloud', 'service-accounts', 'keys', 'create'],
41
+ stderr: 'ERROR: argument OUTPUT_FILE (--service-account : --location): Must be specified.',
42
+ });
43
+ assert.ok(card);
44
+ assert.equal(card.kind, 'command_incomplete_wrong_family');
45
+ });
46
+
47
+ test('permission denied remediation exposes reauth + IAM console actions', () => {
48
+ const card = remediateGcloudPermissionDenied({
49
+ operation: 'compute.instances.list',
50
+ projectId: 'gen-lang-client-0684066529',
51
+ connection: 'Google Cloud · InnerAnimalMedia',
52
+ });
53
+ assert.equal(card.kind, 'permission_denied');
54
+ assert.match(renderRemediationCard(card), /Permission missing/);
55
+ assert.match(renderRemediationCard(card), /Re-authorize Google Cloud/);
56
+ assert.ok(card.actions.some((row) => /console\.cloud\.google\.com\/iam-admin/i.test(row.docs_url || '')));
57
+ });
58
+
59
+ test('github token shadow remediation prefers unset + keyring status', () => {
60
+ const card = remediateGithubTokenShadow({
61
+ envTokenPresent: true,
62
+ keyringHealthy: true,
63
+ scopes: ['repo', 'read:org'],
64
+ });
65
+ assert.ok(card);
66
+ assert.equal(card.kind, 'credential_shadow');
67
+ assert.match(recommendedCommand(card), /unset GITHUB_TOKEN/);
68
+ });
69
+
70
+ test('credentials remediate CLI prints edge-cloud card without secrets', async () => {
71
+ const chunks = [];
72
+ const code = await runCredentials(
73
+ ['remediate', '--', 'gcloud', 'edge-cloud', 'service-accounts', 'keys', 'create'],
74
+ { write: (s) => chunks.push(s) },
75
+ );
76
+ assert.equal(code, 0);
77
+ const out = chunks.join('');
78
+ assert.match(out, /Google Cloud/);
79
+ assert.match(out, /gcloud iam service-accounts list/);
80
+ assert.doesNotMatch(out, /gho_/);
81
+ assert.doesNotMatch(out, /AIza/);
82
+ });
83
+
84
+ test('credentials audit --names-only never includes secret-looking values', async () => {
85
+ const report = await collectCredentialsAudit({
86
+ env: {
87
+ HOME: process.env.HOME,
88
+ AGENTSAM_API_KEY: 'aak_test_should_never_appear_in_output_fields_as_value',
89
+ GITHUB_TOKEN: 'ghp_should_never_be_echoed',
90
+ OPENAI_API_KEY: 'sk-should-never-be-echoed',
91
+ },
92
+ verify: false,
93
+ drift: true,
94
+ namesOnly: true,
95
+ noNetwork: true,
96
+ });
97
+ const blob = JSON.stringify(report);
98
+ assert.doesNotMatch(blob, /aak_test_should_never/);
99
+ assert.doesNotMatch(blob, /ghp_should_never/);
100
+ assert.doesNotMatch(blob, /sk-should-never/);
101
+ assert.equal(report.shell_presence.GITHUB_TOKEN, true);
102
+ assert.equal(report.shell_presence.AGENTSAM_API_KEY, true);
103
+ assert.ok(report.drift.some((row) => row.code === 'github_env_token_present'));
104
+ });
105
+
106
+ test('cheat-sheet exposes System + Providers groups', () => {
107
+ const groups = listCheatSheetGroups();
108
+ assert.ok(groups.some((g) => g.id === 'system'));
109
+ assert.ok(groups.some((g) => g.id === 'providers'));
110
+ const text = renderCheatSheet('2.6.4');
111
+ assert.match(text, /credentials audit/);
112
+ assert.match(text, /cheat-sheet/);
113
+ });
@@ -28,12 +28,18 @@ describe('deploy health', () => {
28
28
 
29
29
  it('reads hostname from wrangler.jsonc', () => {
30
30
  const origin = resolveHealthOrigin({
31
- env: {},
32
31
  wranglerConfigText: '{"routes":[{"pattern":"agentsam.inneranimalmedia.com","custom_domain":true}]}',
33
32
  });
34
33
  assert.equal(origin, 'https://agentsam.inneranimalmedia.com');
35
34
  });
36
35
 
36
+ it('fails loud when wrangler routes pattern is missing', () => {
37
+ assert.throws(
38
+ () => resolveHealthOrigin({ wranglerConfigText: '{}' }),
39
+ (err) => err?.code === 'health_origin_required',
40
+ );
41
+ });
42
+
37
43
  it('treats /health ok:true with connector unconfigured as healthy', async () => {
38
44
  const fetchImpl = async (url) => {
39
45
  if (String(url).endsWith('/health')) {
@@ -48,6 +54,28 @@ describe('deploy health', () => {
48
54
  assert.equal(health.ok, true);
49
55
  assert.equal(health.results['/health'].appOk, true);
50
56
  assert.equal(health.results['/health'].cloudflareConfigured, false);
57
+ assert.equal(health.results['/privacy'].ok, true);
58
+ assert.equal(health.results['/terms'].ok, true);
59
+ });
60
+
61
+ it('fails deploy health when /privacy or /terms are not HTTP 200', async () => {
62
+ const fetchImpl = async (url) => {
63
+ const path = String(url).replace(/^https?:\/\/[^/]+/, '');
64
+ if (path === '/health') {
65
+ return {
66
+ status: 200,
67
+ json: async () => ({ ok: true, connections: { cloudflare: { configured: true } } }),
68
+ };
69
+ }
70
+ if (path === '/privacy' || path === '/terms') {
71
+ return { status: 404, json: async () => ({}) };
72
+ }
73
+ return { status: 200, json: async () => ({}) };
74
+ };
75
+ const health = await probeDeployHealth('https://agentsam.inneranimalmedia.com', { fetchImpl });
76
+ assert.equal(health.ok, false);
77
+ assert.equal(health.results['/privacy'].ok, false);
78
+ assert.equal(health.results['/terms'].ok, false);
51
79
  });
52
80
 
53
81
  it('sends a browser-safe User-Agent so WAF does not 403 the probe', async () => {
@@ -0,0 +1,111 @@
1
+ import assert from 'node:assert/strict';
2
+ import test from 'node:test';
3
+ import {
4
+ resolveGoogleOauthStartUrl,
5
+ runAgentsamGoogleOauthLogin,
6
+ runGcloudAuth,
7
+ } from '../src/commands/gcloud-auth.js';
8
+ import {
9
+ GOOGLE_CLOUD_CONNECTION_SCOPES,
10
+ buildGoogleDesktopAuthUrl,
11
+ googleCloudPermissionChecklist,
12
+ resolveGoogleDesktopClientId,
13
+ } from '../src/lib/google-desktop-oauth.js';
14
+
15
+ const TEST_ENV = {
16
+ IAM_OAUTH_ISSUER: 'https://inneranimalmedia.com',
17
+ GOOGLE_CLIENT_ID: '246811022042-d8q1rc1oki4uv9qiqjah8lvkffb91crp.apps.googleusercontent.com',
18
+ GOOGLE_DESKTOP_CLIENT_ID: '246811022042-cckq00b5seekpkv0in358jhu42n0b6u9.apps.googleusercontent.com',
19
+ };
20
+
21
+ test('hosted --web login emits start URL in --json', async () => {
22
+ let out = '';
23
+ const code = await runAgentsamGoogleOauthLogin({
24
+ write: (s) => {
25
+ out += s;
26
+ },
27
+ json: true,
28
+ nonInteractive: true,
29
+ env: TEST_ENV,
30
+ });
31
+ assert.equal(code, 0);
32
+ const parsed = JSON.parse(out.slice(out.indexOf('{')));
33
+ assert.equal(parsed.mode, 'hosted_identity');
34
+ assert.equal(
35
+ parsed.start_url,
36
+ resolveGoogleOauthStartUrl(TEST_ENV),
37
+ );
38
+ });
39
+
40
+ test('gcloud auth login --web is hosted identity', async () => {
41
+ let out = '';
42
+ const code = await runGcloudAuth(['login', '--web', '--json'], {
43
+ write: (s) => {
44
+ out += s;
45
+ },
46
+ nonInteractive: true,
47
+ env: TEST_ENV,
48
+ });
49
+ assert.equal(code, 0);
50
+ assert.match(out, /hosted_identity|\/api\/oauth\/google\/start/);
51
+ });
52
+
53
+ test('gcloud auth help mentions studio broker default and --desktop/--web/--sdk', async () => {
54
+ let out = '';
55
+ await runGcloudAuth(['help'], {
56
+ write: (s) => {
57
+ out += s;
58
+ },
59
+ });
60
+ assert.match(out, /Studio Web OAuth broker|Worker holds/i);
61
+ assert.match(out, /--desktop/);
62
+ assert.match(out, /--web/);
63
+ assert.match(out, /--sdk/);
64
+ });
65
+
66
+ test('desktop auth URL requests cloud-platform + offline', () => {
67
+ const url = new URL(buildGoogleDesktopAuthUrl({
68
+ clientId: resolveGoogleDesktopClientId(TEST_ENV),
69
+ redirectUri: 'http://127.0.0.1:12345/callback',
70
+ state: 'abc',
71
+ codeChallenge: 'challenge',
72
+ }));
73
+ assert.match(url.searchParams.get('scope') || '', /cloud-platform/);
74
+ assert.equal(url.searchParams.get('access_type'), 'offline');
75
+ assert.equal(url.searchParams.get('code_challenge_method'), 'S256');
76
+ assert.match(GOOGLE_CLOUD_CONNECTION_SCOPES, /openid/);
77
+ });
78
+
79
+ test('permissions checklist separates OAuth scopes from IAM roles', async () => {
80
+ let out = '';
81
+ const code = await runGcloudAuth(['login', '--permissions'], {
82
+ write: (s) => {
83
+ out += s;
84
+ },
85
+ });
86
+ assert.equal(code, 0);
87
+ assert.match(out, /cloud-platform/);
88
+ assert.match(out, /mcp\.toolUser|roles\/mcp/);
89
+ const checklist = googleCloudPermissionChecklist();
90
+ assert.ok(checklist.oauth_scopes_requested.includes('https://www.googleapis.com/auth/cloud-platform'));
91
+ });
92
+
93
+ test('resolveGoogleDesktopClientId fails loud when unset', () => {
94
+ assert.throws(
95
+ () => resolveGoogleDesktopClientId({}),
96
+ (err) => err?.code === 'google_desktop_client_not_configured',
97
+ );
98
+ });
99
+
100
+ test('resolveGoogleDesktopClientIdAsync uses public-config when env unset', async () => {
101
+ const { resolveGoogleDesktopClientIdAsync } = await import('../src/lib/google-desktop-oauth.js');
102
+ const id = await resolveGoogleDesktopClientIdAsync({}, {
103
+ publicConfigUrl: 'https://example.test/api/public-config',
104
+ fetchImpl: async () =>
105
+ new Response(JSON.stringify({
106
+ ok: true,
107
+ google_desktop_client_id: 'from-public-config.apps.googleusercontent.com',
108
+ }), { status: 200 }),
109
+ });
110
+ assert.equal(id, 'from-public-config.apps.googleusercontent.com');
111
+ });
@@ -0,0 +1,83 @@
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
+ diagnoseGoogleCloudAccountMismatch,
8
+ diagnoseInsufficientAccess,
9
+ readGoogleCloudConnection,
10
+ renderInsufficientAccessCard,
11
+ writeGoogleCloudConnection,
12
+ } from '../src/lib/google-cloud-connection.js';
13
+ import { describeAuthShadow, renderLoginResult } from '../src/commands/whoami.js';
14
+
15
+ test('connection preference persists identity+project without secrets', () => {
16
+ const home = fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-conn-'));
17
+ const saved = writeGoogleCloudConnection(
18
+ {
19
+ identity: 'meauxbility@gmail.com',
20
+ organization: 'inneranimals.com',
21
+ project: 'gen-lang-client-0684066529',
22
+ billing_account: '017E01-4426EF-21356F',
23
+ },
24
+ { home },
25
+ );
26
+ assert.equal(saved.identity, 'meauxbility@gmail.com');
27
+ assert.equal(saved.project, 'gen-lang-client-0684066529');
28
+ const again = readGoogleCloudConnection({ home });
29
+ assert.equal(again.organization, 'inneranimals.com');
30
+ assert.doesNotMatch(JSON.stringify(again), /private_key|BEGIN /);
31
+ });
32
+
33
+ test('identity mismatch diagnosis is deterministic', () => {
34
+ const d = diagnoseGoogleCloudAccountMismatch({
35
+ preferred: { identity: 'meauxbility@gmail.com', project: 't-pulsar-483701-q1' },
36
+ activeAccount: 'info@inneranimals.com',
37
+ activeProject: 't-pulsar-483701-q1',
38
+ accounts: [
39
+ { account: 'info@inneranimals.com', status: 'ACTIVE' },
40
+ { account: 'meauxbility@gmail.com', status: '' },
41
+ ],
42
+ });
43
+ assert.equal(d.ok, false);
44
+ assert.equal(d.kind, 'identity_mismatch');
45
+ assert.equal(d.alternate_authenticated, true);
46
+ assert.match(d.remediation.actions[0].command, /gcloud config set account meauxbility@gmail.com/);
47
+ });
48
+
49
+ test('insufficient access card matches product UX', () => {
50
+ const d = diagnoseInsufficientAccess({
51
+ currentAccount: 'info@inneranimals.com',
52
+ requiredRole: 'roles/owner',
53
+ project: 'gen-lang-client-0684066529',
54
+ accounts: [
55
+ { account: 'info@inneranimals.com', roles: ['roles/viewer'] },
56
+ { account: 'meauxbility@gmail.com', roles: ['roles/owner'] },
57
+ ],
58
+ });
59
+ assert.equal(d.kind, 'insufficient_access');
60
+ const text = renderInsufficientAccessCard(d);
61
+ assert.match(text, /This Google account does not have enough access/);
62
+ assert.match(text, /meauxbility@gmail\.com/);
63
+ assert.match(text, /✓ Owner/);
64
+ assert.match(text, /\[enter\]/);
65
+ assert.match(text, /\[a\]/);
66
+ assert.match(text, /\[c\]/);
67
+ });
68
+
69
+ test('login result explains API key shadowing OAuth', () => {
70
+ const status = {
71
+ active_auth: { kind: 'api_key', source: 'environment' },
72
+ api_key: { configured: true, source: 'environment' },
73
+ browser_session: { configured: true, expired: false, refreshable: true },
74
+ };
75
+ const text = renderLoginResult(status);
76
+ assert.match(text, /Browser OAuth login saved/);
77
+ assert.match(text, /not currently authoritative/);
78
+ assert.match(text, /AGENTSAM_API_KEY has higher precedence/);
79
+ assert.match(text, /\[enter\] keep API key/);
80
+ const shadow = describeAuthShadow(status);
81
+ assert.ok(shadow);
82
+ assert.match(shadow.join('\n'), /Authority lanes/);
83
+ });