godot-cli 0.2.0 → 0.4.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.
@@ -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":"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"}
@@ -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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "godot-cli",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
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
5
  "type": "module",
6
6
  "main": "dist/lib.js",