dominus-cli 0.5.1 → 0.5.3

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
@@ -629,6 +629,84 @@ var init_ws_client = __esm({
629
629
  }
630
630
  });
631
631
 
632
+ // src/agent/internal-memory.ts
633
+ var INTERNAL_MEMORY;
634
+ var init_internal_memory = __esm({
635
+ "src/agent/internal-memory.ts"() {
636
+ INTERNAL_MEMORY = `## Internal Memory \u2014 Known Quirks & Lessons
637
+
638
+ These are built-in lessons that ship with Dominus. Follow them exactly.
639
+
640
+ ### create_ui \u2014 property format
641
+ - Each node accepts properties in **either** of two shapes:
642
+ - **Flattened (preferred)**: props as top-level keys next to \`ClassName\`, \`Name\`, \`Children\`.
643
+ \`\`\`json
644
+ { "ClassName": "TextButton", "Name": "Btn", "Text": "OK", "Size": [0, 100, 0, 40] }
645
+ \`\`\`
646
+ - **Nested bag**: props grouped under \`properties\` / \`Properties\` / \`props\` / \`Props\`.
647
+ \`\`\`json
648
+ { "ClassName": "TextButton", "Name": "Btn",
649
+ "properties": { "Text": "OK", "Size": [0, 100, 0, 40] } }
650
+ \`\`\`
651
+ - Do NOT mix a nested \`properties\` bag with flattened props of the same name \u2014 the bag wins.
652
+ - Reserved keys (never treated as instance properties): \`ClassName\`, \`className\`, \`Name\`, \`name\`, \`Children\`, \`children\`, \`properties\`, \`Properties\`, \`props\`, \`Props\`.
653
+
654
+ ### build_multiple \u2014 schema is strict
655
+ - Top-level keys only: \`name\`, \`className\`, \`position\`, \`size\`, \`color\`, \`material\`, \`anchored\`, \`shape\`, \`transparency\`, \`parent\`, \`canCollide\`.
656
+ - Does NOT accept a nested \`properties\` bag. For anything outside those fields use \`insert_instance\` + \`set_properties\`.
657
+ - \`shape\` values: \`Block\`, \`Ball\`, \`Cylinder\`, \`Wedge\`.
658
+
659
+ ### Color formats (accepted everywhere)
660
+ - Hex: \`"#RRGGBB"\`
661
+ - RGB string: \`"rgb(255, 128, 0)"\`
662
+ - BrickColor name: \`"Bright red"\`, \`"Institutional white"\`, \`"Really black"\`, etc.
663
+ - Array: \`[r, g, b]\` (0\u20131 floats) or \`[255, 128, 0]\` (auto-detected if any value > 1)
664
+
665
+ ### UDim2 / UDim / Vector2 / Color3 coercion (create_ui)
666
+ - UDim2: \`[xScale, xOffset, yScale, yOffset]\` or \`{XScale, XOffset, YScale, YOffset}\`.
667
+ - UDim: \`[scale, offset]\` or a plain number (treated as pixels).
668
+ - Vector2 (e.g. \`AnchorPoint\`): \`[x, y]\` or \`{x, y}\`.
669
+ - 2-element arrays are auto-disambiguated by property name (\`AnchorPoint\` \u2192 Vector2, \`CornerRadius\` \u2192 UDim).
670
+
671
+ ### Common GUI property names
672
+ - GUI uses \`Size\`/\`Position\` as **UDim2** \u2014 never Vector3.
673
+ - \`BackgroundColor3\`, \`TextColor3\`, \`BorderColor3\`, \`ImageColor3\` \u2192 Color3.
674
+ - \`Font\` accepts a string enum name like \`"GothamBold"\`, \`"SourceSans"\`.
675
+ - Enum properties take the string name: \`"Center"\`, \`"Left"\`, \`"Fit"\`.
676
+
677
+ ### Tool selection cheat-sheet
678
+ - Single 3D part \u2192 \`create_part\`
679
+ - Many 3D parts (tree, building, vehicle) \u2192 \`build_multiple\` with \`groupName\`
680
+ - Full UI tree \u2192 \`create_ui\` (one call, never loop \`insert_instance\` for UI)
681
+ - **Convert/export existing UI \u2192 \`serialize_ui\`** (NOT get_descendants_properties)
682
+ - Adjusting an existing instance \u2192 \`set_properties\` (not \`run_code\`)
683
+ - Anything exotic or procedural \u2192 \`run_code\` as last resort
684
+
685
+ ### Verification habits
686
+ - After a build, call \`get_explorer\` or \`get_selection\` to confirm the tree looks right.
687
+ - After editing a script, read it back.
688
+ - After \`run_code\`, check \`get_output\` for errors.
689
+
690
+ ### serialize_ui \u2014 the RIGHT tool for UI conversion
691
+ - **Use \`serialize_ui\` when converting existing UI to Roact/React/Fusion components.** It returns a minimal JSON tree with only non-default properties, already in JSON-friendly formats.
692
+ - **Do NOT use \`get_descendants_properties\` for UI conversion** \u2014 it returns a flat list with ~50+ properties per instance (including read-only, deprecated, nil, and default values), which bloats context and confuses conversion.
693
+ - \`serialize_ui\` output maps 1:1 to \`create_ui\` input \u2014 you can round-trip UI through it.
694
+ - The tree structure preserves parent-child hierarchy, so Roact/React children mapping is direct.
695
+
696
+ ### UI \u2192 Roact/React conversion cheat-sheet
697
+ - \`serialize_ui\` path \u2192 JSON tree \u2192 map each node to \`Roact.createElement(ClassName, props, childrenDict)\`
698
+ - UDim2 arrays \`[xS, xO, yS, yO]\` \u2192 \`UDim2.new(xS, xO, yS, yO)\`
699
+ - Color3 hex strings \u2192 \`Color3.fromHex("#RRGGBB")\`
700
+ - Vector2 arrays \u2192 \`Vector2.new(x, y)\`
701
+ - UDim arrays \u2192 \`UDim.new(s, o)\`
702
+ - Enum strings like \`"Center"\` \u2192 \`Enum.TextXAlignment.Center\`
703
+ - FontFace \u2192 \`Font.new(family, weight, style)\`
704
+ - UI modifiers (UICorner, UIStroke, UIGradient, UIListLayout, UIPadding) are CHILDREN not props
705
+ - Use instance Name as dictionary key in children table
706
+ `;
707
+ }
708
+ });
709
+
632
710
  // src/memory/store.ts
633
711
  var store_exports = {};
634
712
  __export(store_exports, {
@@ -1138,7 +1216,7 @@ var init_get_descendants_properties = __esm({
1138
1216
  init_protocol();
1139
1217
  tool6 = {
1140
1218
  name: "get_descendants_properties",
1141
- description: "Easily get all descendants of a UI instance (or any instance) and all of their properties.",
1219
+ description: "Easily get all descendants of a UI instance (or any instance) and all of their properties. By default uses compact mode which strips read-only, nil, deprecated, and default-valued properties to keep responses small.",
1142
1220
  parameters: {
1143
1221
  type: "object",
1144
1222
  properties: {
@@ -1146,6 +1224,10 @@ var init_get_descendants_properties = __esm({
1146
1224
  type: "string",
1147
1225
  description: 'Full instance path (e.g., "Workspace.Part", "StarterGui.ScreenGui")'
1148
1226
  },
1227
+ compact: {
1228
+ type: "boolean",
1229
+ description: "When true (default), strips read-only, nil, deprecated, and default-valued properties to massively reduce response size. Set to false for full property dump."
1230
+ },
1149
1231
  outputFile: {
1150
1232
  type: "string",
1151
1233
  description: "Optional file path to write the JSON result to, useful for very large trees where context limits apply."
@@ -1157,9 +1239,10 @@ var init_get_descendants_properties = __esm({
1157
1239
  if (!ctx.isStudioConnected()) {
1158
1240
  return { success: false, error: "Studio is not connected" };
1159
1241
  }
1242
+ const compact = params.compact !== false;
1160
1243
  const response = await ctx.sendToStudio(
1161
1244
  CliMsg.GET_DESCENDANTS_PROPERTIES,
1162
- { path: params.path },
1245
+ { path: params.path, compact },
1163
1246
  1e3 * 60 * 5
1164
1247
  // 5 minute timeout since getting ALL descendants can take a very long time
1165
1248
  );
@@ -1518,7 +1601,7 @@ var init_create_ui = __esm({
1518
1601
  },
1519
1602
  tree: {
1520
1603
  type: "object",
1521
- description: 'The root UI node. Each node has: ClassName (string), Name (string), any properties as key-value pairs, and Children (array of child nodes). Property values are auto-coerced:\n UDim2: [xScale, xOffset, yScale, yOffset] or {XScale, XOffset, YScale, YOffset}\n Color3: "#hex", "rgb(r,g,b)", [r,g,b], or BrickColor name\n UDim: [scale, offset] or number\n Vector2: [x, y] or {x, y} (auto-disambiguated from UDim by property name)\n NumberRange: [min, max] or number\n Rect: [minX, minY, maxX, maxY] or {MinX, MinY, MaxX, MaxY}\n Font: "GothamBold", "SourceSans", etc. (Enum.Font names)\n Enums: string name like "Center", "Left", "Fit"\n FontFace: {Family, Weight, Style}\n 2-element arrays are auto-disambiguated: AnchorPoint\u2192Vector2, CornerRadius/Padding\u2192UDim, etc.'
1604
+ description: 'The root UI node. Each node has: ClassName (string), Name (string), Children (array of child nodes), and properties. Properties may be specified either flattened at the top level of the node, OR nested under a "properties" / "Properties" / "props" key \u2014 both work. Property values are auto-coerced:\n UDim2: [xScale, xOffset, yScale, yOffset] or {XScale, XOffset, YScale, YOffset}\n Color3: "#hex", "rgb(r,g,b)", [r,g,b], or BrickColor name\n UDim: [scale, offset] or number\n Vector2: [x, y] or {x, y} (auto-disambiguated from UDim by property name)\n NumberRange: [min, max] or number\n Rect: [minX, minY, maxX, maxY] or {MinX, MinY, MaxX, MaxY}\n Font: "GothamBold", "SourceSans", etc. (Enum.Font names)\n Enums: string name like "Center", "Left", "Fit"\n FontFace: {Family, Weight, Style}\n 2-element arrays are auto-disambiguated: AnchorPoint\u2192Vector2, CornerRadius/Padding\u2192UDim, etc.'
1522
1605
  },
1523
1606
  animate: {
1524
1607
  type: "boolean",
@@ -2499,6 +2582,8 @@ async function startMcpServer() {
2499
2582
  const mcp = new McpServer({
2500
2583
  name: "dominus",
2501
2584
  version: "0.2.1"
2585
+ }, {
2586
+ instructions: INTERNAL_MEMORY
2502
2587
  });
2503
2588
  mcp.tool(
2504
2589
  "read_script",
@@ -2561,14 +2646,15 @@ async function startMcpServer() {
2561
2646
  );
2562
2647
  mcp.tool(
2563
2648
  "get_descendants_properties",
2564
- "Easily get all descendants of a UI instance (or any instance) and all of their properties.",
2649
+ "Easily get all descendants of a UI instance (or any instance) and all of their properties. By default uses compact mode which strips read-only, nil, deprecated, and default-valued properties to keep responses small.",
2565
2650
  {
2566
2651
  path: z.string().describe('Full instance path (e.g., "Workspace.Part", "StarterGui.ScreenGui")'),
2652
+ compact: z.boolean().optional().default(true).describe("Strip noisy/default properties (default true). Set false for full dump."),
2567
2653
  outputFile: z.string().optional().describe("Optional file path to write to prevent limit errors/timeouts")
2568
2654
  },
2569
- async ({ path: path5, outputFile }) => {
2655
+ async ({ path: path5, compact, outputFile }) => {
2570
2656
  assertConnected();
2571
- const res = await bridge.sendRequest(CliMsg.GET_DESCENDANTS_PROPERTIES, { path: path5, outputFile }, 1e3 * 60 * 5);
2657
+ const res = await bridge.sendRequest(CliMsg.GET_DESCENDANTS_PROPERTIES, { path: path5, compact, outputFile }, 1e3 * 60 * 5);
2572
2658
  return { content: [{ type: "text", text: JSON.stringify(res.payload, null, 2) }] };
2573
2659
  }
2574
2660
  );
@@ -2885,6 +2971,26 @@ async function startMcpServer() {
2885
2971
  return { content: [{ type: "text", text: JSON.stringify(res.payload, null, 2) }] };
2886
2972
  }
2887
2973
  );
2974
+ mcp.tool(
2975
+ "serialize_ui",
2976
+ "Serialize an existing Roblox UI tree into a compact, create_ui-compatible JSON tree. This is the reverse of create_ui \u2014 reads any GUI instance and returns a declarative JSON tree with ClassName, Name, non-default properties (Color3 as hex, UDim2 as arrays, etc.), and Children. Perfect for: converting existing UI to Roact/React components, cloning/templating, understanding UI structure, or refactoring. Use this INSTEAD of get_descendants_properties when you need to recreate or convert UI.",
2977
+ {
2978
+ path: z.string().describe('Instance path to serialize (e.g. "StarterGui.MyScreenGui")'),
2979
+ maxDepth: z.number().optional().default(50).describe("Maximum tree depth (default 50)")
2980
+ },
2981
+ async ({ path: path5, maxDepth }) => {
2982
+ assertConnected();
2983
+ const res = await bridge.sendRequest(
2984
+ CliMsg.SERIALIZE_UI,
2985
+ { path: path5, maxDepth },
2986
+ 1e3 * 60 * 2
2987
+ );
2988
+ if (!res.payload.success) {
2989
+ return { content: [{ type: "text", text: `Error: ${res.payload.error ?? "Serialization failed"}` }] };
2990
+ }
2991
+ return { content: [{ type: "text", text: JSON.stringify(res.payload.tree, null, 2) }] };
2992
+ }
2993
+ );
2888
2994
  mcp.tool(
2889
2995
  "recall_memory",
2890
2996
  "Search persistent memory for facts about the current Roblox project",
@@ -2951,6 +3057,7 @@ var init_server = __esm({
2951
3057
  init_protocol();
2952
3058
  init_store();
2953
3059
  init_config();
3060
+ init_internal_memory();
2954
3061
  }
2955
3062
  });
2956
3063
  var CROWN_ART = ` \u25C6 \u25C6 \u25C6
@@ -4132,6 +4239,7 @@ function toolToOpenAI(tool29) {
4132
4239
  }
4133
4240
 
4134
4241
  // src/agent/system-prompt.ts
4242
+ init_internal_memory();
4135
4243
  function buildSystemPrompt(opts) {
4136
4244
  const parts = [];
4137
4245
  parts.push(`You are Dominus, an expert AI agent for Roblox Studio development.
@@ -4283,6 +4391,66 @@ GUI classes use DIFFERENT property types than 3D parts:
4283
4391
  - All enum properties from string names
4284
4392
  - Color3 from hex "#RRGGBB", "rgb(r,g,b)", or BrickColor name strings
4285
4393
 
4394
+ ## Serializing & Converting Existing UI
4395
+ When the user asks to convert, export, recreate, or turn an existing UI into a React/Roact component:
4396
+
4397
+ **Use \`serialize_ui\` \u2014 NOT \`get_descendants_properties\`.**
4398
+ \`serialize_ui\` returns a clean, minimal JSON tree with only non-default properties, values already in JSON-friendly formats (hex colors, UDim2 arrays, enum names), and a proper parent-child hierarchy. It's purpose-built for this exact workflow.
4399
+
4400
+ \`get_descendants_properties\` returns a flat list with ALL properties (including read-only, defaults, deprecated) \u2014 it's much larger and harder to convert.
4401
+
4402
+ ### Roblox UI \u2192 Roact/React Conversion Workflow
4403
+ 1. Call \`serialize_ui\` with the path (e.g. \`StarterGui.MyScreenGui.MyFrame\`)
4404
+ 2. The result is a tree like:
4405
+ \`\`\`json
4406
+ {
4407
+ "ClassName": "Frame", "Name": "MyFrame",
4408
+ "Size": [0.5, 0, 0.3, 0], "BackgroundColor3": "#1a1a2e",
4409
+ "Children": [
4410
+ { "ClassName": "UICorner", "CornerRadius": [0, 8] },
4411
+ { "ClassName": "TextLabel", "Name": "Title", "Text": "Hello",
4412
+ "Size": [1, 0, 0.2, 0], "TextColor3": "#ffffff", "BackgroundTransparency": 1 }
4413
+ ]
4414
+ }
4415
+ \`\`\`
4416
+ 3. Convert to Roact/React-lua using these mappings:
4417
+ - Each JSON node \u2192 \`Roact.createElement(ClassName, props, children)\` or \`React.createElement\`
4418
+ - \`UDim2\` arrays \`[xS, xO, yS, yO]\` \u2192 \`UDim2.new(xS, xO, yS, yO)\`
4419
+ - \`Color3\` hex \`"#RRGGBB"\` \u2192 \`Color3.fromHex("#RRGGBB")\`
4420
+ - \`Vector2\` arrays \`[x, y]\` \u2192 \`Vector2.new(x, y)\`
4421
+ - \`UDim\` arrays \`[s, o]\` \u2192 \`UDim.new(s, o)\`
4422
+ - Enum strings \`"Center"\` \u2192 \`Enum.TextXAlignment.Center\` (resolve the full enum path)
4423
+ - \`Children\` array \u2192 child elements table
4424
+ - UI modifiers (UICorner, UIStroke, UIGradient, UIListLayout, UIPadding, UIScale) \u2192 children of the parent element
4425
+
4426
+ ### Example Roact output:
4427
+ \`\`\`lua
4428
+ local function MyFrame()
4429
+ return Roact.createElement("Frame", {
4430
+ Size = UDim2.new(0.5, 0, 0.3, 0),
4431
+ BackgroundColor3 = Color3.fromHex("#1a1a2e"),
4432
+ }, {
4433
+ Corner = Roact.createElement("UICorner", {
4434
+ CornerRadius = UDim.new(0, 8),
4435
+ }),
4436
+ Title = Roact.createElement("TextLabel", {
4437
+ Size = UDim2.new(1, 0, 0.2, 0),
4438
+ Text = "Hello",
4439
+ TextColor3 = Color3.fromHex("#ffffff"),
4440
+ BackgroundTransparency = 1,
4441
+ }),
4442
+ })
4443
+ end
4444
+ \`\`\`
4445
+
4446
+ ### Key rules for conversion:
4447
+ - Use the instance \`Name\` as the dictionary key in the children table
4448
+ - UI modifiers (UICorner, UIStroke, etc.) are CHILDREN, not props
4449
+ - Keep the exact property values from serialize_ui \u2014 don't guess or approximate
4450
+ - For Fusion: \`New "Frame" { Size = UDim2.new(...), [Children] = { ... } }\`
4451
+ - Preserve ZIndex ordering when relevant
4452
+ - FontFace objects \u2192 \`Font.new("rbxasset://fonts/families/...", Enum.FontWeight.Bold)\`
4453
+
4286
4454
  ## ReflectionService
4287
4455
  The \`get_class_info\` tool queries Roblox's ReflectionService to return the complete API surface for any class:
4288
4456
  - All properties with their exact ValueType
@@ -4290,7 +4458,9 @@ The \`get_class_info\` tool queries Roblox's ReflectionService to return the com
4290
4458
  - All events with parameter types
4291
4459
  - Superclass, creatability, serialization info
4292
4460
 
4293
- Use it whenever you're unsure about property names or types. It's fast and cached.`);
4461
+ Use it whenever you're unsure about property names or types. It's fast and cached.
4462
+
4463
+ ${INTERNAL_MEMORY}`);
4294
4464
  return parts.join("\n");
4295
4465
  }
4296
4466