@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
@@ -43,14 +43,36 @@ export function createRuntimeRunId() {
43
43
  export async function startRuntimeRun(value = {}) {
44
44
  const id = clean(value.id) || createRuntimeRunId();
45
45
  await withStore(value.projectRoot || value.cwd, async (db) => {
46
+ const activeStep = (!clean(value.plan_id) || !clean(value.todo_id))
47
+ ? await db.prepare(`
48
+ SELECT t.id AS todo_id, t.plan_id
49
+ FROM agentsam_todo t
50
+ JOIN agentsam_plans p ON p.id = t.plan_id
51
+ WHERE t.status = 'running' AND p.status = 'active'
52
+ ORDER BY t.updated_at_unix DESC, t.created_at_unix DESC
53
+ LIMIT 1
54
+ `).first()
55
+ : null;
56
+ const activePlan = !clean(value.plan_id) && !activeStep?.plan_id
57
+ ? await db.prepare(`
58
+ SELECT id AS plan_id FROM agentsam_plans
59
+ WHERE status = 'active'
60
+ ORDER BY updated_at_unix DESC, created_at_unix DESC
61
+ LIMIT 1
62
+ `).first()
63
+ : null;
64
+ const planId = clean(value.plan_id) || clean(activeStep?.plan_id) || clean(activePlan?.plan_id) || null;
65
+ const todoId = clean(value.todo_id) || clean(activeStep?.todo_id) || null;
46
66
  await db.prepare(`
47
67
  INSERT INTO agentsam_agent_run (
48
- id, account_id, source_client, surface, mode, model_key,
68
+ id, account_id, plan_id, todo_id, source_client, surface, mode, model_key,
49
69
  reasoning_effort, requested_service_tier, status, started_at_unix, updated_at_unix
50
- ) VALUES (?, ?, 'agentsam-cli', 'cli', ?, ?, ?, ?, 'running', unixepoch(), unixepoch())
70
+ ) VALUES (?, ?, ?, ?, 'agentsam-cli', 'cli', ?, ?, ?, ?, 'running', unixepoch(), unixepoch())
51
71
  `).bind(
52
72
  id,
53
73
  clean(value.account_id) || null,
74
+ planId,
75
+ todoId,
54
76
  clean(value.mode) || 'agent',
55
77
  clean(value.model_key) || null,
56
78
  clean(value.reasoning_effort) || null,
@@ -90,6 +90,23 @@ export async function createLocalSqliteDatabase(filePath = '.agentsam/data/agent
90
90
  },
91
91
  };
92
92
  },
93
+ async batch(statements = []) {
94
+ database.exec('BEGIN IMMEDIATE');
95
+ try {
96
+ const results = [];
97
+ for (const statement of statements) {
98
+ if (!statement || typeof statement.run !== 'function') {
99
+ throw new TypeError('Local SQLite batch entries must expose run()');
100
+ }
101
+ results.push(await statement.run());
102
+ }
103
+ database.exec('COMMIT');
104
+ return results;
105
+ } catch (error) {
106
+ try { database.exec('ROLLBACK'); } catch {}
107
+ throw error;
108
+ }
109
+ },
93
110
  exec(sql) {
94
111
  database.exec(sql);
95
112
  },
@@ -0,0 +1,41 @@
1
+ import { defineSamOperation } from '../define.js';
2
+ import { auditPackages } from '../../commands/package.js';
3
+
4
+ export const packageAuditOp = defineSamOperation({
5
+ id: 'package.audit',
6
+ version: 1,
7
+ module: 'package',
8
+ action: 'audit',
9
+ summary: 'Audit AgentSam package publication intent, registry state, and structural blockers.',
10
+ purpose:
11
+ 'Establish deterministic package-distribution authority for @inneranimalmedia packages without publishing anything.',
12
+ outcome:
13
+ 'Return classified package manifests, public-distribution intent, registry state when allowed, and structural blockers.',
14
+ description:
15
+ 'Discover scoped package manifests, classify public/private intent, optionally query npm registry state, and return a bounded read-only audit.',
16
+ skill: { id: 'agentsam-progression-guard', help: true },
17
+ accepts: ['root', 'publicOnly', 'offline'],
18
+ phases: ['discover_manifests', 'classify_intent', 'resolve_registry_state', 'emit_audit'],
19
+ execution: {
20
+ lanes: ['local', 'remote', 'sandbox'],
21
+ model: 'never',
22
+ embedding: 'never',
23
+ network: 'optional',
24
+ sideEffects: 'none',
25
+ provider_spend: 'none',
26
+ },
27
+ risk: 'read_only',
28
+ capabilities: ['package.audit'],
29
+ artifacts: ['package.audit'],
30
+ cli: { command: [['package', 'audit']] },
31
+ docs: { section: 'Packages' },
32
+ status: 'stable',
33
+ async handler(input = {}, ctx = {}) {
34
+ const root = input.root || input.cwd || ctx.cwd || process.cwd();
35
+ return auditPackages({
36
+ root,
37
+ publicOnly: input.publicOnly === true || input.public === true,
38
+ offline: input.offline === true,
39
+ });
40
+ },
41
+ });
package/src/sam/seed.js CHANGED
@@ -8,6 +8,7 @@ import { codebaseindexIngestOp } from './operations/codebaseindex-ingest.js';
8
8
  import { planningAstarOp } from './operations/planning-astar.js';
9
9
  import { planningGoapOp } from './operations/planning-goap.js';
10
10
  import { decisionEvaluateOp } from './operations/decision-evaluate.js';
11
+ import { packageAuditOp } from './operations/package-audit.js';
11
12
 
12
13
  export const SEED_OPERATIONS = [
13
14
  repositoryInspect,
@@ -19,6 +20,7 @@ export const SEED_OPERATIONS = [
19
20
  planningAstarOp,
20
21
  planningGoapOp,
21
22
  decisionEvaluateOp,
23
+ packageAuditOp,
22
24
  ];
23
25
 
24
26
  let seeded = false;
@@ -1,110 +0,0 @@
1
- ---
2
- name: auth
3
- description: >
4
- Add user accounts and sign-in to this TanStack Start app. Use when the app
5
- needs authentication, sign-in, user accounts, protected routes, or per-user
6
- data. Triggers on "auth", "login", "log in", "sign in", "sign up", "account",
7
- "users", "authentication", "protected", "who is logged in", "current user",
8
- "per-user".
9
- metadata:
10
- short-description: "Auth via the Grok broker (Google, X) or local email/password — no other methods supported"
11
- user-invocable: false
12
- ---
13
-
14
- # Auth
15
-
16
- This app runs its **own** [Better Auth](https://better-auth.com) at
17
- `/api/auth/*`, federating to the shared **Grok auth broker** (`auth.grok.me`)
18
- via the `genericOAuth` plugin. This template wires **Google** and **X**.
19
-
20
- **Supported sign-in methods — use ONLY these three; nothing else is supported:
21
- Google, X, and email/password.** No other social/OAuth provider (GitHub, Apple,
22
- Discord, …), no magic links, passkeys, OTP, phone/SMS, or anonymous sign-in. Do
23
- not add entries to `GROK_PROVIDERS`. Method detail and the email/password switch
24
- (edit **only** `src/lib/auth/email-password.ts`): `references/sign-in-methods.md`.
25
- **Exception — gate viewers are signed in already; NEVER render login/re-auth
26
- buttons for them. Connector / app-data apps: ONLY gate "Continue with Grok",
27
- no Google/X buttons**: `references/grok-identity.md`.
28
-
29
- **Sign-in is OFF by default** — the template ships `.grok/app-env.json` with
30
- `{"VITE_AUTH_ENABLED": "false"}`, so only add accounts when the ask calls for
31
- them (AGENTS.md §0.5). Switching it on is "Turning sign-in on" below.
32
-
33
- **Once on, sign-in is REAL — including in the sandbox live preview.** Do **NOT**
34
- scaffold demo/mock/hardcoded users. Preview: popup + baked preview client;
35
- deployed: per-app client + `DATABASE_URL` + zero-click gate sign-in
36
- (`references/prewired-and-env.md`).
37
-
38
- **While OFF** (`VITE_AUTH_ENABLED=false`) a **dev user** is returned so a
39
- non-auth app renders without a signed-in visitor — dev and preview only.
40
- Deployed, the flag is the platform's (always `"true"`), so `requireUserId`
41
- rejects every visitor — auth-off apps use neither it nor `authMiddleware`.
42
-
43
- Everything is **preinstalled and pre-wired in `src/lib/auth/`** — do not
44
- `npm install` anything; `better-auth` is the only auth package (never
45
- `@neondatabase/*`, `@stackframe/*`, or `@clerk/*`). **Do not edit or rewrite any
46
- file under `src/lib/auth/`** — `server.ts` least of all — except
47
- `email-password.ts` for its one flag. Per-file map:
48
- `references/prewired-and-env.md`.
49
-
50
- **`/auth/popup` is already handled by the template Vite plugin**
51
- (`vite.config.ts` → `popup.server.ts`): it never paints the React app. **Do NOT
52
- create `src/routes/auth/popup.tsx`** (or any React page / client OAuth at that
53
- path) — that shows the full app inside the popup, the common failure mode.
54
-
55
- **Never write a `.env` / `.env.local` / `.env.example`** in this sandbox: live
56
- preview needs **zero** env configuration and a deployed app gets its vars
57
- injected by the platform. The knobs that exist are in
58
- `references/prewired-and-env.md` — never expose a non-`VITE_` var to the client.
59
-
60
- `migrations/auth/0001_auth.sql` is the Better Auth schema — **do not edit**. It
61
- sits outside the globbed `migrations/` directory (neither applier descends), so
62
- it is not applied to apps without sign-in; "Turning sign-in on" copies it up.
63
-
64
- ## Turning sign-in on
65
-
66
- Do all of this — the routes alone render the disabled branch:
67
-
68
- 1. **Flag:** delete the `VITE_AUTH_ENABLED` key from `.grok/app-env.json` and
69
- **restart the dev server**. Vite reads env at startup, so HMR will not pick
70
- it up. `npm run dev`, `npm run build` and `npm run preview` all read that
71
- file through `scripts/with-app-env.mjs`, so preview and the built output flip
72
- together — never start Vite directly.
73
- 2. **Schema:** `cp migrations/auth/0001_auth.sql migrations/0001_auth.sql`, then
74
- restart so it applies. It is tracked by basename in `_migrations`, so a
75
- database that already has it will not re-run it.
76
- 3. **Routes:** add `src/routes/api/auth/$.ts` + `src/routes/login.tsx` — copy
77
- both from `references/wiring.md` (the catch-all API route is what makes
78
- `/api/auth/*` and the broker callback work).
79
- 4. **Sign out:** a login with no way out is not done — render `<UserButton />`
80
- from `@/lib/auth/gates` (wires `signOut()`; hides sign-out for gate sessions).
81
- 5. **Existing data:** wrap the app's server functions in `authMiddleware` (an
82
- auth-off app must not have been using it — see the `neon` skill). Rows from
83
- before sign-in existed are **development data**: drop and recreate them
84
- unless the user says otherwise — don't hand them to whoever signs in first.
85
-
86
- ## Building on it once it's on
87
-
88
- - **Sign in / out:** `signIn(providerId)` and `signOut()` from
89
- `@/lib/auth/client`; `GROK_PROVIDERS` renders the buttons. The popup,
90
- bearer-token hand-off, and request attachment are internal — leave them alone.
91
- Prefer `<UserButton />` (it handles the pending and failure states); `signOut()`
92
- rejects when deployed if the server never confirms — catch it. Never
93
- `authClient.signOut()`: it leaves the preview bearer token attached to every
94
- later request, so the visitor stays signed in.
95
- - **Reading the user:** `useCurrentUser()` is display-only (`null` means
96
- *loading OR signed out*, so never redirect on it alone); guard on
97
- `useCurrentUserState()`'s `isPending` instead. Gates (`SignedIn`, `SignedOut`,
98
- `SignInGate`, `RedirectToSignIn`, `UserButton`) live in `@/lib/auth/gates`.
99
- CTA hard rules, skeleton, and cookie-SSR zero-flash: `references/session-ui.md`.
100
- - **Per-user data (mandatory):** every server function that touches per-user data
101
- must use the prewired `authMiddleware` and scope every read **and** write to
102
- `context.userId` — a Postgres driver has full DB access, so nothing else limits
103
- the query. Keep `user_id` columns `TEXT`; never trust a client-supplied user id;
104
- signed out, the middleware throws `UnauthorizedError` (401). Code and
105
- disabled-mode semantics: `references/per-user-data.md`.
106
- - **Security model:** headless broker, `__Host-` cookies + `trustedOrigins`, and
107
- Fetch-Metadata sibling isolation are already wired — never weaken them to make
108
- an error go away (`references/sign-in-methods.md` covers the model and the
109
- "Invalid origin" fix).
110
-
@@ -1,25 +0,0 @@
1
- {
2
- "schema": "agentsam.skill.v1",
3
- "id": "grok-auth",
4
- "name": "Grok \u00b7 auth",
5
- "description": "Auth via the Grok broker (Google, X) or local email/password \u2014 no other methods supported",
6
- "icon": "skill",
7
- "slash": {
8
- "suggested": "/grok-auth"
9
- },
10
- "instructions": {
11
- "source": "local_file",
12
- "ref": "SKILL.md"
13
- },
14
- "execution": {
15
- "mode": "turn",
16
- "tools": [],
17
- "operations": [],
18
- "capabilities": []
19
- },
20
- "provenance": {
21
- "source": "apps/local-studio/.grok/skills",
22
- "vendor": "grok",
23
- "status": "imported"
24
- }
25
- }
@@ -1,64 +0,0 @@
1
- # Sign in with Grok (deployed apps — zero clicks)
2
-
3
- Behind the edge gate, every proxied request from a signed-in Grok viewer
4
- carries an unforgeable `x-grok-identity` JWT (EdDSA, minted per request; the
5
- gate strips any client-supplied copy). The pre-wired `gateIdentitySessions`
6
- plugin (`src/lib/auth/gate-session.server.ts`) verifies it against the gate's
7
- JWKS (`/__gate/identity-key`, via `src/lib/auth/gate-identity.server.ts`) and,
8
- when the app has no session yet, materializes the Better Auth session for that
9
- viewer automatically — no sign-in button, no redirect, no broker round-trip.
10
- `useSession` / `useCurrentUser` simply return the Grok user.
11
-
12
- The broker OAuth flow is the **fallback** for anonymous/public viewers and for
13
- contexts without the gate. The live preview gets the same zero-click identity
14
- from the in-VM preview proxy at `http://127.0.0.1:6014` (preview tokens carry
15
- audience `preview`); the popup mechanism remains the fallback there.
16
-
17
- ## Never render sign-in or re-auth UI to a gate viewer
18
-
19
- A gate-authenticated viewer is **already signed in**, and the gate refreshes
20
- connector tokens on every proxied request — **the platform has no re-auth
21
- concept**. Never render "Re-auth with Grok", "Sign in again", "Refresh
22
- session", or a standing "Continue with Grok" button: sign-in UI may appear
23
- only in the `app-data` skill's `login` error state, after a connector call
24
- actually returned `loginRequired: true`.
25
-
26
- The live preview gets the same zero-click session, so a sign-in button visible
27
- to the owner in the preview indicates a bug (a CTA rendered while the session
28
- check was still pending, or rendered in reaction to a data error) — fix it,
29
- don't restyle it. For any fallback sign-in surface use `<SignInGate>` from
30
- `@/lib/auth/gates`: it renders sign-in UI only after the session check resolved
31
- to no user, never during loading and never from a data error.
32
-
33
- Sign-out is also a no-op for a gate session — the next request re-materializes
34
- it from `x-grok-identity`, an instant sign-back-in loop. `<UserButton />`
35
- already hides its sign-out control for gate sessions; never build a custom
36
- sign-out (or any sign-out route/handler) for gate viewers.
37
-
38
- ## Files (pre-wired — do not edit)
39
-
40
- | File | Role |
41
- |---|---|
42
- | `gate-identity.server.ts` | Verifies the gate's `x-grok-identity` viewer JWT (EdDSA vs the gate JWKS; fail-closed). Server-only. |
43
- | `gate-session.server.ts` | Better Auth plugin that turns a verified gate identity into the app session with zero clicks. Already registered in `server.ts`. |
44
-
45
- ## Env (deployer-injected)
46
-
47
- | Var | Scope | Meaning |
48
- |---|---|---|
49
- | `GROK_PROJECT_ID` | server | deployed apps: enables "Sign in with Grok" (`x-grok-identity` audience check `app:<project_id>`) |
50
- | `GROK_GATE_ORIGIN` | server | gate public origin override (JWKS + issuer pin); unset → preview mode (no `GROK_PROJECT_ID`) defaults to the in-VM proxy `http://127.0.0.1:6014` (audience `preview`), deployed mode derives it from the inbound host |
51
-
52
- Deployed behavior: gate-authenticated viewers are signed in automatically from
53
- `x-grok-identity`; the deployer also injects a per-app broker client +
54
- `DATABASE_URL`, so the fallback sign-in persists identities in Postgres.
55
-
56
- ## Connector / app-data apps: gate sign-in only
57
-
58
- When the `app-data` skill applies, the login page offers ONLY "Continue with
59
- Grok" via the gate sign-in — the zero-click `x-grok-identity` session above, or
60
- the gate-built `loginUrl` returned by a connector call. Do not wire Google/X
61
- buttons for these apps: a broker login can mint an identity that is not the
62
- gate viewer the connector data belongs to. The three-method rule applies to
63
- apps without connector data. Still no new `GROK_PROVIDERS` entries, still never
64
- edit `src/lib/auth/`.
@@ -1,49 +0,0 @@
1
- # Per-user data (server-side — mandatory)
2
-
3
- Pair auth with the DB (see the `neon` skill). A regular Postgres driver has full
4
- DB access, so **every** server function that touches per-user data must verify
5
- the caller and scope rows to them. Use the prewired **`authMiddleware`**: it
6
- resolves the same-origin session to a verified `context.userId` (and rejects
7
- scripted cross-site/sibling requests) — no token threading:
8
-
9
- ```ts
10
- import { createServerFn } from "@tanstack/react-start";
11
- import { getSql } from "@/lib/db";
12
- import { authMiddleware } from "@/lib/auth/middleware";
13
-
14
- export const listTodos = createServerFn({ method: "GET" })
15
- .middleware([authMiddleware])
16
- .handler(async ({ context }) => {
17
- const sql = await getSql();
18
- // Type the row shape — a server fn's return must be provably serializable.
19
- return sql<{ id: number; title: string; done: boolean }>`select id, title, done from todos where user_id = ${context.userId} order by id desc`;
20
- });
21
-
22
- // Inputs go through `.validator()` (the current API); the client passes `{ data }`:
23
- export const addTodo = createServerFn({ method: "POST" })
24
- .validator((title: string) => title.trim())
25
- .middleware([authMiddleware])
26
- .handler(async ({ context, data: title }) => {
27
- if (!title) return;
28
- const sql = await getSql();
29
- await sql`insert into todos (user_id, title) values (${context.userId}, ${title})`;
30
- });
31
- // mutations must scope writes too: `... where id = ${id} and user_id = ${context.userId}`
32
- ```
33
-
34
- Call these from **client code** (effects, event handlers, React Query) — that's
35
- where `Sec-Fetch-Site: same-origin` holds:
36
-
37
- ```ts
38
- useEffect(() => { listTodos().then(setTodos).catch(() => setTodos([])); }, []);
39
- ```
40
-
41
- Semantics: signed out → the middleware throws `UnauthorizedError` (message
42
- `"Unauthorized"`, `status` 401 — match it to send the visitor to sign-in), in the
43
- live preview too (real auth). With auth disabled (`VITE_AUTH_ENABLED=false`) it
44
- resolves the dev user (`"dev-user"`) in dev and preview only — the deployed flag
45
- comes from the deployer (today always `"true"`), so deployed it rejects every
46
- visitor — which is why an app without sign-in must not use the middleware at all
47
- (see the `neon` skill). Keep `user_id` columns
48
- `TEXT` (Better Auth uses text ids; the disabled dev user is `'dev-user'`). Never
49
- trust a client-supplied user id — only the middleware / `requireUserId()` result.
@@ -1,54 +0,0 @@
1
- # What's pre-wired, and the env vars
2
-
3
- ## `src/lib/auth/`
4
-
5
- | File | Use it for |
6
- |---|---|
7
- | `client.ts` | Browser client. `signIn(providerId)`, `signOut()`, `authEnabled`, `GROK_PROVIDERS`. |
8
- | `server.ts` | The Better Auth instance (server-only). **Do not edit or rewrite.** Import only from `/api/auth/$`. |
9
- | `email-password.ts` | **Only** place to enable local email/password (`emailAndPasswordEnabled = true`). |
10
- | `popup.server.ts` | Live-preview popup handler (server-only). Already wired by the Vite plugin — do not create a route for it. |
11
- | `providers.ts` | `GROK_PROVIDERS` — the fixed broker upstream list (Google and X only; don't add others). |
12
- | `use-current-user.ts` | `useCurrentUser()` / `useCurrentUserState()` React hooks. |
13
- | `gates.tsx` | `SignedIn`, `SignedOut`, `RedirectToSignIn`, `UserButton`. |
14
- | `middleware.ts` | `authMiddleware` for server functions → verified `context.userId`. |
15
- | `verify.server.ts` | `requireUserId()` / `getSessionUser()` (server-only) for manual wiring. |
16
-
17
- ## How each mode gets its credentials
18
-
19
- - **Live preview** (`*.grok-sandbox.com`): the app is an embedded iframe, so
20
- sign-in opens a **popup** (a top-level redirect to the broker can't work inside
21
- the iframe) and federates via a baked shared **preview client**
22
- (`src/lib/auth/preview.ts`). The handler 302s straight to the broker/upstream
23
- login; on return the popup posts the session bearer back in a tiny HTML page.
24
- Sessions (and email/password users) persist in the app's embedded PGLite DB —
25
- the SAME DB as app data — and, since the iframe's cookies are partitioned,
26
- ride that bearer token; all of it lives in `src/lib/auth`.
27
- Restarting the preview resets the DB.
28
- - **Deployed**: the deployer injects a per-app client + `DATABASE_URL`, so
29
- sign-in persists identities in Postgres.
30
-
31
- ## Env vars — do **not** create a `.env` file
32
-
33
- **Never write a `.env` / `.env.local` / `.env.example` for auth (or anything
34
- else) in this sandbox.** Live preview sign-in works out of the box with **zero**
35
- env configuration: the server falls back to the baked preview client in
36
- `src/lib/auth/preview.ts`, derives the `*.grok-sandbox.com` origin per-request,
37
- mints a process-stable session secret, and persists sessions in embedded
38
- PGLite. Deployed apps get `GROK_AUTH_*` / `BETTER_AUTH_*` / `DATABASE_URL`
39
- injected by the platform — still not something you write into a file.
40
-
41
- Optional process-env knobs (platform / rare overrides only — **do not** put
42
- these in a file you create):
43
-
44
- | Var | Where | Purpose |
45
- |---|---|---|
46
- | `VITE_AUTH_ENABLED` | client | `"false"` in the shipped `.grok/app-env.json` (dev user); drop the key to turn sign-in ON. Only client-visible auth flag |
47
- | `BETTER_AUTH_URL` | server | app's own public origin; unset in preview (origin is derived per-request) |
48
- | `BETTER_AUTH_SECRET` | server | signs this app's own sessions (process-stable fallback in preview; survives HMR) |
49
- | `GROK_AUTH_ISSUER` | server | the shared broker (defaults to `https://auth.grok.me`) |
50
- | `GROK_AUTH_CLIENT_ID` / `GROK_AUTH_CLIENT_SECRET` | server | per-app client (falls back to the preview client) |
51
- | `DATABASE_URL` | server | when deployed, Better Auth persists here (preview persists to the embedded PGLite — same DB as app data) |
52
-
53
- Never expose a non-`VITE_` var to the client. The preview client id/secret live
54
- server-only in `src/lib/auth/preview.ts`.
@@ -1,133 +0,0 @@
1
- # Reading the user, protecting routes, and preventing flicker
2
-
3
- ## When sign-in UI may render (hard rules)
4
-
5
- - **Connector / owner-data apps: never gate the data fetch behind a session.**
6
- When the data comes from the app's connector grants, the fetch runs on the
7
- gate-injected connector token — a chain that does not involve the app
8
- session. Fetch first; use the session for personalization only (greeting,
9
- per-user rows). Requiring sign-in before fetching adds a click that changes
10
- nothing.
11
- - **A sign-in CTA may render only after the session check has RESOLVED to no
12
- user** — never while `isPending` is true (no CTA flash on load), and never
13
- as a reaction to a data error (the `app-data` skill's error mapping owns
14
- those states; only its `login` kind ever shows "Continue with Grok").
15
- - **In preview, gate identity signs the owner in with zero clicks** — a
16
- visible sign-in button for the owner in the preview is a bug to fix, not a
17
- style choice (`grok-identity.md`).
18
- - **Use `<SignInGate>` from `@/lib/auth/gates`** — `{ children, fallback? }`:
19
- nothing while pending, `children` when signed in, `fallback` (or the
20
- standard provider buttons) only once signed out is known. Do not hand-roll
21
- sign-in CTAs from `useCurrentUser()`.
22
-
23
- ## Reading the user / protecting routes
24
-
25
- `@/lib/auth/use-current-user` (with auth on these reflect the REAL session, so a
26
- preview visitor is signed out until they sign in):
27
-
28
- - `useCurrentUser()` → `AppUser | null` — for display. `null` means *loading OR
29
- signed out*, so never redirect on it alone.
30
- - `useCurrentUserState()` → `{ user, isPending }` — for guards: wait for
31
- `isPending` to clear before treating `user: null` as signed out, or a hard
32
- reload bounces signed-in users to sign-in.
33
-
34
- **State components** from `@/lib/auth/gates`: `SignedIn`, `SignedOut`,
35
- `SignInGate` (`{ children, fallback? }` — nothing while pending, `children`
36
- signed in, `fallback` or the standard provider buttons only once signed out is
37
- known; prefer it over hand-rolled sign-in CTAs), `RedirectToSignIn`,
38
- `UserButton`. (When auth is disabled via `VITE_AUTH_ENABLED=false` they apply
39
- dev-user semantics so a non-auth app still renders.)
40
-
41
- ```tsx
42
- import { useCurrentUser, useCurrentUserState } from "@/lib/auth/use-current-user";
43
- import { RedirectToSignIn, SignedIn, SignedOut, UserButton } from "@/lib/auth/gates";
44
-
45
- function Navbar() {
46
- const user = useCurrentUser(); // display only — null may just mean "loading"
47
- return (
48
- <>
49
- <span>{user?.displayName ?? "Guest"}</span>
50
- <SignedOut><a href="/login">Sign in</a></SignedOut>
51
- <SignedIn><UserButton /></SignedIn>
52
- </>
53
- );
54
- }
55
-
56
- function AccountPage() {
57
- const { user, isPending } = useCurrentUserState();
58
- if (isPending) return null; // session still resolving
59
- if (!user) return <RedirectToSignIn />; // client-side Navigate — not window.location
60
- return <h1>Welcome, {user.displayName}</h1>;
61
- }
62
- ```
63
-
64
- Sign out with `<UserButton />` or `signOut()` from `@/lib/auth/client`.
65
-
66
- Session loading is the **same in live preview and when deployed**: wait for
67
- `isPending` from `useCurrentUserState()` (backed by `/api/auth/get-session`).
68
- The only live-preview difference is **how sign-in starts** (popup + bearer hand-off
69
- instead of a full-page OAuth redirect) — not how guests vs signed-in users are
70
- detected. Prefer `<RedirectToSignIn />` (TanStack `<Navigate>`) over
71
- `window.location.href = "/login"` so a signed-out redirect does not full-reload
72
- the SPA.
73
-
74
- ## Preventing auth flicker
75
-
76
- `useSession()` resolves on the client, so a naive UI flashes signed-out →
77
- signed-in on load. Rules:
78
-
79
- 1. **Gate on `isPending`, not `user` alone — and render a same-sized skeleton.**
80
- Showing the SAME placeholder while `isPending` (server render + first client
81
- paint) makes it one clean swap (skeleton → content) with no flash and no SSR
82
- hydration mismatch. Don't return `null` in a slot that then grows — reserve the
83
- space:
84
-
85
- ```tsx
86
- import { useCurrentUserState } from "@/lib/auth/use-current-user";
87
- import { UserButton } from "@/lib/auth/gates";
88
-
89
- function AuthSlot() {
90
- const { user, isPending } = useCurrentUserState();
91
- if (isPending) return <div className="h-8 w-8 animate-pulse rounded-full bg-black/10" />;
92
- return user ? <UserButton /> : <a href="/login">Sign in</a>;
93
- }
94
- ```
95
-
96
- 2. **Guard at a layout boundary** (nav / page shell), not in leaf components that
97
- mount/unmount — `useSession` is one shared store, so keep one stable consumer
98
- per region instead of re-gating everywhere.
99
-
100
- 3. **Zero-flash when deployed: SSR the session from the cookie.** On a deployed
101
- app (and top-level navigations) the session cookie is same-origin, so the server
102
- already knows the user on the first request — resolve it in the root route and
103
- render the authed shell immediately:
104
-
105
- ```tsx
106
- // src/routes/__root.tsx (excerpt)
107
- import { createServerFn } from "@tanstack/react-start";
108
- import { createRootRoute } from "@tanstack/react-router";
109
-
110
- const fetchSessionUser = createServerFn({ method: "GET" }).handler(async () => {
111
- // Cookie path only — works when deployed / on top-level loads.
112
- const { getSessionUser } = await import("@/lib/auth/verify.server");
113
- const u = await getSessionUser();
114
- return u ? { id: u.id, email: u.email } : null;
115
- });
116
-
117
- export const Route = createRootRoute({
118
- beforeLoad: async () => ({ sessionUser: await fetchSessionUser() }),
119
- // Merge into the existing root — keep the existing head().
120
- // component: prefer `sessionUser` for the FIRST paint when deployed, then
121
- // `useCurrentUserState()` for live in-page updates.
122
- });
123
- ```
124
-
125
- Sign-in/out navigate, so `beforeLoad` re-runs and the context stays fresh; call
126
- `router.invalidate()` if you change auth state without navigating.
127
-
128
- In live preview the session often rides a bearer after popup sign-in, so cookie
129
- SSR may still return null until the client `useSession()` runs with the bearer
130
- attached — still gate on `isPending`, same as when deployed.
131
-
132
- The template already enables Better Auth's `session.cookieCache`, so `/get-session`
133
- answers from a cookie when one is present (no DB round-trip).
@@ -1,55 +0,0 @@
1
- # Supported sign-in methods (Google, X, email/password — and nothing else)
2
-
3
- Use **only** these three — no other method is supported:
4
-
5
- - **Google** and **X** — federated through the Grok broker (pre-wired here). The
6
- broker federates these two upstreams and nothing else, so do **not** add entries
7
- to `GROK_PROVIDERS` beyond them (the broker rejects an unknown `idp`).
8
- - **Email + password** — this app's OWN Better Auth, persisted in your database
9
- (never the broker, never mocked). Better Auth is DB-backed in BOTH modes — real
10
- Postgres when deployed and the embedded PGLite in the sandbox preview — so
11
- email/password accounts are stored and survive across requests, **in preview
12
- too**. It's off by default. Enable it by editing **only**
13
- `src/lib/auth/email-password.ts`:
14
-
15
- ```ts
16
- // src/lib/auth/email-password.ts
17
- export const emailAndPasswordEnabled = true; // was false
18
- ```
19
-
20
- **Do not edit or rewrite `src/lib/auth/server.ts`** (or any other file under
21
- `src/lib/auth/` except `email-password.ts` for this flag). That file is
22
- pre-wired; "fixing" it by regenerating Better Auth config breaks live-preview
23
- sign-in.
24
-
25
- The pre-applied schema already has the `account.password` column — no migration
26
- needed. Then build sign-up / sign-in forms with `authClient.signUp.email(...)`
27
- and `authClient.signIn.email(...)` from `@/lib/auth/client`.
28
-
29
- **Do not** add `emailAndPassword` as a plugin entry (that is a syntax/type
30
- error). **Do not** invent a new Better Auth config.
31
-
32
- If sign-up/sign-in returns **"Invalid origin"**, do **not** disable CSRF and
33
- do **not** edit `server.ts`. The template's `trustedOrigins` already covers
34
- `*.grok-sandbox.com` and local loopback on port 8080 (`localhost` /
35
- `127.0.0.1` / `[::1]`). Open the app at one of those origins (not a random
36
- host/port).
37
-
38
- Do **NOT** add or use anything else: no other social / OAuth providers (GitHub,
39
- Apple, Discord, Microsoft, Facebook, …), and no magic links, passkeys, one-time
40
- codes / OTP, phone / SMS, or anonymous sign-in.
41
-
42
- ## Security model (already handled — don't undo it)
43
-
44
- - **Headless broker**: the broker offers the upstream sign-in methods
45
- and holds their shared secrets; this app only holds its own per-app client
46
- id/secret and names the upstream it wants via each provider's `idp` hint. The
47
- broker forwards straight to Google/X. Users never see the broker.
48
- - **`__Host-` cookies + `trustedOrigins`**: a sibling `*.grok.me` app can't toss a
49
- `Domain=.grok.me` cookie, and Better Auth rejects cross-origin `/api/auth`
50
- calls.
51
- - **Sibling isolation**: `authMiddleware` rejects scripted cross-site/same-site
52
- requests (Fetch-Metadata), so a sibling can't ride this app's session cookie
53
- into its server functions.
54
- - The upstream Google/X tokens live only on the broker; this app only ever gets a
55
- broker-issued identity and mints its own local session.