@inneranimalmedia/agentsam-sdk 2.6.7 → 2.6.9

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 (371) hide show
  1. package/README.md +37 -0
  2. package/apps/README.md +25 -0
  3. package/apps/cad-creator/shared/cad/package.json +1 -1
  4. package/apps/client-cms-editor/backend/package.json +4 -6
  5. package/apps/client-cms-editor/frontend/package.json +6 -8
  6. package/apps/client-cms-editor/frontend/tsconfig.json +27 -8
  7. package/apps/client-cms-editor/package.json +1 -1
  8. package/apps/client-cms-editor/shared/cms/package.json +4 -6
  9. package/docs/LOCAL_ENGINE_COMPUTE_AUDIT_PLAN.md +299 -0
  10. package/docs/REPO_FILE_MAP.txt +132 -0
  11. package/migrations/d1/0018_goap_control_plane_remaster.sql +40 -0
  12. package/migrations/d1/0019_agentsam_agent_run_plan_todo.sql +14 -0
  13. package/migrations/d1/README_PORTABLE_CONTROL_PLANE.md +20 -9
  14. package/migrations/runtime/0002_goap_blackboard_v1.sql +15 -0
  15. package/migrations/runtime/0004_agent_run_plan_linkage.sql +8 -0
  16. package/native/agentsam-machine/cli/Cargo.toml +8 -1
  17. package/native/agentsam-machine/cli/README.md +21 -0
  18. package/native/agentsam-machine/core/Cargo.toml +7 -0
  19. package/native/agentsam-machine/core/README.md +14 -0
  20. package/native/agentsam-machine/core/build.rs +33 -0
  21. package/native/agentsam-machine/core/contracts/source-types.v1.json +353 -0
  22. package/native/agentsam-machine/core/src/lib.rs +6 -0
  23. package/native/agentsam-machine/core/src/source_types.rs +2 -2
  24. package/package.json +31 -10
  25. package/packages/agentsam-brand/package.json +1 -1
  26. package/packages/agentsam-contracts/package.json +71 -20
  27. package/packages/agentsam-contracts/scripts/build.mjs +18 -0
  28. package/packages/agentsam-contracts/test/contracts.test.mjs +4 -1
  29. package/packages/agentsam-contracts/test/repository.test.mjs +4 -1
  30. package/packages/agentsam-contracts/tsconfig.build.json +10 -0
  31. package/packages/agentsam-errors/package.json +3 -2
  32. package/packages/agentsam-errors/src/index.js +1 -0
  33. package/packages/agentsam-errors/src/tool.js +56 -0
  34. package/packages/agentsam-errors/test/tool.test.mjs +58 -0
  35. package/packages/agentsam-goap/README.md +52 -0
  36. package/packages/agentsam-goap/package.json +37 -0
  37. package/packages/agentsam-goap/src/adapters/d1-sqlite.js +570 -0
  38. package/packages/agentsam-goap/src/adapters/memory.js +199 -0
  39. package/packages/agentsam-goap/src/contracts.js +226 -0
  40. package/packages/agentsam-goap/src/control-plane.js +112 -0
  41. package/packages/agentsam-goap/src/errors.js +157 -0
  42. package/packages/agentsam-goap/src/index.js +5 -0
  43. package/packages/agentsam-goap/src/world.js +202 -0
  44. package/packages/agentsam-goap/test/goap-control-plane.test.mjs +245 -0
  45. package/packages/agentsam-goap/test/world.test.mjs +79 -0
  46. package/packages/agentsam-knowledge/package.json +3 -2
  47. package/packages/agentsam-nav/package.json +1 -1
  48. package/packages/agentsam-queue-control/package.json +1 -1
  49. package/packages/agentsam-rapid-rust/src/main.rs +1 -0
  50. package/packages/agentsam-repository/package.json +3 -2
  51. package/packages/agentsam-repository/src/goap.js +13 -14
  52. package/packages/agentsam-repository/src/tickets.js +15 -22
  53. package/packages/agentsam-repository/test/goap-tickets-workspace-state.test.mjs +19 -8
  54. package/packages/agentsam-vault/package.json +8 -5
  55. package/packages/agentsam-workbench/package.json +44 -17
  56. package/packages/connectors/cloudflare/package.json +4 -2
  57. package/packages/heuristic-theme/package.json +1 -1
  58. package/packages/identity/package.json +4 -3
  59. package/packages/identity/tests/lane1-packed-consumer.test.mjs +10 -2
  60. package/packages/providers/completeful/package.json +1 -1
  61. package/packages/theme-church-site/README.md +2 -2
  62. package/packages/theme-church-site/package.json +3 -4
  63. package/packages/theme-church-site/src/index.js +1 -1
  64. package/packages/theme-church-site/test/theme.test.mjs +1 -1
  65. package/packages/theme-companions-site/README.md +2 -2
  66. package/packages/theme-companions-site/package.json +3 -4
  67. package/packages/theme-companions-site/src/index.js +1 -1
  68. package/packages/theme-companions-site/test/theme.test.mjs +1 -1
  69. package/packages/theme-floors-site/README.md +2 -2
  70. package/packages/theme-floors-site/package.json +3 -4
  71. package/packages/theme-floors-site/src/index.js +1 -1
  72. package/packages/theme-floors-site/test/theme.test.mjs +1 -1
  73. package/packages/theme-fuelnfree-site/README.md +2 -2
  74. package/packages/theme-fuelnfree-site/package.json +3 -4
  75. package/packages/theme-fuelnfree-site/src/index.js +1 -1
  76. package/packages/theme-fuelnfree-site/test/theme.test.mjs +1 -1
  77. package/packages/theme-handyman-site/README.md +2 -2
  78. package/packages/theme-handyman-site/package.json +3 -4
  79. package/packages/theme-handyman-site/src/index.js +1 -1
  80. package/packages/theme-handyman-site/test/theme.test.mjs +1 -1
  81. package/packages/theme-insurance-site/README.md +2 -2
  82. package/packages/theme-insurance-site/package.json +3 -4
  83. package/packages/theme-insurance-site/src/index.js +1 -1
  84. package/packages/theme-insurance-site/test/theme.test.mjs +1 -1
  85. package/packages/theme-scenes/package.json +1 -1
  86. package/packages/theme-shinshu-site/README.md +2 -2
  87. package/packages/theme-shinshu-site/package.json +3 -4
  88. package/packages/theme-shinshu-site/src/index.js +1 -1
  89. package/packages/theme-shinshu-site/test/theme.test.mjs +1 -1
  90. package/packages/work-graph/package.json +3 -2
  91. package/protocol/local-engine/benchmark.v1.schema.json +14 -0
  92. package/protocol/local-engine/engine.v1.schema.json +17 -0
  93. package/python/agentsam_sdk/repository/intelligence/discovery.py +27 -2
  94. package/python/agentsam_sdk/repository/intelligence/git.py +4 -0
  95. package/python/tests/test_repository_intelligence.py +30 -0
  96. package/src/cli/command-catalog.js +3 -1
  97. package/src/cli.js +20 -1
  98. package/src/commands/app.js +10 -0
  99. package/src/commands/engine.js +10 -0
  100. package/src/commands/goap-world.js +134 -0
  101. package/src/commands/goap.js +11 -4
  102. package/src/commands/machine-binary.js +33 -27
  103. package/src/commands/machine-runtime.js +266 -0
  104. package/src/commands/machine.js +155 -51
  105. package/src/commands/package.js +537 -0
  106. package/src/commands/plan-ledger.js +370 -0
  107. package/src/commands/plan.js +183 -0
  108. package/src/commands/runtime.js +25 -10
  109. package/src/commands/setup.js +30 -6
  110. package/src/commands/skill.js +78 -17
  111. package/src/commands/terminal.js +20 -8
  112. package/src/errors/contract.js +4 -4
  113. package/src/errors/diagnostic.js +1 -1
  114. package/src/errors/index.js +1 -1
  115. package/src/index.js +20 -0
  116. package/src/indexing/ingest/materials.js +237 -30
  117. package/src/knowledge/source.js +1 -1
  118. package/src/lib/setup/runtime.js +4 -2
  119. package/src/lib/slash-commands.js +1 -1
  120. package/src/local/runtime-store.js +24 -2
  121. package/src/local/sqlite.js +17 -0
  122. package/src/local-engine/assets.js +37 -0
  123. package/src/local-engine/audit.js +133 -0
  124. package/src/local-engine/benchmark.js +26 -0
  125. package/src/local-engine/contracts.js +101 -0
  126. package/src/local-engine/engines.js +142 -0
  127. package/src/local-engine/index.js +18 -0
  128. package/src/local-engine/runtime.js +39 -0
  129. package/src/sam/operations/package-audit.js +41 -0
  130. package/src/sam/seed.js +2 -0
  131. package/skills/grok-auth/SKILL.md +0 -110
  132. package/skills/grok-auth/agentsam.skill.json +0 -25
  133. package/skills/grok-auth/references/grok-identity.md +0 -64
  134. package/skills/grok-auth/references/per-user-data.md +0 -49
  135. package/skills/grok-auth/references/prewired-and-env.md +0 -54
  136. package/skills/grok-auth/references/session-ui.md +0 -133
  137. package/skills/grok-auth/references/sign-in-methods.md +0 -55
  138. package/skills/grok-auth/references/wiring.md +0 -71
  139. package/skills/grok-building-games/SKILL.md +0 -213
  140. package/skills/grok-building-games/agentsam.skill.json +0 -25
  141. package/skills/grok-building-games/references/3d-libs.md +0 -64
  142. package/skills/grok-building-games/references/ai-pathfinding.md +0 -122
  143. package/skills/grok-building-games/references/audio.md +0 -129
  144. package/skills/grok-building-games/references/babylon.md +0 -202
  145. package/skills/grok-building-games/references/collision-physics.md +0 -122
  146. package/skills/grok-building-games/references/ecs-architecture.md +0 -111
  147. package/skills/grok-building-games/references/game-feel-juice.md +0 -110
  148. package/skills/grok-building-games/references/genres/board-card-chess.md +0 -89
  149. package/skills/grok-building-games/references/genres/endless-runner.md +0 -83
  150. package/skills/grok-building-games/references/genres/fps.md +0 -105
  151. package/skills/grok-building-games/references/genres/platformer-2d.md +0 -97
  152. package/skills/grok-building-games/references/genres/puzzle-match3-tetris.md +0 -131
  153. package/skills/grok-building-games/references/genres/racing-kart.md +0 -106
  154. package/skills/grok-building-games/references/genres/topdown-twin-stick.md +0 -97
  155. package/skills/grok-building-games/references/genres/tower-defense.md +0 -84
  156. package/skills/grok-building-games/references/genres/voxel-minecraft.md +0 -89
  157. package/skills/grok-building-games/references/input.md +0 -139
  158. package/skills/grok-building-games/references/phaser.md +0 -277
  159. package/skills/grok-building-games/references/procedural-generation.md +0 -141
  160. package/skills/grok-building-games/references/save-persistence.md +0 -108
  161. package/skills/grok-building-games/references/threejs-foundational.md +0 -148
  162. package/skills/grok-controls/SKILL.md +0 -274
  163. package/skills/grok-controls/agentsam.skill.json +0 -25
  164. package/skills/grok-design-ui/SKILL.md +0 -122
  165. package/skills/grok-design-ui/agentsam.skill.json +0 -25
  166. package/skills/grok-design-ui/references/animations.md +0 -379
  167. package/skills/grok-design-ui/references/performance.md +0 -88
  168. package/skills/grok-design-ui/references/refined-ui.md +0 -384
  169. package/skills/grok-design-ui/references/surfaces.md +0 -247
  170. package/skills/grok-design-ui/references/typography.md +0 -123
  171. package/skills/grok-game-animation-frames/SKILL.md +0 -84
  172. package/skills/grok-game-animation-frames/agentsam.skill.json +0 -25
  173. package/skills/grok-game-asset-core/SKILL.md +0 -69
  174. package/skills/grok-game-asset-core/agentsam.skill.json +0 -25
  175. package/skills/grok-game-character-consistency/SKILL.md +0 -69
  176. package/skills/grok-game-character-consistency/agentsam.skill.json +0 -25
  177. package/skills/grok-game-tilesets/SKILL.md +0 -65
  178. package/skills/grok-game-tilesets/agentsam.skill.json +0 -25
  179. package/skills/grok-game-ui-icons/SKILL.md +0 -56
  180. package/skills/grok-game-ui-icons/agentsam.skill.json +0 -25
  181. package/skills/grok-generate2dmap/LICENSE +0 -21
  182. package/skills/grok-generate2dmap/SKILL.md +0 -120
  183. package/skills/grok-generate2dmap/SOURCE.md +0 -6
  184. package/skills/grok-generate2dmap/agentsam.skill.json +0 -25
  185. package/skills/grok-generate2dmap/references/deliverables.md +0 -101
  186. package/skills/grok-generate2dmap/references/layered-map-contract.md +0 -209
  187. package/skills/grok-generate2dmap/references/map-strategies.md +0 -341
  188. package/skills/grok-generate2dmap/references/object-production-gate.md +0 -24
  189. package/skills/grok-generate2dmap/references/pipeline.md +0 -149
  190. package/skills/grok-generate2dmap/references/prop-pack-contract.md +0 -174
  191. package/skills/grok-generate2dmap/references/side-scroll-stages.md +0 -29
  192. package/skills/grok-generate2dmap/scripts/compose_layered_preview.py +0 -157
  193. package/skills/grok-generate2dmap/scripts/extract_prop_pack.py +0 -369
  194. package/skills/grok-generate2dsprite/LICENSE +0 -21
  195. package/skills/grok-generate2dsprite/SKILL.md +0 -313
  196. package/skills/grok-generate2dsprite/SOURCE.md +0 -6
  197. package/skills/grok-generate2dsprite/agentsam.skill.json +0 -25
  198. package/skills/grok-generate2dsprite/references/modes.md +0 -124
  199. package/skills/grok-generate2dsprite/references/prompt-rules.md +0 -315
  200. package/skills/grok-generate2dsprite/scripts/generate2dsprite.py +0 -1031
  201. package/skills/grok-generate2dsprite/scripts/make_layout_guide.py +0 -109
  202. package/skills/grok-imagine/SKILL.md +0 -201
  203. package/skills/grok-imagine/agentsam.skill.json +0 -25
  204. package/skills/grok-multiplayer-p2p/SKILL.md +0 -111
  205. package/skills/grok-multiplayer-p2p/agentsam.skill.json +0 -25
  206. package/skills/grok-multiplayer-p2p/references/react-binding.md +0 -144
  207. package/skills/grok-multiplayer-p2p/references/signaling-relay.md +0 -269
  208. package/skills/grok-neon/SKILL.md +0 -157
  209. package/skills/grok-neon/agentsam.skill.json +0 -25
  210. package/skills/grok-og/SKILL.md +0 -102
  211. package/skills/grok-og/agentsam.skill.json +0 -25
  212. package/skills/grok-og/references/brand-pass.md +0 -53
  213. package/skills/grok-og/references/custom-card.md +0 -107
  214. package/skills/grok-og/references/favicon-and-icons.md +0 -48
  215. package/skills/grok-og/references/og-type-contract.md +0 -18
  216. package/skills/grok-og/references/placeholder-card.md +0 -21
  217. package/skills/grok-og/references/x-banner.md +0 -41
  218. package/skills/grok-threejs/SKILL.md +0 -67
  219. package/skills/grok-threejs/agentsam.skill.json +0 -25
  220. package/skills/grok-threejs/references/llms-full.txt +0 -2780
  221. package/skills/grok-video2dsprite/LICENSE +0 -21
  222. package/skills/grok-video2dsprite/SKILL.md +0 -236
  223. package/skills/grok-video2dsprite/SOURCE.md +0 -6
  224. package/skills/grok-video2dsprite/agentsam.skill.json +0 -25
  225. package/skills/grok-video2dsprite/references/pipeline.md +0 -90
  226. package/skills/grok-video2dsprite/references/prompt-rules.md +0 -63
  227. package/skills/grok-video2dsprite/scripts/video2dsprite.py +0 -490
  228. package/skills/grok-xai-api/SKILL.md +0 -152
  229. package/skills/grok-xai-api/agentsam.skill.json +0 -25
  230. package/test/account-session.test.mjs +0 -101
  231. package/test/agent-capabilities.test.mjs +0 -67
  232. package/test/app-authority-context.test.mjs +0 -32
  233. package/test/app-building-skills.test.mjs +0 -61
  234. package/test/apps-scaffold-contract.test.mjs +0 -115
  235. package/test/blender-cad.test.mjs +0 -146
  236. package/test/cad-docker.test.mjs +0 -96
  237. package/test/capabilities.test.mjs +0 -133
  238. package/test/cli/api-key-env-whoami.test.mjs +0 -129
  239. package/test/cli/catalog-authority.test.mjs +0 -64
  240. package/test/cli/codebaseindex-plan-ux.test.mjs +0 -37
  241. package/test/cli/eval-live.test.mjs +0 -219
  242. package/test/cli/go.test.mjs +0 -128
  243. package/test/cli/local-vault-and-provider-setup.test.mjs +0 -268
  244. package/test/cli/machine-command.test.mjs +0 -34
  245. package/test/cli/mcp-client.test.mjs +0 -256
  246. package/test/cli/preferences-runtime.test.mjs +0 -11
  247. package/test/cli/runtime-persist.test.mjs +0 -56
  248. package/test/cli/runtime-ui.test.mjs +0 -141
  249. package/test/cli/rust-command.test.mjs +0 -21
  250. package/test/cli/skill-npm-and-env.test.mjs +0 -52
  251. package/test/cli/status-actions.test.mjs +0 -88
  252. package/test/cli/wireframes-go-registry.test.mjs +0 -139
  253. package/test/cli-preferences.test.mjs +0 -46
  254. package/test/cloudflare-connector.test.mjs +0 -93
  255. package/test/cloudflare-runtime.test.mjs +0 -82
  256. package/test/context.test.mjs +0 -159
  257. package/test/credentials-audit.test.mjs +0 -113
  258. package/test/deploy-health-scan.test.mjs +0 -95
  259. package/test/deploy-receipt.test.mjs +0 -91
  260. package/test/dockerize.test.mjs +0 -93
  261. package/test/error-diagnostics.test.mjs +0 -124
  262. package/test/eval-context.test.mjs +0 -37
  263. package/test/execution-approvals.test.mjs +0 -27
  264. package/test/fixtures/cad/courtyard-house.json +0 -208
  265. package/test/fixtures/knowledge-rpc-worker.mjs +0 -16
  266. package/test/fixtures/project-authority/customer-app/.agentsam/app.json +0 -5
  267. package/test/fixtures/project-authority/customer-app/apps/my-product/index.ts +0 -1
  268. package/test/fixtures/project-authority/customer-app/wrangler.toml +0 -17
  269. package/test/gcloud-auth.test.mjs +0 -111
  270. package/test/go/build-source-identity.test.mjs +0 -31
  271. package/test/go/cloudflare-probe.test.mjs +0 -317
  272. package/test/go/distribution.test.mjs +0 -28
  273. package/test/google-cloud-connection.test.mjs +0 -83
  274. package/test/google-cloud-inventory.test.mjs +0 -64
  275. package/test/indexing-provider.test.mjs +0 -29
  276. package/test/init-options.test.mjs +0 -35
  277. package/test/integration/ai-access-onboarding.test.mjs +0 -47
  278. package/test/integration/app-command.test.mjs +0 -85
  279. package/test/integration/autorag-project-authority.integration.test.mjs +0 -51
  280. package/test/integration/autorag-runtime-discovery.test.mjs +0 -107
  281. package/test/integration/cad-discovery.test.mjs +0 -158
  282. package/test/integration/cad-docker-executor.test.mjs +0 -249
  283. package/test/integration/cad-execution.test.mjs +0 -184
  284. package/test/integration/cad-project-app.test.mjs +0 -31
  285. package/test/integration/cad-project-d1.test.mjs +0 -25
  286. package/test/integration/cad-project-native.test.mjs +0 -24
  287. package/test/integration/cad-project-workflow.test.mjs +0 -9
  288. package/test/integration/cad-project.test.mjs +0 -85
  289. package/test/integration/cli-help.test.mjs +0 -41
  290. package/test/integration/cms-app-scaffold.test.mjs +0 -77
  291. package/test/integration/cms-site-tenancy-contract.test.mjs +0 -268
  292. package/test/integration/codebaseindex-ingest.test.mjs +0 -255
  293. package/test/integration/core-client.integration.test.mjs +0 -55
  294. package/test/integration/database-hosted-honesty.test.mjs +0 -49
  295. package/test/integration/desktop-keychain-boundary.test.mjs +0 -45
  296. package/test/integration/error-runtime-rpc.test.mjs +0 -71
  297. package/test/integration/features-resolve.test.mjs +0 -147
  298. package/test/integration/hosted-work-host-authority.test.mjs +0 -47
  299. package/test/integration/icon-registry.test.mjs +0 -67
  300. package/test/integration/ingest-discover-models.test.mjs +0 -30
  301. package/test/integration/inspect-path-cli.test.mjs +0 -46
  302. package/test/integration/install-script.test.mjs +0 -110
  303. package/test/integration/inventory-core.test.mjs +0 -53
  304. package/test/integration/inventory-eligibility.test.mjs +0 -59
  305. package/test/integration/inventory-evidence.test.mjs +0 -125
  306. package/test/integration/knowledge-rpc.test.mjs +0 -112
  307. package/test/integration/local-fs.test.mjs +0 -113
  308. package/test/integration/local-provider-bridge.test.mjs +0 -65
  309. package/test/integration/local-studio-settings-production.test.mjs +0 -40
  310. package/test/integration/lockfile-sync.test.mjs +0 -26
  311. package/test/integration/merkle-cli.test.mjs +0 -61
  312. package/test/integration/merkle-persistence-identity.test.mjs +0 -48
  313. package/test/integration/plugins-cloudflare.integration.test.mjs +0 -28
  314. package/test/integration/provider-env-cli.test.mjs +0 -60
  315. package/test/integration/provider-factory.test.mjs +0 -197
  316. package/test/integration/repository-company-graph.test.mjs +0 -90
  317. package/test/integration/runtime-migrations.test.mjs +0 -87
  318. package/test/integration/runtime-status.integration.test.mjs +0 -227
  319. package/test/integration/sam-activity-recovery.test.mjs +0 -147
  320. package/test/integration/sam-decision.test.mjs +0 -584
  321. package/test/integration/sam-kernel.test.mjs +0 -99
  322. package/test/integration/sam-planning-astar.test.mjs +0 -279
  323. package/test/integration/scaffold-cloudflare.test.mjs +0 -46
  324. package/test/integration/skill-runtime.test.mjs +0 -240
  325. package/test/integration/storage-architecture.test.mjs +0 -154
  326. package/test/integration/store-discovery.test.mjs +0 -44
  327. package/test/integration/studio-fs-pty-e2e.test.mjs +0 -294
  328. package/test/integration/terminal-exec.integration.test.mjs +0 -86
  329. package/test/integration/theme-package-registry.test.mjs +0 -31
  330. package/test/integration/tool-runtime.test.mjs +0 -124
  331. package/test/integration/tool-schema.test.mjs +0 -59
  332. package/test/jr-dev-skill.test.mjs +0 -26
  333. package/test/knowledge-context-pack.test.mjs +0 -19
  334. package/test/knowledge-postgres.test.mjs +0 -40
  335. package/test/knowledge-service.test.mjs +0 -110
  336. package/test/knowledge.test.mjs +0 -206
  337. package/test/live/terminal-transport.live.test.mjs +0 -24
  338. package/test/local-sessions.test.mjs +0 -57
  339. package/test/local-studio-deploy.test.mjs +0 -83
  340. package/test/loopback-oauth.test.mjs +0 -53
  341. package/test/merkle-render.test.mjs +0 -31
  342. package/test/mini.test.mjs +0 -140
  343. package/test/model-catalog.test.mjs +0 -70
  344. package/test/models.test.mjs +0 -309
  345. package/test/npm10-lock.test.mjs +0 -29
  346. package/test/ollama.test.mjs +0 -137
  347. package/test/open-url.test.mjs +0 -64
  348. package/test/openai-responses.test.mjs +0 -155
  349. package/test/portable-context.test.mjs +0 -94
  350. package/test/project-config.test.mjs +0 -81
  351. package/test/project-rules.test.mjs +0 -44
  352. package/test/provider-credentials.test.mjs +0 -106
  353. package/test/rehydrate.test.mjs +0 -25
  354. package/test/release-hygiene.test.mjs +0 -42
  355. package/test/repository-snapshot-view.test.mjs +0 -112
  356. package/test/responses-runner.test.mjs +0 -465
  357. package/test/runtime-activity.test.mjs +0 -98
  358. package/test/sdk-worker-contract.test.mjs +0 -72
  359. package/test/security.test.mjs +0 -266
  360. package/test/setup-planner.test.mjs +0 -74
  361. package/test/setup-runtime.test.mjs +0 -51
  362. package/test/shell.test.mjs +0 -281
  363. package/test/skills.test.mjs +0 -22
  364. package/test/smoke.mjs +0 -122
  365. package/test/telemetry.test.mjs +0 -79
  366. package/test/terminal/local-pty.mock.test.mjs +0 -153
  367. package/test/terminal-machine-identity.test.mjs +0 -88
  368. package/test/theme-portability.test.mjs +0 -14
  369. package/test/tools-search.test.mjs +0 -73
  370. package/test/unit/website-assets-bindings.test.mjs +0 -60
  371. package/test/whoami-resume.test.mjs +0 -157
@@ -1,109 +0,0 @@
1
- #!/usr/bin/env python3
2
- """Create a layout-only guide image for sprite sheet generation."""
3
-
4
- from __future__ import annotations
5
-
6
- import argparse
7
- from pathlib import Path
8
-
9
- from PIL import Image, ImageDraw
10
-
11
-
12
- def draw_dashed_line(
13
- draw: ImageDraw.ImageDraw,
14
- start: tuple[int, int],
15
- end: tuple[int, int],
16
- *,
17
- fill: str,
18
- width: int,
19
- dash: int,
20
- gap: int,
21
- ) -> None:
22
- x1, y1 = start
23
- x2, y2 = end
24
- if x1 == x2:
25
- for y in range(min(y1, y2), max(y1, y2), dash + gap):
26
- draw.line((x1, y, x2, min(y + dash, max(y1, y2))), fill=fill, width=width)
27
- return
28
- if y1 == y2:
29
- for x in range(min(x1, x2), max(x1, x2), dash + gap):
30
- draw.line((x, y1, min(x + dash, max(x1, x2)), y2), fill=fill, width=width)
31
- return
32
- raise ValueError("draw_dashed_line only supports horizontal or vertical lines")
33
-
34
-
35
- def parse_args() -> argparse.Namespace:
36
- parser = argparse.ArgumentParser(description=__doc__)
37
- parser.add_argument("--rows", type=int, required=True)
38
- parser.add_argument("--cols", type=int, required=True)
39
- parser.add_argument("--cell-width", type=int, default=384)
40
- parser.add_argument("--cell-height", type=int, default=384)
41
- parser.add_argument("--safe-margin-x", type=int, default=52)
42
- parser.add_argument("--safe-margin-y", type=int, default=52)
43
- parser.add_argument("--output", type=Path, required=True)
44
- parser.add_argument(
45
- "--label-cells",
46
- action="store_true",
47
- help="Draw small row,column labels. Leave off for normal imagegen references.",
48
- )
49
- return parser.parse_args()
50
-
51
-
52
- def main() -> None:
53
- args = parse_args()
54
- if args.rows <= 0 or args.cols <= 0:
55
- raise SystemExit("--rows and --cols must be positive")
56
- if args.cell_width <= 0 or args.cell_height <= 0:
57
- raise SystemExit("--cell-width and --cell-height must be positive")
58
-
59
- width = args.cols * args.cell_width
60
- height = args.rows * args.cell_height
61
- image = Image.new("RGB", (width, height), "#f8f8f8")
62
- draw = ImageDraw.Draw(image)
63
-
64
- for row in range(args.rows):
65
- for col in range(args.cols):
66
- left = col * args.cell_width
67
- top = row * args.cell_height
68
- right = left + args.cell_width - 1
69
- bottom = top + args.cell_height - 1
70
- safe_left = left + args.safe_margin_x
71
- safe_top = top + args.safe_margin_y
72
- safe_right = right - args.safe_margin_x
73
- safe_bottom = bottom - args.safe_margin_y
74
-
75
- draw.rectangle((left, top, right, bottom), outline="#111111", width=4)
76
- draw.rectangle(
77
- (safe_left, safe_top, safe_right, safe_bottom), outline="#2f80ed", width=3
78
- )
79
-
80
- center_x = left + args.cell_width // 2
81
- center_y = top + args.cell_height // 2
82
- draw_dashed_line(
83
- draw,
84
- (center_x, safe_top),
85
- (center_x, safe_bottom),
86
- fill="#b8b8b8",
87
- width=2,
88
- dash=14,
89
- gap=16,
90
- )
91
- draw_dashed_line(
92
- draw,
93
- (safe_left, center_y),
94
- (safe_right, center_y),
95
- fill="#b8b8b8",
96
- width=2,
97
- dash=14,
98
- gap=16,
99
- )
100
-
101
- if args.label_cells:
102
- draw.text((left + 12, top + 10), f"{row + 1},{col + 1}", fill="#777777")
103
-
104
- args.output.parent.mkdir(parents=True, exist_ok=True)
105
- image.save(args.output)
106
-
107
-
108
- if __name__ == "__main__":
109
- main()
@@ -1,201 +0,0 @@
1
- ---
2
- name: imagine
3
- description: >
4
- How to use the Imagine tools in Grok Build: imagine_text_to_image,
5
- imagine_image_to_image, imagine_reference_to_image, imagine_text_to_video,
6
- imagine_image_to_video, imagine_reference_to_video, and render_file for chat
7
- previews. When to build a visual with code instead of generating it,
8
- prompt-craft, reference-first handling of real people, factual grounding, and
9
- asset-consistency. Load this whenever generating or editing an image or video
10
- is on the table. Tool-usage-driven, not triggered by a user merely mentioning
11
- images.
12
- metadata:
13
- short-description: "Prompting and workflow guidance for Imagine image/video tools"
14
- user-invocable: false
15
- ---
16
-
17
- # Imagine
18
-
19
- Grok Build uses the **split Imagine computer stack** (`grok_computer` variants).
20
- There is **no** consolidated `imagine_image` or `imagine_video` tool — always
21
- call the modality-specific name from the table below.
22
-
23
- | Tool | Role |
24
- |------|------|
25
- | `imagine_text_to_image` | New image from a text prompt only (no source). |
26
- | `imagine_image_to_image` | Edit / restyle **one** existing image (sandbox path). |
27
- | `imagine_reference_to_image` | Combine **2+** reference images (sandbox paths). |
28
- | `imagine_text_to_video` | New video from a text prompt only (no source). |
29
- | `imagine_image_to_video` | Animate **one** still (sandbox path) into a video. |
30
- | `imagine_reference_to_video` | Video from **1+** reference images (sandbox paths). |
31
- | `render_file` | Show a sandbox image/video path to the user in chat. |
32
-
33
- **Path-based handles.** These tools read/write the shared sandbox:
34
-
35
- - Generation returns a sandbox **`file_path`** (under artifacts). Open it with
36
- `read_file` / shell; show the user with **`render_file`**.
37
- - Edit / animate tools take that path (or paths) as input — match the live
38
- schema (`image`, `images`, etc.). Never invent paths.
39
- - Never call `imagine_image` / `imagine_video`. Asset-id helpers
40
- (`imagine_create_asset` / `imagine_view_media` / `render_imagine_media`) are
41
- **not** on this stack.
42
-
43
- Apply this whenever you're considering or about to call any of these tools.
44
-
45
- ## Handle flow (mandatory mental model)
46
-
47
- ```text
48
- generate → file_path → render_file (show user) / read_file or scripts (QC)
49
- edit / animate → pass prior file_path(s) into image_to_* / reference_to_*
50
- ```
51
-
52
- - **Use the path the tool actually returned** — do not invent filesystem paths.
53
- - **Show the user media** with `render_file`, not ad-hoc markdown image links.
54
-
55
- ## Build accurate visuals with code, not the image tools
56
-
57
- 1. **Image models are unreliable at exact text, numbers, and structure.** They can handle short text or a simple layout, but they often garble words, invent numbers, draw chart bars that match no data, or point diagram arrows nowhere, and the more that has to be exact, the worse they do. A detailed prompt doesn't make it dependable, and another `imagine_image_to_image` edit usually won't fix it. So when a result needs specific text, data, or structure to be correct (charts from real numbers, labeled or technical diagrams, math explainers, tables, screens with real copy), construct the asset with code, where you control the exact content. Prefer HTML and CSS, which give much better layout, typography, and polish than Python plotting. When only the look matters (photos, illustrations, characters, scenes, decorative art), the image tools are the right choice. Which one fits depends on what the output needs to get right, not on how the request is worded.
58
-
59
- ## Verifying discrete accuracy (loop)
60
-
61
- When the output must get specific text, numbers, data, or structure right, don't trust the first result - verify it in a loop:
62
-
63
- 1. Produce the result (generate, or per *Build accurate visuals with code*, construct it in code).
64
- 2. Inspect the actual output - use `read_file` (image understanding) on the result path - and confirm every word, number, label, and structural detail matches the requirement, and that nothing overlaps, clips, or runs off-canvas.
65
- 3. If anything is wrong, fix and re-verify:
66
- - Garbled text, invented numbers, or broken layout from an image model? Don't just re-prompt - it will likely garble it again. Rebuild it with code.
67
- - Overlapping or clipped elements in code-built output? Re-lay-out with auto-layout (HTML/CSS) rather than nudging coordinates by hand.
68
- - Otherwise make one targeted edit via `imagine_image_to_image` with the prior path.
69
- 4. Only finish when the discrete content is exactly correct. If it can't be made accurate, tell the user instead of shipping something wrong.
70
-
71
- ## Core Principles
72
-
73
- 1. **You own the prompt.** If the user gives a detailed prompt or asks you to use theirs, use it verbatim. Otherwise craft the final prompt: front-load the subject, give strong high-level direction for mood, composition, lighting, and style without over-specifying every detail, write natural prose rather than keyword tags, and describe positively instead of using negative prompts. For edits, describe only what changes. Target 2-5 sentences.
74
- 2. **Reference-first for real people.** Never use pure text-to-image for a named real person or group, including face swaps, posters, cartoons, and cinematic or editorial depictions. Use `imagine_image_to_image` **with a real reference path** instead, and never produce non-consensual, sexualized, or minor-involving likenesses. See Real People and References for the procedure.
75
- 3. **Ground facts with search first.** If any part of the request depends on a real-world fact, identity, brand or product, place, event, or top/latest/current result, search the web before generating and put the actual verified details into the prompt. Don't rely on memory, and don't write vague placeholders like "the current president"; write the verified name.
76
- 4. **Reuse a base for consistency.** When the same character, object, or setting must appear across multiple images, generate one base with `imagine_text_to_image`, keep its `file_path`, then pass that path to `imagine_image_to_image` for every variation. Don't re-run text-to-image from scratch for a recurring subject.
77
- 5. **Handle failures gracefully.** On a moderation or safety block, stop; don't retry and don't paraphrase the prompt to evade the filter. Tell the user it was blocked and offer a different direction. If a reference is weak or a result looks off-target, say so and ask for an upload or redirect rather than silently iterating.
78
- 6. **Plan multi-step workflows.** Sequence the steps; only parallelize generations that belong to the same step.
79
- 7. **Review at the end.** Confirm the generations you intended actually executed and match what was asked. Render final assets with `render_file`.
80
- 8. **Don't assume tool behavior.** Don't invent tool parameters, return values, or environment capabilities that aren't actually provided; verify rather than guess.
81
-
82
- ## Choosing the tool
83
-
84
- | Situation | Call |
85
- |-----------|------|
86
- | New image, no source | `imagine_text_to_image` with `prompt` (+ `aspect_ratio`) |
87
- | Edit / restyle / recolor one existing image | `imagine_image_to_image` with `prompt` + source path |
88
- | Combine 2+ reference images into one | `imagine_reference_to_image` with `prompt` + source paths |
89
- | Iterate on a previous result | `imagine_image_to_image` with prior path |
90
- | Named real person or group | `imagine_image_to_image` with a real reference path after web search |
91
- | Generic / invented subject from scratch | `imagine_text_to_image` |
92
- | New video, no source | `imagine_text_to_video` with `prompt` |
93
- | Animate one still | `imagine_image_to_video` with that still's path |
94
- | Multi-ref video | `imagine_reference_to_video` with image path(s) |
95
-
96
- Rule of thumb: **no refs → text_to_*; one ref → image_to_*; 2+ refs → reference_to_*.**
97
-
98
- ## `imagine_text_to_image`
99
-
100
- Generate a new image from a text prompt.
101
-
102
- Inputs:
103
-
104
- - `prompt` (required) - full description of the desired image.
105
- - `aspect_ratio` - one of `1:1`, `3:4`, `4:3`, `2:3`, `3:2`, `9:16`, `16:9`, `21:9`, `5:2`, `50:11`, or `unknown`. Use `16:9` for OG share cards and `50:11` for the X feed banner when generating a custom `public/x-banner.jpg` for **games** (every app wires `x:game:image`; only games call Imagine for it — see the `og` skill); for a true 2:1 canvas, call the xAI Images API.
106
-
107
- To produce multiple variations, make multiple `imagine_text_to_image` calls with distinct prompts. The tool does not expose `n` or `count` parameters.
108
-
109
- ## `imagine_image_to_image`
110
-
111
- Edit one existing image.
112
-
113
- Inputs (names follow the live schema — typically a singular sandbox path):
114
-
115
- - `prompt` (required) - what to change (describe only the edit).
116
- - Source path field (required) - sandbox path returned by a prior generation or download.
117
- - `aspect_ratio` - only set when the user explicitly wants a ratio change.
118
-
119
- ## `imagine_reference_to_image`
120
-
121
- Compose one image from 2+ reference paths.
122
-
123
- Inputs:
124
-
125
- - `prompt` (required).
126
- - Source paths (required) - 2+ sandbox paths.
127
- - `aspect_ratio` - optional.
128
-
129
- For a single source edit, use `imagine_image_to_image` instead.
130
-
131
- ## `imagine_text_to_video`
132
-
133
- Generate a new video from a text prompt only (no source frame).
134
-
135
- Inputs:
136
-
137
- - `prompt` (required) - short present-tense shot description.
138
- - `duration` / `aspect_ratio` / resolution fields as exposed by the live schema.
139
-
140
- Prefer short shots; same prompt-craft rules as image-to-video below.
141
-
142
- ## `imagine_image_to_video`
143
-
144
- Animate one still into a video.
145
-
146
- Inputs:
147
-
148
- - Singular source still path (required).
149
- - `prompt` - short present-tense shot (recommended; required by some variants).
150
- - `duration` - `6` (default), `10`, or `15` when exposed.
151
- - `aspect_ratio` - optional; omit to keep the source ratio when animating one image.
152
-
153
- **Prefer short shots.** Build video as a planned sequence of short clips, not one long take:
154
-
155
- 1. Plan the story as shots - one beat each.
156
- 2. Prefer more 6s shots over fewer long ones.
157
- 3. Create each shot's source still with `imagine_text_to_image` / `imagine_image_to_image` (keep character paths consistent).
158
- 4. Animate with `imagine_image_to_video` + that still path.
159
-
160
- Key behaviors:
161
-
162
- - **Prompt-craft:** one short, vivid moment in present tense with a clear camera movement, in 1-2 sentences.
163
- - **Minimal but interesting:** one clear subject and a single simple motion or camera move.
164
- - **Complex source?** Keep the subject fixed and move only the camera, or break into simpler shots.
165
- - **Real people:** reference-first - drive from a verified reference; never animate a named person without one.
166
- - Don't loop the same clip unless asked.
167
- - Assemble multi-shot timelines with FFmpeg stream copy on the returned video paths.
168
-
169
- ## `imagine_reference_to_video`
170
-
171
- Video from one or more reference image paths guided by a prompt. Prefer composing a single still with `imagine_reference_to_image` first, then `imagine_image_to_video`, when the goal is a clean first frame.
172
-
173
- ## Writing Strong Prompts
174
-
175
- Describe, roughly in this order: **subject -> action/pose -> setting -> style -> composition -> lighting/mood -> key details.**
176
-
177
- - Be specific and concrete; lead with the most important elements.
178
- - State what to include rather than what to exclude.
179
- - Use one coherent scene per prompt.
180
- - Match `aspect_ratio` to the use case: `9:16` for phone/story, `16:9` for banner/video frame or OG share cards, `1:1` for avatar/icon.
181
-
182
- ## Real People and References
183
-
184
- 1. Search the web first to confirm identity, role, relationship, or event, even when it seems obvious.
185
- 2. Obtain a strong reference image on disk (user upload or search → sandbox path), then call `imagine_image_to_image` with that path. A user-uploaded photo is best.
186
- 3. If no suitable reference exists, ask the user to upload one rather than generating from a weak base.
187
-
188
- ## Showing results
189
-
190
- - Call `render_file` with the sandbox `file_path` so the user sees the image/video in chat.
191
- - For your own QC and scripts, `read_file` / shell on that path.
192
-
193
- Game sprites and maps have their own pipelines — follow `generate2dsprite`,
194
- `video2dsprite`, and `generate2dmap` for those.
195
-
196
- ## Failure modes to avoid
197
-
198
- - Calling consolidated names `imagine_image` or `imagine_video` (they are not available).
199
- - Passing a list to `imagine_image_to_image` / `imagine_image_to_video` (singular source only).
200
- - Inventing a filesystem path that the tool never returned.
201
- - Running chroma/ffmpeg on a path you made up without a real generation/`file_path`.
@@ -1,25 +0,0 @@
1
- {
2
- "schema": "agentsam.skill.v1",
3
- "id": "grok-imagine",
4
- "name": "Grok \u00b7 imagine",
5
- "description": "Prompting and workflow guidance for Imagine image/video tools",
6
- "icon": "skill",
7
- "slash": {
8
- "suggested": "/grok-imagine"
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,111 +0,0 @@
1
- ---
2
- name: multiplayer-p2p
3
- description: >
4
- Peer-to-peer realtime multiplayer over WebRTC data channels: every user of
5
- the deployed app connects directly to every other user (full mesh), the
6
- server only brokers the handshake at /api/rtc. Lowest possible latency, zero
7
- per-message server cost. Use for 2-8 player co-op/casual realtime: shared
8
- cursors, drawing, party games, casual action. Triggers: p2p, peer to peer,
9
- webrtc, low latency multiplayer, direct connection.
10
- metadata:
11
- short-description: "WebRTC P2P mesh, signaled at /api/rtc"
12
- user-invocable: false
13
- ---
14
-
15
- # Multiplayer (WebRTC peer-to-peer)
16
-
17
- All visitors on the same deployed domain join one default room, opening a
18
- native WebRTC data channel directly to every other visitor — game traffic
19
- itself never touches a server. A tiny relay at `/api/rtc` handles only the
20
- routing of the connection handshake (SDP/ICE) while peers connect. What you
21
- use from the kit is client-side only; the relay is yours.
22
-
23
- Latency is browser↔browser (often 5–40ms) with zero per-tick server cost.
24
-
25
- | Piece | Path |
26
- |---|---|
27
- | Mesh primitive (start here) | `P2PRoom` from `@/lib/multiplayer` |
28
- | React room binding (optional, you create) | `src/lib/multiplayer/use-p2p-room.ts` |
29
- | Signaling relay (you create) | `src/lib/multiplayer/signaling.server.ts` |
30
- | HTTP mount (you create) | `src/routes/api/rtc.ts` |
31
-
32
- **Trust model — read before choosing P2P.** There is no server authority:
33
- every peer runs its own copy of the rules and can lie (position, score,
34
- anything). Peers also learn each other's IP addresses during ICE. P2P is for
35
- **co-op and casual play among people who choose to play together** — never for
36
- competitive ranking, cheat-sensitive, or anonymous-stranger matchmaking.
37
- Competitive or cheat-sensitive play is not supported in this template: push
38
- back in product terms rather than shipping it on P2P.
39
-
40
- Practical limits: a full mesh is O(N²) connections — cap rooms at ~8 peers.
41
- Roughly 10–20% of peer pairs sit behind strict NATs and cannot connect; the
42
- kit surfaces this per peer as `connectionState: "failed"` — show it in the
43
- UI rather than hanging.
44
-
45
- ## Setup (once)
46
-
47
- Create the two server files — nothing works without them:
48
-
49
- 1. `src/lib/multiplayer/signaling.server.ts` — the DB-backed signaling relay
50
- (Neon deployed, PGLite in preview).
51
- 2. `src/routes/api/rtc.ts` — mounts it at `/api/rtc` (GET poll, POST
52
- signal/leave).
53
-
54
- **Copy both from `references/signaling-relay.md`**, which also carries the
55
- schema note: the relay creates its own two tables on first use
56
- (`CREATE TABLE IF NOT EXISTS`), so **nothing goes in `migrations/`** unless you
57
- deliberately want to own the schema.
58
-
59
- ## Using the primitive
60
-
61
- `P2PRoom` is framework-free, and a "room" is just a rendezvous key — a lobby
62
- code, a 1:1 call id, a shared-document id, any string (≤64 chars). Any
63
- architecture sits on top of the same three calls:
64
-
65
- ```ts
66
- import { P2PRoom } from "@/lib/multiplayer";
67
-
68
- const p2p = new P2PRoom({
69
- room: "doc-42",
70
- selfId: myId,
71
- name: "ani",
72
- onPeersChanged: (peers) => render(peers),
73
- onMessage: (from, data, channel) => apply(from, data, channel),
74
- });
75
- await p2p.join();
76
- p2p.broadcast(state); // unreliable "state" channel — game-rate, stale drops
77
- p2p.send(event, to); // reliable channel — exactly-once events (to optional)
78
- p2p.close();
79
- ```
80
-
81
- For the common "everyone on this app plays together" shape in React, copy the
82
- `useP2PRoom` hook (plus a worked component: game-rate broadcast loop at ~20
83
- sends/s, reliable one-shot events) from `references/react-binding.md`.
84
-
85
- Patterns:
86
-
87
- 1. `broadcast()` = unreliable/unordered, for continuously-refreshed state
88
- (positions, cursors). `send()` = reliable/ordered, for events that must
89
- arrive exactly once. Never stream game-rate state on `send()`; interpolate
90
- between broadcasts for smooth motion.
91
- 2. Late joiners know nothing: on a new peer appearing in `p2p.peers`, an
92
- existing peer should `send()` it the current shared state. Exactly one
93
- peer must answer: compare ids among the peers that were ALREADY in the
94
- room (your `selfId` plus `p2p.peers` minus the newcomer) and answer only
95
- if your `selfId` is the smallest — so two simultaneous joiners neither
96
- double-answer nor go unanswered.
97
- 3. Room ids: omit for "everyone on this app plays together"; pass
98
- `room: code` for private lobbies (generate a short code, put it in the URL).
99
- 4. Peers disappear without goodbye (tab close, sleep): treat a peer missing
100
- from `p2p.peers` as gone and drop its entities.
101
- 5. A React binding that captures `room`/`name` on first render (the one in
102
- `references/react-binding.md` does) needs a remount to change them — key the
103
- component on the room code.
104
-
105
- ## Diagnostics
106
-
107
- Each entry in `p2p.peers` carries `connectionState`, `rttMs` (data-channel
108
- ping), and `candidateType` (`host`/`srflx` = direct). To override STUN, add
109
- `VITE_STUN_URLS` (comma-separated) to `.grok/app-env.json` and **restart the dev
110
- server** (Vite reads env at startup; HMR will not pick it up) — never write a
111
- `.env` in this sandbox.
@@ -1,25 +0,0 @@
1
- {
2
- "schema": "agentsam.skill.v1",
3
- "id": "grok-multiplayer-p2p",
4
- "name": "Grok \u00b7 multiplayer-p2p",
5
- "description": "WebRTC P2P mesh, signaled at /api/rtc",
6
- "icon": "skill",
7
- "slash": {
8
- "suggested": "/grok-multiplayer-p2p"
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,144 +0,0 @@
1
- # React room binding (optional — copy if it fits your app)
2
-
3
- For the common "everyone on this app plays together" shape, copy this hook to
4
- `src/lib/multiplayer/use-p2p-room.ts` and adapt it freely — it is yours, not
5
- part of the kit. It captures `room`/`name` on first render, so changing them
6
- later requires remounting the component (key it on the room code).
7
-
8
-
9
- ```ts
10
- /**
11
- * React binding for P2PRoom. Identity and room id are captured once on mount
12
- * (useState initializers) so re-renders never tear down the mesh: the P2PRoom
13
- * instance lives exactly as long as the component that mounted it, and
14
- * changing `room`/`name` requires a remount (key the component on them).
15
- */
16
- import { useCallback, useEffect, useRef, useState } from "react";
17
- import { P2PRoom, type PeerInfo } from "./p2p";
18
-
19
- export interface UseP2PRoomOptions {
20
- /** Defaults to a per-deployment room derived from the hostname. */
21
- room?: string;
22
- name?: string;
23
- }
24
-
25
- export interface P2PRoomHandle {
26
- selfId: string;
27
- room: string;
28
- /** Remote peers only (self excluded), with live connection diagnostics. */
29
- peers: PeerInfo[];
30
- joined: boolean;
31
- /** Unreliable game-state fanout to every connected peer. */
32
- broadcast: (data: unknown) => void;
33
- /** Reliable ordered send to one peer (or all when peerId is omitted). */
34
- send: (data: unknown, peerId?: string) => void;
35
- /** Subscribe to incoming messages; returns an unsubscribe function. */
36
- onMessage: (
37
- fn: (from: string, data: unknown, channel: "state" | "reliable") => void,
38
- ) => () => void;
39
- }
40
-
41
- function defaultRoom(): string {
42
- if (typeof window === "undefined") return "room-ssr";
43
- // DNS labels can be 63 chars; the signaling ID regex caps room ids at 64 —
44
- // truncate so `room-` + label always fits.
45
- return `room-${window.location.hostname.split(".")[0]}`.slice(0, 64);
46
- }
47
-
48
- export function useP2PRoom(options: UseP2PRoomOptions = {}): P2PRoomHandle {
49
- const [selfId] = useState(() => `p-${Math.random().toString(36).slice(2, 10)}`);
50
- const [room] = useState(() => options.room ?? defaultRoom());
51
- const [name] = useState(() => options.name ?? selfId);
52
- const [peers, setPeers] = useState<PeerInfo[]>([]);
53
- const [joined, setJoined] = useState(false);
54
- const roomRef = useRef<P2PRoom | null>(null);
55
- const listeners = useRef(
56
- new Set<(from: string, data: unknown, channel: "state" | "reliable") => void>(),
57
- );
58
-
59
- useEffect(() => {
60
- const p2p = new P2PRoom({
61
- room,
62
- selfId,
63
- name,
64
- onPeersChanged: setPeers,
65
- onMessage: (from, data, channel) => {
66
- for (const fn of listeners.current) fn(from, data, channel);
67
- },
68
- // `joined` flips on the FIRST successful poll — join() itself resolves
69
- // even when the first poll fails (the loop keeps retrying).
70
- onConnected: () => setJoined(true),
71
- });
72
- roomRef.current = p2p;
73
- void p2p.join();
74
- return () => {
75
- roomRef.current = null;
76
- p2p.close();
77
- };
78
- }, [room, selfId, name]);
79
-
80
- // Stable identities (both close over refs) so consumers can safely list
81
- // these in effect deps without re-subscribing every render.
82
- const broadcast = useCallback((data: unknown) => roomRef.current?.broadcast(data), []);
83
- const send = useCallback(
84
- (data: unknown, peerId?: string) => roomRef.current?.send(data, peerId),
85
- [],
86
- );
87
- const onMessage = useCallback(
88
- (fn: (from: string, data: unknown, channel: "state" | "reliable") => void) => {
89
- listeners.current.add(fn);
90
- return () => {
91
- listeners.current.delete(fn);
92
- };
93
- },
94
- [],
95
- );
96
-
97
- return { selfId, room, peers, joined, broadcast, send, onMessage };
98
- }
99
- ```
100
-
101
-
102
- Used in a component:
103
-
104
-
105
- ```tsx
106
- import { useP2PRoom } from "@/lib/multiplayer";
107
-
108
- function Game() {
109
- const p2p = useP2PRoom({ name: "ani" }); // room defaults per deployment
110
- const [positions, setPositions] = useState<Record<string, Pos>>({});
111
-
112
- useEffect(
113
- () =>
114
- p2p.onMessage((from, data, channel) => {
115
- if (channel === "state") {
116
- setPositions((p) => ({ ...p, [from]: data as Pos }));
117
- }
118
- }),
119
- [p2p.onMessage],
120
- );
121
-
122
- // Game-rate state: broadcast on the unreliable channel (stale packets drop).
123
- // 20-30 sends/s is plenty; interpolate between updates for smooth motion.
124
- useEffect(() => {
125
- let raf = 0;
126
- let lastSent = 0;
127
- const loop = (now: number) => {
128
- if (now - lastSent >= 50) {
129
- // ~20 sends/s
130
- p2p.broadcast(myPositionRef.current);
131
- lastSent = now;
132
- }
133
- raf = requestAnimationFrame(loop);
134
- };
135
- raf = requestAnimationFrame(loop);
136
- return () => cancelAnimationFrame(raf);
137
- }, [p2p.broadcast]);
138
-
139
- // One-shot actions (chat, "start game"): reliable + ordered.
140
- const sendChat = (text: string) => p2p.send({ chat: text });
141
-
142
- return <Board peers={p2p.peers} positions={positions} />;
143
- }
144
- ```