capybara-mcp-shared 0.1.0 → 0.1.2
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.
- package/dist/constants.d.ts +10 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +13 -0
- package/dist/constants.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/game-id.d.ts +8 -0
- package/dist/lib/game-id.d.ts.map +1 -0
- package/dist/lib/game-id.js +30 -0
- package/dist/lib/game-id.js.map +1 -0
- package/dist/schemas/asset-tool-schema.d.ts +277 -971
- package/dist/schemas/asset-tool-schema.d.ts.map +1 -1
- package/dist/schemas/asset-tool-schema.js +186 -291
- package/dist/schemas/asset-tool-schema.js.map +1 -1
- package/dist/streaming/api-client.d.ts.map +1 -1
- package/dist/streaming/api-client.js +8 -1
- package/dist/streaming/api-client.js.map +1 -1
- package/dist/types/api.d.ts +6 -0
- package/dist/types/api.d.ts.map +1 -1
- package/package.json +4 -2
|
@@ -14,367 +14,262 @@ export const assetTypeSchema = z.enum([
|
|
|
14
14
|
"map_vfx",
|
|
15
15
|
"music_bg",
|
|
16
16
|
]);
|
|
17
|
-
const referenceIdSchema = z
|
|
18
|
-
.union([z.string(), z.array(z.string()).min(1)])
|
|
19
|
-
.describe("Dependency handle(s) pointing at completed asset(s) the pipeline must wait for. Use a single string for one dependency; use a string array when multiple assets must exist first.");
|
|
20
17
|
const outputFramesSchema = z
|
|
21
|
-
.preprocess((value) =>
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
export const mapConnectionDirectionSchema = z
|
|
30
|
-
.enum(["right", "left", "down"])
|
|
31
|
-
.describe("Direction FROM the reference map TO the new map. 'right' = new map is east of reference; 'left' = west; 'down' = south. Never 'up' — North is always the wall side.");
|
|
32
|
-
export const mapConnectionSchema = z.object({
|
|
18
|
+
.preprocess((value) => value == null
|
|
19
|
+
? undefined
|
|
20
|
+
: typeof value === "number"
|
|
21
|
+
? String(value)
|
|
22
|
+
: value, z.enum(["8", "12", "16", "24"]).optional())
|
|
23
|
+
.transform((value) => value == null ? undefined : Number(value))
|
|
24
|
+
.describe("Target frame count for looping sheets. Use 8 frames for subtle idle sways, 12 frames for walks and standard tasks, and 16 frames for complex, multi-stage actions.");
|
|
25
|
+
const mapConnectionSchema = z.object({
|
|
33
26
|
referenceId: z
|
|
34
27
|
.string()
|
|
35
|
-
.describe("
|
|
36
|
-
direction:
|
|
28
|
+
.describe("ID of the existing map this connection connects to."),
|
|
29
|
+
direction: z
|
|
30
|
+
.enum(["right", "left", "down"])
|
|
31
|
+
.describe("Direction of travel from the reference map to this new map. East/West/South edges are walkable. North (up) is reserved for structural walls."),
|
|
37
32
|
});
|
|
38
33
|
const mapOverlayStateSchema = z.object({
|
|
39
34
|
label: z
|
|
40
35
|
.string()
|
|
41
|
-
.describe("
|
|
36
|
+
.describe("Stable state ID for this overlay state (e.g., 'closed', 'open', 'looted', 'repaired')."),
|
|
42
37
|
prompt: z
|
|
43
38
|
.string()
|
|
44
|
-
.describe("Visual prompt
|
|
39
|
+
.describe("Visual-only prompt of the structure in this state. Exclude characters or floating UI labels."),
|
|
45
40
|
});
|
|
46
|
-
const
|
|
41
|
+
const coreFields = {
|
|
47
42
|
id: z
|
|
48
43
|
.string()
|
|
49
|
-
.describe("Unique asset
|
|
50
|
-
prompt: z
|
|
44
|
+
.describe("Unique asset ID used as the storage key and dependency handle."),
|
|
45
|
+
prompt: z
|
|
46
|
+
.string()
|
|
47
|
+
.describe("Primary visual or audio prompt. Exclude camera terms like 'top-down', '2.5D', or 'isometric' for world assets. Focus on layout, materials, and flat ambient lighting."),
|
|
51
48
|
gamePlay: z
|
|
52
49
|
.string()
|
|
53
50
|
.min(1)
|
|
54
|
-
.describe("
|
|
51
|
+
.describe("Detailed wiring instructions for the coding agent. Describe spawn areas, collision behaviors, boundary limits, and interaction triggers."),
|
|
55
52
|
};
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
type: assetTypeSchema.describe("Asset mode layer type."),
|
|
62
|
-
propsMultipleBreakdown: z
|
|
63
|
-
.string()
|
|
64
|
-
.optional()
|
|
65
|
-
.describe("ONLY FOR props_multiple: Optional secondary prompt mapping numbered bounding boxes to individual prop descriptions. This is NOT a substitute for the required prompt field."),
|
|
66
|
-
multipleHudsBreakdown: z
|
|
67
|
-
.string()
|
|
68
|
-
.optional()
|
|
69
|
-
.describe("ONLY FOR multiple_huds: Optional secondary prompt mapping numbered HUD widgets to individual descriptions, ids/names, and intended runtime behavior. This is NOT a substitute for the required prompt field."),
|
|
70
|
-
anchorDescription: z
|
|
71
|
-
.string()
|
|
72
|
-
.optional()
|
|
73
|
-
.describe("ONLY FOR props_map_overlay: Description of the exact existing map-baked structure/prop being overlaid, including its location on the map."),
|
|
74
|
-
overlayStateBreakdown: z
|
|
75
|
-
.array(mapOverlayStateSchema)
|
|
76
|
-
.min(1)
|
|
77
|
-
.optional()
|
|
78
|
-
.describe("ONLY FOR props_map_overlay: Required array of overlay states ({ label, prompt }[]). Each entry is one visual state on the same map anchor."),
|
|
79
|
-
defaultAnimation: z
|
|
53
|
+
const assetArray = (schema, description) => z.array(schema).default([]).describe(description);
|
|
54
|
+
const baseMapSchema = z.object({
|
|
55
|
+
...coreFields,
|
|
56
|
+
id: coreFields.id.describe("Unique map ID starting with 'map_' (e.g., 'map_town_hall'). Depicts the unaltered, 'before' state of the environment."),
|
|
57
|
+
art_reference_url: z
|
|
80
58
|
.string()
|
|
81
59
|
.optional()
|
|
82
|
-
.describe("
|
|
83
|
-
characterBodyFormat: characterBodyFormatSchema.optional(),
|
|
84
|
-
referenceId: referenceIdSchema.optional(),
|
|
85
|
-
outputFrames: outputFramesSchema
|
|
86
|
-
.optional()
|
|
87
|
-
.describe("ONLY FOR character_animation: Spritesheet frame count for the Pixel Engine animator. REQUIRED on every character_animation."),
|
|
88
|
-
connections: z
|
|
89
|
-
.array(mapConnectionSchema)
|
|
90
|
-
.min(1)
|
|
91
|
-
.max(3)
|
|
92
|
-
.optional()
|
|
93
|
-
.describe("ONLY FOR extend_map: One entry per existing map this room connects to. Index 0 is the anchor used for outpainting. Additional entries declare other open transition sides."),
|
|
94
|
-
});
|
|
95
|
-
const baseMapSchema = z.object({
|
|
96
|
-
...baseAssetFields,
|
|
97
|
-
id: baseAssetFields.id.describe("Unique id for a base map. Start with 'map_' followed by a descriptive name (e.g., 'map_wooden_desk_room')."),
|
|
98
|
-
prompt: baseAssetFields.prompt.describe("For base_map: Describe the environment theme, North boundary, 5-8 small/compact/modest major floor props, and 5-8 small/compact/modest decor floor props. Keep furniture rectilinear. Keep dynamic gameplay items, pickups, NPCs, changing clues, and stateful objects out of the prompt; put them in gamePlay and separate prop/character/overlay assets. Omit camera perspective keywords (like top-down or 2.5D) as the pipeline enforces them automatically."),
|
|
99
|
-
gamePlay: baseAssetFields.gamePlay.describe("For base_map: Tell the codeAgent the rough player spawn area and rough placement for any characters/NPCs/enemies, plus WHICH props/characters belong on WHICH obstacles; ensure furniture mentioned here is in the map prompt."),
|
|
60
|
+
.describe("Optional art style reference for this map: an http(s) image URL or a local file path. The tool fetches/reads it and sends base64 to the API."),
|
|
100
61
|
});
|
|
101
62
|
const extendMapSchema = z.object({
|
|
102
|
-
...
|
|
103
|
-
id:
|
|
104
|
-
prompt: baseAssetFields.prompt.describe("For extend_map: Describe the new outpainted wing with 5-8 small/compact/modest floor props per map tile/wing, keeping every shared seam completely open with no props, furniture, blockers, or decor. MUST match the reference map's shell type (interior stays interior, exterior stays exterior), copy the reference floor material phrase verbatim, and match north-wall material for interiors. Keep dynamic gameplay items out of the prompt and put them in gamePlay/prop assets. New room purpose is fine; changing environment type (indoor↔outdoor, biome, or terrain) is invalid — use base_map instead."),
|
|
105
|
-
gamePlay: baseAssetFields.gamePlay.describe("For extend_map: State shell continuity with the reference map (e.g. 'same interior metallic lab wing'), transition direction, rough spawn/entry area, important placements, and gameplay interactions — not just 'seamless walk'."),
|
|
63
|
+
...coreFields,
|
|
64
|
+
id: coreFields.id.describe("Unique ID starting with 'map_extend_' (e.g., 'map_extend_kitchen'). Represents an adjacent wing of the same biome and flooring material."),
|
|
106
65
|
connections: z
|
|
107
66
|
.array(mapConnectionSchema)
|
|
108
67
|
.min(1)
|
|
109
68
|
.max(3)
|
|
110
|
-
.describe("
|
|
69
|
+
.describe("At least one adjacent map boundary. Transition seams must be left completely open."),
|
|
111
70
|
});
|
|
112
71
|
const editMapSchema = z.object({
|
|
113
|
-
...
|
|
114
|
-
id:
|
|
115
|
-
|
|
116
|
-
gamePlay: baseAssetFields.gamePlay.describe("For edit_map: Explain what changes and why."),
|
|
117
|
-
referenceId: referenceIdSchema.describe("One id of a completed base_map or extend_map."),
|
|
72
|
+
...coreFields,
|
|
73
|
+
id: coreFields.id.describe("Unique ID starting with 'map_edit_'. Use ONLY for static, post-build changes to map obstacles (e.g., removing a fallen tree blocking a path)."),
|
|
74
|
+
referenceId: z.string().describe("ID of the existing map being modified."),
|
|
118
75
|
});
|
|
119
76
|
const mapVfxSchema = z.object({
|
|
120
|
-
...
|
|
121
|
-
id:
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
77
|
+
...coreFields,
|
|
78
|
+
id: coreFields.id.describe("Unique ID starting with 'map_vfx_'. Use for looping environmental animations (e.g., flickering fire, swaying lanterns, river ripples)."),
|
|
79
|
+
referenceId: z
|
|
80
|
+
.string()
|
|
81
|
+
.describe("ID of the existing map hosting this visual effect overlay."),
|
|
125
82
|
});
|
|
126
83
|
const baseCharacterSchema = z.object({
|
|
127
|
-
...
|
|
128
|
-
id:
|
|
129
|
-
characterBodyFormat:
|
|
130
|
-
|
|
131
|
-
|
|
84
|
+
...coreFields,
|
|
85
|
+
id: coreFields.id.describe("Unique ID starting with 'char_' (e.g., 'char_merchant'). Represents the empty-handed, baseline sprite facing forward and turned 3/4 right."),
|
|
86
|
+
characterBodyFormat: z
|
|
87
|
+
.enum(["humanoid", "quadruped_animal"])
|
|
88
|
+
.default("humanoid")
|
|
89
|
+
.describe("Body format. Use humanoid for player and bipedal NPCs. Use quadruped_animal for livestock or wildlife."),
|
|
132
90
|
defaultAnimation: z
|
|
133
91
|
.string()
|
|
134
92
|
.optional()
|
|
135
|
-
.describe("
|
|
93
|
+
.describe("Engine idle preset name (e.g., 'Breathing Idle'). Omit on empty-handed parents of Job NPCs."),
|
|
136
94
|
});
|
|
137
95
|
const baseCharacterVariantSchema = z.object({
|
|
138
|
-
...
|
|
139
|
-
id:
|
|
140
|
-
|
|
141
|
-
|
|
96
|
+
...coreFields,
|
|
97
|
+
id: coreFields.id.describe("Unique ID starting with 'char_' (e.g., 'char_blacksmith_working'). Used for Job NPCs. Depicts the character holding their signature prop in their default pose."),
|
|
98
|
+
referenceId: z
|
|
99
|
+
.union([z.string(), z.array(z.string()).min(1)])
|
|
100
|
+
.describe("Parent character ID, or an array of the parent character ID and held tool prop ID."),
|
|
142
101
|
defaultAnimation: z
|
|
143
102
|
.string()
|
|
144
103
|
.optional()
|
|
145
|
-
.describe("
|
|
146
|
-
referenceId: referenceIdSchema.describe("Parent base_character id, OR [base_character_id, prop_id] when blending a props_single or props_multiple asset into the pose. Job NPCs: one variant per character with the single signature prop — all task/walk clips reference this variant, not the empty-handed base_character."),
|
|
104
|
+
.describe("Engine idle preset name (e.g., 'Breathing Idle') to auto-generate a looping idle sheet while holding a prop."),
|
|
147
105
|
});
|
|
148
106
|
const characterAnimationSchema = z.object({
|
|
149
|
-
...
|
|
150
|
-
id:
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
outputFrames: outputFramesSchema
|
|
107
|
+
...coreFields,
|
|
108
|
+
id: coreFields.id.describe("Unique ID starting with 'char_' (e.g., 'char_player_walk'). Represents a looping sprite sheet."),
|
|
109
|
+
referenceId: z
|
|
110
|
+
.union([z.string(), z.array(z.string()).min(1)])
|
|
111
|
+
.describe("ID of the base character this animation sheet is for."),
|
|
112
|
+
outputFrames: outputFramesSchema,
|
|
155
113
|
});
|
|
156
114
|
const propsSingleSchema = z.object({
|
|
157
|
-
...
|
|
158
|
-
id:
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
115
|
+
...coreFields,
|
|
116
|
+
id: coreFields.id.describe("Unique ID starting with 'prop_' (e.g., 'prop_iron_key'). A single portable item, pickup, or weapon. Describe as a physical shape without text."),
|
|
117
|
+
referenceId: z
|
|
118
|
+
.union([z.string(), z.array(z.string()).min(1)])
|
|
119
|
+
.describe("Map ID when world-anchored, or parent HUD ID when UI-anchored."),
|
|
120
|
+
});
|
|
121
|
+
const propsMultipleSchema = z.object({
|
|
122
|
+
...coreFields,
|
|
123
|
+
id: coreFields.id.describe("Unique ID starting with 'prop_' (e.g., 'prop_farming_tools'). A sequential sheet of related items or lifecycle states (e.g., tilled soil stages)."),
|
|
124
|
+
referenceId: z
|
|
125
|
+
.union([z.string(), z.array(z.string()).min(1)])
|
|
126
|
+
.describe("Map ID when world-anchored, or parent HUD ID when UI-anchored."),
|
|
127
|
+
propsMultipleBreakdown: z
|
|
128
|
+
.string()
|
|
129
|
+
.min(1)
|
|
130
|
+
.describe("Description mapping each item index left-to-right on the sheet."),
|
|
164
131
|
});
|
|
165
132
|
const propsMapOverlaySchema = z.object({
|
|
166
|
-
id:
|
|
133
|
+
id: coreFields.id.describe("Unique ID starting with 'prop_' (e.g., 'prop_dungeon_door'). A stateful texture overlay aligned with an existing map structure."),
|
|
167
134
|
anchorDescription: z
|
|
168
135
|
.string()
|
|
169
|
-
.describe("
|
|
170
|
-
gamePlay:
|
|
171
|
-
referenceId:
|
|
136
|
+
.describe("Exact description of the map-baked structure this overlay aligns with (e.g., 'iron cell gate on north wall')."),
|
|
137
|
+
gamePlay: coreFields.gamePlay,
|
|
138
|
+
referenceId: z
|
|
139
|
+
.string()
|
|
140
|
+
.describe("ID of the base or extend map hosting the anchor structure."),
|
|
172
141
|
overlayStateBreakdown: z
|
|
173
142
|
.array(mapOverlayStateSchema)
|
|
174
143
|
.min(1)
|
|
175
|
-
.describe("
|
|
176
|
-
});
|
|
177
|
-
const propsMultipleSchema = z.object({
|
|
178
|
-
...baseAssetFields,
|
|
179
|
-
id: baseAssetFields.id.describe("Unique id for a multi-prop sheet. Start with 'prop_'."),
|
|
180
|
-
prompt: baseAssetFields.prompt.describe("For props_multiple: Describe isolated, small pick-up items as purely physical shapes. This primary prompt is REQUIRED; use it for the overall composition, and use propsMultipleBreakdown only as extra numbered split guidance."),
|
|
181
|
-
gamePlay: baseAssetFields.gamePlay.describe("For props_multiple: Pickup, placement, inventory, cursor use, state progression, or crafting role."),
|
|
182
|
-
propsMultipleBreakdown: z
|
|
183
|
-
.string()
|
|
184
|
-
.optional()
|
|
185
|
-
.describe("Optional secondary prompt mapping numbered bounding boxes to individual prop descriptions (e.g., 'Prop 1: bare dark tilled soil; Prop 2: tiny green sprout'). This is NOT a substitute for the required prompt field."),
|
|
186
|
-
referenceId: referenceIdSchema
|
|
187
|
-
.describe("Optional placement/style reference. Use a base_map or extend_map id for world props; use a hud_element id for UI-layer props. Omit to default to the batch map.")
|
|
188
|
-
.optional(),
|
|
144
|
+
.describe("Visual state variants for the anchor. Exclude a top-level prompt field on this asset."),
|
|
189
145
|
});
|
|
190
146
|
const hudElementSchema = z.object({
|
|
191
|
-
...
|
|
192
|
-
id:
|
|
193
|
-
prompt: baseAssetFields.prompt.describe("For hud_element: Describe the full UI layout using the HUD art-vs-code strategy: generated art owns atmosphere and stable chrome; code owns state, data, accessibility, and interactivity. Immersive/gameplay-facing HUDs (title/start screens, result screens, health/resource frames, hotbars, inventory grids, dialogue, shop, inspect/case-file views, compact status widgets, stylized quest/ledger shells) should bake stable frames, slots, panel borders, short stable labels, neutral button chrome, and title/menu artwork into the image. Title menus (hud_title_menu / hud_start_screen): cinematic full-screen composition with baked game title and baked neutral menu button artwork for stable labels such as Start Game, Load Game, Continue, Settings, or Credits; arrange buttons with clear rectangular hit regions for transparent code overlays. Hybrid information screens need a generated thematic backplate/border/header but a plain high-contrast blank surface for runtime text. Clean system UI such as settings, keybindings, save/load lists, and credits should usually be code-rendered rather than custom HUD art. Use neutral/default chrome only; put runtime state in gamePlay. Floating UI panels need solid flat neon green chroma-key background (#00FF00); full-screen title menus should use high-fidelity cinematic backgrounds instead."),
|
|
194
|
-
gamePlay: baseAssetFields.gamePlay.describe("For hud_element: Explain UI wiring and runtime-only visual state that must NOT appear in the prompt: transparent hit regions, active tab highlights, hover/focus effects, disabled dimming/masks, dynamic text/numbers, slot contents, meter fill levels, scroll/list contents, and click behavior."),
|
|
147
|
+
...coreFields,
|
|
148
|
+
id: coreFields.id.describe("Unique ID starting with 'hud_' (e.g., 'hud_start_screen'). Full-screen overlays, dialogue borders, menu boards, or shop panels."),
|
|
195
149
|
});
|
|
196
150
|
const multipleHudsSchema = z.object({
|
|
197
|
-
...
|
|
198
|
-
id:
|
|
199
|
-
prompt: baseAssetFields.prompt.describe("For multiple_huds: Describe several small isolated HUD widgets generated together in one sheet for cost-effective cropping/codegen. Use for compact reusable UI chrome like dialogue panels, quest widgets, status widgets, tooltip frames, command bubbles, notification plaques, portrait frames, and small inventory subpanels. The sheet must have a solid neon green #00FF00 background, generous spacing between widgets, neutral/default chrome only, and blank high-contrast runtime text surfaces. Do NOT use for full-screen title menus, result screens, large shop screens, or highly complex unique layouts; use hud_element for those."),
|
|
200
|
-
gamePlay: baseAssetFields.gamePlay.describe("For multiple_huds: Explain the runtime role of each cropped widget, including dynamic text/data, transparent hit regions, hover/focus effects, open/close behavior, and where each small HUD should appear."),
|
|
151
|
+
...coreFields,
|
|
152
|
+
id: coreFields.id.describe("Unique ID starting with 'hud_' (e.g., 'hud_small_panels'). A single green chroma-key sheet containing small reusable HUD widgets."),
|
|
201
153
|
multipleHudsBreakdown: z
|
|
202
154
|
.string()
|
|
203
|
-
.describe("
|
|
155
|
+
.describe("Cropping coordinates and descriptions for each small widget on the sheet."),
|
|
204
156
|
});
|
|
205
157
|
const musicBgSchema = z.object({
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
158
|
+
id: coreFields.id.describe("Unique ID starting with 'music_' (e.g., 'music_pastoral_theme'). Background tracks. Always start with the word 'Instrumental' and include rhythmic anchors. No SFX."),
|
|
159
|
+
prompt: coreFields.prompt,
|
|
160
|
+
gamePlay: z
|
|
161
|
+
.string()
|
|
162
|
+
.optional()
|
|
163
|
+
.describe("Optional in-game usage context for the track."),
|
|
210
164
|
});
|
|
211
|
-
const
|
|
212
|
-
export const assetToolSchema = z
|
|
213
|
-
.object({
|
|
165
|
+
const assetBatchFields = {
|
|
214
166
|
artStyle: z
|
|
215
167
|
.string()
|
|
216
|
-
.describe("Shared style
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
propsMapOverlays: assetArray(propsMapOverlaySchema, "Map-anchored structural overlay props. Use when a state change must align with a specific map-baked structure (open cupboard, repaired building, opened chest). Returns image URL + box_2d per state. Not for portable pickups or generic zone tiles."),
|
|
231
|
-
hudElements: assetArray(hudElementSchema, "HUD/UI image assets to generate."),
|
|
232
|
-
multipleHuds: assetArray(multipleHudsSchema, "Multi-HUD sheets to generate. Each sheet is cropped into multiple small HUD widgets and each crop receives generated widget code."),
|
|
233
|
-
backgroundMusic: assetArray(musicBgSchema, "Background music assets to generate."),
|
|
234
|
-
})
|
|
235
|
-
.describe("Expensive asset generation request. Before filling this schema, decide the complete asset batch needed for the user's requested outcome. Preserve the user's visual wording, style constraints, placement, and exclusions in the asset prompts/gamePlay; do not simplify them into a different asset idea. Bundle all related asset needs for the user's current turn into one call. Do not call assetsAgent again to verify, double-check, or add items that should have been included in the same batch unless the first call failed/incomplete, a required dependency blocks describing the second batch up front, or the user explicitly approves another separate batch.")
|
|
236
|
-
.refine((input) => input.baseMaps.length +
|
|
237
|
-
input.extendMaps.length +
|
|
238
|
-
input.editMaps.length +
|
|
239
|
-
input.mapVfx.length +
|
|
240
|
-
input.baseCharacters.length +
|
|
241
|
-
input.baseCharacterVariants.length +
|
|
242
|
-
input.characterAnimations.length +
|
|
243
|
-
input.propsSingles.length +
|
|
244
|
-
input.propsMultiples.length +
|
|
245
|
-
input.propsMapOverlays.length +
|
|
246
|
-
input.hudElements.length +
|
|
247
|
-
input.multipleHuds.length +
|
|
248
|
-
input.backgroundMusic.length >
|
|
249
|
-
0, "At least one asset array must contain an asset.");
|
|
250
|
-
const withType = (assets, type) => (assets ?? []).map((asset) => ({ ...asset, type }));
|
|
251
|
-
export const mapAssetToolInputToLegacy = (input) => ({
|
|
252
|
-
artStyle: input.artStyle,
|
|
253
|
-
isFirstBuild: input.isFirstBuild,
|
|
254
|
-
assets: [
|
|
255
|
-
...withType(input.baseMaps, "base_map"),
|
|
256
|
-
...withType(input.extendMaps, "extend_map"),
|
|
257
|
-
...withType(input.editMaps, "edit_map"),
|
|
258
|
-
...withType(input.mapVfx, "map_vfx"),
|
|
259
|
-
...withType(input.hudElements, "hud_element"),
|
|
260
|
-
...withType(input.multipleHuds, "multiple_huds"),
|
|
261
|
-
...withType(input.baseCharacters, "base_character"),
|
|
262
|
-
...withType(input.propsSingles, "props_single"),
|
|
263
|
-
...withType(input.propsMultiples, "props_multiple"),
|
|
264
|
-
...input.propsMapOverlays.map((asset) => ({
|
|
265
|
-
...asset,
|
|
266
|
-
type: "props_map_overlay",
|
|
267
|
-
prompt: asset.overlayStateBreakdown
|
|
268
|
-
.map((state) => `${state.label}: ${state.prompt}`)
|
|
269
|
-
.join(" | "),
|
|
270
|
-
})),
|
|
271
|
-
...withType(input.baseCharacterVariants, "base_character_variant"),
|
|
272
|
-
...withType(input.characterAnimations, "character_animation"),
|
|
273
|
-
...withType(input.backgroundMusic, "music_bg"),
|
|
274
|
-
],
|
|
275
|
-
});
|
|
276
|
-
export const codingAgentTaskTypeSchema = z.enum([
|
|
277
|
-
"new_game",
|
|
278
|
-
"bug_fix",
|
|
279
|
-
"revisit_previous_bug_fix",
|
|
280
|
-
"feature_implementation",
|
|
281
|
-
"explore",
|
|
282
|
-
"general",
|
|
283
|
-
]);
|
|
284
|
-
const codingAgentTaskFieldDescription = "What the coding agent should do this turn. Scale the detail to 'type' — do NOT force a full game brief on every call. The coding agent automatically reads the asset manifest, so always omit file paths and pixel dimensions and focus on functional game logic and asset behavior. " +
|
|
285
|
-
"Preserve the user's actual wording and context. Include a short current-vs-desired framing when relevant: what the user says currently happens, what they want instead, when it should happen, what UI/game state it applies to, and any negations or 'not X, but Y' distinctions. Put implementation hints after that preserved context, not instead of it. " +
|
|
286
|
-
"This is an expensive coding tool: before setting task/type, decide the user's requested outcome, pick the workflow type, and draft one bundled task brief that covers all related code work. Default to one codeAgent call per user turn, bundle all related code changes into one task, and never call it again just to verify, double-check, or polish the same successful task. A second same-turn codeAgent call is only for a failed/incomplete prior call, a clear user-reported unresolved prior bug via revisit_previous_bug_fix, or genuinely independent work that cannot be safely bundled. " +
|
|
287
|
-
"For 'new_game': on the first build the server injects the approved plan automatically — pass a short placeholder (for example \"Use approved plan\"). " +
|
|
288
|
-
"For 'bug_fix': use when something is broken, incorrect, crashing, or not working as expected for the first fix attempt on that bug. Pass one or more related bug reports in a single task (e.g. 'Player falls through floor; inventory count is wrong'). Do not use 'explore' first as a preflight. " +
|
|
289
|
-
"For 'revisit_previous_bug_fix': use only after a prior successful codeAgent bug_fix when the user says the bug still isn't fixed and their updated description is clear enough to act on. Loads the last bug-fix session and retries without re-analyzing the compiled bundle. Pass the user's updated bug description in task. If the user's report is vague or may reflect misunderstood intent, ask a clarifying follow-up question in chat instead of calling this type. " +
|
|
290
|
-
"For 'feature_implementation': use when the user wants new behavior, mechanics, UI, asset wiring, SDK integrations, balance changes, or polish — not fixing broken existing behavior. Pass one or more related feature requests in a single task. Do not use 'explore' first as a preflight. " +
|
|
291
|
-
"If a single user turn mixes bug fixes and feature work, prefer one bundled codeAgent call using the dominant type when the items affect the same feature, subsystem, UI flow, or player-facing outcome. Split only for genuinely independent tasks that require different workflows and cannot be safely bundled. " +
|
|
292
|
-
"For 'explore': a plain read-only question about the codebase, asset manifest, wired gameplay, or game state (e.g., 'List all asset IDs and types in src/data' or 'Summarize the current map layout and wired mechanics'). Do not request any changes. Never use for broken behavior or implementation requests unless the user explicitly asks for read-only/no-change analysis. " +
|
|
293
|
-
"For 'general': fallback only when the task clearly needs code changes but does not fit new_game, bug_fix, revisit_previous_bug_fix, feature_implementation, or explore. Pass a concise task brief.";
|
|
294
|
-
const codingAgentTypeFieldDescription = "Select the coding workflow. " +
|
|
295
|
-
"This is an expensive coding tool: before choosing the type, decide the bundled task brief and choose the one workflow that best fits the user's requested outcome. Do not use a second codeAgent call for verification after a successful complete result. " +
|
|
296
|
-
"'new_game': the first playable implementation after assets are generated on a brand-new game (no prior successful codeAgent run in this workspace); starts a fresh coding session. " +
|
|
297
|
-
"'bug_fix': first attempt to fix broken behavior after the first build. Builds and analyzes the compiled bundle for root cause, then implements a minimal fix. Use for errors, crashes, logic bugs, and initial 'not working' reports. A single call may include multiple related bug fixes in the task string. " +
|
|
298
|
-
"'revisit_previous_bug_fix': retry a bug fix after a prior successful bug_fix when the user says it still isn't fixed and you have a clear updated description. Resumes the last bug-fix Pi session without re-analyzing the compiled bundle. If the user's report is vague or you may have misunderstood the original bug, ask a clarifying follow-up in chat instead. " +
|
|
299
|
-
"'feature_implementation': add or change game behavior after the first build when nothing is fundamentally broken. Use for new mechanics, UI behavior, asset wiring, SDK integrations, balance changes, and polish. A single call may include multiple related feature requests in the task string. " +
|
|
300
|
-
"When one user turn contains both bug fixes and feature requests, prefer one bundled call with the dominant type when the items are related; split only for genuinely independent tasks that require different workflows. Do not use 'explore' first as a preflight for either workflow. " +
|
|
301
|
-
"'explore': read-only inspection of the codebase, asset manifest, wired gameplay, or game state with NO changes; pass a plain exploration question as the task. Never use for broken behavior, vague 'not working' reports, or implementation requests unless the user explicitly asks for read-only diagnosis. " +
|
|
302
|
-
"'general': last resort when code changes are needed but no other workflow applies. Runs the coding agent directly on the task without specialized pre-analysis.";
|
|
303
|
-
export const parseCodingAgentTaskType = (type) => {
|
|
304
|
-
const parsed = codingAgentTaskTypeSchema.safeParse(type);
|
|
305
|
-
if (parsed.success) {
|
|
306
|
-
return { ok: true, value: parsed.data };
|
|
307
|
-
}
|
|
308
|
-
const allowed = codingAgentTaskTypeSchema.options
|
|
309
|
-
.map((option) => `"${option}"`)
|
|
310
|
-
.join(" | ");
|
|
311
|
-
return {
|
|
312
|
-
ok: false,
|
|
313
|
-
summary: `Invalid codeAgent type "${type}". Expected one of: ${allowed}.`,
|
|
314
|
-
};
|
|
168
|
+
.describe("Shared visual style constraints for all assets in this batch to maintain stylistic consistency."),
|
|
169
|
+
baseMaps: assetArray(baseMapSchema, "New base maps."),
|
|
170
|
+
extendMaps: assetArray(extendMapSchema, "Map extensions connected to existing maps."),
|
|
171
|
+
editMaps: assetArray(editMapSchema, "Static edits to an existing map."),
|
|
172
|
+
mapVfx: assetArray(mapVfxSchema, "Animated VFX on an existing map."),
|
|
173
|
+
baseCharacters: assetArray(baseCharacterSchema, "Character sprites."),
|
|
174
|
+
baseCharacterVariants: assetArray(baseCharacterVariantSchema, "Job-NPC prop-in-pose variants."),
|
|
175
|
+
characterAnimations: assetArray(characterAnimationSchema, "Character animation sheets."),
|
|
176
|
+
propsSingles: assetArray(propsSingleSchema, "Single pickup props."),
|
|
177
|
+
propsMultiples: assetArray(propsMultipleSchema, "Multi-prop sprite sheets."),
|
|
178
|
+
propsMapOverlays: assetArray(propsMapOverlaySchema, "Map-anchored overlay states (doors, chests, etc.)."),
|
|
179
|
+
hudElements: assetArray(hudElementSchema, "HUD/UI images."),
|
|
180
|
+
multipleHuds: assetArray(multipleHudsSchema, "Multi-widget HUD sheets."),
|
|
181
|
+
backgroundMusic: assetArray(musicBgSchema, "Background music tracks."),
|
|
315
182
|
};
|
|
316
|
-
|
|
317
|
-
export const codingAgentToolLooseSchema = z.object({
|
|
318
|
-
task: z.string().describe(codingAgentTaskFieldDescription),
|
|
319
|
-
type: z.string().describe(codingAgentTypeFieldDescription),
|
|
320
|
-
});
|
|
321
|
-
export const codingAgentToolSchema = z.object({
|
|
322
|
-
task: z.string().describe(codingAgentTaskFieldDescription),
|
|
323
|
-
type: codingAgentTaskTypeSchema.describe(codingAgentTypeFieldDescription),
|
|
324
|
-
});
|
|
325
|
-
export const newGameCodeAgentToolSchema = z.object({});
|
|
326
|
-
export const exploreCodeAgentToolSchema = z.object({
|
|
327
|
-
query: z
|
|
328
|
-
.string()
|
|
329
|
-
.min(1)
|
|
330
|
-
.describe("One high-level natural-language, read-only codebase question for the coding agent to answer. Ask for current behavior, ownership, risks, and the safest implementation path. Do NOT include shell commands, grep terms, guessed file paths, or a file-by-file checklist unless those exact details came from prior tool output."),
|
|
331
|
-
isFollowup: z
|
|
332
|
-
.boolean()
|
|
333
|
-
.describe("Spell this field exactly as isFollowup. Use true only when continuing the most recent successful exploreCodeAgent session in this chat. Use false for a fresh, unrelated user goal. When true, the query should summarize the previous user question, the prior exploreCodeAgent query, the exploreCodeAgent output, and what needs clarification now."),
|
|
334
|
-
});
|
|
335
|
-
export const implementCodeAgentToolSchema = z.object({
|
|
336
|
-
task: z
|
|
337
|
-
.string()
|
|
338
|
-
.min(1)
|
|
339
|
-
.describe("One high-level natural-language implementation task for the coding agent. Write in first-person as a playtester reporting visible symptoms — do not guess file paths, subsystems, or technical root causes. NEVER embed or append raw file contents (assets.md, SCENES.md, package.json, scene files, or source code); Codex reads those autonomously. Do not write this as a chat transcript. For normal bugs/features, lead with the task and desired outcome, then include the user's symptom language as player report/context. For browser/runtime errors, keep the useful exception signature but drop hosted workspace URLs, repeated stack frames, minified line/column offsets, and bundled main.js/dist/main.js locations; do not infer feature/domain ownership from a property name alone. Ask the coding agent to ground the fix in actual code/assets and validate appropriately — do not invent root causes, subsystems, file names, inspected paths, or exact validation results. When isFollowup is true, summarize the prior same-tool chain in this task: what the user originally said, what you previously asked implementCodeAgent to do, what implementCodeAgent output, what changed or remained incomplete, and what the user is asking now. When attemptType is stuck_bug_loop, use isFollowup false and put the full stuck-bug context in this brief: original user report(s) verbatim, what you asked implementCodeAgent in each prior attempt, each prior implementCodeAgent output, previous changes it reported, latest user feedback verbatim, baseline commitId from the first checkpoint in that bug chain when available, and ask the coding agent to re-investigate from first principles, identify the real cause, and fix it. Do not split normal bug fixes or feature changes into locate/fix/verify task lists."),
|
|
340
|
-
isFollowup: z
|
|
341
|
-
.boolean()
|
|
342
|
-
.default(false)
|
|
343
|
-
.describe("Spell this field exactly as isFollowup. Use true only when continuing the most recent successful implementCodeAgent session in this chat. Use false for a fresh user goal, for an unrelated goal, or when the prior same-tool session was exploreCodeAgent rather than implementCodeAgent. For attemptType stuck_bug_loop, always use false — context goes in the task brief, not session history."),
|
|
344
|
-
attemptType: z
|
|
345
|
-
.enum(["normal", "stuck_bug_loop"])
|
|
346
|
-
.default("normal")
|
|
347
|
-
.describe("Use normal for fresh implementation and ordinary same-session follow-ups. Use stuck_bug_loop only when the user reports the same bug is still unresolved after one or more prior implementCodeAgent attempts; pair with isFollowup false and put original user report(s), what you asked implementCodeAgent in each prior attempt, each prior implementCodeAgent output, previous changes it reported, latest user feedback, and baseline commitId (if available) in the task brief. This starts a fresh coding-agent session with the full prior chain in the prompt."),
|
|
348
|
-
});
|
|
349
|
-
export const ASSET_TOOL_DESCRIPTION = "Generate layered game assets for a Stardew Valley–style 2.5D top-down (¾ bird's-eye) browser game. " +
|
|
350
|
-
"Preserve the user's visual wording, style constraints, placement, and exclusions in the asset brief; do not simplify them into a different asset idea. " +
|
|
351
|
-
"This is an expensive generation tool: before calling it, decide the complete asset batch needed for the user's requested outcome. Bundle all related asset needs into one call, and do not call it again to verify or add items that belonged in the same batch unless the first call failed/incomplete or the user explicitly approves another separate batch.";
|
|
352
|
-
export const mcpGenerateAssetInputSchema = assetToolSchema.and(z.object({
|
|
183
|
+
const mcpClientExtraFields = {
|
|
353
184
|
output_dir: z
|
|
354
185
|
.string()
|
|
355
186
|
.optional()
|
|
356
|
-
.describe("
|
|
187
|
+
.describe("Write directory. Defaults to workspace root."),
|
|
357
188
|
workspace_root: z
|
|
358
189
|
.string()
|
|
359
190
|
.optional()
|
|
360
|
-
.describe("Root
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
.optional()
|
|
364
|
-
.describe("Optional plan text for first-time asset generation when assets.md is empty (replaces in-app plan chat lookup)."),
|
|
365
|
-
art_reference_url: z
|
|
366
|
-
.string()
|
|
367
|
-
.optional()
|
|
368
|
-
.describe("Optional art style reference image URL for base_map generation."),
|
|
369
|
-
}));
|
|
370
|
-
export const mcpGenerateAssetRequestSchema = mcpGenerateAssetInputSchema.and(z.object({
|
|
191
|
+
.describe("Root to read assets.md and src/data/*.json from."),
|
|
192
|
+
};
|
|
193
|
+
const mcpServerExtraFields = {
|
|
371
194
|
workspace_files: z
|
|
372
195
|
.record(z.string(), z.string())
|
|
373
196
|
.optional()
|
|
374
|
-
.describe("
|
|
375
|
-
session_id: z
|
|
197
|
+
.describe("Repo-relative path → file content."),
|
|
198
|
+
session_id: z.string().optional().describe("Stable generation session id."),
|
|
199
|
+
gameId: z
|
|
376
200
|
.string()
|
|
377
201
|
.optional()
|
|
378
|
-
.describe("
|
|
379
|
-
}
|
|
202
|
+
.describe("Existing game id from index.html; set automatically by the client."),
|
|
203
|
+
};
|
|
204
|
+
const countAssets = (input) => (input.baseMaps?.length ?? 0) +
|
|
205
|
+
(input.extendMaps?.length ?? 0) +
|
|
206
|
+
(input.editMaps?.length ?? 0) +
|
|
207
|
+
(input.mapVfx?.length ?? 0) +
|
|
208
|
+
(input.baseCharacters?.length ?? 0) +
|
|
209
|
+
(input.baseCharacterVariants?.length ?? 0) +
|
|
210
|
+
(input.characterAnimations?.length ?? 0) +
|
|
211
|
+
(input.propsSingles?.length ?? 0) +
|
|
212
|
+
(input.propsMultiples?.length ?? 0) +
|
|
213
|
+
(input.propsMapOverlays?.length ?? 0) +
|
|
214
|
+
(input.hudElements?.length ?? 0) +
|
|
215
|
+
(input.multipleHuds?.length ?? 0) +
|
|
216
|
+
(input.backgroundMusic?.length ?? 0);
|
|
217
|
+
/** MCP tool input — assets grouped by type. */
|
|
218
|
+
export const assetToolSchema = z.object(assetBatchFields);
|
|
219
|
+
const withType = (assets, type) => (assets ?? []).map((asset) => ({ ...asset, type }));
|
|
220
|
+
/** Flatten grouped MCP input into the API payload agent-server expects. */
|
|
221
|
+
export const flattenAssetToolInput = (input) => {
|
|
222
|
+
if (countAssets(input) === 0) {
|
|
223
|
+
throw new Error("At least one asset array must contain an asset.");
|
|
224
|
+
}
|
|
225
|
+
return {
|
|
226
|
+
artStyle: input.artStyle,
|
|
227
|
+
assets: [
|
|
228
|
+
...withType(input.baseMaps, "base_map"),
|
|
229
|
+
...withType(input.extendMaps, "extend_map"),
|
|
230
|
+
...withType(input.editMaps, "edit_map"),
|
|
231
|
+
...withType(input.mapVfx, "map_vfx"),
|
|
232
|
+
...withType(input.baseCharacters, "base_character"),
|
|
233
|
+
...withType(input.baseCharacterVariants, "base_character_variant"),
|
|
234
|
+
...withType(input.characterAnimations, "character_animation"),
|
|
235
|
+
...withType(input.propsSingles, "props_single"),
|
|
236
|
+
...withType(input.propsMultiples, "props_multiple"),
|
|
237
|
+
...withType(input.hudElements, "hud_element"),
|
|
238
|
+
...withType(input.multipleHuds, "multiple_huds"),
|
|
239
|
+
...withType(input.backgroundMusic, "music_bg"),
|
|
240
|
+
...(input.propsMapOverlays ?? []).map((asset) => ({
|
|
241
|
+
...asset,
|
|
242
|
+
type: "props_map_overlay",
|
|
243
|
+
prompt: asset.overlayStateBreakdown
|
|
244
|
+
.map((state) => `${state.label}: ${state.prompt}`)
|
|
245
|
+
.join(" | "),
|
|
246
|
+
})),
|
|
247
|
+
],
|
|
248
|
+
};
|
|
249
|
+
};
|
|
250
|
+
/** Accept grouped MCP input or an already-flattened REST payload. */
|
|
251
|
+
export const normalizeAssetToolInput = (input) => {
|
|
252
|
+
if (Array.isArray(input.assets)) {
|
|
253
|
+
const flat = input;
|
|
254
|
+
if (flat.assets.length === 0) {
|
|
255
|
+
throw new Error("At least one asset must be provided.");
|
|
256
|
+
}
|
|
257
|
+
return flat;
|
|
258
|
+
}
|
|
259
|
+
return flattenAssetToolInput(input);
|
|
260
|
+
};
|
|
261
|
+
export const ASSET_TOOL_DESCRIPTION = "Generate visual and audio game assets for a 2.5D top-down (3/4 oblique) browser game. " +
|
|
262
|
+
"Bundle all related assets (maps, characters, walk loops, HUD layout, and looping background music) " +
|
|
263
|
+
"for the current design phase into a single tool invocation to maintain stylistic consistency and establish proper dependency linking.";
|
|
264
|
+
// Plain z.object — MCP SDK only advertises tool parameters for object schemas
|
|
265
|
+
// (not z.and / z.refine), otherwise clients see { properties: {} }.
|
|
266
|
+
export const mcpGenerateAssetInputSchema = z.object({
|
|
267
|
+
...assetBatchFields,
|
|
268
|
+
...mcpClientExtraFields,
|
|
269
|
+
});
|
|
270
|
+
export const mcpGenerateAssetRequestSchema = z.object({
|
|
271
|
+
...assetBatchFields,
|
|
272
|
+
...mcpClientExtraFields,
|
|
273
|
+
...mcpServerExtraFields,
|
|
274
|
+
});
|
|
380
275
|
//# sourceMappingURL=asset-tool-schema.js.map
|