uloop-cli 0.46.0 → 0.47.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "uloop-cli",
3
- "version": "0.46.0",
3
+ "version": "0.47.0",
4
4
  "//version": "x-release-please-version",
5
5
  "description": "CLI tool for Unity Editor communication via uLoopMCP",
6
6
  "main": "dist/cli.bundle.cjs",
@@ -9,7 +9,8 @@
9
9
  },
10
10
  "type": "module",
11
11
  "scripts": {
12
- "build": "esbuild src/cli.ts --bundle --platform=node --format=cjs --outfile=dist/cli.bundle.cjs --sourcemap --banner:js='#!/usr/bin/env node' --loader:.md=text",
12
+ "generate-skills": "npx tsx scripts/generate-bundled-skills.ts",
13
+ "build": "npm run generate-skills && esbuild src/cli.ts --bundle --platform=node --format=cjs --outfile=dist/cli.bundle.cjs --sourcemap --banner:js='#!/usr/bin/env node' --loader:.md=text",
13
14
  "lint": "eslint src",
14
15
  "lint:fix": "eslint src --fix",
15
16
  "format": "prettier --write src/**/*.ts",
@@ -46,6 +47,7 @@
46
47
  },
47
48
  "devDependencies": {
48
49
  "@eslint/js": "9.39.2",
50
+ "tsx": "4.19.0",
49
51
  "@types/jest": "30.0.0",
50
52
  "@types/node": "25.0.2",
51
53
  "@types/semver": "^7.7.1",
@@ -0,0 +1,159 @@
1
+ /**
2
+ * Auto-generates bundled-skills.ts from skill-definitions directory.
3
+ * Scans all SKILL.md files and generates import statements and BUNDLED_SKILLS array.
4
+ * Skills with `internal: true` in frontmatter are excluded from generation.
5
+ *
6
+ * Usage: npx tsx scripts/generate-bundled-skills.ts
7
+ */
8
+
9
+ import { readdirSync, readFileSync, writeFileSync, existsSync } from 'fs';
10
+ import { join, dirname } from 'path';
11
+ import { fileURLToPath } from 'url';
12
+
13
+ const __filename = fileURLToPath(import.meta.url);
14
+ const __dirname = dirname(__filename);
15
+
16
+ const SKILL_DEFINITIONS_DIR = join(__dirname, '../src/skills/skill-definitions');
17
+ const OUTPUT_FILE = join(__dirname, '../src/skills/bundled-skills.ts');
18
+
19
+ interface SkillMetadata {
20
+ dirName: string;
21
+ name: string;
22
+ isInternal: boolean;
23
+ }
24
+
25
+ function parseFrontmatter(content: string): Record<string, string | boolean> {
26
+ const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
27
+ if (!frontmatterMatch) {
28
+ return {};
29
+ }
30
+
31
+ const frontmatter: Record<string, string | boolean> = {};
32
+ const lines = frontmatterMatch[1].split('\n');
33
+
34
+ for (const line of lines) {
35
+ const colonIndex = line.indexOf(':');
36
+ if (colonIndex === -1) {
37
+ continue;
38
+ }
39
+
40
+ const key = line.slice(0, colonIndex).trim();
41
+ const value = line.slice(colonIndex + 1).trim();
42
+
43
+ if (value === 'true') {
44
+ frontmatter[key] = true;
45
+ } else if (value === 'false') {
46
+ frontmatter[key] = false;
47
+ } else {
48
+ frontmatter[key] = value;
49
+ }
50
+ }
51
+
52
+ return frontmatter;
53
+ }
54
+
55
+ function getSkillMetadata(dirName: string): SkillMetadata | null {
56
+ const skillPath = join(SKILL_DEFINITIONS_DIR, dirName, 'SKILL.md');
57
+
58
+ if (!existsSync(skillPath)) {
59
+ return null;
60
+ }
61
+
62
+ const content = readFileSync(skillPath, 'utf-8');
63
+ const frontmatter = parseFrontmatter(content);
64
+
65
+ const name = typeof frontmatter.name === 'string' ? frontmatter.name : dirName;
66
+ const isInternal = frontmatter.internal === true;
67
+
68
+ return { dirName, name, isInternal };
69
+ }
70
+
71
+ function toVariableName(dirName: string): string {
72
+ return dirName
73
+ .replace(/^uloop-/, '')
74
+ .replace(/-([a-z])/g, (_, char) => char.toUpperCase())
75
+ .concat('Skill');
76
+ }
77
+
78
+ function generateBundledSkillsFile(skills: SkillMetadata[]): string {
79
+ const imports = skills
80
+ .map((skill) => {
81
+ const varName = toVariableName(skill.dirName);
82
+ return `import ${varName} from './skill-definitions/${skill.dirName}/SKILL.md';`;
83
+ })
84
+ .join('\n');
85
+
86
+ const entries = skills
87
+ .map((skill) => {
88
+ const varName = toVariableName(skill.dirName);
89
+ return ` {
90
+ name: '${skill.name}',
91
+ dirName: '${skill.dirName}',
92
+ content: ${varName},
93
+ },`;
94
+ })
95
+ .join('\n');
96
+
97
+ return `/**
98
+ * AUTO-GENERATED FILE - DO NOT EDIT MANUALLY
99
+ * Generated by: scripts/generate-bundled-skills.ts
100
+ *
101
+ * This file is automatically generated from skill-definitions directory.
102
+ * To add a new skill, create a new directory in skill-definitions with a SKILL.md file.
103
+ * To exclude a skill from bundling, add \`internal: true\` to its frontmatter.
104
+ */
105
+
106
+ ${imports}
107
+
108
+ export interface BundledSkill {
109
+ name: string;
110
+ dirName: string;
111
+ content: string;
112
+ }
113
+
114
+ export const BUNDLED_SKILLS: BundledSkill[] = [
115
+ ${entries}
116
+ ];
117
+
118
+ export function getBundledSkillByName(name: string): BundledSkill | undefined {
119
+ return BUNDLED_SKILLS.find((skill) => skill.name === name);
120
+ }
121
+ `;
122
+ }
123
+
124
+ function main(): void {
125
+ const dirs = readdirSync(SKILL_DEFINITIONS_DIR, { withFileTypes: true })
126
+ .filter((dirent) => dirent.isDirectory())
127
+ .map((dirent) => dirent.name)
128
+ .sort();
129
+
130
+ const allSkills: SkillMetadata[] = [];
131
+ const internalSkills: string[] = [];
132
+
133
+ for (const dirName of dirs) {
134
+ const metadata = getSkillMetadata(dirName);
135
+ if (metadata === null) {
136
+ console.warn(`Warning: No SKILL.md found in ${dirName}, skipping`);
137
+ continue;
138
+ }
139
+
140
+ if (metadata.isInternal) {
141
+ internalSkills.push(metadata.name);
142
+ continue;
143
+ }
144
+
145
+ allSkills.push(metadata);
146
+ }
147
+
148
+ const output = generateBundledSkillsFile(allSkills);
149
+ writeFileSync(OUTPUT_FILE, output, 'utf-8');
150
+
151
+ console.log(`Generated ${OUTPUT_FILE}`);
152
+ console.log(` - Included: ${allSkills.length} skills`);
153
+ if (internalSkills.length > 0) {
154
+ console.log(` - Excluded (internal): ${internalSkills.join(', ')}`);
155
+ }
156
+ }
157
+
158
+ main();
159
+
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.46.0",
2
+ "version": "0.47.0",
3
3
  "tools": [
4
4
  {
5
5
  "name": "compile",
@@ -1,21 +1,26 @@
1
1
  /**
2
- * Bundled skill definitions for uloop CLI.
3
- * These skills are embedded at build time via esbuild --loader:.md=text
2
+ * AUTO-GENERATED FILE - DO NOT EDIT MANUALLY
3
+ * Generated by: scripts/generate-bundled-skills.ts
4
+ *
5
+ * This file is automatically generated from skill-definitions directory.
6
+ * To add a new skill, create a new directory in skill-definitions with a SKILL.md file.
7
+ * To exclude a skill from bundling, add `internal: true` to its frontmatter.
4
8
  */
5
9
 
6
- import compileSkill from './skill-definitions/uloop-compile/SKILL.md';
7
- import getLogsSkill from './skill-definitions/uloop-get-logs/SKILL.md';
8
- import runTestsSkill from './skill-definitions/uloop-run-tests/SKILL.md';
10
+ import captureGameviewSkill from './skill-definitions/uloop-capture-gameview/SKILL.md';
9
11
  import clearConsoleSkill from './skill-definitions/uloop-clear-console/SKILL.md';
12
+ import compileSkill from './skill-definitions/uloop-compile/SKILL.md';
13
+ import controlPlayModeSkill from './skill-definitions/uloop-control-play-mode/SKILL.md';
14
+ import executeDynamicCodeSkill from './skill-definitions/uloop-execute-dynamic-code/SKILL.md';
15
+ import executeMenuItemSkill from './skill-definitions/uloop-execute-menu-item/SKILL.md';
16
+ import findGameObjectsSkill from './skill-definitions/uloop-find-game-objects/SKILL.md';
10
17
  import focusWindowSkill from './skill-definitions/uloop-focus-window/SKILL.md';
11
18
  import getHierarchySkill from './skill-definitions/uloop-get-hierarchy/SKILL.md';
12
- import unitySearchSkill from './skill-definitions/uloop-unity-search/SKILL.md';
19
+ import getLogsSkill from './skill-definitions/uloop-get-logs/SKILL.md';
13
20
  import getMenuItemsSkill from './skill-definitions/uloop-get-menu-items/SKILL.md';
14
- import executeMenuItemSkill from './skill-definitions/uloop-execute-menu-item/SKILL.md';
15
- import findGameObjectsSkill from './skill-definitions/uloop-find-game-objects/SKILL.md';
16
- import captureGameviewSkill from './skill-definitions/uloop-capture-gameview/SKILL.md';
17
- import executeDynamicCodeSkill from './skill-definitions/uloop-execute-dynamic-code/SKILL.md';
18
21
  import getProviderDetailsSkill from './skill-definitions/uloop-get-provider-details/SKILL.md';
22
+ import runTestsSkill from './skill-definitions/uloop-run-tests/SKILL.md';
23
+ import unitySearchSkill from './skill-definitions/uloop-unity-search/SKILL.md';
19
24
 
20
25
  export interface BundledSkill {
21
26
  name: string;
@@ -24,14 +29,31 @@ export interface BundledSkill {
24
29
  }
25
30
 
26
31
  export const BUNDLED_SKILLS: BundledSkill[] = [
27
- { name: 'uloop-compile', dirName: 'uloop-compile', content: compileSkill },
28
- { name: 'uloop-get-logs', dirName: 'uloop-get-logs', content: getLogsSkill },
29
- { name: 'uloop-run-tests', dirName: 'uloop-run-tests', content: runTestsSkill },
30
- { name: 'uloop-clear-console', dirName: 'uloop-clear-console', content: clearConsoleSkill },
31
- { name: 'uloop-focus-window', dirName: 'uloop-focus-window', content: focusWindowSkill },
32
- { name: 'uloop-get-hierarchy', dirName: 'uloop-get-hierarchy', content: getHierarchySkill },
33
- { name: 'uloop-unity-search', dirName: 'uloop-unity-search', content: unitySearchSkill },
34
- { name: 'uloop-get-menu-items', dirName: 'uloop-get-menu-items', content: getMenuItemsSkill },
32
+ {
33
+ name: 'uloop-capture-gameview',
34
+ dirName: 'uloop-capture-gameview',
35
+ content: captureGameviewSkill,
36
+ },
37
+ {
38
+ name: 'uloop-clear-console',
39
+ dirName: 'uloop-clear-console',
40
+ content: clearConsoleSkill,
41
+ },
42
+ {
43
+ name: 'uloop-compile',
44
+ dirName: 'uloop-compile',
45
+ content: compileSkill,
46
+ },
47
+ {
48
+ name: 'uloop-control-play-mode',
49
+ dirName: 'uloop-control-play-mode',
50
+ content: controlPlayModeSkill,
51
+ },
52
+ {
53
+ name: 'uloop-execute-dynamic-code',
54
+ dirName: 'uloop-execute-dynamic-code',
55
+ content: executeDynamicCodeSkill,
56
+ },
35
57
  {
36
58
  name: 'uloop-execute-menu-item',
37
59
  dirName: 'uloop-execute-menu-item',
@@ -43,20 +65,40 @@ export const BUNDLED_SKILLS: BundledSkill[] = [
43
65
  content: findGameObjectsSkill,
44
66
  },
45
67
  {
46
- name: 'uloop-capture-gameview',
47
- dirName: 'uloop-capture-gameview',
48
- content: captureGameviewSkill,
68
+ name: 'uloop-focus-window',
69
+ dirName: 'uloop-focus-window',
70
+ content: focusWindowSkill,
49
71
  },
50
72
  {
51
- name: 'uloop-execute-dynamic-code',
52
- dirName: 'uloop-execute-dynamic-code',
53
- content: executeDynamicCodeSkill,
73
+ name: 'uloop-get-hierarchy',
74
+ dirName: 'uloop-get-hierarchy',
75
+ content: getHierarchySkill,
76
+ },
77
+ {
78
+ name: 'uloop-get-logs',
79
+ dirName: 'uloop-get-logs',
80
+ content: getLogsSkill,
81
+ },
82
+ {
83
+ name: 'uloop-get-menu-items',
84
+ dirName: 'uloop-get-menu-items',
85
+ content: getMenuItemsSkill,
54
86
  },
55
87
  {
56
88
  name: 'uloop-get-provider-details',
57
89
  dirName: 'uloop-get-provider-details',
58
90
  content: getProviderDetailsSkill,
59
91
  },
92
+ {
93
+ name: 'uloop-run-tests',
94
+ dirName: 'uloop-run-tests',
95
+ content: runTestsSkill,
96
+ },
97
+ {
98
+ name: 'uloop-unity-search',
99
+ dirName: 'uloop-unity-search',
100
+ content: unitySearchSkill,
101
+ },
60
102
  ];
61
103
 
62
104
  export function getBundledSkillByName(name: string): BundledSkill | undefined {
@@ -0,0 +1,48 @@
1
+ ---
2
+ name: uloop-control-play-mode
3
+ description: Control Unity Editor play mode via uloop CLI. Use when you need to: (1) Start play mode for testing, (2) Stop play mode after testing, (3) Pause play mode for debugging.
4
+ ---
5
+
6
+ # uloop control-play-mode
7
+
8
+ Control Unity Editor play mode (play/stop/pause).
9
+
10
+ ## Usage
11
+
12
+ ```bash
13
+ uloop control-play-mode [options]
14
+ ```
15
+
16
+ ## Parameters
17
+
18
+ | Parameter | Type | Default | Description |
19
+ |-----------|------|---------|-------------|
20
+ | `--action` | string | `Play` | Action to perform: `Play`, `Stop`, `Pause` |
21
+
22
+ ## Examples
23
+
24
+ ```bash
25
+ # Start play mode
26
+ uloop control-play-mode --action Play
27
+
28
+ # Stop play mode
29
+ uloop control-play-mode --action Stop
30
+
31
+ # Pause play mode
32
+ uloop control-play-mode --action Pause
33
+ ```
34
+
35
+ ## Output
36
+
37
+ Returns JSON with the current play mode state:
38
+ - `IsPlaying`: Whether Unity is currently in play mode
39
+ - `IsPaused`: Whether play mode is paused
40
+ - `Message`: Description of the action performed
41
+
42
+ ## Notes
43
+
44
+ - Play action starts the game in the Unity Editor (also resumes from pause)
45
+ - Stop action exits play mode and returns to edit mode
46
+ - Pause action pauses the game while remaining in play mode
47
+ - Useful for automated testing workflows
48
+
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  name: uloop-get-project-info
3
3
  description: Get Unity project information via uloop CLI. Use when you need to: (1) Check Unity Editor version, (2) Get project settings and platform info, (3) Retrieve project metadata for diagnostics.
4
+ internal: true
4
5
  ---
5
6
 
6
7
  # uloop get-project-info
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  name: uloop-get-version
3
3
  description: Get uLoopMCP version information via uloop CLI. Use when you need to: (1) Check uLoopMCP package version, (2) Verify installation is working correctly, (3) Troubleshoot version compatibility issues.
4
+ internal: true
4
5
  ---
5
6
 
6
7
  # uloop get-version
package/src/version.ts CHANGED
@@ -4,4 +4,4 @@
4
4
  * This file exists to avoid bundling the entire package.json into the CLI bundle.
5
5
  * This version is automatically updated by release-please.
6
6
  */
7
- export const VERSION = '0.46.0'; // x-release-please-version
7
+ export const VERSION = '0.47.0'; // x-release-please-version