dominus-cli 0.5.5 → 0.5.7

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/index.js CHANGED
@@ -680,8 +680,20 @@ These are built-in lessons that ship with Dominus. Follow them exactly.
680
680
  - Full UI tree \u2192 \`create_ui\` (one call, never loop \`insert_instance\` for UI)
681
681
  - **Convert/export existing UI \u2192 \`serialize_ui\`** (NOT get_descendants_properties)
682
682
  - Adjusting an existing instance \u2192 \`set_properties\` (not \`run_code\`)
683
+ - **Inspecting user's selection \u2192 \`get_selection\`, then \`get_properties\` or \`serialize_ui\`**
684
+ - **Reading properties \u2192 \`get_properties\` (NEVER \`run_code\` with dump scripts)**
685
+ - **Browsing the tree \u2192 \`get_explorer\`**
683
686
  - Anything exotic or procedural \u2192 \`run_code\` as last resort
684
687
 
688
+ ### NEVER use run_code for:
689
+ - Getting properties of an instance \u2192 use \`get_properties\` or \`serialize_ui\`
690
+ - Dumping selection info \u2192 use \`get_selection\` + \`get_properties\`
691
+ - Creating instances \u2192 use \`create_part\`, \`create_ui\`, \`insert_instance\`, \`build_multiple\`
692
+ - Modifying properties \u2192 use \`set_properties\` or \`bulk_set_properties\`
693
+ - Reading scripts \u2192 use \`read_script\`
694
+ - Browsing the explorer \u2192 use \`get_explorer\`
695
+ \`run_code\` is ONLY for procedural logic, terrain generation, raycasts, physics queries, or custom algorithms with no tool equivalent.
696
+
685
697
  ### Verification habits
686
698
  - After a build, call \`get_explorer\` or \`get_selection\` to confirm the tree looks right.
687
699
  - After editing a script, read it back.
@@ -2624,7 +2636,7 @@ async function startMcpServer() {
2624
2636
  );
2625
2637
  mcp.tool(
2626
2638
  "run_code",
2627
- "Execute Luau code in Roblox Studio and return output",
2639
+ "Execute arbitrary Luau code in Roblox Studio. LAST RESORT \u2014 only use when no dedicated tool exists. Do NOT use for: reading properties (use get_properties/get_selection/serialize_ui), creating instances (use create_part/create_ui/insert_instance/build_multiple), modifying properties (use set_properties/bulk_set_properties), or inspecting the tree (use get_explorer). Valid uses: complex procedural generation, terrain algorithms, raycasting, custom logic with no tool equivalent.",
2628
2640
  { code: z.string().describe("Luau code to execute") },
2629
2641
  async ({ code }) => {
2630
2642
  assertConnected();
@@ -2720,7 +2732,7 @@ async function startMcpServer() {
2720
2732
  );
2721
2733
  mcp.tool(
2722
2734
  "get_selection",
2723
- "Get the currently selected instances in Roblox Studio",
2735
+ 'Get the currently selected instances in Roblox Studio. Returns paths and class names of all selected objects. Use this FIRST when the user says "my selection" or "what I have selected". Then use get_properties or serialize_ui on the returned paths to inspect details.',
2724
2736
  {},
2725
2737
  async () => {
2726
2738
  assertConnected();
@@ -2995,184 +3007,6 @@ async function startMcpServer() {
2995
3007
  return { content: [{ type: "text", text: JSON.stringify(res.payload.tree, null, 2) }] };
2996
3008
  }
2997
3009
  );
2998
- mcp.tool(
2999
- "move_instance",
3000
- "Move (reparent) an instance to a new parent in Roblox Studio. Preserves the instance and all descendants \u2014 much better than delete + recreate. Sets a ChangeHistoryService waypoint so the move can be undone.",
3001
- {
3002
- path: z.string().describe('Full path of the instance to move (e.g. "Workspace.OldFolder.MyPart")'),
3003
- newParent: z.string().describe('Full path of the new parent (e.g. "Workspace.NewFolder")')
3004
- },
3005
- async ({ path: path5, newParent }) => {
3006
- assertConnected();
3007
- const res = await bridge.sendRequest(
3008
- CliMsg.MOVE_INSTANCE,
3009
- { path: path5, newParent }
3010
- );
3011
- return { content: [{ type: "text", text: JSON.stringify(res.payload, null, 2) }] };
3012
- }
3013
- );
3014
- mcp.tool(
3015
- "bulk_set_properties",
3016
- "Set properties on multiple instances at once in a single call. Much faster than calling set_properties repeatedly. Two modes:\n1. Explicit: provide targets array of {path, properties} objects\n2. Filter: provide root + className + properties to apply to all matches",
3017
- {
3018
- targets: z.array(z.object({
3019
- path: z.string(),
3020
- properties: z.record(z.unknown())
3021
- })).optional().describe("Array of {path, properties} for explicit mode"),
3022
- root: z.string().optional().describe("Root path to search under (filter mode)"),
3023
- className: z.string().optional().describe("Only apply to instances of this ClassName (filter mode)"),
3024
- properties: z.record(z.unknown()).optional().describe("Properties to set on all matches (filter mode)")
3025
- },
3026
- async (params) => {
3027
- assertConnected();
3028
- const res = await bridge.sendRequest(
3029
- CliMsg.BULK_SET_PROPERTIES,
3030
- {
3031
- targets: params.targets,
3032
- root: params.root,
3033
- className: params.className,
3034
- properties: params.properties
3035
- },
3036
- 1e3 * 60
3037
- );
3038
- return { content: [{ type: "text", text: JSON.stringify(res.payload, null, 2) }] };
3039
- }
3040
- );
3041
- mcp.tool(
3042
- "find_replace_scripts",
3043
- "Find and replace text across all scripts in the game (or under a root path). Supports plain text and Lua patterns. Use dryRun=true to preview changes without applying.",
3044
- {
3045
- find: z.string().describe("Text or Lua pattern to search for"),
3046
- replace: z.string().describe("Replacement text (supports Lua pattern captures like %1, %2)"),
3047
- root: z.string().optional().describe("Root path to limit search scope (optional)"),
3048
- usePattern: z.boolean().optional().default(false).describe("Treat find/replace as Lua patterns"),
3049
- dryRun: z.boolean().optional().default(false).describe("Preview matches without modifying scripts")
3050
- },
3051
- async (params) => {
3052
- assertConnected();
3053
- const res = await bridge.sendRequest(
3054
- CliMsg.FIND_REPLACE_SCRIPTS,
3055
- {
3056
- find: params.find,
3057
- replace: params.replace,
3058
- root: params.root,
3059
- usePattern: params.usePattern,
3060
- dryRun: params.dryRun
3061
- },
3062
- 1e3 * 60 * 5
3063
- );
3064
- return { content: [{ type: "text", text: JSON.stringify(res.payload, null, 2) }] };
3065
- }
3066
- );
3067
- mcp.tool(
3068
- "undo",
3069
- "Undo the last action in Roblox Studio (ChangeHistoryService). Works like Ctrl+Z. Use to roll back mistakes.",
3070
- {},
3071
- async () => {
3072
- assertConnected();
3073
- const res = await bridge.sendRequest(CliMsg.UNDO, {});
3074
- return { content: [{ type: "text", text: JSON.stringify(res.payload) }] };
3075
- }
3076
- );
3077
- mcp.tool(
3078
- "redo",
3079
- "Redo the last undone action in Roblox Studio (ChangeHistoryService). Works like Ctrl+Y.",
3080
- {},
3081
- async () => {
3082
- assertConnected();
3083
- const res = await bridge.sendRequest(CliMsg.REDO, {});
3084
- return { content: [{ type: "text", text: JSON.stringify(res.payload) }] };
3085
- }
3086
- );
3087
- mcp.tool(
3088
- "move_instance",
3089
- "Move (reparent) an instance to a new parent in Roblox Studio. Preserves the instance and all descendants \u2014 much better than delete + recreate. Sets a ChangeHistoryService waypoint so the move can be undone.",
3090
- {
3091
- path: z.string().describe('Full path of the instance to move (e.g. "Workspace.OldFolder.MyPart")'),
3092
- newParent: z.string().describe('Full path of the new parent (e.g. "Workspace.NewFolder")')
3093
- },
3094
- async ({ path: path5, newParent }) => {
3095
- assertConnected();
3096
- const res = await bridge.sendRequest(
3097
- CliMsg.MOVE_INSTANCE,
3098
- { path: path5, newParent }
3099
- );
3100
- return { content: [{ type: "text", text: JSON.stringify(res.payload, null, 2) }] };
3101
- }
3102
- );
3103
- mcp.tool(
3104
- "bulk_set_properties",
3105
- "Set properties on multiple instances at once in a single call. Much faster than calling set_properties repeatedly. Two modes:\n1. Explicit: provide targets array of {path, properties} objects\n2. Filter: provide root + className + properties to apply to all matches",
3106
- {
3107
- targets: z.array(z.object({
3108
- path: z.string(),
3109
- properties: z.record(z.unknown())
3110
- })).optional().describe("Array of {path, properties} for explicit mode"),
3111
- root: z.string().optional().describe("Root path to search under (filter mode)"),
3112
- className: z.string().optional().describe("Only apply to instances of this ClassName (filter mode)"),
3113
- properties: z.record(z.unknown()).optional().describe("Properties to set on all matches (filter mode)")
3114
- },
3115
- async (params) => {
3116
- assertConnected();
3117
- const res = await bridge.sendRequest(
3118
- CliMsg.BULK_SET_PROPERTIES,
3119
- {
3120
- targets: params.targets,
3121
- root: params.root,
3122
- className: params.className,
3123
- properties: params.properties
3124
- },
3125
- 1e3 * 60
3126
- );
3127
- return { content: [{ type: "text", text: JSON.stringify(res.payload, null, 2) }] };
3128
- }
3129
- );
3130
- mcp.tool(
3131
- "find_replace_scripts",
3132
- "Find and replace text across all scripts in the game (or under a root path). Supports plain text and Lua patterns. Use dryRun=true to preview changes without applying.",
3133
- {
3134
- find: z.string().describe("Text or Lua pattern to search for"),
3135
- replace: z.string().describe("Replacement text (supports Lua pattern captures like %1, %2)"),
3136
- root: z.string().optional().describe("Root path to limit search scope (optional)"),
3137
- usePattern: z.boolean().optional().default(false).describe("Treat find/replace as Lua patterns"),
3138
- dryRun: z.boolean().optional().default(false).describe("Preview matches without modifying scripts")
3139
- },
3140
- async (params) => {
3141
- assertConnected();
3142
- const res = await bridge.sendRequest(
3143
- CliMsg.FIND_REPLACE_SCRIPTS,
3144
- {
3145
- find: params.find,
3146
- replace: params.replace,
3147
- root: params.root,
3148
- usePattern: params.usePattern,
3149
- dryRun: params.dryRun
3150
- },
3151
- 1e3 * 60 * 5
3152
- );
3153
- return { content: [{ type: "text", text: JSON.stringify(res.payload, null, 2) }] };
3154
- }
3155
- );
3156
- mcp.tool(
3157
- "undo",
3158
- "Undo the last action in Roblox Studio (ChangeHistoryService). Works like Ctrl+Z. Use to roll back mistakes.",
3159
- {},
3160
- async () => {
3161
- assertConnected();
3162
- const res = await bridge.sendRequest(CliMsg.UNDO, {});
3163
- return { content: [{ type: "text", text: JSON.stringify(res.payload) }] };
3164
- }
3165
- );
3166
- mcp.tool(
3167
- "redo",
3168
- "Redo the last undone action in Roblox Studio (ChangeHistoryService). Works like Ctrl+Y.",
3169
- {},
3170
- async () => {
3171
- assertConnected();
3172
- const res = await bridge.sendRequest(CliMsg.REDO, {});
3173
- return { content: [{ type: "text", text: JSON.stringify(res.payload) }] };
3174
- }
3175
- );
3176
3010
  mcp.tool(
3177
3011
  "recall_memory",
3178
3012
  "Search persistent memory for facts about the current Roblox project",
@@ -4437,10 +4271,22 @@ You are deeply knowledgeable about:
4437
4271
 
4438
4272
  You have direct access to Roblox Studio through tools. You can read/edit scripts, run code, browse the explorer tree, manage instances, and run tests -- all in real-time via WebSocket.
4439
4273
 
4274
+ ## CRITICAL: NEVER use run_code for tasks that have a dedicated tool
4275
+ run_code is a LAST RESORT. You have 30+ specialized tools \u2014 use them.
4276
+ - Reading properties \u2192 get_properties, get_selection, get_descendants_properties
4277
+ - Inspecting selection \u2192 get_selection (returns paths), then get_properties or serialize_ui
4278
+ - Creating parts \u2192 create_part, build_multiple
4279
+ - Creating UI \u2192 create_ui
4280
+ - Modifying properties \u2192 set_properties, bulk_set_properties
4281
+ - Browsing the tree \u2192 get_explorer
4282
+ - Reading/editing scripts \u2192 read_script, edit_script
4283
+ - Converting UI \u2192 serialize_ui
4284
+ Only use run_code for: procedural generation, terrain algorithms, raycasting, physics queries, or other logic that no tool covers.
4285
+
4440
4286
  When the user asks you to do something, you should:
4441
4287
  1. Use your tools to gather context (read scripts, check explorer, recall memory)
4442
4288
  2. Plan your approach for complex tasks
4443
- 3. Execute changes using your tools (edit scripts, run code, insert instances)
4289
+ 3. Execute changes using the appropriate dedicated tools (NOT run_code unless truly necessary)
4444
4290
  4. Verify your changes worked (read back, check output for errors)
4445
4291
  5. Remember important facts for future sessions`);
4446
4292
  if (opts.connected) {