sbox-mcp-server 1.2.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 (45) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +90 -0
  3. package/dist/index.d.ts +13 -0
  4. package/dist/index.js +155 -0
  5. package/dist/tools/assets.d.ts +8 -0
  6. package/dist/tools/assets.js +80 -0
  7. package/dist/tools/audio.d.ts +8 -0
  8. package/dist/tools/audio.js +101 -0
  9. package/dist/tools/components.d.ts +11 -0
  10. package/dist/tools/components.js +78 -0
  11. package/dist/tools/console.d.ts +8 -0
  12. package/dist/tools/console.js +59 -0
  13. package/dist/tools/discovery.d.ts +13 -0
  14. package/dist/tools/discovery.js +58 -0
  15. package/dist/tools/gameobjects.d.ts +4 -0
  16. package/dist/tools/gameobjects.js +197 -0
  17. package/dist/tools/materials.d.ts +8 -0
  18. package/dist/tools/materials.js +82 -0
  19. package/dist/tools/networking.d.ts +11 -0
  20. package/dist/tools/networking.js +227 -0
  21. package/dist/tools/physics.d.ts +8 -0
  22. package/dist/tools/physics.js +130 -0
  23. package/dist/tools/playmode.d.ts +11 -0
  24. package/dist/tools/playmode.js +140 -0
  25. package/dist/tools/prefabs.d.ts +8 -0
  26. package/dist/tools/prefabs.js +94 -0
  27. package/dist/tools/project.d.ts +12 -0
  28. package/dist/tools/project.js +90 -0
  29. package/dist/tools/publishing.d.ts +11 -0
  30. package/dist/tools/publishing.js +168 -0
  31. package/dist/tools/scenes.d.ts +8 -0
  32. package/dist/tools/scenes.js +75 -0
  33. package/dist/tools/scripts.d.ts +9 -0
  34. package/dist/tools/scripts.js +132 -0
  35. package/dist/tools/status.d.ts +8 -0
  36. package/dist/tools/status.js +49 -0
  37. package/dist/tools/templates.d.ts +11 -0
  38. package/dist/tools/templates.js +135 -0
  39. package/dist/tools/ui.d.ts +8 -0
  40. package/dist/tools/ui.js +116 -0
  41. package/dist/tools/world.d.ts +20 -0
  42. package/dist/tools/world.js +272 -0
  43. package/dist/transport/bridge-client.d.ts +60 -0
  44. package/dist/transport/bridge-client.js +239 -0
  45. package/package.json +54 -0
@@ -0,0 +1,116 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * UI tools: create_razor_ui, add_screen_panel, add_world_panel.
4
+ * Manages s&box's Razor-based UI system — .razor component files, ScreenPanel, and WorldPanel.
5
+ */
6
+ export function registerUITools(server, bridge) {
7
+ // ── create_razor_ui ───────────────────────────────────────────────
8
+ server.tool("create_razor_ui", "Create a Razor UI component file (.razor) with optional SCSS stylesheet. Generates boilerplate for HUD, menu, or basic panel types", {
9
+ name: z
10
+ .string()
11
+ .describe("Component name (e.g. 'GameHud', 'MainMenu')"),
12
+ directory: z
13
+ .string()
14
+ .optional()
15
+ .describe("Subdirectory under code/ for the file. Defaults to 'UI'"),
16
+ panelType: z
17
+ .enum(["basic", "hud", "menu"])
18
+ .optional()
19
+ .describe("Type of panel to generate: 'basic' (simple panel), 'hud' (health/score overlay), 'menu' (title + buttons). Defaults to 'basic'"),
20
+ description: z
21
+ .string()
22
+ .optional()
23
+ .describe("Description of what this UI panel does"),
24
+ includeStyles: z
25
+ .boolean()
26
+ .optional()
27
+ .describe("Generate a companion .razor.scss stylesheet. Defaults to true"),
28
+ content: z
29
+ .string()
30
+ .optional()
31
+ .describe("Raw .razor content (skips boilerplate generation)"),
32
+ styles: z
33
+ .string()
34
+ .optional()
35
+ .describe("Raw .razor.scss content (only used with raw content mode)"),
36
+ }, async (params) => {
37
+ const res = await bridge.send("create_razor_ui", params);
38
+ if (!res.success) {
39
+ return { content: [{ type: "text", text: `Error: ${res.error}` }] };
40
+ }
41
+ return {
42
+ content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }],
43
+ };
44
+ });
45
+ // ── add_screen_panel ──────────────────────────────────────────────
46
+ server.tool("add_screen_panel", "Create a new GameObject with a ScreenPanel component for full-screen UI overlay (HUD, menus, etc.)", {
47
+ name: z
48
+ .string()
49
+ .optional()
50
+ .describe("Name for the UI GameObject. Defaults to 'Screen UI'"),
51
+ zIndex: z
52
+ .number()
53
+ .optional()
54
+ .describe("Z-index for layering multiple screen panels"),
55
+ panelComponent: z
56
+ .string()
57
+ .optional()
58
+ .describe("Name of a Razor PanelComponent to add (e.g. 'GameHud')"),
59
+ parent: z
60
+ .string()
61
+ .optional()
62
+ .describe("GUID of parent GameObject"),
63
+ }, async (params) => {
64
+ const res = await bridge.send("add_screen_panel", params);
65
+ if (!res.success) {
66
+ return { content: [{ type: "text", text: `Error: ${res.error}` }] };
67
+ }
68
+ return {
69
+ content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }],
70
+ };
71
+ });
72
+ // ── add_world_panel ───────────────────────────────────────────────
73
+ server.tool("add_world_panel", "Create a new GameObject with a WorldPanel component for in-world 3D UI (health bars, signs, nameplates)", {
74
+ name: z
75
+ .string()
76
+ .optional()
77
+ .describe("Name for the UI GameObject. Defaults to 'World UI'"),
78
+ position: z
79
+ .object({ x: z.number(), y: z.number(), z: z.number() })
80
+ .optional()
81
+ .describe("World position for the panel"),
82
+ rotation: z
83
+ .object({
84
+ pitch: z.number(),
85
+ yaw: z.number(),
86
+ roll: z.number(),
87
+ })
88
+ .optional()
89
+ .describe("Rotation as euler angles"),
90
+ worldScale: z
91
+ .number()
92
+ .optional()
93
+ .describe("Scale of the world panel. Smaller = smaller in world"),
94
+ lookAtCamera: z
95
+ .boolean()
96
+ .optional()
97
+ .describe("Whether the panel always faces the camera (billboard)"),
98
+ panelComponent: z
99
+ .string()
100
+ .optional()
101
+ .describe("Name of a Razor PanelComponent to add (e.g. 'NpcNameplate')"),
102
+ parent: z
103
+ .string()
104
+ .optional()
105
+ .describe("GUID of parent GameObject"),
106
+ }, async (params) => {
107
+ const res = await bridge.send("add_world_panel", params);
108
+ if (!res.success) {
109
+ return { content: [{ type: "text", text: `Error: ${res.error}` }] };
110
+ }
111
+ return {
112
+ content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }],
113
+ };
114
+ });
115
+ }
116
+ //# sourceMappingURL=ui.js.map
@@ -0,0 +1,20 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { BridgeClient } from "../transport/bridge-client.js";
3
+ /**
4
+ * World-generation and map-editing tools.
5
+ *
6
+ * Drives terrain (MapBuilder), caves (CaveBuilder), and forests (ForestGenerator)
7
+ * components. Includes a generic invoke_button for pressing any [Button] on any
8
+ * component, sculpt brushes for direct heightmap editing, and place_along_path
9
+ * for dropping assets along a curve.
10
+ *
11
+ * Most "add_*" tools default to rebuilding the affected feature (Build Terrain,
12
+ * Build Cave, Generate Forest) so changes are visible immediately. Set
13
+ * `rebuild: false` to batch many edits and rebuild manually.
14
+ *
15
+ * Component lookup: by default each tool finds the first instance of the
16
+ * relevant component (MapBuilder, CaveBuilder, ForestGenerator) in the scene.
17
+ * Pass `id` (GameObject GUID) to target a specific GameObject.
18
+ */
19
+ export declare function registerWorldTools(server: McpServer, bridge: BridgeClient): void;
20
+ //# sourceMappingURL=world.d.ts.map
@@ -0,0 +1,272 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * World-generation and map-editing tools.
4
+ *
5
+ * Drives terrain (MapBuilder), caves (CaveBuilder), and forests (ForestGenerator)
6
+ * components. Includes a generic invoke_button for pressing any [Button] on any
7
+ * component, sculpt brushes for direct heightmap editing, and place_along_path
8
+ * for dropping assets along a curve.
9
+ *
10
+ * Most "add_*" tools default to rebuilding the affected feature (Build Terrain,
11
+ * Build Cave, Generate Forest) so changes are visible immediately. Set
12
+ * `rebuild: false` to batch many edits and rebuild manually.
13
+ *
14
+ * Component lookup: by default each tool finds the first instance of the
15
+ * relevant component (MapBuilder, CaveBuilder, ForestGenerator) in the scene.
16
+ * Pass `id` (GameObject GUID) to target a specific GameObject.
17
+ */
18
+ export function registerWorldTools(server, bridge) {
19
+ // ── invoke_button ────────────────────────────────────────────────
20
+ server.tool("invoke_button", "Press a [Button] on a component (e.g. 'Build Terrain' on MapBuilder). Matches by attribute label, then method name. The keystone for driving any component-with-buttons workflow.", {
21
+ component: z
22
+ .string()
23
+ .describe("Component type name (e.g. 'MapBuilder', 'CaveBuilder')"),
24
+ button: z
25
+ .string()
26
+ .describe("Button label or method name (e.g. 'Build Terrain', 'Generate Forest')"),
27
+ id: z
28
+ .string()
29
+ .optional()
30
+ .describe("Optional GameObject GUID — if omitted, finds first matching component in scene"),
31
+ }, async (params) => {
32
+ const res = await bridge.send("invoke_button", params);
33
+ if (!res.success)
34
+ return { content: [{ type: "text", text: `Error: ${res.error}` }] };
35
+ return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
36
+ });
37
+ // ── list_component_buttons ───────────────────────────────────────
38
+ server.tool("list_component_buttons", "List all [Button]s available on a component. Use before invoke_button to discover what's there.", {
39
+ component: z.string().describe("Component type name"),
40
+ id: z.string().optional().describe("Optional GameObject GUID"),
41
+ }, async (params) => {
42
+ const res = await bridge.send("list_component_buttons", params);
43
+ if (!res.success)
44
+ return { content: [{ type: "text", text: `Error: ${res.error}` }] };
45
+ return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
46
+ });
47
+ // ── raycast_terrain ──────────────────────────────────────────────
48
+ server.tool("raycast_terrain", "Sample MapBuilder terrain height at world (x, y). Returns z (the surface height). Use to place props on the terrain surface.", {
49
+ x: z.number().describe("World X coordinate"),
50
+ y: z.number().describe("World Y coordinate"),
51
+ id: z.string().optional().describe("Optional GameObject GUID for MapBuilder"),
52
+ }, async (params) => {
53
+ const res = await bridge.send("raycast_terrain", params);
54
+ if (!res.success)
55
+ return { content: [{ type: "text", text: `Error: ${res.error}` }] };
56
+ return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
57
+ });
58
+ // ── add_terrain_hill ─────────────────────────────────────────────
59
+ server.tool("add_terrain_hill", "Add a hill (cosine-falloff bump) to MapBuilder. Negative height creates a depression.", {
60
+ x: z.number().describe("World X of hill center"),
61
+ y: z.number().describe("World Y of hill center"),
62
+ radius: z.number().default(500).describe("Hill radius in world units"),
63
+ height: z.number().default(100).describe("Peak height (negative for depression)"),
64
+ rebuild: z.boolean().default(true).describe("Rebuild terrain after adding (set false to batch)"),
65
+ id: z.string().optional(),
66
+ }, async (params) => {
67
+ const res = await bridge.send("add_terrain_hill", params);
68
+ if (!res.success)
69
+ return { content: [{ type: "text", text: `Error: ${res.error}` }] };
70
+ return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
71
+ });
72
+ // ── add_terrain_clearing ─────────────────────────────────────────
73
+ server.tool("add_terrain_clearing", "Add a flat clearing zone to MapBuilder (lerps height toward base inside radius).", {
74
+ x: z.number(),
75
+ y: z.number(),
76
+ radius: z.number().default(300),
77
+ rebuild: z.boolean().default(true),
78
+ id: z.string().optional(),
79
+ }, async (params) => {
80
+ const res = await bridge.send("add_terrain_clearing", params);
81
+ if (!res.success)
82
+ return { content: [{ type: "text", text: `Error: ${res.error}` }] };
83
+ return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
84
+ });
85
+ // ── add_terrain_trail ────────────────────────────────────────────
86
+ server.tool("add_terrain_trail", "Carve a trail depression between two points on MapBuilder.", {
87
+ from: z.object({ x: z.number(), y: z.number() }),
88
+ to: z.object({ x: z.number(), y: z.number() }),
89
+ rebuild: z.boolean().default(true),
90
+ id: z.string().optional(),
91
+ }, async (params) => {
92
+ const res = await bridge.send("add_terrain_trail", params);
93
+ if (!res.success)
94
+ return { content: [{ type: "text", text: `Error: ${res.error}` }] };
95
+ return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
96
+ });
97
+ // ── clear_terrain_features ───────────────────────────────────────
98
+ server.tool("clear_terrain_features", "Wipe Hills, Clearings, Trails, or all features from MapBuilder. 'what' is one of: Hills, Clearings, Trails, CavePath, all (default).", {
99
+ what: z
100
+ .enum(["Hills", "Clearings", "Trails", "CavePath", "all"])
101
+ .default("all"),
102
+ rebuild: z.boolean().default(true),
103
+ id: z.string().optional(),
104
+ }, async (params) => {
105
+ const res = await bridge.send("clear_terrain_features", params);
106
+ if (!res.success)
107
+ return { content: [{ type: "text", text: `Error: ${res.error}` }] };
108
+ return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
109
+ });
110
+ // ── add_cave_waypoint ────────────────────────────────────────────
111
+ server.tool("add_cave_waypoint", "Append (or insert) a waypoint to CaveBuilder.Path. Z is depth (negative = underground).", {
112
+ x: z.number(),
113
+ y: z.number(),
114
+ z: z.number().default(0).describe("Z depth — negative = underground"),
115
+ index: z
116
+ .number()
117
+ .int()
118
+ .optional()
119
+ .describe("Optional insert position (default: append to end)"),
120
+ rebuild: z.boolean().default(true),
121
+ id: z.string().optional(),
122
+ }, async (params) => {
123
+ const res = await bridge.send("add_cave_waypoint", params);
124
+ if (!res.success)
125
+ return { content: [{ type: "text", text: `Error: ${res.error}` }] };
126
+ return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
127
+ });
128
+ // ── clear_cave_path ──────────────────────────────────────────────
129
+ server.tool("clear_cave_path", "Clear all waypoints in CaveBuilder and remove the cave from the scene.", {
130
+ id: z.string().optional(),
131
+ }, async (params) => {
132
+ const res = await bridge.send("clear_cave_path", params);
133
+ if (!res.success)
134
+ return { content: [{ type: "text", text: `Error: ${res.error}` }] };
135
+ return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
136
+ });
137
+ // ── add_forest_poi ───────────────────────────────────────────────
138
+ server.tool("add_forest_poi", "Add a point of interest (clearing) to ForestGenerator.POIs. Returns the index of the new POI for use with add_forest_trail.", {
139
+ name: z.string().default("POI"),
140
+ x: z.number(),
141
+ y: z.number(),
142
+ radius: z.number().default(300),
143
+ density_multiplier: z
144
+ .number()
145
+ .default(1)
146
+ .describe("Multiplies forest density inside this POI's region"),
147
+ rebuild: z
148
+ .boolean()
149
+ .default(false)
150
+ .describe("Forest gen is slow (~1s); default false to batch"),
151
+ id: z.string().optional(),
152
+ }, async (params) => {
153
+ const res = await bridge.send("add_forest_poi", params);
154
+ if (!res.success)
155
+ return { content: [{ type: "text", text: `Error: ${res.error}` }] };
156
+ return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
157
+ });
158
+ // ── add_forest_trail ─────────────────────────────────────────────
159
+ server.tool("add_forest_trail", "Add a trail gap between two POIs (by index) to ForestGenerator.Trails.", {
160
+ from_index: z.number().int(),
161
+ to_index: z.number().int(),
162
+ rebuild: z.boolean().default(false),
163
+ id: z.string().optional(),
164
+ }, async (params) => {
165
+ const res = await bridge.send("add_forest_trail", params);
166
+ if (!res.success)
167
+ return { content: [{ type: "text", text: `Error: ${res.error}` }] };
168
+ return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
169
+ });
170
+ // ── set_forest_seed ──────────────────────────────────────────────
171
+ server.tool("set_forest_seed", "Set ForestGenerator.Seed and regenerate. Useful for re-rolling layouts.", {
172
+ seed: z.number().int().default(77),
173
+ rebuild: z.boolean().default(true),
174
+ id: z.string().optional(),
175
+ }, async (params) => {
176
+ const res = await bridge.send("set_forest_seed", params);
177
+ if (!res.success)
178
+ return { content: [{ type: "text", text: `Error: ${res.error}` }] };
179
+ return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
180
+ });
181
+ // ── clear_forest_pois ────────────────────────────────────────────
182
+ server.tool("clear_forest_pois", "Wipe all POIs and trails in ForestGenerator and clear placed forest objects from the scene.", {
183
+ id: z.string().optional(),
184
+ }, async (params) => {
185
+ const res = await bridge.send("clear_forest_pois", params);
186
+ if (!res.success)
187
+ return { content: [{ type: "text", text: `Error: ${res.error}` }] };
188
+ return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
189
+ });
190
+ // ── sculpt_terrain ───────────────────────────────────────────────
191
+ server.tool("sculpt_terrain", "Apply a heightmap brush at (x, y) to MapBuilder. Modes: raise, lower, flatten, smooth. Modifies the current heightmap directly and rebuilds the mesh; survives between calls until you press Build Terrain again.", {
192
+ x: z.number().describe("World X of brush center"),
193
+ y: z.number().describe("World Y of brush center"),
194
+ radius: z.number().default(400).describe("Brush radius in world units"),
195
+ strength: z.number().default(50).describe("Height delta (units) for raise/lower; ignored for flatten/smooth"),
196
+ mode: z.enum(["raise", "lower", "flatten", "smooth"]).default("raise"),
197
+ id: z.string().optional(),
198
+ }, async (params) => {
199
+ const res = await bridge.send("sculpt_terrain", params);
200
+ if (!res.success)
201
+ return { content: [{ type: "text", text: `Error: ${res.error}` }] };
202
+ return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
203
+ });
204
+ // ── paint_forest_density ─────────────────────────────────────────
205
+ server.tool("paint_forest_density", "Add a circular biome region with overridden forest density. Multiple regions stack via cosine falloff. density: 0=no trees, 1=normal, 2=double.", {
206
+ x: z.number(),
207
+ y: z.number(),
208
+ radius: z.number().default(800),
209
+ density: z.number().default(1).describe("Density multiplier (0=clear, 1=normal, 2=dense)"),
210
+ rebuild: z.boolean().default(false),
211
+ id: z.string().optional(),
212
+ }, async (params) => {
213
+ const res = await bridge.send("paint_forest_density", params);
214
+ if (!res.success)
215
+ return { content: [{ type: "text", text: `Error: ${res.error}` }] };
216
+ return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
217
+ });
218
+ // ── place_along_path ─────────────────────────────────────────────
219
+ server.tool("place_along_path", "Drop instances of a model along a path (list of points). Useful for fences, lampposts, road markers, lined-up rocks.", {
220
+ model: z.string().describe("Model path (e.g. 'models/dev/box.vmdl' or installed-asset path)"),
221
+ points: z
222
+ .array(z.object({ x: z.number(), y: z.number(), z: z.number().default(0) }))
223
+ .min(2)
224
+ .describe("Path waypoints (at least 2)"),
225
+ spacing: z.number().default(200).describe("Distance between placements (world units)"),
226
+ jitter: z.number().default(0).describe("Max random offset perpendicular to path"),
227
+ min_scale: z.number().default(1),
228
+ max_scale: z.number().default(1),
229
+ seed: z.number().int().default(42),
230
+ name: z.string().default("PathItem").describe("Base name for placed objects"),
231
+ }, async (params) => {
232
+ const res = await bridge.send("place_along_path", params);
233
+ if (!res.success)
234
+ return { content: [{ type: "text", text: `Error: ${res.error}` }] };
235
+ return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
236
+ });
237
+ // ── build_terrain_mesh ───────────────────────────────────────────
238
+ server.tool("build_terrain_mesh", "Build a standalone heightmap terrain mesh from a hills/clearings JSON spec — independent of MapBuilder. Use when you don't have a MapBuilder component in the scene and want one-shot terrain.", {
239
+ size: z.number().default(9600).describe("Total terrain size (world units, square)"),
240
+ resolution: z.number().int().default(64).describe("Grid resolution per side"),
241
+ name: z.string().default("Generated Terrain"),
242
+ hills: z
243
+ .array(z.object({
244
+ x: z.number(),
245
+ y: z.number(),
246
+ radius: z.number().default(500),
247
+ height: z.number().default(100),
248
+ }))
249
+ .default([]),
250
+ clearings: z
251
+ .array(z.object({ x: z.number(), y: z.number(), radius: z.number().default(300) }))
252
+ .default([]),
253
+ }, async (params) => {
254
+ const res = await bridge.send("build_terrain_mesh", params);
255
+ if (!res.success)
256
+ return { content: [{ type: "text", text: `Error: ${res.error}` }] };
257
+ return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
258
+ });
259
+ // ── set_prefab_ref ───────────────────────────────────────────────
260
+ server.tool("set_prefab_ref", "Set a GameObject-typed property on a component to a loaded prefab. Use this when set_property can't handle prefab references (which it can't, because prefabs are GameObjects not primitives).", {
261
+ id: z.string().describe("GUID of the GameObject holding the component"),
262
+ component: z.string().describe("Component type name"),
263
+ property: z.string().describe("Property name to set (must be GameObject-typed)"),
264
+ prefabPath: z.string().describe("Prefab asset path (e.g. 'prefabs/player.prefab')"),
265
+ }, async (params) => {
266
+ const res = await bridge.send("set_prefab_ref", params);
267
+ if (!res.success)
268
+ return { content: [{ type: "text", text: `Error: ${res.error}` }] };
269
+ return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
270
+ });
271
+ }
272
+ //# sourceMappingURL=world.js.map
@@ -0,0 +1,60 @@
1
+ /**
2
+ * File-based IPC transport for communicating with the s&box Bridge Addon.
3
+ *
4
+ * Instead of WebSocket, this uses a shared temp directory where:
5
+ * - MCP server writes request files (req_*.json)
6
+ * - s&box addon polls for them, processes, and writes response files (res_*.json)
7
+ * - MCP server polls for response files
8
+ */
9
+ /** A single command request sent to the s&box Bridge. */
10
+ export interface BridgeRequest {
11
+ id: string;
12
+ command: string;
13
+ params: Record<string, unknown>;
14
+ }
15
+ /** Response from the s&box Bridge. Check `success` before reading `data`. */
16
+ export interface BridgeResponse {
17
+ id: string;
18
+ success: boolean;
19
+ data?: unknown;
20
+ error?: string;
21
+ }
22
+ /**
23
+ * File-based IPC client that communicates with the s&box Bridge Addon.
24
+ */
25
+ export declare class BridgeClient {
26
+ private requestCounter;
27
+ private ipcDir;
28
+ private connected;
29
+ private lastPongTime;
30
+ private host;
31
+ private port;
32
+ static readonly POLL_INTERVAL_MS = 50;
33
+ static readonly STATUS_CHECK_INTERVAL_MS = 5000;
34
+ constructor(host?: string, port?: number);
35
+ /**
36
+ * Check if the s&box Bridge is running by looking for the status file.
37
+ */
38
+ connect(): Promise<void>;
39
+ /**
40
+ * Send a command to the s&box Bridge and wait for its response.
41
+ */
42
+ send(command: string, params?: Record<string, unknown>, timeoutMs?: number): Promise<BridgeResponse>;
43
+ /**
44
+ * Send multiple commands as a batch.
45
+ */
46
+ sendBatch(commands: Array<{
47
+ command: string;
48
+ params?: Record<string, unknown>;
49
+ }>, timeoutMs?: number): Promise<BridgeResponse>;
50
+ /**
51
+ * Check if bridge is alive by looking for status file.
52
+ */
53
+ ping(): Promise<number>;
54
+ isConnected(): boolean;
55
+ getHost(): string;
56
+ getPort(): number;
57
+ getLastPongTime(): number;
58
+ disconnect(): void;
59
+ }
60
+ //# sourceMappingURL=bridge-client.d.ts.map