portals-mcp 1.2.3-beta.4 → 1.3.0

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 (187) hide show
  1. package/README.md +156 -118
  2. package/dist/analytics.d.ts +2 -0
  3. package/dist/analytics.d.ts.map +1 -0
  4. package/dist/api.d.ts +47 -0
  5. package/dist/api.d.ts.map +1 -0
  6. package/dist/api.js +1 -1
  7. package/dist/auth-store.d.ts +9 -0
  8. package/dist/auth-store.d.ts.map +1 -0
  9. package/dist/auth.d.ts +5 -0
  10. package/dist/auth.d.ts.map +1 -0
  11. package/dist/auth.js +76 -76
  12. package/dist/camera-utils.d.ts +126 -0
  13. package/dist/camera-utils.d.ts.map +1 -0
  14. package/dist/context-assembler.d.ts +32 -0
  15. package/dist/context-assembler.d.ts.map +1 -0
  16. package/dist/context-assembler.js +1 -1
  17. package/dist/context-recommend.d.ts +35 -0
  18. package/dist/context-recommend.d.ts.map +1 -0
  19. package/dist/docs.d.ts +18 -0
  20. package/dist/docs.d.ts.map +1 -0
  21. package/dist/docs.js +1 -1
  22. package/dist/feedback-prompts.d.ts +23 -0
  23. package/dist/feedback-prompts.d.ts.map +1 -0
  24. package/dist/global-learning.d.ts +14 -0
  25. package/dist/global-learning.d.ts.map +1 -0
  26. package/dist/global-learning.js +1 -1
  27. package/dist/harness-core/capabilityResolver.d.ts +9 -0
  28. package/dist/harness-core/capabilityResolver.d.ts.map +1 -0
  29. package/dist/harness-core/capabilityResolver.js +211 -0
  30. package/dist/harness-core/failureLogger.d.ts +54 -0
  31. package/dist/harness-core/failureLogger.d.ts.map +1 -0
  32. package/dist/harness-core/failureLogger.js +36 -0
  33. package/dist/harness-core/index.d.ts +8 -0
  34. package/dist/harness-core/index.d.ts.map +1 -0
  35. package/dist/harness-core/index.js +7 -0
  36. package/dist/harness-core/projectInspector.d.ts +51 -0
  37. package/dist/harness-core/projectInspector.d.ts.map +1 -0
  38. package/dist/harness-core/projectInspector.js +206 -0
  39. package/dist/harness-core/registryLoader.d.ts +5 -0
  40. package/dist/harness-core/registryLoader.d.ts.map +1 -0
  41. package/dist/harness-core/registryLoader.js +56 -0
  42. package/dist/harness-core/responseContract.d.ts +39 -0
  43. package/dist/harness-core/responseContract.d.ts.map +1 -0
  44. package/dist/harness-core/responseContract.js +35 -0
  45. package/dist/harness-core/types.d.ts +88 -0
  46. package/dist/harness-core/types.d.ts.map +1 -0
  47. package/dist/harness-core/types.js +7 -0
  48. package/dist/harness-core/validation.d.ts +15 -0
  49. package/dist/harness-core/validation.d.ts.map +1 -0
  50. package/dist/harness-core/validation.js +27 -0
  51. package/dist/index.d.ts +3 -0
  52. package/dist/index.d.ts.map +1 -0
  53. package/dist/index.js +2 -0
  54. package/dist/intelligence-bridge.d.ts +78 -0
  55. package/dist/intelligence-bridge.d.ts.map +1 -0
  56. package/dist/intelligence-types.d.ts +464 -0
  57. package/dist/intelligence-types.d.ts.map +1 -0
  58. package/dist/lookup.d.ts +27 -0
  59. package/dist/lookup.d.ts.map +1 -0
  60. package/dist/lookup.js +47 -0
  61. package/dist/marketplace-client.d.ts +119 -0
  62. package/dist/marketplace-client.d.ts.map +1 -0
  63. package/dist/marketplace-client.js +326 -0
  64. package/dist/prompts.d.ts +3 -0
  65. package/dist/prompts.d.ts.map +1 -0
  66. package/dist/prompts.js +28 -0
  67. package/dist/python-runner.d.ts +19 -0
  68. package/dist/python-runner.d.ts.map +1 -0
  69. package/dist/recipe-scores.d.ts +42 -0
  70. package/dist/recipe-scores.d.ts.map +1 -0
  71. package/dist/recipe-search.d.ts +29 -0
  72. package/dist/recipe-search.d.ts.map +1 -0
  73. package/dist/recipe-search.js +18 -0
  74. package/dist/resources/ai/bootstrap.json +15 -5
  75. package/dist/resources/architecture/portals-harness-architecture.md +138 -0
  76. package/dist/resources/guide/rules-and-conventions.md +2 -1
  77. package/dist/resources/guide/workflow-steps.md +22 -57
  78. package/dist/resources/harness/capabilities/current.json +163 -0
  79. package/dist/resources/harness/evals/creative-workarounds.json +42 -0
  80. package/dist/resources/harness/evals/debugging.json +37 -0
  81. package/dist/resources/harness/evals/direct-supported.json +42 -0
  82. package/dist/resources/harness/evals/hallucination-traps.json +35 -0
  83. package/dist/resources/harness/evals/model-agnostic.json +37 -0
  84. package/dist/resources/harness/evals/performance.json +26 -0
  85. package/dist/resources/harness/failure-log-schema.json +28 -0
  86. package/dist/resources/harness/in-game-integration.md +63 -0
  87. package/dist/resources/harness/limitations/current.json +96 -0
  88. package/dist/resources/harness/patterns/boss-phases.json +43 -0
  89. package/dist/resources/harness/patterns/checkpoint.json +41 -0
  90. package/dist/resources/harness/patterns/coin-counter.json +41 -0
  91. package/dist/resources/harness/patterns/lap-counter.json +43 -0
  92. package/dist/resources/harness/patterns/locked-door.json +47 -0
  93. package/dist/resources/harness/patterns/npc-quest-state.json +41 -0
  94. package/dist/resources/harness/patterns/pressure-plate-puzzle.json +41 -0
  95. package/dist/resources/harness/patterns/simple-inventory.json +43 -0
  96. package/dist/resources/harness/patterns/stealth-detection.json +42 -0
  97. package/dist/resources/harness/patterns/timer.json +41 -0
  98. package/dist/resources/harness/product-native-harness-scope.md +230 -0
  99. package/dist/resources/harness/response-contract.json +24 -0
  100. package/dist/resources/harness/shared-core-package.md +69 -0
  101. package/dist/resources/index/effects.json +703 -699
  102. package/dist/resources/index/intents.json +10 -10
  103. package/dist/resources/index/items.json +393 -393
  104. package/dist/resources/index/knowledge-map.json +314 -296
  105. package/dist/resources/logic/js-display-html.md +431 -0
  106. package/dist/resources/logic/js-function-reference.md +238 -185
  107. package/dist/resources/logic/js-use-effector.md +825 -727
  108. package/dist/resources/logic/multiplayer.md +258 -163
  109. package/dist/resources/logic/string-variables.md +94 -99
  110. package/dist/resources/python/README.md +25 -63
  111. package/dist/resources/python/lib/__pycache__/portals_effects.cpython-314.pyc +0 -0
  112. package/dist/resources/python/lib/__pycache__/portals_ops.cpython-314.pyc +0 -0
  113. package/dist/resources/python/lib/__pycache__/portals_utils.cpython-314.pyc +0 -0
  114. package/dist/resources/python/lib/board_helpers.py +3 -3
  115. package/dist/resources/python/lib/portals_core.py +1122 -1093
  116. package/dist/resources/python/lib/portals_effects.py +9 -2
  117. package/dist/resources/python/lib/portals_ops.py +913 -560
  118. package/dist/resources/python/lib/portals_utils.py +5 -5
  119. package/dist/resources/python/tools/apply_ops.py +96 -14
  120. package/dist/resources/python/tools/index_room.py +1 -1
  121. package/dist/resources/python/tools/sync_room.py +1 -1
  122. package/dist/resources/python/tools/validate_room.py +1607 -1566
  123. package/dist/resources/recipes/game-hud/implementation.md +195 -0
  124. package/dist/resources/recipes/keypad/implementation.md +6 -13
  125. package/dist/resources/recipes/logic-board/implementation.md +19 -26
  126. package/dist/resources/recipes/manifest.json +177 -143
  127. package/dist/resources/recipes/match-queue/implementation.md +261 -0
  128. package/dist/resources/recipes/patterns.md +201 -167
  129. package/dist/resources/recipes/position-heartbeat/implementation.md +5 -7
  130. package/dist/resources/ref/items/blink-light.json +9 -0
  131. package/dist/resources/ref/items/camera.json +5 -0
  132. package/dist/resources/ref/items/collectible.json +9 -0
  133. package/dist/resources/ref/items/combat-npc.json +24 -0
  134. package/dist/resources/ref/items/cube.json +76 -62
  135. package/dist/resources/ref/items/destructible.json +8 -1
  136. package/dist/resources/ref/items/effects-vfx.json +5 -0
  137. package/dist/resources/ref/items/elemental.json +7 -1
  138. package/dist/resources/ref/items/glb.json +7 -1
  139. package/dist/resources/ref/items/gun.json +12 -1
  140. package/dist/resources/ref/items/image.json +8 -1
  141. package/dist/resources/ref/items/jump-pad.json +4 -0
  142. package/dist/resources/ref/items/leaderboard.json +6 -0
  143. package/dist/resources/ref/items/light.json +7 -0
  144. package/dist/resources/ref/items/npc.json +10 -1
  145. package/dist/resources/ref/items/portal.json +6 -0
  146. package/dist/resources/ref/items/spawn.json +51 -45
  147. package/dist/resources/ref/items/spotlight.json +63 -44
  148. package/dist/resources/ref/items/text.json +5 -0
  149. package/dist/resources/ref/items/trigger-zone.json +6 -0
  150. package/dist/resources/ref/items/vehicle.json +14 -1
  151. package/dist/resources/ref/items/video.json +7 -1
  152. package/dist/resources/ref/pitfalls.json +185 -157
  153. package/dist/resources/ref/systems/display-html.json +81 -0
  154. package/dist/resources/ref/systems/function-effector-js.json +60 -54
  155. package/dist/resources/ref/systems/function-effector.json +4 -4
  156. package/dist/resources/ref/systems/iframes.json +4 -3
  157. package/dist/resources/ref/systems/multiplayer.json +64 -57
  158. package/dist/resources/ref/systems/parent-child.json +52 -43
  159. package/dist/resources/ref/systems/string-variables.json +42 -40
  160. package/dist/resources/ref/systems/timers.json +57 -57
  161. package/dist/resources/ref/systems/variables.json +6 -0
  162. package/dist/resources/reference/api-cheatsheet.md +216 -200
  163. package/dist/resources/reference/glb-asset-catalog.md +6 -16
  164. package/dist/resources/reference/gotchas.md +195 -121
  165. package/dist/resources/reference/iframes.md +12 -8
  166. package/dist/resources/reference/interactions.md +863 -854
  167. package/dist/resources/reference/items/building.md +277 -265
  168. package/dist/resources/reference/items/lighting.md +95 -80
  169. package/dist/resources/reference/items/media.md +90 -90
  170. package/dist/resources/reference/room-index.md +5 -7
  171. package/dist/resources/reference/sandbox-environment.md +122 -0
  172. package/dist/resources/reference/variable-scopes.md +100 -0
  173. package/dist/resources/workflows/blender-to-portals.md +1 -1
  174. package/dist/resources/workflows/builder-workflow.md +40 -97
  175. package/dist/resources/workflows/modular-build-workflow.md +91 -585
  176. package/dist/resources/workflows/quality-review.md +30 -36
  177. package/dist/session-tracker.d.ts +56 -0
  178. package/dist/session-tracker.d.ts.map +1 -0
  179. package/dist/tools.d.ts +4 -0
  180. package/dist/tools.d.ts.map +1 -0
  181. package/dist/tools.js +1181 -169
  182. package/dist/utils.d.ts +3 -0
  183. package/dist/utils.d.ts.map +1 -0
  184. package/dist/ws-bridge.d.ts +42 -0
  185. package/dist/ws-bridge.d.ts.map +1 -0
  186. package/dist/ws-bridge.js +10 -1
  187. package/package.json +68 -48
package/README.md CHANGED
@@ -1,118 +1,156 @@
1
- # portals-mcp
2
-
3
- An [MCP](https://modelcontextprotocol.io) server that turns AI assistants into game designers for the [Portals](https://theportal.to) 3D platform. Any LLM that speaks MCP can build interactive rooms, wire up game logic, and iterate on designs using natural language.
4
-
5
- ## Quick Start
6
-
7
- ### 1. Run
8
-
9
- ```bash
10
- npx portals-mcp@latest
11
- ```
12
-
13
- ### 2. Configure your MCP client
14
-
15
- ```json
16
- {
17
- "mcpServers": {
18
- "portals": {
19
- "command": "npx",
20
- "args": ["portals-mcp"]
21
- }
22
- }
23
- }
24
- ```
25
-
26
- ### 3. Bootstrap a session
27
-
28
- 1. Call `authenticate`. Alternatively, set `PORTALS_ACCESS_KEY` in a `.env` file next to your project to skip the browser prompt.
29
- 2. Call `recommend_context` with a task description.
30
- 3. Read each URI in `context_handshake.required_resources`.
31
- 4. Pass `contextToken` to any mutating tool.
32
-
33
- ## Tools
34
-
35
- ### Authentication & Discovery
36
-
37
- | Tool | Description |
38
- |------|-------------|
39
- | `authenticate` | Authenticate with Portals access key or browser flow |
40
- | `get_help` | Setup/workflow guidance with matching docs resources |
41
- | `recommend_context` | Recommends docs and tool sequence for a task, issues context token |
42
- | `lookup` | Fast knowledge lookup for items, triggers, effects, systems, recipes |
43
- | `search_recipes` | Search recipe manifest by keywords, tags, and patterns |
44
-
45
- ### Room Management
46
-
47
- | Tool | Description |
48
- |------|-------------|
49
- | `create_room` | Create from 18 templates (art-gallery, blank, spaceship, etc.) |
50
- | `duplicate_room` | Clone a room with all data |
51
- | `get_room_data` | Download room snapshot to temp JSON |
52
- | `query_room` | Query room data for specific items, logic, or structure |
53
- | `update_room_settings` | Modify name, description, image, privacy, loading screens |
54
-
55
- ### Building
56
-
57
- | Tool | Description |
58
- |------|-------------|
59
- | `set_room_data` | Replace entire room data (full snapshot) |
60
- | `apply_operations` | Targeted ops: `add_item`, `modify_item`, `remove_item`, `add_logic_task`, `clear_logic_tasks`, `add_quest`, `remove_quest`, `add_component` |
61
- | `run_python_tool` | Gateway to Python tools (validate, query, index, merge, sync, minimap, etc.) |
62
-
63
- ### Assets
64
-
65
- | Tool | Description |
66
- |------|-------------|
67
- | `upload_glb` / `upload_glbs_from_folder` | Upload 3D models (.glb) with optional Draco compression |
68
- | `upload_image` / `upload_images_from_folder` | Upload images (.jpg, .png, .gif) |
69
-
70
- ### Scene Design
71
-
72
- | Tool | Description |
73
- |------|-------------|
74
- | `analyze_scene` | Spatial composition analysis — zones, relationships, design checks |
75
- | `render_scene` | Screenshot of the live 3D scene via the game's MCP camera |
76
- | `compare_scene` | Before/after snapshot diff |
77
- | `position_camera` | Compute optimal camera placement to frame one or more items |
78
- | `record_video` | Record a video fly-through from a CameraObject |
79
-
80
- ### Live Game Connection
81
-
82
- | Tool | Description |
83
- |------|-------------|
84
- | `connect_to_game` | Connect to a live game client via WebSocket bridge |
85
- | `poll_game_events` | Poll for events from the live game (Ctrl+Click items, Shift+Click locations) |
86
- | `change_task_state` | Activate, complete, or reset tasks in a live game |
87
-
88
- ### Feedback
89
-
90
- | Tool | Description |
91
- |------|-------------|
92
- | `rate_push` | Per-push rating (1-5) after each build action |
93
- | `rate_build` | Final session rating with aspects, tags, and comments |
94
- | `mark_context_relevant` | Report which docs were useful for future recommendation improvements |
95
-
96
- ## Resources
97
-
98
- The server bundles ~140 `docs://` resources covering item specs, workflow guides, recipes, templates, and more. Resources are served from the package — no external docs repo required.
99
-
100
- | Category | URI Pattern | Count | Examples |
101
- |----------|-------------|-------|----------|
102
- | Reference specs | `docs://ref/*` | 40 | 26 item specs, systems, interactions, components |
103
- | Extended reference | `docs://reference/*` | 17 | Full API docs, cameras, movement, quests |
104
- | Python tools & libs | `docs://python/*` | 27 | apply_ops, query_room, portals_core, portals_effects |
105
- | Recipes | `docs://recipes/*` | 18 | Dice roll, board game, keypad, side-scroller, leaderboard, cutscene camera |
106
- | Workflows | `docs://workflows/*` | 13 | Scene design, validation, quality review, asset pipeline |
107
- | Scene design | `docs://scene/*` | 6 | Composition, density, placement strategies |
108
- | Indexes | `docs://index/*` | 5 | Items, triggers, effects, knowledge map |
109
- | Logic & scripting | `docs://logic/*` | 5 | JS reference, expressions, multiplayer, string variables |
110
- | Guides | `docs://guide/*` | 3 | Rules & conventions, workflow steps |
111
- | AI bootstrap | `docs://ai/*` | 3 | Execution policy, tool output contracts |
112
- | Templates | `docs://templates/*` | 2 | Game design doc, demo room |
113
- | Usage rules | `docs://usage-rules` | 1 | Tool roles & error handling |
114
- | Catalog | `docs://catalog` | | JSON index of all resource URIs |
115
-
116
- ## License
117
-
118
- ISC
1
+ # portals-mcp
2
+
3
+ An [MCP](https://modelcontextprotocol.io) server that turns AI assistants into game designers for the [Portals](https://portals.to) 3D platform. Any LLM that speaks MCP can build interactive rooms, wire up game logic, and iterate on designs using natural language.
4
+
5
+ ## Quick Start
6
+
7
+ ### 1. Run
8
+
9
+ ```bash
10
+ npx portals-mcp@latest
11
+ ```
12
+
13
+ ### 2. Configure your MCP client
14
+
15
+ ```json
16
+ {
17
+ "mcpServers": {
18
+ "portals": {
19
+ "command": "npx",
20
+ "args": ["portals-mcp"]
21
+ }
22
+ }
23
+ }
24
+ ```
25
+
26
+ ### 3. Bootstrap a session
27
+
28
+ 1. Call `authenticate`. Alternatively, set `PORTALS_ACCESS_KEY` in a `.env` file next to your project to skip the browser prompt.
29
+ 2. Call `get_context` with a task description for targeted specs, gotchas, and recipes.
30
+ 3. For gameplay mechanics, call `resolve_gameplay_capability` or `plan_gameplay_mechanic` before making platform claims.
31
+ 4. Use `apply_operations` for scoped edits or `set_room_data` for full-snapshot replacement.
32
+
33
+ ## Tools
34
+
35
+ ### Authentication & Discovery
36
+
37
+ | Tool | Description |
38
+ |------|-------------|
39
+ | `authenticate` | Authenticate with Portals access key or browser flow |
40
+ | `get_help` | Setup/workflow guidance with matching docs resources |
41
+ | `get_context` | Returns targeted specs, syntax references, gotchas, recipes, and suggested tools |
42
+ | `lookup` | Fast knowledge lookup for items, triggers, effects, systems, recipes |
43
+ | `resolve_gameplay_capability` | Classify gameplay requests as supported directly, workaround, unsupported, or unknown |
44
+ | `plan_gameplay_mechanic` | Return a compact implementation contract with required capabilities, objects, variables, triggers, validation, risks, and sources |
45
+ | `search_recipes` | Search recipe manifest by keywords, tags, and patterns |
46
+
47
+ ### Room Management
48
+
49
+ | Tool | Description |
50
+ |------|-------------|
51
+ | `create_room` | Create from 18 templates (art-gallery, blank, spaceship, etc.) |
52
+ | `duplicate_room` | Clone a room with all data |
53
+ | `get_room_data` | Download room snapshot to temp JSON |
54
+ | `inspect_room_data` | Summarize room-data counts, item types, variables, triggers/actions, and warnings without dumping full JSON |
55
+ | `query_room` | Query room data for specific items, logic, or structure |
56
+ | `update_room_settings` | Modify name, description, image, privacy, loading screens |
57
+
58
+ ### Building
59
+
60
+ | Tool | Description |
61
+ |------|-------------|
62
+ | `set_room_data` | Replace entire room data (full snapshot) |
63
+ | `apply_operations` | Targeted ops: `add_item`, `modify_item`, `remove_item`, `add_logic_task`, `clear_logic_tasks`, `add_quest`, `remove_quest`, `add_component` |
64
+
65
+ ### Assets
66
+
67
+ | Tool | Description |
68
+ |------|-------------|
69
+ | `upload_glb` | Upload one `.glb` file or all `.glb` files in a folder |
70
+ | `upload_image` | Upload one image file or all supported image files in a folder |
71
+
72
+ ### Scene Design
73
+
74
+ | Tool | Description |
75
+ |------|-------------|
76
+ | `analyze_scene` | Spatial composition analysis — zones, relationships, design checks |
77
+ | `render_scene` | Screenshot of the live 3D scene via the game's MCP camera |
78
+ | `compare_scene` | Before/after snapshot diff |
79
+ | `position_camera` | Compute optimal camera placement to frame one or more items |
80
+ | `record_video` | Record a video fly-through from a CameraObject |
81
+
82
+ ### Live Game Connection
83
+
84
+ | Tool | Description |
85
+ |------|-------------|
86
+ | `connect_to_game` | Connect to a live game client via WebSocket bridge |
87
+ | `poll_game_events` | Poll for events from the live game (Ctrl+Click items, Shift+Click locations) |
88
+ | `change_task_state` | Activate, complete, or reset tasks in a live game |
89
+ | `get_runtime_data` | Fetch live runtime variables and JS effector results |
90
+
91
+ ### Generated Assets
92
+
93
+ | Tool | Description |
94
+ |------|-------------|
95
+ | `text_to_3d_model` | Generate a 3D model from text |
96
+ | `image_to_3d_model` | Generate a 3D model from an image |
97
+ | `check_3d_model_task` | Poll 3D model generation status |
98
+ | `text_to_speech` | Generate speech audio |
99
+ | `generate_sound_effect` | Generate sound effect audio |
100
+ | `list_generated_sounds` | List generated sounds for the current user |
101
+
102
+ ## Resources
103
+
104
+ The server bundles ~148 `docs://` resources covering item specs, workflow guides, recipes, harness grounding data, and more. Resources are served from the package — no external docs repo required.
105
+
106
+ | Category | URI Pattern | Count | Examples |
107
+ |----------|-------------|-------|----------|
108
+ | Reference specs | `docs://ref/*` | 40 | 26 item specs, systems, interactions, components |
109
+ | Extended reference | `docs://reference/*` | 17 | Full API docs, cameras, movement, quests |
110
+ | Python tools & libs | `docs://python/*` | 27 | apply_ops, query_room, portals_core, portals_effects |
111
+ | Recipes | `docs://recipes/*` | 18 | Dice roll, board game, keypad, side-scroller, leaderboard, cutscene camera |
112
+ | Workflows | `docs://workflows/*` | 13 | Scene design, validation, quality review, asset pipeline |
113
+ | Indexes | `docs://index/*` | 5 | Items, triggers, effects, knowledge map |
114
+ | Logic & scripting | `docs://logic/*` | 5 | JS reference, expressions, multiplayer, string variables |
115
+ | Guides | `docs://guide/*` | 3 | Rules & conventions, workflow steps |
116
+ | AI bootstrap | `docs://ai/*` | 3 | Execution policy, tool output contracts |
117
+ | Harness grounding | `docs://harness/*` | — | Capabilities, limitations, patterns, response contract, eval fixtures |
118
+ | Architecture | `docs://architecture/*` | — | Harness architecture assessment and migration plan |
119
+ | Usage rules | `docs://usage-rules` | 1 | Tool roles & error handling |
120
+ | Catalog | `docs://catalog` | — | JSON index of all resource URIs |
121
+
122
+ ## Testing
123
+
124
+ ```bash
125
+ npm test
126
+ npm run build
127
+ npm run test:mcp-client
128
+ ```
129
+
130
+ Harness-specific checks:
131
+
132
+ ```bash
133
+ npm run check:harness
134
+ npm run check:harness-package
135
+ npm run eval:harness
136
+ ```
137
+
138
+ ## Shared Harness Core
139
+
140
+ The harness grounding layer is available as an independently buildable package under `packages/harness-core`:
141
+
142
+ ```ts
143
+ import { resolveGameDevRequest } from "@portals/harness-core";
144
+ ```
145
+
146
+ The MCP package also exposes a compatibility subpath:
147
+
148
+ ```ts
149
+ import { resolveGameDevRequest } from "portals-mcp/harness-core";
150
+ ```
151
+
152
+ Use `@portals/harness-core` as the target dependency for product-native harness services once it is published or wired internally.
153
+
154
+ ## License
155
+
156
+ ISC
@@ -0,0 +1,2 @@
1
+ export declare function trackEvent(event: string, uid: string, properties?: Record<string, unknown>): void;
2
+ //# sourceMappingURL=analytics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analytics.d.ts","sourceRoot":"","sources":["../src/analytics.ts"],"names":[],"mappings":"AAIA,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAuBjG"}
package/dist/api.d.ts ADDED
@@ -0,0 +1,47 @@
1
+ export declare function setAccessKey(key: string): void;
2
+ export declare function isAuthenticated(): boolean;
3
+ export declare function getAccessKey(): string;
4
+ export declare function setUid(id: string): void;
5
+ export declare function getUid(): string | null;
6
+ export declare function uploadJsonToS3(fileName: string, data: Buffer): Promise<string>;
7
+ export declare function uploadRoomData(roomId: string, jsonUrl: string): Promise<void>;
8
+ export declare function validateAccessKey(accessKey: string): Promise<string>;
9
+ export declare function uploadGlb(fileName: string, fileData: Buffer, enableDraco?: boolean): Promise<{
10
+ assetURL: string;
11
+ objectKey: string;
12
+ }>;
13
+ export declare function getImageMimeType(ext: string): string;
14
+ export declare function uploadImage(roomId: string, fileData: Buffer, fileType: string): Promise<{
15
+ assetURL: string;
16
+ objectKey: string;
17
+ }>;
18
+ export declare function createRoom(templateName: string, customTemplateName?: string): Promise<{
19
+ roomId: string;
20
+ name: string;
21
+ }>;
22
+ export declare function duplicateRoom(roomId: string): Promise<{
23
+ newRoomId: string;
24
+ name: string;
25
+ }>;
26
+ export interface RoomSettings {
27
+ Name?: string | undefined;
28
+ Description?: string | undefined;
29
+ Image?: string | undefined;
30
+ Purpose?: string | undefined;
31
+ Discord?: string | undefined;
32
+ MuteGuests?: boolean | undefined;
33
+ ShowOnDirectory?: boolean | undefined;
34
+ HighRes?: boolean | undefined;
35
+ PasswordProtected?: boolean | undefined;
36
+ HideNameOnLoadingScreen?: boolean | undefined;
37
+ LoadingImages?: string[] | undefined;
38
+ CustomLoader?: boolean | undefined;
39
+ }
40
+ export declare function updateRoomSettings(roomId: string, settings: RoomSettings): Promise<void>;
41
+ export declare function sendUserMessage(content: string, roomId?: string): Promise<void>;
42
+ export declare function uploadAudio(roomId: string, fileData: Buffer, fileType: string): Promise<{
43
+ assetURL: string;
44
+ objectKey: string;
45
+ }>;
46
+ export declare function downloadRoomData(roomId: string): Promise<Buffer>;
47
+ //# sourceMappingURL=api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
package/dist/api.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import fetch from "node-fetch";
2
- const API_BASE = process.env.API_BASE || "https://theportal.to";
2
+ const API_BASE = process.env.API_BASE || "https://portals.to";
3
3
  let accessKey = null;
4
4
  let currentUid = null;
5
5
  /**
@@ -0,0 +1,9 @@
1
+ interface StoredCredentials {
2
+ accessKey: string;
3
+ uid: string;
4
+ }
5
+ export declare function saveCredentials(accessKey: string, uid: string): void;
6
+ export declare function loadCredentials(): StoredCredentials | null;
7
+ export declare function clearCredentials(): void;
8
+ export {};
9
+ //# sourceMappingURL=auth-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-store.d.ts","sourceRoot":"","sources":["../src/auth-store.ts"],"names":[],"mappings":"AAOA,UAAU,iBAAiB;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAOpE;AAED,wBAAgB,eAAe,IAAI,iBAAiB,GAAG,IAAI,CAY1D;AAED,wBAAgB,gBAAgB,IAAI,IAAI,CAMvC"}
package/dist/auth.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ export declare function authenticateViaBrowser(): Promise<{
2
+ uid: string;
3
+ accessKey: string;
4
+ }>;
5
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AA4HA,wBAAgB,sBAAsB,IAAI,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CA2EpF"}
package/dist/auth.js CHANGED
@@ -23,7 +23,7 @@ function openBrowser(url) {
23
23
  break;
24
24
  }
25
25
  }
26
- const PORTAL_URL = "https://theportal.to/mcp";
26
+ const PORTAL_URL = "https://portals.to/mcp";
27
27
  const DEFAULT_AUTH_TIMEOUT_MS = 3 * 60 * 1000;
28
28
  const MIN_AUTH_TIMEOUT_MS = 30 * 1000;
29
29
  const MAX_AUTH_TIMEOUT_MS = 10 * 60 * 1000;
@@ -38,84 +38,84 @@ function authTimeoutMs() {
38
38
  }
39
39
  return Math.max(MIN_AUTH_TIMEOUT_MS, Math.min(MAX_AUTH_TIMEOUT_MS, parsed));
40
40
  }
41
- const PAGE_STYLE = `
42
- * { box-sizing: border-box; margin: 0; padding: 0; }
43
- body {
44
- font-family: system-ui, -apple-system, sans-serif;
45
- display: flex;
46
- justify-content: center;
47
- align-items: center;
48
- min-height: 100vh;
49
- padding: 30px;
50
- background: #111216;
51
- color: #F9FBFE;
52
- }
53
- body::before {
54
- content: "";
55
- position: fixed;
56
- inset: 0;
57
- background: url("https://cdn.theportal.to/0000/dashboard/login-background.jpg") center/cover no-repeat;
58
- z-index: -1;
59
- }
60
- .card {
61
- background: #111216;
62
- border-radius: clamp(28px, 3vw, 40px);
63
- padding: clamp(30px, 4vw, 40px) clamp(20px, 4vw, 43px);
64
- width: 100%;
65
- max-width: 450px;
66
- min-width: 320px;
67
- min-height: 200px;
68
- text-align: center;
69
- display: flex;
70
- flex-direction: column;
71
- align-items: center;
72
- justify-content: center;
73
- }
74
- .icon { width: 100px; margin-bottom: 20px; }
75
- h1 {
76
- font-size: clamp(35px, 4vw, 48px);
77
- font-weight: bold;
78
- color: #F9FBFE;
79
- margin-bottom: 30px;
80
- }
81
- p {
82
- font-size: 16px;
83
- color: #F5FAFF;
84
- line-height: 1.5;
85
- }
41
+ const PAGE_STYLE = `
42
+ * { box-sizing: border-box; margin: 0; padding: 0; }
43
+ body {
44
+ font-family: system-ui, -apple-system, sans-serif;
45
+ display: flex;
46
+ justify-content: center;
47
+ align-items: center;
48
+ min-height: 100vh;
49
+ padding: 30px;
50
+ background: #111216;
51
+ color: #F9FBFE;
52
+ }
53
+ body::before {
54
+ content: "";
55
+ position: fixed;
56
+ inset: 0;
57
+ background: url("https://cdn.theportal.to/0000/dashboard/login-background.jpg") center/cover no-repeat;
58
+ z-index: -1;
59
+ }
60
+ .card {
61
+ background: #111216;
62
+ border-radius: clamp(28px, 3vw, 40px);
63
+ padding: clamp(30px, 4vw, 40px) clamp(20px, 4vw, 43px);
64
+ width: 100%;
65
+ max-width: 450px;
66
+ min-width: 320px;
67
+ min-height: 200px;
68
+ text-align: center;
69
+ display: flex;
70
+ flex-direction: column;
71
+ align-items: center;
72
+ justify-content: center;
73
+ }
74
+ .icon { width: 100px; margin-bottom: 20px; }
75
+ h1 {
76
+ font-size: clamp(35px, 4vw, 48px);
77
+ font-weight: bold;
78
+ color: #F9FBFE;
79
+ margin-bottom: 30px;
80
+ }
81
+ p {
82
+ font-size: 16px;
83
+ color: #F5FAFF;
84
+ line-height: 1.5;
85
+ }
86
86
  `;
87
87
  const PORTALS_ICON = `<svg class="icon" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M50 5L90 27.5V72.5L50 95L10 72.5V27.5L50 5Z" stroke="currentColor" stroke-width="3" fill="none"/><circle cx="50" cy="50" r="18" stroke="currentColor" stroke-width="3" fill="none"/></svg>`;
88
- const SUCCESS_HTML = `<!DOCTYPE html>
89
- <html lang="en">
90
- <head>
91
- <meta charset="UTF-8">
92
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
93
- <title>Portals MCP — Authenticated</title>
94
- <style>${PAGE_STYLE}</style>
95
- </head>
96
- <body>
97
- <div class="card">
98
- ${PORTALS_ICON}
99
- <h1>mcp access</h1>
100
- <p>Authenticated! You can close this tab and return to Claude Code.</p>
101
- </div>
102
- </body>
88
+ const SUCCESS_HTML = `<!DOCTYPE html>
89
+ <html lang="en">
90
+ <head>
91
+ <meta charset="UTF-8">
92
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
93
+ <title>Portals MCP — Authenticated</title>
94
+ <style>${PAGE_STYLE}</style>
95
+ </head>
96
+ <body>
97
+ <div class="card">
98
+ ${PORTALS_ICON}
99
+ <h1>mcp access</h1>
100
+ <p>Authenticated! You can close this tab and return to Claude Code.</p>
101
+ </div>
102
+ </body>
103
103
  </html>`;
104
- const ERROR_HTML = (msg) => `<!DOCTYPE html>
105
- <html lang="en">
106
- <head>
107
- <meta charset="UTF-8">
108
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
109
- <title>Portals MCP — Error</title>
110
- <style>${PAGE_STYLE}</style>
111
- </head>
112
- <body>
113
- <div class="card">
114
- ${PORTALS_ICON}
115
- <h1>mcp access</h1>
116
- <p>${escapeHtml(msg)}</p>
117
- </div>
118
- </body>
104
+ const ERROR_HTML = (msg) => `<!DOCTYPE html>
105
+ <html lang="en">
106
+ <head>
107
+ <meta charset="UTF-8">
108
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
109
+ <title>Portals MCP — Error</title>
110
+ <style>${PAGE_STYLE}</style>
111
+ </head>
112
+ <body>
113
+ <div class="card">
114
+ ${PORTALS_ICON}
115
+ <h1>mcp access</h1>
116
+ <p>${escapeHtml(msg)}</p>
117
+ </div>
118
+ </body>
119
119
  </html>`;
120
120
  export function authenticateViaBrowser() {
121
121
  return new Promise((resolve, reject) => {