dominus-cli 0.5.0 → 0.5.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/index.js CHANGED
@@ -19,6 +19,7 @@ import { randomBytes } from 'crypto';
19
19
  import Spinner from 'ink-spinner';
20
20
  import OpenAI from 'openai';
21
21
  import https from 'https';
22
+ import { fileURLToPath } from 'url';
22
23
 
23
24
  var __defProp = Object.defineProperty;
24
25
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -628,6 +629,66 @@ var init_ws_client = __esm({
628
629
  }
629
630
  });
630
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
+ - Adjusting an existing instance \u2192 \`set_properties\` (not \`run_code\`)
682
+ - Anything exotic or procedural \u2192 \`run_code\` as last resort
683
+
684
+ ### Verification habits
685
+ - After a build, call \`get_explorer\` or \`get_selection\` to confirm the tree looks right.
686
+ - After editing a script, read it back.
687
+ - After \`run_code\`, check \`get_output\` for errors.
688
+ `;
689
+ }
690
+ });
691
+
631
692
  // src/memory/store.ts
632
693
  var store_exports = {};
633
694
  __export(store_exports, {
@@ -1517,7 +1578,7 @@ var init_create_ui = __esm({
1517
1578
  },
1518
1579
  tree: {
1519
1580
  type: "object",
1520
- 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.'
1581
+ 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.'
1521
1582
  },
1522
1583
  animate: {
1523
1584
  type: "boolean",
@@ -2498,6 +2559,8 @@ async function startMcpServer() {
2498
2559
  const mcp = new McpServer({
2499
2560
  name: "dominus",
2500
2561
  version: "0.2.1"
2562
+ }, {
2563
+ instructions: INTERNAL_MEMORY
2501
2564
  });
2502
2565
  mcp.tool(
2503
2566
  "read_script",
@@ -2950,6 +3013,7 @@ var init_server = __esm({
2950
3013
  init_protocol();
2951
3014
  init_store();
2952
3015
  init_config();
3016
+ init_internal_memory();
2953
3017
  }
2954
3018
  });
2955
3019
  var CROWN_ART = ` \u25C6 \u25C6 \u25C6
@@ -4131,6 +4195,7 @@ function toolToOpenAI(tool29) {
4131
4195
  }
4132
4196
 
4133
4197
  // src/agent/system-prompt.ts
4198
+ init_internal_memory();
4134
4199
  function buildSystemPrompt(opts) {
4135
4200
  const parts = [];
4136
4201
  parts.push(`You are Dominus, an expert AI agent for Roblox Studio development.
@@ -4289,7 +4354,9 @@ The \`get_class_info\` tool queries Roblox's ReflectionService to return the com
4289
4354
  - All events with parameter types
4290
4355
  - Superclass, creatability, serialization info
4291
4356
 
4292
- Use it whenever you're unsure about property names or types. It's fast and cached.`);
4357
+ Use it whenever you're unsure about property names or types. It's fast and cached.
4358
+
4359
+ ${INTERNAL_MEMORY}`);
4293
4360
  return parts.join("\n");
4294
4361
  }
4295
4362
 
@@ -4751,7 +4818,62 @@ function formatUpdateMessage(info) {
4751
4818
  ""
4752
4819
  ].join("\n");
4753
4820
  }
4754
- var VERSION = "0.2.1";
4821
+ async function autoUpdate(currentVersion) {
4822
+ const info = await checkForUpdate(currentVersion);
4823
+ if (!info?.updateAvailable) {
4824
+ return { success: true, from: currentVersion, to: currentVersion };
4825
+ }
4826
+ const managers = [
4827
+ { name: "pnpm", check: "pnpm list -g dominus-cli", cmd: "pnpm add -g dominus-cli@latest" },
4828
+ { name: "npm", check: "npm list -g dominus-cli", cmd: "npm install -g dominus-cli@latest" },
4829
+ { name: "yarn", check: "yarn global list --pattern dominus-cli", cmd: "yarn global add dominus-cli@latest" }
4830
+ ];
4831
+ let installCmd = null;
4832
+ for (const mgr of managers) {
4833
+ try {
4834
+ const out = execSync(mgr.check, { stdio: "pipe", timeout: 1e4 }).toString();
4835
+ if (out.includes("dominus-cli")) {
4836
+ installCmd = mgr.cmd;
4837
+ break;
4838
+ }
4839
+ } catch {
4840
+ }
4841
+ }
4842
+ if (!installCmd) {
4843
+ try {
4844
+ const out = execSync("pnpm list -g dominus-cli", { stdio: "pipe", timeout: 1e4 }).toString();
4845
+ if (out.includes("link:")) {
4846
+ const pkgPath = path4.resolve(__dirname$1, "..");
4847
+ if (fs5.existsSync(path4.join(pkgPath, ".git"))) {
4848
+ try {
4849
+ execSync("git pull", { cwd: pkgPath, stdio: "pipe", timeout: 3e4 });
4850
+ execSync("pnpm install", { cwd: pkgPath, stdio: "pipe", timeout: 6e4 });
4851
+ execSync("pnpm build", { cwd: pkgPath, stdio: "pipe", timeout: 6e4 });
4852
+ execSync("pnpm build:plugin", { cwd: pkgPath, stdio: "pipe", timeout: 3e4 });
4853
+ return { success: true, from: currentVersion, to: info.latestVersion };
4854
+ } catch (err) {
4855
+ return { success: false, from: currentVersion, to: info.latestVersion, error: `Git pull/rebuild failed: ${err}` };
4856
+ }
4857
+ }
4858
+ return { success: false, from: currentVersion, to: info.latestVersion, error: 'Linked install without git \u2014 run "pnpm build" manually in the repo' };
4859
+ }
4860
+ } catch {
4861
+ }
4862
+ }
4863
+ if (!installCmd) {
4864
+ installCmd = `npm install -g ${NPM_PACKAGE}@latest`;
4865
+ }
4866
+ try {
4867
+ execSync(installCmd, { stdio: "pipe", timeout: 12e4 });
4868
+ writeCache({ lastCheck: 0, latestVersion: null });
4869
+ return { success: true, from: currentVersion, to: info.latestVersion };
4870
+ } catch (err) {
4871
+ return { success: false, from: currentVersion, to: info.latestVersion, error: `Update command failed: ${err}` };
4872
+ }
4873
+ }
4874
+ var __dirname$1 = path4.dirname(new URL(import.meta.url).pathname.replace(/^\/([A-Z]:)/, "$1"));
4875
+ var __dirname2 = path4.dirname(fileURLToPath(import.meta.url));
4876
+ var VERSION = JSON.parse(fs5.readFileSync(path4.join(__dirname2, "..", "package.json"), "utf-8")).version;
4755
4877
  var program = new Command();
4756
4878
  program.name("dominus").description("AI-powered autonomous agent for Roblox Studio development").version(VERSION);
4757
4879
  program.command("start", { isDefault: true }).description("Launch the Dominus TUI agent").option("-p, --port <port>", "WebSocket server port", "18088").action(async (opts) => {
@@ -4863,9 +4985,24 @@ rulesCmd.command("list").description("List all rules").action(() => {
4863
4985
  }
4864
4986
  console.log("");
4865
4987
  });
4988
+ program.command("update").description("Auto-update Dominus to the latest version").action(async () => {
4989
+ console.log(` Current version: ${VERSION}`);
4990
+ console.log(" Checking for updates...");
4991
+ const result = await autoUpdate(VERSION);
4992
+ if (result.from === result.to && result.success) {
4993
+ console.log(" Already on the latest version.");
4994
+ return;
4995
+ }
4996
+ if (result.success) {
4997
+ console.log(` \u2714 Updated: ${result.from} \u2192 ${result.to}`);
4998
+ console.log(" Restart dominus to use the new version.");
4999
+ } else {
5000
+ console.error(` \u2718 Update failed: ${result.error}`);
5001
+ }
5002
+ });
4866
5003
  program.command("install-plugin").description("Build & install the Dominus plugin into Roblox Studio").action(async () => {
4867
- const { execSync: execSync2 } = await import('child_process');
4868
- const packageRoot = path4.resolve(import.meta.dirname ?? __dirname, "..");
5004
+ const { execSync: execSync3 } = await import('child_process');
5005
+ const packageRoot = path4.resolve(import.meta.dirname ?? __dirname2, "..");
4869
5006
  const pluginDir = path4.join(packageRoot, "plugin");
4870
5007
  const pluginProject = path4.join(pluginDir, "default.project.json");
4871
5008
  const studioPlugins = path4.join(
@@ -4886,14 +5023,14 @@ program.command("install-plugin").description("Build & install the Dominus plugi
4886
5023
  }
4887
5024
  let rojoAvailable = false;
4888
5025
  try {
4889
- execSync2("rojo --version", { stdio: "pipe" });
5026
+ execSync3("rojo --version", { stdio: "pipe" });
4890
5027
  rojoAvailable = true;
4891
5028
  } catch {
4892
5029
  }
4893
5030
  if (rojoAvailable) {
4894
5031
  try {
4895
5032
  console.log(" Building plugin with Rojo...");
4896
- execSync2(`rojo build "${pluginDir}" -o "${destFile}"`, { stdio: "pipe" });
5033
+ execSync3(`rojo build "${pluginDir}" -o "${destFile}"`, { stdio: "pipe" });
4897
5034
  console.log(` \u2714 Plugin built and installed to: ${destFile}`);
4898
5035
  console.log(" Restart Roblox Studio to load the plugin.");
4899
5036
  } catch (err) {