godot-cli 0.1.0 → 0.3.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/CHANGELOG.md CHANGED
@@ -1,25 +1,25 @@
1
- # Changelog
2
-
3
- All notable changes to `godot-cli` are documented in this file.
4
-
5
- ## 0.1.0
6
-
7
- Initial release. A cross-platform CLI for Godot-MCP, mirroring `unity-mcp-cli`'s feature set and structure,
8
- adapted for Godot.
9
-
10
- - `open` — resolve the Godot editor binary (`GODOT_BIN`/`GODOT4_BIN` → PATH → per-OS common dirs) and
11
- launch `--editor --path <project>` with the `GODOT_MCP_*` connection env vars.
12
- - `run-tool` / `run-system-tool` — POST to `<url>/api/tools/<name>` and `<url>/api/system-tools/<name>`.
13
- - `status` — detect a running Godot editor and probe MCP-server health.
14
- - `wait-for-ready` — poll the server until it answers `ping`.
15
- - `setup-mcp` — write an AI-agent MCP-client config (claude-code, claude-desktop, cursor, vscode, custom)
16
- pointing at the Godot server's `<host>/mcp` URL.
17
- - `configure` — list / enable / disable tools, prompts, and resources in the project-local
18
- `.godot-mcp/features.json`.
19
- - `close` — gracefully terminate the Godot editor for a project (`--force` to hard-kill).
20
- - `install-plugin` / `remove-plugin` — enable/disable the `godot_mcp` addon in `project.godot`
21
- `[editor_plugins]`.
22
- - `update` — check npm for a newer version and install it.
23
-
24
- `setup-skills` is intentionally not ported: Godot skills are generated addon-side by the McpPlugin engine,
25
- and the Godot MCP server exposes no skill-generate HTTP endpoint.
1
+ # Changelog
2
+
3
+ All notable changes to `godot-cli` are documented in this file.
4
+
5
+ ## 0.1.0
6
+
7
+ Initial release. A cross-platform CLI for Godot-MCP, mirroring `unity-mcp-cli`'s feature set and structure,
8
+ adapted for Godot.
9
+
10
+ - `open` — resolve the Godot editor binary (`GODOT_BIN`/`GODOT4_BIN` → PATH → per-OS common dirs) and
11
+ launch `--editor --path <project>` with the `GODOT_MCP_*` connection env vars.
12
+ - `run-tool` / `run-system-tool` — POST to `<url>/api/tools/<name>` and `<url>/api/system-tools/<name>`.
13
+ - `status` — detect a running Godot editor and probe MCP-server health.
14
+ - `wait-for-ready` — poll the server until it answers `ping`.
15
+ - `setup-mcp` — write an AI-agent MCP-client config (claude-code, claude-desktop, cursor, vscode, custom)
16
+ pointing at the Godot server's `<host>/mcp` URL.
17
+ - `configure` — list / enable / disable tools, prompts, and resources in the project-local
18
+ `.godot-mcp/features.json`.
19
+ - `close` — gracefully terminate the Godot editor for a project (`--force` to hard-kill).
20
+ - `install-plugin` / `remove-plugin` — enable/disable the `godot_mcp` addon in `project.godot`
21
+ `[editor_plugins]`.
22
+ - `update` — check npm for a newer version and install it.
23
+
24
+ `setup-skills` is intentionally not ported: Godot skills are generated addon-side by the McpPlugin engine,
25
+ and the Godot MCP server exposes no skill-generate HTTP endpoint.
package/README.md CHANGED
@@ -1,101 +1,101 @@
1
- # godot-cli
2
-
3
- Cross-platform CLI for **Godot-MCP** — the [Godot](https://godotengine.org/) editor addon that bridges
4
- LLMs (Claude, Cursor, Copilot, …) with the Godot editor via the
5
- [Model Context Protocol](https://modelcontextprotocol.io/).
6
-
7
- The CLI is the Godot analog of [`unity-mcp-cli`](https://www.npmjs.com/package/unity-mcp-cli): it resolves
8
- and launches the Godot editor with the right `GODOT_MCP_*` connection environment variables, runs MCP and
9
- system tools over the server's HTTP API, probes server health, writes AI-agent MCP-client config, and
10
- enables/disables the `godot_mcp` addon in a project.
11
-
12
- > **Licensed under Apache-2.0.**
13
-
14
- ## Install
15
-
16
- ```bash
17
- npm install -g godot-cli
18
- # or run ad-hoc:
19
- npx godot-cli <command>
20
- ```
21
-
22
- Requires Node `^20.19.0 || >=22.12.0`.
23
-
24
- ## Commands
25
-
26
- | Command | What it does |
27
- | --- | --- |
28
- | `open [path]` | Resolve the Godot editor binary and launch `--editor --path <project>` with `GODOT_MCP_*` connection env vars. |
29
- | `run-tool <tool> [path]` | POST to `<url>/api/tools/<tool>` with JSON input. |
30
- | `run-system-tool <tool> [path]` | POST to `<url>/api/system-tools/<tool>` (tools not exposed to MCP clients). |
31
- | `status [path]` | Detect a running Godot editor for the project and probe MCP-server health. |
32
- | `wait-for-ready [path]` | Poll the MCP server until it answers `ping`. |
33
- | `setup-mcp <agent> [path]` | Write the agent's MCP-client config pointing at the Godot server's `<host>/mcp` URL. |
34
- | `configure [path]` | List / enable / disable tools, prompts, and resources in the project-local `.godot-mcp/features.json`. |
35
- | `close [path]` | Gracefully stop the Godot editor running for a project (`--force` to hard-kill). |
36
- | `install-plugin [path]` | Enable the `godot_mcp` addon in `project.godot` `[editor_plugins]`. |
37
- | `remove-plugin [path]` | Disable the `godot_mcp` addon in `project.godot` `[editor_plugins]`. |
38
- | `update` | Check npm for a newer `godot-cli` and install it. |
39
-
40
- ### Editor resolution (`open`)
41
-
42
- `open` locates the Godot editor binary in this order:
43
-
44
- 1. `--editor-path <path>` (explicit).
45
- 2. `GODOT_BIN` / `GODOT4_BIN` environment variables.
46
- 3. The first matching Godot binary on `PATH` (the mono build is preferred on Windows).
47
- 4. Per-OS common install directories — Windows prefers the mono build; macOS resolves the
48
- `.app/Contents/MacOS/Godot` binary; Linux scans common extracted-binary locations.
49
-
50
- ### Connection env vars
51
-
52
- `open` forwards these to the editor process (names match the addon's `GodotMcpConfig`):
53
-
54
- | Flag | Env var |
55
- | --- | --- |
56
- | `--url <host>` | `GODOT_MCP_HOST` |
57
- | `--cloud-url <url>` | `GODOT_MCP_CLOUD_URL` |
58
- | `--token <token>` | `GODOT_MCP_TOKEN` |
59
- | `--auth None\|Required` | `GODOT_MCP_AUTH_OPTION` |
60
- | `--mode Cloud\|Custom` | `GODOT_MCP_CONNECTION_MODE` |
61
- | `--log-level <level>` | `GODOT_MCP_LOG_LEVEL` |
62
-
63
- ### Server URL resolution (`run-tool` / `status` / `wait-for-ready`)
64
-
65
- Unlike Unity, the Godot plugin is a **server-less client** whose persisted config lives in `user://`
66
- (outside the project tree), so there is no deterministic project-path → port hash. The server base URL is
67
- resolved as:
68
-
69
- 1. `--url <url>` (explicit override).
70
- 2. `GODOT_MCP_HOST` env (Custom-mode host).
71
- 3. `GODOT_MCP_CLOUD_URL` env / Cloud mode → cloud base (`https://ai-game.dev`).
72
- 4. Default custom host (`http://localhost:8080`).
73
-
74
- Pass `--url http://localhost:<port>` to target a local/self-hosted server.
75
-
76
- ## `setup-skills` is not in v1
77
-
78
- Unlike the Unity CLI, there is **no `setup-skills` command**. Godot skills are generated **addon-side** by
79
- the McpPlugin engine on plugin boot (`GodotMcpConnection.Start` → `GenerateSkillFilesIfNeeded`, driven by
80
- the `GodotMcpConfig.GenerateSkillFiles` toggle, with a manual "Generate" button in the dock's Skills card).
81
- The Godot MCP server exposes **no** `skill-generate` HTTP endpoint for the CLI to call, so porting
82
- `setup-skills` would have nothing to invoke. It is intentionally out of scope for v1.
83
-
84
- ## Library API
85
-
86
- The package also exports a side-effect-free library (the `.` entry):
87
-
88
- ```ts
89
- import { openProject, runTool, setupMcp, installPlugin } from 'godot-cli';
90
- ```
91
-
92
- Every function returns a discriminated union (`{ kind: 'success', ... }` / `{ kind: 'failure', error }`)
93
- and never throws past the public boundary.
94
-
95
- ## Development
96
-
97
- ```bash
98
- npm install
99
- npm run build # tsc → dist/ (ESM)
100
- npm test # vitest
101
- ```
1
+ # godot-cli
2
+
3
+ Cross-platform CLI for **Godot-MCP** — the [Godot](https://godotengine.org/) editor addon that bridges
4
+ LLMs (Claude, Cursor, Copilot, …) with the Godot editor via the
5
+ [Model Context Protocol](https://modelcontextprotocol.io/).
6
+
7
+ The CLI is the Godot analog of [`unity-mcp-cli`](https://www.npmjs.com/package/unity-mcp-cli): it resolves
8
+ and launches the Godot editor with the right `GODOT_MCP_*` connection environment variables, runs MCP and
9
+ system tools over the server's HTTP API, probes server health, writes AI-agent MCP-client config, and
10
+ enables/disables the `godot_mcp` addon in a project.
11
+
12
+ > **Licensed under Apache-2.0.**
13
+
14
+ ## Install
15
+
16
+ ```bash
17
+ npm install -g godot-cli
18
+ # or run ad-hoc:
19
+ npx godot-cli <command>
20
+ ```
21
+
22
+ Requires Node `^20.19.0 || >=22.12.0`.
23
+
24
+ ## Commands
25
+
26
+ | Command | What it does |
27
+ | --- | --- |
28
+ | `open [path]` | Resolve the Godot editor binary and launch `--editor --path <project>` with `GODOT_MCP_*` connection env vars. |
29
+ | `run-tool <tool> [path]` | POST to `<url>/api/tools/<tool>` with JSON input. |
30
+ | `run-system-tool <tool> [path]` | POST to `<url>/api/system-tools/<tool>` (tools not exposed to MCP clients). |
31
+ | `status [path]` | Detect a running Godot editor for the project and probe MCP-server health. |
32
+ | `wait-for-ready [path]` | Poll the MCP server until it answers `ping`. |
33
+ | `setup-mcp <agent> [path]` | Write the agent's MCP-client config pointing at the Godot server's `<host>/mcp` URL. |
34
+ | `configure [path]` | List / enable / disable tools, prompts, and resources in the project-local `.godot-mcp/features.json`. |
35
+ | `close [path]` | Gracefully stop the Godot editor running for a project (`--force` to hard-kill). |
36
+ | `install-plugin [path]` | Enable the `godot_mcp` addon in `project.godot` `[editor_plugins]`. |
37
+ | `remove-plugin [path]` | Disable the `godot_mcp` addon in `project.godot` `[editor_plugins]`. |
38
+ | `update` | Check npm for a newer `godot-cli` and install it. |
39
+
40
+ ### Editor resolution (`open`)
41
+
42
+ `open` locates the Godot editor binary in this order:
43
+
44
+ 1. `--editor-path <path>` (explicit).
45
+ 2. `GODOT_BIN` / `GODOT4_BIN` environment variables.
46
+ 3. The first matching Godot binary on `PATH` (the mono build is preferred on Windows).
47
+ 4. Per-OS common install directories — Windows prefers the mono build; macOS resolves the
48
+ `.app/Contents/MacOS/Godot` binary; Linux scans common extracted-binary locations.
49
+
50
+ ### Connection env vars
51
+
52
+ `open` forwards these to the editor process (names match the addon's `GodotMcpConfig`):
53
+
54
+ | Flag | Env var |
55
+ | --- | --- |
56
+ | `--url <host>` | `GODOT_MCP_HOST` |
57
+ | `--cloud-url <url>` | `GODOT_MCP_CLOUD_URL` |
58
+ | `--token <token>` | `GODOT_MCP_TOKEN` |
59
+ | `--auth None\|Required` | `GODOT_MCP_AUTH_OPTION` |
60
+ | `--mode Cloud\|Custom` | `GODOT_MCP_CONNECTION_MODE` |
61
+ | `--log-level <level>` | `GODOT_MCP_LOG_LEVEL` |
62
+
63
+ ### Server URL resolution (`run-tool` / `status` / `wait-for-ready`)
64
+
65
+ Unlike Unity, the Godot plugin is a **server-less client** whose persisted config lives in `user://`
66
+ (outside the project tree), so there is no deterministic project-path → port hash. The server base URL is
67
+ resolved as:
68
+
69
+ 1. `--url <url>` (explicit override).
70
+ 2. `GODOT_MCP_HOST` env (Custom-mode host).
71
+ 3. `GODOT_MCP_CLOUD_URL` env / Cloud mode → cloud base (`https://ai-game.dev`).
72
+ 4. Default custom host (`http://localhost:8080`).
73
+
74
+ Pass `--url http://localhost:<port>` to target a local/self-hosted server.
75
+
76
+ ## `setup-skills` is not in v1
77
+
78
+ Unlike the Unity CLI, there is **no `setup-skills` command**. Godot skills are generated **addon-side** by
79
+ the McpPlugin engine on plugin boot (`GodotMcpConnection.Start` → `GenerateSkillFilesIfNeeded`, driven by
80
+ the `GodotMcpConfig.GenerateSkillFiles` toggle, with a manual "Generate" button in the dock's Skills card).
81
+ The Godot MCP server exposes **no** `skill-generate` HTTP endpoint for the CLI to call, so porting
82
+ `setup-skills` would have nothing to invoke. It is intentionally out of scope for v1.
83
+
84
+ ## Library API
85
+
86
+ The package also exports a side-effect-free library (the `.` entry):
87
+
88
+ ```ts
89
+ import { openProject, runTool, setupMcp, installPlugin } from 'godot-cli';
90
+ ```
91
+
92
+ Every function returns a discriminated union (`{ kind: 'success', ... }` / `{ kind: 'failure', error }`)
93
+ and never throws past the public boundary.
94
+
95
+ ## Development
96
+
97
+ ```bash
98
+ npm install
99
+ npm run build # tsc → dist/ (ESM)
100
+ npm test # vitest
101
+ ```
package/bin/godot-cli.js CHANGED
@@ -1,2 +1,2 @@
1
- #!/usr/bin/env node
2
- import '../dist/index.js';
1
+ #!/usr/bin/env node
2
+ import '../dist/index.js';
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare const createProjectCommand: Command;
@@ -0,0 +1,49 @@
1
+ import { Command } from 'commander';
2
+ import * as path from 'path';
3
+ import * as ui from '../utils/ui.js';
4
+ import { verbose } from '../utils/ui.js';
5
+ import { createProject } from '../lib/create-project.js';
6
+ export const createProjectCommand = new Command('create-project')
7
+ .description('Scaffold a minimal valid Godot 4.x project (project.godot + icon.svg). Pass --dotnet to also scaffold a Godot.NET.Sdk (C#) csproj. Refuses to overwrite an existing Godot/Unity/Unreal project.')
8
+ .argument('[path]', 'Target directory to scaffold the project into (defaults to current directory)')
9
+ .option('--path <path>', 'Target directory to scaffold the project into')
10
+ .option('--name <name>', 'Project name (defaults to a name derived from the folder name)')
11
+ .option('--dotnet', 'Also scaffold a Godot.NET.Sdk (C#) csproj')
12
+ .action(async (positionalPath, options) => {
13
+ const resolvedPath = positionalPath ?? options.path ?? process.cwd();
14
+ const projectPath = path.resolve(resolvedPath);
15
+ ui.heading('Creating Godot project');
16
+ verbose(`Target path: ${projectPath}`);
17
+ verbose(`--dotnet: ${options.dotnet === true}`);
18
+ const spinner = ui.startSpinner('Scaffolding project...');
19
+ const result = await createProject({
20
+ projectPath,
21
+ name: options.name,
22
+ dotnet: options.dotnet === true,
23
+ });
24
+ if (result.kind === 'failure') {
25
+ spinner.error('Failed to create project');
26
+ ui.error(result.errorMessage);
27
+ // Surface failure-shape diagnostics BEFORE exiting: leftover files a
28
+ // partial rollback could not remove, plus any rollback warnings.
29
+ if (result.filesWritten.length > 0) {
30
+ ui.label('Files left behind (cleanup failed)', result.filesWritten.join(', '));
31
+ }
32
+ for (const warning of result.warnings) {
33
+ console.log('');
34
+ ui.warn(warning);
35
+ }
36
+ process.exit(1);
37
+ }
38
+ spinner.success(`Created Godot project "${result.projectName}"`);
39
+ ui.label('Project path', result.projectPath);
40
+ ui.label('Files written', result.filesWritten.join(', '));
41
+ if (result.dotnet) {
42
+ ui.label('C# (.NET)', 'enabled');
43
+ }
44
+ for (const warning of result.warnings) {
45
+ console.log('');
46
+ ui.warn(warning);
47
+ }
48
+ });
49
+ //# sourceMappingURL=create-project.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-project.js","sourceRoot":"","sources":["../../src/commands/create-project.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,EAAE,MAAM,gBAAgB,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAQzD,MAAM,CAAC,MAAM,oBAAoB,GAAG,IAAI,OAAO,CAAC,gBAAgB,CAAC;KAC9D,WAAW,CACV,iMAAiM,CAClM;KACA,QAAQ,CAAC,QAAQ,EAAE,+EAA+E,CAAC;KACnG,MAAM,CAAC,eAAe,EAAE,+CAA+C,CAAC;KACxE,MAAM,CAAC,eAAe,EAAE,gEAAgE,CAAC;KACzF,MAAM,CAAC,UAAU,EAAE,2CAA2C,CAAC;KAC/D,MAAM,CAAC,KAAK,EAAE,cAAkC,EAAE,OAAgC,EAAE,EAAE;IACrF,MAAM,YAAY,GAAG,cAAc,IAAI,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IACrE,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IAE/C,EAAE,CAAC,OAAO,CAAC,wBAAwB,CAAC,CAAC;IACrC,OAAO,CAAC,gBAAgB,WAAW,EAAE,CAAC,CAAC;IACvC,OAAO,CAAC,aAAa,OAAO,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC,CAAC;IAEhD,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,wBAAwB,CAAC,CAAC;IAC1D,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC;QACjC,WAAW;QACX,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,MAAM,EAAE,OAAO,CAAC,MAAM,KAAK,IAAI;KAChC,CAAC,CAAC;IAEH,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC9B,OAAO,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;QAC1C,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;QAC9B,qEAAqE;QACrE,iEAAiE;QACjE,IAAI,MAAM,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACnC,EAAE,CAAC,KAAK,CAAC,oCAAoC,EAAE,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QACjF,CAAC;QACD,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;YACtC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAChB,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACnB,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,OAAO,CAAC,OAAO,CAAC,0BAA0B,MAAM,CAAC,WAAW,GAAG,CAAC,CAAC;IACjE,EAAE,CAAC,KAAK,CAAC,cAAc,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC;IAC7C,EAAE,CAAC,KAAK,CAAC,eAAe,EAAE,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAC1D,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QAClB,EAAE,CAAC,KAAK,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;IACnC,CAAC;IAED,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QACtC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACnB,CAAC;AACH,CAAC,CAAC,CAAC"}
package/dist/index.js CHANGED
@@ -7,6 +7,7 @@ import { statusCommand } from './commands/status.js';
7
7
  import { waitForReadyCommand } from './commands/wait-for-ready.js';
8
8
  import { setupMcpCommand } from './commands/setup-mcp.js';
9
9
  import { configureCommand } from './commands/configure.js';
10
+ import { createProjectCommand } from './commands/create-project.js';
10
11
  import { closeCommand } from './commands/close.js';
11
12
  import { createUpdateCommand } from './commands/update.js';
12
13
  import { installPluginCommand } from './commands/install-plugin.js';
@@ -25,6 +26,7 @@ program
25
26
  const subcommands = [
26
27
  closeCommand,
27
28
  configureCommand,
29
+ createProjectCommand,
28
30
  installPluginCommand,
29
31
  openCommand,
30
32
  removePluginCommand,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,mBAAmB,EAAE,KAAK,IAAI,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAClF,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAEnG,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,GAAG,GAAG,OAAO,CAAC,iBAAiB,CAAwB,CAAC;AAE9D,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,WAAW,CAAC;KACjB,WAAW,CAAC,kDAAkD,CAAC;KAC/D,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC;KACpB,MAAM,CAAC,eAAe,EAAE,kCAAkC,CAAC,CAAC;AAE/D,2BAA2B;AAC3B,MAAM,WAAW,GAAG;IAClB,YAAY;IACZ,gBAAgB;IAChB,oBAAoB;IACpB,oBAAoB;IACpB,WAAW;IACX,mBAAmB;IACnB,cAAc;IACd,oBAAoB;IACpB,eAAe;IACf,aAAa;IACb,mBAAmB,CAAC,GAAG,CAAC,OAAO,CAAC;IAChC,mBAAmB;CACpB,CAAC;AAEF,KAAK,MAAM,GAAG,IAAI,WAAW,EAAE,CAAC;IAC9B,GAAG,CAAC,MAAM,CAAC,eAAe,EAAE,kCAAkC,CAAC,CAAC;IAChE,mBAAmB,CAAC,GAAG,CAAC,CAAC;IACzB,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;AAC1B,CAAC;AAED,2EAA2E;AAC3E,mBAAmB,CAAC,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;AAE1C,gDAAgD;AAChD,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,YAAY,EAAE,aAAa,EAAE,EAAE;IACxD,MAAM,IAAI,GAAG,aAAa,CAAC,eAAe,EAA2B,CAAC;IACtE,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;QACjB,UAAU,CAAC,IAAI,CAAC,CAAC;IACnB,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,qCAAqC;AACrC,OAAO,CAAC,MAAM,CAAC,GAAG,EAAE;IAClB,OAAO,CAAC,UAAU,EAAE,CAAC;AACvB,CAAC,CAAC,CAAC;AAEH,mFAAmF;AACnF,MAAM,kBAAkB,GAAG,eAAe,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AAEnG,OAAO,CAAC,UAAU,EAAE;KACjB,IAAI,CAAC,KAAK,IAAI,EAAE;IACf,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC;IACxC,IAAI,MAAM,EAAE,CAAC;QACX,uBAAuB,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IACzD,CAAC;AACH,CAAC,CAAC;KACD,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACb,OAAO,CAAE,GAAa,CAAC,OAAO,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IAC/C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,88 @@
1
+ import type { CreateProjectOptions, CreateProjectResult } from './types.js';
2
+ /**
3
+ * `Godot.NET.Sdk` version pinned into a scaffolded `--dotnet` csproj. Matches
4
+ * the addon's own min-version floor (`Godot-MCP.csproj` pins `4.3.0`) and the
5
+ * `config/features` "4.3" floor written into `project.godot`. A consumer can
6
+ * bump this to their editor version freely; the scaffold targets the floor so
7
+ * the generated project opens in any Godot 4.3+ editor.
8
+ */
9
+ export declare const GODOT_SDK_VERSION = "4.3.0";
10
+ /**
11
+ * Default `icon.svg` written into a scaffolded project — a self-contained,
12
+ * valid SVG using Godot's signature rounded-rect blue background. Mirrors the
13
+ * shape of the icon Godot writes for a fresh project (the exact glyph differs;
14
+ * what matters is a valid default icon the editor can load at `res://icon.svg`).
15
+ */
16
+ export declare const DEFAULT_ICON_SVG = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"128\" height=\"128\" viewBox=\"0 0 128 128\">\n <rect width=\"124\" height=\"124\" x=\"2\" y=\"2\" fill=\"#363d52\" stroke=\"#212532\" stroke-width=\"4\" rx=\"14\"/>\n <g fill=\"#fff\">\n <circle cx=\"48\" cy=\"58\" r=\"10\"/>\n <circle cx=\"80\" cy=\"58\" r=\"10\"/>\n <rect x=\"40\" y=\"82\" width=\"48\" height=\"8\" rx=\"4\"/>\n </g>\n</svg>\n";
17
+ /** Engine project marker detected when refusing to scaffold over an existing project. */
18
+ export type ProjectMarkerEngine = 'godot' | 'unity' | 'unreal';
19
+ /**
20
+ * Derive the project name from an explicit option, falling back to the target
21
+ * folder's base name. Returns `GodotProject` only when both are empty. Pure.
22
+ */
23
+ export declare function deriveProjectName(projectPath: string, explicitName?: string): string;
24
+ /**
25
+ * The `[dotnet] project/assembly_name` value AND the csproj filename. Godot
26
+ * itself permits hyphens here (the infra testbed uses `Godot-Test-Project`), so
27
+ * the name is kept verbatim apart from trimming; falls back when empty. Pure.
28
+ */
29
+ export declare function toAssemblyName(projectName: string): string;
30
+ /**
31
+ * The csproj `<RootNamespace>` — must be a valid C# identifier, so every char
32
+ * that is not a letter/digit/underscore is stripped and a leading digit is
33
+ * prefixed with `_`. Mirrors the testbed's `Godot-Test-Project` ->
34
+ * `GodotTestProject` derivation. Pure.
35
+ */
36
+ export declare function toRootNamespace(projectName: string): string;
37
+ /**
38
+ * Escape a string for embedding inside a double-quoted Godot `ConfigFile`
39
+ * value (the `project.godot` format): backslash -> `\\` and double-quote ->
40
+ * `\"`. Without this, a name containing `"` or `\` produces a `project.godot`
41
+ * Godot cannot parse — or, worse, lets a crafted name inject arbitrary config
42
+ * keys. Pure. Exported for unit tests.
43
+ */
44
+ export declare function escapeGodotConfigString(value: string): string;
45
+ /**
46
+ * Validate a project name before any filesystem write. Rejected when the name
47
+ * would corrupt the generated `project.godot` (line breaks inside a quoted
48
+ * `ConfigFile` string) or would escape / break the `--dotnet` csproj filename
49
+ * (path separators, `..` traversal, or characters illegal in a filename).
50
+ * Returns a human-readable reason when invalid, or `null` when safe. Pure.
51
+ */
52
+ export declare function validateProjectName(projectName: string): string | null;
53
+ /**
54
+ * Detect whether `dir` already hosts a project for any supported engine and, if
55
+ * so, which marker file proves it. Checks (in order) a Godot `project.godot`, a
56
+ * Unity `ProjectSettings/ProjectVersion.txt`, and any Unreal `*.uproject` file
57
+ * directly inside `dir`. Returns `null` when no marker is present (including
58
+ * when `dir` does not exist). Side-effect-free beyond read-only `fs` probing.
59
+ */
60
+ export declare function detectExistingProjectMarker(dir: string): {
61
+ engine: ProjectMarkerEngine;
62
+ markerPath: string;
63
+ } | null;
64
+ /**
65
+ * Render the body of a minimal valid Godot 4.x `project.godot`
66
+ * (`config_version=5`). When `dotnet` is set, adds the `"C#"` feature and a
67
+ * `[dotnet]` section carrying the assembly name. Pure. Exported for unit tests.
68
+ */
69
+ export declare function renderProjectGodot(projectName: string, dotnet: boolean): string;
70
+ /**
71
+ * Render a `Godot.NET.Sdk` csproj matching the infra `Godot-Test-Project/`
72
+ * reference shape (Sdk + `net8.0` + `Nullable` + `RootNamespace`). The testbed's
73
+ * addon-specific `PackageReference`s are intentionally NOT included — a freshly
74
+ * scaffolded project is not necessarily an addon consumer. Pure. Exported for
75
+ * unit tests.
76
+ */
77
+ export declare function renderCsproj(projectName: string): string;
78
+ /**
79
+ * Scaffold a minimal valid Godot 4.x project — the library-callable equivalent
80
+ * of the `create-project` CLI command. Library-safe: never calls
81
+ * `process.exit`, never prints, never throws past the public boundary.
82
+ *
83
+ * Writes `project.godot` (`config_version=5`) + `icon.svg`, plus a
84
+ * `Godot.NET.Sdk` csproj when `dotnet` is set. Refuses (structured failure, no
85
+ * writes) when the target already contains a Godot/Unity/Unreal project marker.
86
+ * Pure `fs` operations only — no Godot binary required.
87
+ */
88
+ export declare function createProject(options: CreateProjectOptions): Promise<CreateProjectResult>;
@@ -0,0 +1,314 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ import { resolveProjectPath } from './open.js';
4
+ import { emitProgress } from './progress.js';
5
+ /**
6
+ * `Godot.NET.Sdk` version pinned into a scaffolded `--dotnet` csproj. Matches
7
+ * the addon's own min-version floor (`Godot-MCP.csproj` pins `4.3.0`) and the
8
+ * `config/features` "4.3" floor written into `project.godot`. A consumer can
9
+ * bump this to their editor version freely; the scaffold targets the floor so
10
+ * the generated project opens in any Godot 4.3+ editor.
11
+ */
12
+ export const GODOT_SDK_VERSION = '4.3.0';
13
+ /**
14
+ * Default `icon.svg` written into a scaffolded project — a self-contained,
15
+ * valid SVG using Godot's signature rounded-rect blue background. Mirrors the
16
+ * shape of the icon Godot writes for a fresh project (the exact glyph differs;
17
+ * what matters is a valid default icon the editor can load at `res://icon.svg`).
18
+ */
19
+ export const DEFAULT_ICON_SVG = `<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 128 128">
20
+ <rect width="124" height="124" x="2" y="2" fill="#363d52" stroke="#212532" stroke-width="4" rx="14"/>
21
+ <g fill="#fff">
22
+ <circle cx="48" cy="58" r="10"/>
23
+ <circle cx="80" cy="58" r="10"/>
24
+ <rect x="40" y="82" width="48" height="8" rx="4"/>
25
+ </g>
26
+ </svg>
27
+ `;
28
+ /**
29
+ * Derive the project name from an explicit option, falling back to the target
30
+ * folder's base name. Returns `GodotProject` only when both are empty. Pure.
31
+ */
32
+ export function deriveProjectName(projectPath, explicitName) {
33
+ const trimmed = explicitName?.trim();
34
+ if (trimmed)
35
+ return trimmed;
36
+ const base = path.basename(path.resolve(projectPath));
37
+ return base.length > 0 ? base : 'GodotProject';
38
+ }
39
+ /**
40
+ * The `[dotnet] project/assembly_name` value AND the csproj filename. Godot
41
+ * itself permits hyphens here (the infra testbed uses `Godot-Test-Project`), so
42
+ * the name is kept verbatim apart from trimming; falls back when empty. Pure.
43
+ */
44
+ export function toAssemblyName(projectName) {
45
+ const cleaned = projectName.trim();
46
+ return cleaned.length > 0 ? cleaned : 'GodotProject';
47
+ }
48
+ /**
49
+ * The csproj `<RootNamespace>` — must be a valid C# identifier, so every char
50
+ * that is not a letter/digit/underscore is stripped and a leading digit is
51
+ * prefixed with `_`. Mirrors the testbed's `Godot-Test-Project` ->
52
+ * `GodotTestProject` derivation. Pure.
53
+ */
54
+ export function toRootNamespace(projectName) {
55
+ const cleaned = projectName.replace(/[^A-Za-z0-9_]/g, '');
56
+ if (cleaned.length === 0)
57
+ return 'GodotProject';
58
+ return /^[0-9]/.test(cleaned) ? `_${cleaned}` : cleaned;
59
+ }
60
+ /**
61
+ * Escape a string for embedding inside a double-quoted Godot `ConfigFile`
62
+ * value (the `project.godot` format): backslash -> `\\` and double-quote ->
63
+ * `\"`. Without this, a name containing `"` or `\` produces a `project.godot`
64
+ * Godot cannot parse — or, worse, lets a crafted name inject arbitrary config
65
+ * keys. Pure. Exported for unit tests.
66
+ */
67
+ export function escapeGodotConfigString(value) {
68
+ return value.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
69
+ }
70
+ /**
71
+ * Validate a project name before any filesystem write. Rejected when the name
72
+ * would corrupt the generated `project.godot` (line breaks inside a quoted
73
+ * `ConfigFile` string) or would escape / break the `--dotnet` csproj filename
74
+ * (path separators, `..` traversal, or characters illegal in a filename).
75
+ * Returns a human-readable reason when invalid, or `null` when safe. Pure.
76
+ */
77
+ export function validateProjectName(projectName) {
78
+ if (/[\r\n]/.test(projectName))
79
+ return 'must not contain line breaks';
80
+ if (/[/\\]/.test(projectName))
81
+ return 'must not contain path separators ("/" or "\\")';
82
+ if (projectName.includes('..'))
83
+ return 'must not contain ".." path segments';
84
+ if (/[<>:"|?*]/.test(projectName))
85
+ return 'must not contain reserved characters (< > : " | ? *)';
86
+ return null;
87
+ }
88
+ /**
89
+ * Detect whether `dir` already hosts a project for any supported engine and, if
90
+ * so, which marker file proves it. Checks (in order) a Godot `project.godot`, a
91
+ * Unity `ProjectSettings/ProjectVersion.txt`, and any Unreal `*.uproject` file
92
+ * directly inside `dir`. Returns `null` when no marker is present (including
93
+ * when `dir` does not exist). Side-effect-free beyond read-only `fs` probing.
94
+ */
95
+ export function detectExistingProjectMarker(dir) {
96
+ const godot = path.join(dir, 'project.godot');
97
+ if (fs.existsSync(godot))
98
+ return { engine: 'godot', markerPath: godot };
99
+ const unity = path.join(dir, 'ProjectSettings', 'ProjectVersion.txt');
100
+ if (fs.existsSync(unity))
101
+ return { engine: 'unity', markerPath: unity };
102
+ if (fs.existsSync(dir)) {
103
+ try {
104
+ const uproject = fs
105
+ .readdirSync(dir)
106
+ .find((entry) => entry.toLowerCase().endsWith('.uproject'));
107
+ if (uproject)
108
+ return { engine: 'unreal', markerPath: path.join(dir, uproject) };
109
+ }
110
+ catch {
111
+ // A readdir failure here is not a marker; the scaffold's own mkdir/write
112
+ // below will surface any real filesystem error as a structured failure.
113
+ }
114
+ }
115
+ return null;
116
+ }
117
+ /**
118
+ * Render the body of a minimal valid Godot 4.x `project.godot`
119
+ * (`config_version=5`). When `dotnet` is set, adds the `"C#"` feature and a
120
+ * `[dotnet]` section carrying the assembly name. Pure. Exported for unit tests.
121
+ */
122
+ export function renderProjectGodot(projectName, dotnet) {
123
+ const features = dotnet ? 'PackedStringArray("4.3", "C#")' : 'PackedStringArray("4.3")';
124
+ const dotnetSection = dotnet
125
+ ? `\n[dotnet]\n\nproject/assembly_name="${escapeGodotConfigString(toAssemblyName(projectName))}"\n`
126
+ : '';
127
+ return `; Engine configuration file.
128
+ ; It's best edited using the editor UI and not directly,
129
+ ; since the parameters that go here are not all obvious.
130
+ ;
131
+ ; Format:
132
+ ; [section] ; section goes between []
133
+ ; param=value ; assign values to parameters
134
+
135
+ config_version=5
136
+
137
+ [application]
138
+
139
+ config/name="${escapeGodotConfigString(projectName)}"
140
+ config/features=${features}
141
+ config/icon="res://icon.svg"
142
+ ${dotnetSection}`;
143
+ }
144
+ /**
145
+ * Render a `Godot.NET.Sdk` csproj matching the infra `Godot-Test-Project/`
146
+ * reference shape (Sdk + `net8.0` + `Nullable` + `RootNamespace`). The testbed's
147
+ * addon-specific `PackageReference`s are intentionally NOT included — a freshly
148
+ * scaffolded project is not necessarily an addon consumer. Pure. Exported for
149
+ * unit tests.
150
+ */
151
+ export function renderCsproj(projectName) {
152
+ return `<Project Sdk="Godot.NET.Sdk/${GODOT_SDK_VERSION}">
153
+
154
+ <PropertyGroup>
155
+ <TargetFramework>net8.0</TargetFramework>
156
+ <EnableDynamicLoading>true</EnableDynamicLoading>
157
+ <Nullable>enable</Nullable>
158
+ <RootNamespace>${toRootNamespace(projectName)}</RootNamespace>
159
+ </PropertyGroup>
160
+
161
+ </Project>
162
+ `;
163
+ }
164
+ /**
165
+ * Scaffold a minimal valid Godot 4.x project — the library-callable equivalent
166
+ * of the `create-project` CLI command. Library-safe: never calls
167
+ * `process.exit`, never prints, never throws past the public boundary.
168
+ *
169
+ * Writes `project.godot` (`config_version=5`) + `icon.svg`, plus a
170
+ * `Godot.NET.Sdk` csproj when `dotnet` is set. Refuses (structured failure, no
171
+ * writes) when the target already contains a Godot/Unity/Unreal project marker.
172
+ * Pure `fs` operations only — no Godot binary required.
173
+ */
174
+ export async function createProject(options) {
175
+ const warnings = [];
176
+ const filesWritten = [];
177
+ // Original bytes of any pre-existing file we overwrite, so a failed scaffold
178
+ // can RESTORE the caller's file rather than delete it during rollback.
179
+ const overwrittenOriginals = new Map();
180
+ let resolvedProjectPath;
181
+ let projectDirExistedBefore = true;
182
+ try {
183
+ const { projectPath } = resolveProjectPath(options.projectPath, process.cwd());
184
+ resolvedProjectPath = projectPath;
185
+ const dotnet = options.dotnet === true;
186
+ const projectName = deriveProjectName(projectPath, options.name);
187
+ // Validate the name BEFORE any writes — line breaks would corrupt the
188
+ // quoted `project.godot` strings, and path separators / `..` / reserved
189
+ // chars would let a crafted `--dotnet` csproj filename escape the target.
190
+ const nameError = validateProjectName(projectName);
191
+ if (nameError) {
192
+ const hint = options.name?.trim()
193
+ ? ''
194
+ : ' (derived from the target folder name — pass --name to override)';
195
+ throw new Error(`Invalid project name "${projectName}": ${nameError}.${hint}`);
196
+ }
197
+ emitProgress(options.onProgress, {
198
+ phase: 'start',
199
+ message: `Creating Godot project at ${projectPath}`,
200
+ });
201
+ // Refuse to scaffold over an existing project of ANY engine BEFORE writing.
202
+ const existing = detectExistingProjectMarker(projectPath);
203
+ if (existing) {
204
+ throw new Error(`Refusing to scaffold: target already contains a ${existing.engine} project marker (${existing.markerPath}).`);
205
+ }
206
+ // Create the target directory (and any parents) if absent. Record whether
207
+ // it pre-existed so a failed scaffold can remove a directory it created
208
+ // (but never one the caller already had).
209
+ projectDirExistedBefore = fs.existsSync(projectPath);
210
+ fs.mkdirSync(projectPath, { recursive: true });
211
+ // Write one file, recording it for rollback and warning when an existing
212
+ // non-marker file is clobbered.
213
+ const writeFile = (filePath, contents) => {
214
+ // Only a pre-existing regular FILE is an overwrite worth warning about /
215
+ // snapshotting; a directory at this path isn't a file we can clobber (the
216
+ // write below will throw), so it must not produce a phantom warning.
217
+ if (fs.existsSync(filePath) && fs.statSync(filePath).isFile()) {
218
+ warnings.push(`Overwrote existing file: ${filePath}`);
219
+ // Snapshot the caller's original bytes (once) so rollback restores them
220
+ // instead of deleting a file they already had. If the read fails, fall
221
+ // back to delete-on-rollback (best-effort).
222
+ if (!overwrittenOriginals.has(filePath)) {
223
+ try {
224
+ overwrittenOriginals.set(filePath, fs.readFileSync(filePath));
225
+ }
226
+ catch {
227
+ // Unreadable: treat as freshly-written (rmSync on rollback).
228
+ }
229
+ }
230
+ }
231
+ fs.writeFileSync(filePath, contents);
232
+ filesWritten.push(filePath);
233
+ };
234
+ // Write the icon and (optional) csproj first, then `project.godot` LAST so
235
+ // the engine marker only exists once the scaffold fully succeeds — a
236
+ // mid-write failure leaves no marker to brick a corrected retry.
237
+ const iconPath = path.join(projectPath, 'icon.svg');
238
+ writeFile(iconPath, DEFAULT_ICON_SVG);
239
+ if (dotnet) {
240
+ const csprojPath = path.join(projectPath, `${toAssemblyName(projectName)}.csproj`);
241
+ writeFile(csprojPath, renderCsproj(projectName));
242
+ }
243
+ const projectGodotPath = path.join(projectPath, 'project.godot');
244
+ writeFile(projectGodotPath, renderProjectGodot(projectName, dotnet));
245
+ emitProgress(options.onProgress, {
246
+ phase: 'project-scaffolded',
247
+ message: `Scaffolded ${filesWritten.length} file(s)`,
248
+ projectPath,
249
+ });
250
+ emitProgress(options.onProgress, { phase: 'done', message: 'Project created.' });
251
+ return {
252
+ kind: 'success',
253
+ success: true,
254
+ projectPath,
255
+ projectName,
256
+ dotnet,
257
+ filesWritten,
258
+ warnings,
259
+ };
260
+ }
261
+ catch (err) {
262
+ // Roll back any files written before the failure (best-effort, reverse
263
+ // order) so a failed/refused scaffold leaves the target as it was found.
264
+ // A file we OVERWROTE is restored to its original bytes (never deleted —
265
+ // that would leave the caller with less than they started with); a file we
266
+ // freshly created is removed. Only entries whose cleanup FAILED stay in
267
+ // `leftover` — honouring the CreateProjectFailure.filesWritten contract
268
+ // (non-empty only when a partial scaffold could not be fully cleaned up).
269
+ const leftover = [];
270
+ for (const filePath of [...filesWritten].reverse()) {
271
+ try {
272
+ const original = overwrittenOriginals.get(filePath);
273
+ if (original !== undefined) {
274
+ fs.writeFileSync(filePath, original);
275
+ // The overwrite was reverted, so drop the now-inaccurate warning.
276
+ const idx = warnings.indexOf(`Overwrote existing file: ${filePath}`);
277
+ if (idx !== -1)
278
+ warnings.splice(idx, 1);
279
+ }
280
+ else {
281
+ fs.rmSync(filePath, { force: true });
282
+ }
283
+ }
284
+ catch {
285
+ warnings.push(`Failed to roll back partially-written file: ${filePath}`);
286
+ leftover.push(filePath);
287
+ }
288
+ }
289
+ // We iterated in reverse for cleanup; restore write order for the contract.
290
+ leftover.reverse();
291
+ // If we created the target directory and rollback emptied it, remove it too
292
+ // so a failed scaffold leaves the target as it was found. Best-effort: a
293
+ // non-empty dir (pre-existing sibling content) keeps the rmdir from firing.
294
+ if (resolvedProjectPath && !projectDirExistedBefore && leftover.length === 0) {
295
+ try {
296
+ fs.rmdirSync(resolvedProjectPath);
297
+ }
298
+ catch {
299
+ // Directory not empty or already gone — leave it; cleanup is best-effort.
300
+ }
301
+ }
302
+ const errorObj = err instanceof Error ? err : new Error(String(err));
303
+ return {
304
+ kind: 'failure',
305
+ success: false,
306
+ projectPath: resolvedProjectPath,
307
+ warnings,
308
+ filesWritten: leftover,
309
+ errorMessage: errorObj.message,
310
+ error: errorObj,
311
+ };
312
+ }
313
+ }
314
+ //# sourceMappingURL=create-project.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-project.js","sourceRoot":"","sources":["../../src/lib/create-project.ts"],"names":[],"mappings":"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"}
@@ -9,6 +9,10 @@ export type ProgressEvent = {
9
9
  phase: 'manifest-patched';
10
10
  message: string;
11
11
  manifestPath: string;
12
+ } | {
13
+ phase: 'project-scaffolded';
14
+ message: string;
15
+ projectPath: string;
12
16
  } | {
13
17
  phase: 'editor-resolved';
14
18
  message: string;
@@ -118,6 +122,47 @@ export interface OpenEnvInputs {
118
122
  mode?: OpenProjectOptions['mode'];
119
123
  logLevel?: OpenProjectOptions['logLevel'];
120
124
  }
125
+ export interface CreateProjectOptions {
126
+ /** Target directory to scaffold the project into. Defaults to `process.cwd()`. */
127
+ projectPath?: string;
128
+ /**
129
+ * Project name written to `config/name` (and the `[dotnet]` assembly name /
130
+ * csproj filename when `dotnet` is set). Defaults to a name derived from the
131
+ * target folder name.
132
+ */
133
+ name?: string;
134
+ /** When `true`, additionally scaffold a `Godot.NET.Sdk` (C#) csproj. */
135
+ dotnet?: boolean;
136
+ onProgress?: ProgressCallback;
137
+ }
138
+ export interface CreateProjectSuccess {
139
+ kind: 'success';
140
+ success: true;
141
+ projectPath: string;
142
+ /** The resolved project name (explicit arg or folder-name derivation). */
143
+ projectName: string;
144
+ /** Whether the C# (`--dotnet`) csproj was scaffolded. */
145
+ dotnet: boolean;
146
+ /** Absolute paths of every file written, in write order. */
147
+ filesWritten: string[];
148
+ warnings: string[];
149
+ }
150
+ export interface CreateProjectFailure {
151
+ kind: 'failure';
152
+ success: false;
153
+ projectPath?: string;
154
+ warnings: string[];
155
+ /**
156
+ * Absolute paths of any files written before the failure, in write order.
157
+ * Empty when the scaffold was refused before writing or after a successful
158
+ * best-effort rollback; non-empty only when cleanup of a partial scaffold
159
+ * could not be completed — lets the consumer finish the cleanup.
160
+ */
161
+ filesWritten: string[];
162
+ errorMessage: string;
163
+ error: Error;
164
+ }
165
+ export type CreateProjectResult = CreateProjectSuccess | CreateProjectFailure;
121
166
  export type RunToolFailureReason = 'invalid-input' | 'connection-refused' | 'connection-reset' | 'network-error' | 'timeout' | 'http-error' | 'unknown';
122
167
  /**
123
168
  * Options accepted by both {@link runTool} and {@link runSystemTool}.
package/dist/lib.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export { openProject } from './lib/open.js';
2
+ export { createProject } from './lib/create-project.js';
2
3
  export { runTool, runSystemTool } from './lib/run-tool.js';
3
4
  export { setupMcp, listAgentIds } from './lib/setup-mcp.js';
4
5
  export { installPlugin, removePlugin } from './lib/install-plugin.js';
5
- export type { ProgressEvent, ProgressCallback, ResultKind, OpenProjectOptions, OpenProjectResult, OpenProjectSuccess, OpenProjectFailure, OpenProjectAuthOption, OpenProjectConnectionMode, RunToolOptions, RunToolResult, RunToolSuccess, RunToolFailure, RunToolFailureReason, RunSystemToolOptions, RunSystemToolResult, RunSystemToolSuccess, RunSystemToolFailure, SetupMcpOptions, SetupMcpResult, SetupMcpSuccess, SetupMcpFailure, InstallPluginOptions, InstallPluginResult, InstallPluginSuccess, InstallPluginFailure, RemovePluginOptions, RemovePluginResult, RemovePluginSuccess, RemovePluginFailure, } from './lib/types.js';
6
+ export type { ProgressEvent, ProgressCallback, ResultKind, OpenProjectOptions, OpenProjectResult, OpenProjectSuccess, OpenProjectFailure, OpenProjectAuthOption, OpenProjectConnectionMode, CreateProjectOptions, CreateProjectResult, CreateProjectSuccess, CreateProjectFailure, RunToolOptions, RunToolResult, RunToolSuccess, RunToolFailure, RunToolFailureReason, RunSystemToolOptions, RunSystemToolResult, RunSystemToolSuccess, RunSystemToolFailure, SetupMcpOptions, SetupMcpResult, SetupMcpSuccess, SetupMcpFailure, InstallPluginOptions, InstallPluginResult, InstallPluginSuccess, InstallPluginFailure, RemovePluginOptions, RemovePluginResult, RemovePluginSuccess, RemovePluginFailure, } from './lib/types.js';
package/dist/lib.js CHANGED
@@ -13,6 +13,7 @@
13
13
  // Consumers: `import { openProject } from 'godot-cli'` (maps to this file
14
14
  // via the `exports` field in package.json).
15
15
  export { openProject } from './lib/open.js';
16
+ export { createProject } from './lib/create-project.js';
16
17
  export { runTool, runSystemTool } from './lib/run-tool.js';
17
18
  export { setupMcp, listAgentIds } from './lib/setup-mcp.js';
18
19
  export { installPlugin, removePlugin } from './lib/install-plugin.js';
package/dist/lib.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"lib.js","sourceRoot":"","sources":["../src/lib.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,EAAE;AACF,eAAe;AACf,+EAA+E;AAC/E,wDAAwD;AACxD,oDAAoD;AACpD,yEAAyE;AACzE,4DAA4D;AAC5D,+EAA+E;AAC/E,gEAAgE;AAChE,6EAA6E;AAC7E,EAAE;AACF,0EAA0E;AAC1E,4CAA4C;AAE5C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC"}
1
+ {"version":3,"file":"lib.js","sourceRoot":"","sources":["../src/lib.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,EAAE;AACF,eAAe;AACf,+EAA+E;AAC/E,wDAAwD;AACxD,oDAAoD;AACpD,yEAAyE;AACzE,4DAA4D;AAC5D,+EAA+E;AAC/E,gEAAgE;AAChE,6EAA6E;AAC7E,EAAE;AACF,0EAA0E;AAC1E,4CAA4C;AAE5C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC"}
package/docs/README.md CHANGED
@@ -1,7 +1,7 @@
1
- # godot-cli — docs
2
-
3
- Additional documentation for `godot-cli`. See the package [`README.md`](../README.md) for the full
4
- command reference and library API.
5
-
6
- Localized READMEs (e.g. `README.es.md`, `README.ja.md`, `README.zh-CN.md`) may be added here over time,
7
- mirroring the Unity-MCP CLI's translation set.
1
+ # godot-cli — docs
2
+
3
+ Additional documentation for `godot-cli`. See the package [`README.md`](../README.md) for the full
4
+ command reference and library API.
5
+
6
+ Localized READMEs (e.g. `README.es.md`, `README.ja.md`, `README.zh-CN.md`) may be added here over time,
7
+ mirroring the Unity-MCP CLI's translation set.
package/package.json CHANGED
@@ -1,73 +1,73 @@
1
- {
2
- "name": "godot-cli",
3
- "version": "0.1.0",
4
- "description": "Cross-platform CLI tool for Godot-MCP (Skills & MCP). Resolves and launches the Godot editor with MCP connection env vars, runs MCP/system tools over HTTP, probes server health, configures AI agents (Claude Code, Cursor, VS Code, …), and enables/disables the godot_mcp addon. Works with Claude Code, Cursor, Copilot, and any MCP client.",
5
- "type": "module",
6
- "main": "dist/lib.js",
7
- "types": "dist/lib.d.ts",
8
- "exports": {
9
- ".": {
10
- "types": "./dist/lib.d.ts",
11
- "import": "./dist/lib.js"
12
- },
13
- "./cli": {
14
- "types": "./dist/cli.d.ts",
15
- "import": "./dist/cli.js"
16
- }
17
- },
18
- "bin": {
19
- "godot-cli": "bin/godot-cli.js"
20
- },
21
- "files": [
22
- "dist",
23
- "bin",
24
- "README.md",
25
- "CHANGELOG.md",
26
- "docs"
27
- ],
28
- "scripts": {
29
- "build": "tsc",
30
- "pretest": "npm run build",
31
- "test": "vitest run",
32
- "test:watch": "vitest",
33
- "prepublishOnly": "npm run build",
34
- "prepack": "npm run build"
35
- },
36
- "keywords": [
37
- "cli",
38
- "godot",
39
- "godot ai",
40
- "godot skills",
41
- "godot mcp",
42
- "ai skills",
43
- "ai mcp",
44
- "ai",
45
- "mcp",
46
- "model-context-protocol",
47
- "gamedev",
48
- "game-dev"
49
- ],
50
- "author": {
51
- "name": "Ivan Murzak",
52
- "url": "https://github.com/IvanMurzak"
53
- },
54
- "license": "Apache-2.0",
55
- "repository": {
56
- "type": "git",
57
- "url": "https://github.com/IvanMurzak/Godot-MCP.git",
58
- "directory": "cli"
59
- },
60
- "engines": {
61
- "node": "^20.19.0 || >=22.12.0"
62
- },
63
- "dependencies": {
64
- "chalk": "^5.6.2",
65
- "commander": "^13.1.0",
66
- "yocto-spinner": "^1.1.0"
67
- },
68
- "devDependencies": {
69
- "@types/node": "^22.15.0",
70
- "typescript": "^5.8.0",
71
- "vitest": "^3.1.0"
72
- }
73
- }
1
+ {
2
+ "name": "godot-cli",
3
+ "version": "0.3.0",
4
+ "description": "Cross-platform CLI tool for Godot-MCP (Skills & MCP). Resolves and launches the Godot editor with MCP connection env vars, runs MCP/system tools over HTTP, probes server health, configures AI agents (Claude Code, Cursor, VS Code, …), and enables/disables the godot_mcp addon. Works with Claude Code, Cursor, Copilot, and any MCP client.",
5
+ "type": "module",
6
+ "main": "dist/lib.js",
7
+ "types": "dist/lib.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/lib.d.ts",
11
+ "import": "./dist/lib.js"
12
+ },
13
+ "./cli": {
14
+ "types": "./dist/cli.d.ts",
15
+ "import": "./dist/cli.js"
16
+ }
17
+ },
18
+ "bin": {
19
+ "godot-cli": "bin/godot-cli.js"
20
+ },
21
+ "files": [
22
+ "dist",
23
+ "bin",
24
+ "README.md",
25
+ "CHANGELOG.md",
26
+ "docs"
27
+ ],
28
+ "scripts": {
29
+ "build": "tsc",
30
+ "pretest": "npm run build",
31
+ "test": "vitest run",
32
+ "test:watch": "vitest",
33
+ "prepublishOnly": "npm run build",
34
+ "prepack": "npm run build"
35
+ },
36
+ "keywords": [
37
+ "cli",
38
+ "godot",
39
+ "godot ai",
40
+ "godot skills",
41
+ "godot mcp",
42
+ "ai skills",
43
+ "ai mcp",
44
+ "ai",
45
+ "mcp",
46
+ "model-context-protocol",
47
+ "gamedev",
48
+ "game-dev"
49
+ ],
50
+ "author": {
51
+ "name": "Ivan Murzak",
52
+ "url": "https://github.com/IvanMurzak"
53
+ },
54
+ "license": "Apache-2.0",
55
+ "repository": {
56
+ "type": "git",
57
+ "url": "https://github.com/IvanMurzak/Godot-MCP.git",
58
+ "directory": "cli"
59
+ },
60
+ "engines": {
61
+ "node": "^20.19.0 || >=22.12.0"
62
+ },
63
+ "dependencies": {
64
+ "chalk": "^5.6.2",
65
+ "commander": "^13.1.0",
66
+ "yocto-spinner": "^1.1.0"
67
+ },
68
+ "devDependencies": {
69
+ "@types/node": "^22.15.0",
70
+ "typescript": "^5.8.0",
71
+ "vitest": "^3.1.0"
72
+ }
73
+ }