godot-cli 0.11.1 → 0.12.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/README.md +29 -2
- package/dist/commands/install-plugin.js +44 -6
- package/dist/commands/install-plugin.js.map +1 -1
- package/dist/lib/install-plugin.d.ts +15 -8
- package/dist/lib/install-plugin.js +238 -16
- package/dist/lib/install-plugin.js.map +1 -1
- package/dist/lib/types.d.ts +67 -0
- package/dist/lib.d.ts +1 -1
- package/dist/utils/addon-deps.d.ts +15 -0
- package/dist/utils/addon-deps.js +27 -0
- package/dist/utils/addon-deps.js.map +1 -0
- package/dist/utils/addon-source.d.ts +36 -0
- package/dist/utils/addon-source.js +68 -0
- package/dist/utils/addon-source.js.map +1 -0
- package/dist/utils/csproj-deps.d.ts +40 -0
- package/dist/utils/csproj-deps.js +121 -0
- package/dist/utils/csproj-deps.js.map +1 -0
- package/dist/utils/unzip.d.ts +25 -0
- package/dist/utils/unzip.js +79 -0
- package/dist/utils/unzip.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -34,8 +34,8 @@ Requires Node `^20.19.0 || >=22.12.0`.
|
|
|
34
34
|
| `setup-skills <agent> [path]` | Generate Godot-MCP skill files (a `SKILL.md`-per-tool-family) under the agent's skills path. `--list` shows each agent's skills support. |
|
|
35
35
|
| `configure [path]` | List / enable / disable tools, prompts, and resources in the project-local `.godot-mcp/features.json`. |
|
|
36
36
|
| `close [path]` | Gracefully stop the Godot editor running for a project (`--force` to hard-kill). |
|
|
37
|
-
| `install-plugin [path]` |
|
|
38
|
-
| `remove-plugin [path]` | Disable the `godot_mcp` addon in `project.godot` `[editor_plugins]
|
|
37
|
+
| `install-plugin [path]` | Install the `godot_mcp` addon end-to-end: materialize `res://addons/godot_mcp/` (download the matching GitHub release, or `--source <path>` a local copy), add the required NuGet `PackageReference`s to the project `.csproj`, and enable the plugin. Idempotent. |
|
|
38
|
+
| `remove-plugin [path]` | Disable the `godot_mcp` addon in `project.godot` `[editor_plugins]` (does not delete the addon files). |
|
|
39
39
|
| `update` | Check npm for a newer `godot-cli` and install it. |
|
|
40
40
|
|
|
41
41
|
### Editor resolution (`open`)
|
|
@@ -97,6 +97,33 @@ exposes no skill-generate HTTP endpoint, so no server or running editor is requi
|
|
|
97
97
|
`GodotMcpConnection.Start` → `GenerateSkillFilesIfNeeded`; the CLI command is the
|
|
98
98
|
server-less, scriptable path that does not need a live editor.)
|
|
99
99
|
|
|
100
|
+
## `install-plugin`
|
|
101
|
+
|
|
102
|
+
`godot-cli install-plugin [path]` is a **real installer** — it makes a from-scratch terminal install
|
|
103
|
+
produce a working project, in one idempotent command:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
godot-cli install-plugin ./MyGodotProject # download the matching release + install
|
|
107
|
+
godot-cli install-plugin --version 0.11.1 ./MyGodotProject # pin a specific addon release
|
|
108
|
+
godot-cli install-plugin --source ./Godot-MCP/addons/godot_mcp ./MyGodotProject # offline / dev copy
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
It performs three steps:
|
|
112
|
+
|
|
113
|
+
1. **Materialize `res://addons/godot_mcp/`.** By default it downloads `godot-mcp-addon-<version>.zip`
|
|
114
|
+
over HTTPS from **github.com only** (the `IvanMurzak/Godot-MCP` release `v<version>`; the version
|
|
115
|
+
defaults to the CLI's own version). Non-`github.com` hosts and plain `http` are rejected. With
|
|
116
|
+
`--source <path>` it copies the addon from a local directory instead (no network) — `<path>` may be a
|
|
117
|
+
directory that *is* `addons/godot_mcp` or one that *contains* it.
|
|
118
|
+
2. **Add the NuGet packages** the addon needs (`com.IvanMurzak.ReflectorNet`, `com.IvanMurzak.McpPlugin`)
|
|
119
|
+
to the project's `.csproj`, idempotently — adding when missing, reconciling a stale version, and
|
|
120
|
+
leaving a correct pin untouched. The versions are single-sourced from the addon's own
|
|
121
|
+
`Godot-MCP.csproj` pins, so the scaffold can never drift.
|
|
122
|
+
3. **Enable the plugin** in `project.godot` `[editor_plugins]`.
|
|
123
|
+
|
|
124
|
+
It is library-safe (returns a `{ kind: 'success' | 'failure' }` union; never throws past the public
|
|
125
|
+
boundary) and idempotent — re-running on an already-installed project reports no change.
|
|
126
|
+
|
|
100
127
|
## Library API
|
|
101
128
|
|
|
102
129
|
The package also exports a side-effect-free library (the `.` entry):
|
|
@@ -1,30 +1,68 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
|
+
import { createRequire } from 'module';
|
|
2
3
|
import * as path from 'path';
|
|
3
4
|
import * as ui from '../utils/ui.js';
|
|
4
5
|
import { verbose } from '../utils/ui.js';
|
|
5
6
|
import { installPlugin } from '../lib/install-plugin.js';
|
|
7
|
+
/** The CLI's own version — the default addon release version to download. */
|
|
8
|
+
function cliVersion() {
|
|
9
|
+
try {
|
|
10
|
+
const require = createRequire(import.meta.url);
|
|
11
|
+
const pkg = require('../../package.json');
|
|
12
|
+
return pkg.version;
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return '';
|
|
16
|
+
}
|
|
17
|
+
}
|
|
6
18
|
export const installPluginCommand = new Command('install-plugin')
|
|
7
|
-
.description('
|
|
19
|
+
.description('Install the godot_mcp addon into a Godot C# project: materialize res://addons/godot_mcp/ (download the matching GitHub release, or --source a local copy), add the required NuGet PackageReferences to the project .csproj, and enable the plugin in project.godot.')
|
|
8
20
|
.argument('[path]', 'Path to the Godot project')
|
|
9
21
|
.option('--path <path>', 'Path to the Godot project')
|
|
22
|
+
.option('--source <path>', 'Install the addon from a local directory (offline / dev / CI) instead of downloading it')
|
|
23
|
+
.option('--version <x.y.z>', 'Addon release version to download (defaults to this CLI version). Ignored with --source.')
|
|
10
24
|
.action(async (positionalPath, options) => {
|
|
11
25
|
const resolvedPath = positionalPath ?? options.path ?? process.cwd();
|
|
12
26
|
const projectPath = path.resolve(resolvedPath);
|
|
13
|
-
ui.heading('
|
|
27
|
+
ui.heading('Installing godot_mcp addon');
|
|
14
28
|
verbose(`Project path: ${projectPath}`);
|
|
15
|
-
|
|
16
|
-
|
|
29
|
+
if (options.source)
|
|
30
|
+
verbose(`--source: ${options.source}`);
|
|
31
|
+
const spinner = ui.startSpinner('Installing addon...');
|
|
32
|
+
const result = await installPlugin({
|
|
33
|
+
godotProjectPath: projectPath,
|
|
34
|
+
source: options.source,
|
|
35
|
+
version: options.version ?? cliVersion(),
|
|
36
|
+
});
|
|
17
37
|
if (result.kind === 'failure') {
|
|
18
|
-
spinner.error('Failed to
|
|
38
|
+
spinner.error('Failed to install plugin');
|
|
19
39
|
ui.error(result.error.message);
|
|
40
|
+
for (const warning of result.warnings) {
|
|
41
|
+
console.log('');
|
|
42
|
+
ui.warn(warning);
|
|
43
|
+
}
|
|
20
44
|
process.exit(1);
|
|
21
45
|
}
|
|
22
46
|
if (result.changed) {
|
|
23
|
-
spinner.success('godot_mcp addon enabled');
|
|
47
|
+
spinner.success('godot_mcp addon installed and enabled');
|
|
24
48
|
}
|
|
25
49
|
else {
|
|
26
50
|
spinner.success('godot_mcp addon was already enabled');
|
|
27
51
|
}
|
|
52
|
+
// Addon files outcome.
|
|
53
|
+
if (result.materialize.source === 'download') {
|
|
54
|
+
ui.label('Addon files', `downloaded → ${result.materialize.addonDir}`);
|
|
55
|
+
}
|
|
56
|
+
else if (result.materialize.source === 'local') {
|
|
57
|
+
ui.label('Addon files', `copied from ${result.materialize.sourceDir} → ${result.materialize.addonDir}`);
|
|
58
|
+
}
|
|
59
|
+
// csproj outcome.
|
|
60
|
+
if (result.csproj.csprojPath) {
|
|
61
|
+
const summary = result.csproj.packages
|
|
62
|
+
.map((p) => `${p.id}@${p.version} (${p.action})`)
|
|
63
|
+
.join(', ');
|
|
64
|
+
ui.label('NuGet packages', summary || '(none)');
|
|
65
|
+
}
|
|
28
66
|
ui.label('project.godot', result.projectGodotPath);
|
|
29
67
|
ui.label('Enabled plugins', result.enabledPlugins.join(', ') || '(none)');
|
|
30
68
|
for (const warning of result.warnings) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"install-plugin.js","sourceRoot":"","sources":["../../src/commands/install-plugin.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;
|
|
1
|
+
{"version":3,"file":"install-plugin.js","sourceRoot":"","sources":["../../src/commands/install-plugin.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,16 +1,23 @@
|
|
|
1
1
|
import { projectGodotPath as resolveProjectGodotPath } from '../utils/project-godot.js';
|
|
2
2
|
import type { InstallPluginOptions, InstallPluginResult, RemovePluginOptions, RemovePluginResult } from './types.js';
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
* `enabled` array. Library-safe: no stdout noise, no process.exit, no throws
|
|
6
|
-
* past the public boundary.
|
|
4
|
+
* Install the `godot_mcp` addon into a Godot C# project as a REAL installer:
|
|
7
5
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
6
|
+
* 1. Materialize `res://addons/godot_mcp/` — by default downloading
|
|
7
|
+
* `godot-mcp-addon-<version>.zip` over HTTPS from github.com only (the
|
|
8
|
+
* `IvanMurzak/Godot-MCP` release `v<version>`), or, with `--source <path>`,
|
|
9
|
+
* copying the addon from a local directory (offline / dev / CI).
|
|
10
|
+
* 2. Add the two NuGet `PackageReference`s the addon needs to the consumer
|
|
11
|
+
* `.csproj`, idempotently and single-sourced from the addon's own pins.
|
|
12
|
+
* 3. Flip the `[editor_plugins] enabled` flag in `project.godot`.
|
|
12
13
|
*
|
|
13
|
-
*
|
|
14
|
+
* Library-safe: no stdout noise, no `process.exit`, no throws past the public
|
|
15
|
+
* boundary; returns a `{ kind: 'success' | 'failure' }` union. Idempotent: a
|
|
16
|
+
* re-run that finds the addon present, the pins present, and the plugin already
|
|
17
|
+
* enabled reports `changed: false` and makes no writes. On a download/copy
|
|
18
|
+
* failure the project is left as found: both paths materialize into a temp
|
|
19
|
+
* sibling and only swap it into the addon dir after a fully successful
|
|
20
|
+
* fetch+extract / copy, so a partial materialization is rolled back.
|
|
14
21
|
*/
|
|
15
22
|
export declare function installPlugin(opts: InstallPluginOptions): Promise<InstallPluginResult>;
|
|
16
23
|
/**
|
|
@@ -1,18 +1,32 @@
|
|
|
1
1
|
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
2
3
|
import { GODOT_MCP_PLUGIN_PATH, projectGodotPath as resolveProjectGodotPath, togglePluginInText, } from '../utils/project-godot.js';
|
|
4
|
+
import { addAddonPackageReferences } from '../utils/csproj-deps.js';
|
|
5
|
+
import { ADDON_PACKAGE_REFERENCES } from '../utils/addon-deps.js';
|
|
6
|
+
import { addonDownloadUrl, assertTrustedDownloadUrl, } from '../utils/addon-source.js';
|
|
7
|
+
import { parseZip } from '../utils/unzip.js';
|
|
3
8
|
import { emitProgress } from './progress.js';
|
|
4
9
|
import { requireGodotProject } from './validation.js';
|
|
10
|
+
/** Relative path of the addon dir inside a Godot project. */
|
|
11
|
+
const ADDON_REL_DIR = path.join('addons', 'godot_mcp');
|
|
5
12
|
/**
|
|
6
|
-
*
|
|
7
|
-
* `enabled` array. Library-safe: no stdout noise, no process.exit, no throws
|
|
8
|
-
* past the public boundary.
|
|
13
|
+
* Install the `godot_mcp` addon into a Godot C# project as a REAL installer:
|
|
9
14
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
15
|
+
* 1. Materialize `res://addons/godot_mcp/` — by default downloading
|
|
16
|
+
* `godot-mcp-addon-<version>.zip` over HTTPS from github.com only (the
|
|
17
|
+
* `IvanMurzak/Godot-MCP` release `v<version>`), or, with `--source <path>`,
|
|
18
|
+
* copying the addon from a local directory (offline / dev / CI).
|
|
19
|
+
* 2. Add the two NuGet `PackageReference`s the addon needs to the consumer
|
|
20
|
+
* `.csproj`, idempotently and single-sourced from the addon's own pins.
|
|
21
|
+
* 3. Flip the `[editor_plugins] enabled` flag in `project.godot`.
|
|
14
22
|
*
|
|
15
|
-
*
|
|
23
|
+
* Library-safe: no stdout noise, no `process.exit`, no throws past the public
|
|
24
|
+
* boundary; returns a `{ kind: 'success' | 'failure' }` union. Idempotent: a
|
|
25
|
+
* re-run that finds the addon present, the pins present, and the plugin already
|
|
26
|
+
* enabled reports `changed: false` and makes no writes. On a download/copy
|
|
27
|
+
* failure the project is left as found: both paths materialize into a temp
|
|
28
|
+
* sibling and only swap it into the addon dir after a fully successful
|
|
29
|
+
* fetch+extract / copy, so a partial materialization is rolled back.
|
|
16
30
|
*/
|
|
17
31
|
export async function installPlugin(opts) {
|
|
18
32
|
const warnings = [];
|
|
@@ -30,26 +44,32 @@ export async function installPlugin(opts) {
|
|
|
30
44
|
const { projectPath, projectGodotPath } = validated;
|
|
31
45
|
emitProgress(opts.onProgress, {
|
|
32
46
|
phase: 'start',
|
|
33
|
-
message: `
|
|
47
|
+
message: `Installing godot_mcp addon into ${projectPath}`,
|
|
34
48
|
});
|
|
49
|
+
// 1. Materialize the addon files (download / local copy / skip).
|
|
50
|
+
const materialize = await materializeAddon(projectPath, opts, warnings);
|
|
51
|
+
// 2. Patch the consumer csproj with the addon's NuGet PackageReferences.
|
|
52
|
+
const csproj = patchConsumerCsproj(projectPath, warnings, opts.onProgress);
|
|
53
|
+
// 3. Enable the plugin in project.godot.
|
|
35
54
|
const text = fs.readFileSync(projectGodotPath, 'utf-8');
|
|
36
|
-
const
|
|
37
|
-
if (
|
|
38
|
-
fs.writeFileSync(projectGodotPath,
|
|
55
|
+
const toggled = togglePluginInText(text, true, GODOT_MCP_PLUGIN_PATH);
|
|
56
|
+
if (toggled.kind === 'changed') {
|
|
57
|
+
fs.writeFileSync(projectGodotPath, toggled.text);
|
|
39
58
|
emitProgress(opts.onProgress, {
|
|
40
59
|
phase: 'manifest-patched',
|
|
41
60
|
message: `Wrote ${projectGodotPath}`,
|
|
42
61
|
manifestPath: projectGodotPath,
|
|
43
62
|
});
|
|
44
63
|
}
|
|
45
|
-
|
|
46
|
-
emitProgress(opts.onProgress, { phase: 'done', message: 'godot_mcp addon enabled.' });
|
|
64
|
+
emitProgress(opts.onProgress, { phase: 'done', message: 'godot_mcp addon installed.' });
|
|
47
65
|
return {
|
|
48
66
|
kind: 'success',
|
|
49
67
|
success: true,
|
|
50
|
-
changed:
|
|
68
|
+
changed: toggled.kind === 'changed',
|
|
51
69
|
projectGodotPath,
|
|
52
|
-
enabledPlugins:
|
|
70
|
+
enabledPlugins: toggled.enabled,
|
|
71
|
+
materialize,
|
|
72
|
+
csproj,
|
|
53
73
|
warnings,
|
|
54
74
|
};
|
|
55
75
|
}
|
|
@@ -62,6 +82,208 @@ export async function installPlugin(opts) {
|
|
|
62
82
|
};
|
|
63
83
|
}
|
|
64
84
|
}
|
|
85
|
+
/**
|
|
86
|
+
* Materialize `addons/godot_mcp/` into the project from the GitHub release zip
|
|
87
|
+
* (default) or a local `--source` directory. Idempotent for the local-copy and
|
|
88
|
+
* download paths: the target dir is replaced atomically-ish (extract/copy into a
|
|
89
|
+
* temp sibling, then swap), so a failure leaves the existing addon untouched.
|
|
90
|
+
*/
|
|
91
|
+
async function materializeAddon(projectPath, opts, warnings) {
|
|
92
|
+
const addonDir = path.join(projectPath, ADDON_REL_DIR);
|
|
93
|
+
if (opts.skipMaterialize === true) {
|
|
94
|
+
if (!fs.existsSync(path.join(addonDir, 'plugin.cfg'))) {
|
|
95
|
+
warnings.push(`skipMaterialize was set but ${path.join(addonDir, 'plugin.cfg')} is absent — the editor cannot load the plugin until the addon files are present.`);
|
|
96
|
+
}
|
|
97
|
+
return { source: 'skipped', addonDir };
|
|
98
|
+
}
|
|
99
|
+
if (opts.source !== undefined && opts.source !== '') {
|
|
100
|
+
const sourceDir = resolveAddonSourceDir(opts.source);
|
|
101
|
+
copyAddonFromLocal(sourceDir, projectPath, addonDir, opts.onProgress);
|
|
102
|
+
emitProgress(opts.onProgress, {
|
|
103
|
+
phase: 'addon-materialized',
|
|
104
|
+
message: `Copied addon from ${sourceDir}`,
|
|
105
|
+
addonDir,
|
|
106
|
+
source: 'local',
|
|
107
|
+
});
|
|
108
|
+
return { source: 'local', addonDir, sourceDir };
|
|
109
|
+
}
|
|
110
|
+
// Download path. Default the version to the CLI's own version (passed by the
|
|
111
|
+
// command via opts.version); fail clearly if neither is available.
|
|
112
|
+
const version = (opts.version ?? '').trim();
|
|
113
|
+
if (version === '') {
|
|
114
|
+
throw new Error('No addon version to download. Pass --version <x.y.z> or --source <path> to install from a local copy.');
|
|
115
|
+
}
|
|
116
|
+
const url = addonDownloadUrl(version);
|
|
117
|
+
assertTrustedDownloadUrl(url); // fail-closed: github.com + https only.
|
|
118
|
+
emitProgress(opts.onProgress, {
|
|
119
|
+
phase: 'addon-downloading',
|
|
120
|
+
message: `Downloading addon ${version} from ${url}`,
|
|
121
|
+
url,
|
|
122
|
+
});
|
|
123
|
+
const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
|
|
124
|
+
const response = await fetchImpl(url);
|
|
125
|
+
if (!response.ok) {
|
|
126
|
+
throw new Error(`Failed to download addon ${version}: HTTP ${response.status} ${response.statusText} from ${url}. ` +
|
|
127
|
+
`Verify the release v${version} exists, or use --source <path> for an offline/dev install.`);
|
|
128
|
+
}
|
|
129
|
+
const archive = Buffer.from(await response.arrayBuffer());
|
|
130
|
+
emitProgress(opts.onProgress, { phase: 'addon-extracting', message: 'Extracting addon zip' });
|
|
131
|
+
const entries = parseZip(archive);
|
|
132
|
+
extractAddonEntries(entries, projectPath, addonDir);
|
|
133
|
+
emitProgress(opts.onProgress, {
|
|
134
|
+
phase: 'addon-materialized',
|
|
135
|
+
message: `Downloaded + extracted addon to ${addonDir}`,
|
|
136
|
+
addonDir,
|
|
137
|
+
source: 'download',
|
|
138
|
+
});
|
|
139
|
+
return { source: 'download', addonDir, downloadUrl: url };
|
|
140
|
+
}
|
|
141
|
+
/** Resolve + validate a `--source` directory: it must exist and contain plugin.cfg. */
|
|
142
|
+
function resolveAddonSourceDir(source) {
|
|
143
|
+
const resolved = path.resolve(source);
|
|
144
|
+
// Accept either a path that IS addons/godot_mcp (contains plugin.cfg directly)
|
|
145
|
+
// or a path that CONTAINS addons/godot_mcp.
|
|
146
|
+
if (fs.existsSync(path.join(resolved, 'plugin.cfg'))) {
|
|
147
|
+
return resolved;
|
|
148
|
+
}
|
|
149
|
+
const nested = path.join(resolved, 'addons', 'godot_mcp');
|
|
150
|
+
if (fs.existsSync(path.join(nested, 'plugin.cfg'))) {
|
|
151
|
+
return nested;
|
|
152
|
+
}
|
|
153
|
+
throw new Error(`--source ${resolved} does not contain a godot_mcp addon (no plugin.cfg found at it or at addons/godot_mcp/).`);
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Materialize the addon into a fresh staging sibling via `fill`, then atomically
|
|
157
|
+
* swap it into `addonDir`. A mid-fill failure leaves the existing addon untouched
|
|
158
|
+
* (staging is discarded), honoring the install's documented rollback guarantee.
|
|
159
|
+
* Shared by both the local-copy and download/extract paths.
|
|
160
|
+
*/
|
|
161
|
+
function stageThenSwapAddon(projectPath, addonDir, fill) {
|
|
162
|
+
const addonReal = path.resolve(addonDir);
|
|
163
|
+
const staging = path.resolve(projectPath, `.godot-mcp-addon-staging-${process.pid}-${Date.now()}`);
|
|
164
|
+
fs.rmSync(staging, { recursive: true, force: true });
|
|
165
|
+
fs.mkdirSync(staging, { recursive: true });
|
|
166
|
+
try {
|
|
167
|
+
fill(staging);
|
|
168
|
+
// Swap staging -> addonDir only after `fill` fully succeeded.
|
|
169
|
+
fs.rmSync(addonReal, { recursive: true, force: true });
|
|
170
|
+
fs.mkdirSync(path.dirname(addonReal), { recursive: true });
|
|
171
|
+
fs.renameSync(staging, addonReal);
|
|
172
|
+
}
|
|
173
|
+
finally {
|
|
174
|
+
// Best-effort cleanup if the swap didn't consume staging.
|
|
175
|
+
fs.rmSync(staging, { recursive: true, force: true });
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Recursively copy a local addon dir into the project's addons/godot_mcp/. Stages
|
|
180
|
+
* into a temp sibling and swaps, so a mid-copy failure leaves the existing addon
|
|
181
|
+
* intact (matching the download path's rollback guarantee). Deterministic +
|
|
182
|
+
* idempotent: the swap replaces any existing addon dir.
|
|
183
|
+
*/
|
|
184
|
+
function copyAddonFromLocal(sourceDir, projectPath, addonDir, onProgress) {
|
|
185
|
+
emitProgress(onProgress, { phase: 'addon-extracting', message: `Copying addon from ${sourceDir}` });
|
|
186
|
+
stageThenSwapAddon(projectPath, addonDir, (staging) => {
|
|
187
|
+
fs.cpSync(sourceDir, staging, { recursive: true });
|
|
188
|
+
if (!fs.existsSync(path.join(staging, 'plugin.cfg'))) {
|
|
189
|
+
throw new Error(`Copy completed but ${path.join(sourceDir, 'plugin.cfg')} did not yield a plugin.cfg.`);
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Write the zip entries that live under `addons/godot_mcp/` into the project. The
|
|
195
|
+
* release zip expands to `addons/godot_mcp/...`, so entries are written relative
|
|
196
|
+
* to the project root. Path-safety: every resolved target MUST stay inside the
|
|
197
|
+
* staging dir (reject zip-slip `../` traversal). The target addon dir is replaced
|
|
198
|
+
* atomically so the install is deterministic + idempotent and rollback-safe.
|
|
199
|
+
*/
|
|
200
|
+
function extractAddonEntries(entries, projectPath, addonDir) {
|
|
201
|
+
stageThenSwapAddon(projectPath, addonDir, (staging) => {
|
|
202
|
+
let wrotePluginCfg = false;
|
|
203
|
+
for (const entry of entries) {
|
|
204
|
+
// Only the addons/godot_mcp/ subtree is relevant.
|
|
205
|
+
const prefix = 'addons/godot_mcp/';
|
|
206
|
+
if (!entry.path.startsWith(prefix))
|
|
207
|
+
continue;
|
|
208
|
+
const rel = entry.path.slice(prefix.length);
|
|
209
|
+
if (rel === '')
|
|
210
|
+
continue; // the dir entry itself
|
|
211
|
+
const target = path.resolve(staging, rel);
|
|
212
|
+
// Zip-slip guard: target must remain under staging.
|
|
213
|
+
if (target !== staging && !target.startsWith(staging + path.sep)) {
|
|
214
|
+
throw new Error(`Refusing to extract entry escaping the addon dir: ${entry.path}`);
|
|
215
|
+
}
|
|
216
|
+
if (entry.isDirectory) {
|
|
217
|
+
fs.mkdirSync(target, { recursive: true });
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
220
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
221
|
+
fs.writeFileSync(target, entry.bytes);
|
|
222
|
+
if (rel === 'plugin.cfg')
|
|
223
|
+
wrotePluginCfg = true;
|
|
224
|
+
}
|
|
225
|
+
if (!wrotePluginCfg) {
|
|
226
|
+
throw new Error('Downloaded addon zip did not contain addons/godot_mcp/plugin.cfg — the archive is not a valid godot_mcp addon release.');
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Find the consumer's `.csproj` (the one Godot compiles the addon into) and add
|
|
232
|
+
* the two addon NuGet PackageReferences idempotently. The csproj is the single
|
|
233
|
+
* `*.csproj` at the project root (the `--dotnet` scaffold writes
|
|
234
|
+
* `<AssemblyName>.csproj` there). When there is no csproj (a GDScript-only
|
|
235
|
+
* project), the patch is skipped with a warning — the addon's C# cannot compile
|
|
236
|
+
* without one, but that is the consumer's project shape to fix.
|
|
237
|
+
*/
|
|
238
|
+
function patchConsumerCsproj(projectPath, warnings, onProgress) {
|
|
239
|
+
const csprojPath = findConsumerCsproj(projectPath, warnings);
|
|
240
|
+
if (csprojPath === null) {
|
|
241
|
+
warnings.push('No .csproj found at the project root — the godot_mcp addon is C# and needs a Godot.NET.Sdk project. ' +
|
|
242
|
+
`Create one (e.g. \`godot-cli create-project --dotnet\`) and add the ${ADDON_PACKAGE_REFERENCES.map((r) => r.id).join(' + ')} PackageReferences.`);
|
|
243
|
+
return { changed: false, packages: [] };
|
|
244
|
+
}
|
|
245
|
+
const before = fs.readFileSync(csprojPath, 'utf-8');
|
|
246
|
+
const patched = addAddonPackageReferences(before);
|
|
247
|
+
if (patched.changed) {
|
|
248
|
+
fs.writeFileSync(csprojPath, patched.text);
|
|
249
|
+
emitProgress(onProgress, {
|
|
250
|
+
phase: 'csproj-patched',
|
|
251
|
+
message: `Added addon PackageReferences to ${csprojPath}`,
|
|
252
|
+
csprojPath,
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
return {
|
|
256
|
+
csprojPath,
|
|
257
|
+
changed: patched.changed,
|
|
258
|
+
packages: patched.changes.map((c) => ({
|
|
259
|
+
id: c.id,
|
|
260
|
+
action: c.action,
|
|
261
|
+
version: c.version,
|
|
262
|
+
})),
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
/** The single `*.csproj` directly at the project root, or null when none/ambiguous. */
|
|
266
|
+
function findConsumerCsproj(projectPath, warnings) {
|
|
267
|
+
let names;
|
|
268
|
+
try {
|
|
269
|
+
names = fs.readdirSync(projectPath).filter((n) => n.toLowerCase().endsWith('.csproj'));
|
|
270
|
+
}
|
|
271
|
+
catch {
|
|
272
|
+
return null;
|
|
273
|
+
}
|
|
274
|
+
if (names.length === 0)
|
|
275
|
+
return null;
|
|
276
|
+
// A scaffolded Godot project has exactly one root csproj. If there are several,
|
|
277
|
+
// pick deterministically (first alphabetically) — better than failing the whole
|
|
278
|
+
// install; all root csprojs compile into the same Godot assembly and would each
|
|
279
|
+
// need the pins, but warn so the heuristic's choice is observable.
|
|
280
|
+
names.sort();
|
|
281
|
+
if (names.length > 1) {
|
|
282
|
+
warnings.push(`Multiple .csproj files found at the project root (${names.join(', ')}); patched ${names[0]}. ` +
|
|
283
|
+
'If a different one is the Godot project, add the addon PackageReferences to it as well.');
|
|
284
|
+
}
|
|
285
|
+
return path.join(projectPath, names[0]);
|
|
286
|
+
}
|
|
65
287
|
/**
|
|
66
288
|
* Disable the `godot_mcp` addon in a project's `project.godot`
|
|
67
289
|
* `[editor_plugins]` `enabled` array. Idempotent: disabling an already-absent
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"install-plugin.js","sourceRoot":"","sources":["../../src/lib/install-plugin.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"install-plugin.js","sourceRoot":"","sources":["../../src/lib/install-plugin.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/types.d.ts
CHANGED
|
@@ -9,6 +9,22 @@ export type ProgressEvent = {
|
|
|
9
9
|
phase: 'manifest-patched';
|
|
10
10
|
message: string;
|
|
11
11
|
manifestPath: string;
|
|
12
|
+
} | {
|
|
13
|
+
phase: 'addon-downloading';
|
|
14
|
+
message: string;
|
|
15
|
+
url: string;
|
|
16
|
+
} | {
|
|
17
|
+
phase: 'addon-extracting';
|
|
18
|
+
message: string;
|
|
19
|
+
} | {
|
|
20
|
+
phase: 'addon-materialized';
|
|
21
|
+
message: string;
|
|
22
|
+
addonDir: string;
|
|
23
|
+
source: 'download' | 'local';
|
|
24
|
+
} | {
|
|
25
|
+
phase: 'csproj-patched';
|
|
26
|
+
message: string;
|
|
27
|
+
csprojPath: string;
|
|
12
28
|
} | {
|
|
13
29
|
phase: 'project-scaffolded';
|
|
14
30
|
message: string;
|
|
@@ -237,8 +253,55 @@ export type RunSystemToolFailure = RunToolFailure;
|
|
|
237
253
|
export interface InstallPluginOptions {
|
|
238
254
|
/** Absolute or relative path to the Godot project root. */
|
|
239
255
|
godotProjectPath: string;
|
|
256
|
+
/**
|
|
257
|
+
* Local directory to copy `addons/godot_mcp/` from instead of downloading it
|
|
258
|
+
* from the GitHub release (offline / dev / CI path). When set, no network call
|
|
259
|
+
* is made; the directory must contain the addon files (a `plugin.cfg`).
|
|
260
|
+
*/
|
|
261
|
+
source?: string;
|
|
262
|
+
/**
|
|
263
|
+
* Addon release version to download (`<version>` in
|
|
264
|
+
* `godot-mcp-addon-<version>.zip`, tag `v<version>`). Defaults to the CLI's own
|
|
265
|
+
* version. Ignored when `source` is set. Used only on the download path.
|
|
266
|
+
*/
|
|
267
|
+
version?: string;
|
|
268
|
+
/**
|
|
269
|
+
* Skip materializing the addon files (download / copy) and only enable the
|
|
270
|
+
* plugin + patch the csproj. Restores the pre-installer behavior for callers
|
|
271
|
+
* that manage the addon files themselves.
|
|
272
|
+
*/
|
|
273
|
+
skipMaterialize?: boolean;
|
|
274
|
+
/**
|
|
275
|
+
* Injectable fetch for tests (mock the GitHub download). Defaults to
|
|
276
|
+
* `globalThis.fetch`. Used only on the download path.
|
|
277
|
+
*/
|
|
278
|
+
fetchImpl?: typeof fetch;
|
|
240
279
|
onProgress?: ProgressCallback;
|
|
241
280
|
}
|
|
281
|
+
/** What `install-plugin` did to materialize the `addons/godot_mcp/` files. */
|
|
282
|
+
export interface AddonMaterializeOutcome {
|
|
283
|
+
/** Where the addon files came from. `skipped` when `skipMaterialize` was set. */
|
|
284
|
+
source: 'download' | 'local' | 'skipped';
|
|
285
|
+
/** Absolute path to the materialized `addons/godot_mcp/` directory. */
|
|
286
|
+
addonDir: string;
|
|
287
|
+
/** The download URL used (download path only). */
|
|
288
|
+
downloadUrl?: string;
|
|
289
|
+
/** The local source directory used (`--source` path only). */
|
|
290
|
+
sourceDir?: string;
|
|
291
|
+
}
|
|
292
|
+
/** What `install-plugin` did to the consumer `.csproj`'s PackageReferences. */
|
|
293
|
+
export interface CsprojPatchOutcome {
|
|
294
|
+
/** Absolute path to the consumer `.csproj` that was patched, if one was found. */
|
|
295
|
+
csprojPath?: string;
|
|
296
|
+
/** True when the csproj text was modified. */
|
|
297
|
+
changed: boolean;
|
|
298
|
+
/** Per-package summary: each addon pin's add / update / unchanged outcome. */
|
|
299
|
+
packages: {
|
|
300
|
+
id: string;
|
|
301
|
+
action: 'added' | 'updated' | 'unchanged';
|
|
302
|
+
version: string;
|
|
303
|
+
}[];
|
|
304
|
+
}
|
|
242
305
|
export interface InstallPluginSuccess {
|
|
243
306
|
kind: 'success';
|
|
244
307
|
success: true;
|
|
@@ -246,6 +309,10 @@ export interface InstallPluginSuccess {
|
|
|
246
309
|
changed: boolean;
|
|
247
310
|
projectGodotPath: string;
|
|
248
311
|
enabledPlugins: string[];
|
|
312
|
+
/** Addon-files materialization outcome (download / local copy / skipped). */
|
|
313
|
+
materialize: AddonMaterializeOutcome;
|
|
314
|
+
/** Consumer csproj PackageReference patch outcome. */
|
|
315
|
+
csproj: CsprojPatchOutcome;
|
|
249
316
|
warnings: string[];
|
|
250
317
|
}
|
|
251
318
|
export interface InstallPluginFailure {
|
package/dist/lib.d.ts
CHANGED
|
@@ -4,4 +4,4 @@ export { runTool, runSystemTool } from './lib/run-tool.js';
|
|
|
4
4
|
export { setupMcp, listAgentIds } from './lib/setup-mcp.js';
|
|
5
5
|
export { setupSkills } from './lib/setup-skills.js';
|
|
6
6
|
export { installPlugin, removePlugin } from './lib/install-plugin.js';
|
|
7
|
-
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, SetupSkillsOptions, SetupSkillsResult, SetupSkillsSuccess, SetupSkillsFailure, InstallPluginOptions, InstallPluginResult, InstallPluginSuccess, InstallPluginFailure, RemovePluginOptions, RemovePluginResult, RemovePluginSuccess, RemovePluginFailure, } from './lib/types.js';
|
|
7
|
+
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, SetupSkillsOptions, SetupSkillsResult, SetupSkillsSuccess, SetupSkillsFailure, InstallPluginOptions, InstallPluginResult, InstallPluginSuccess, InstallPluginFailure, AddonMaterializeOutcome, CsprojPatchOutcome, RemovePluginOptions, RemovePluginResult, RemovePluginSuccess, RemovePluginFailure, } from './lib/types.js';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** A single NuGet `<PackageReference>` the consumer csproj must declare. */
|
|
2
|
+
export interface AddonPackageReference {
|
|
3
|
+
/** The NuGet package id (the `Include=` attribute). */
|
|
4
|
+
id: string;
|
|
5
|
+
/** The pinned version (the `Version=` attribute). */
|
|
6
|
+
version: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* The exact NuGet `PackageReference`s the consumer's project `.csproj` needs,
|
|
10
|
+
* single-sourced from the addon's `Godot-MCP.csproj` pins. Order matches the
|
|
11
|
+
* addon csproj (ReflectorNet first, then McpPlugin).
|
|
12
|
+
*/
|
|
13
|
+
export declare const ADDON_PACKAGE_REFERENCES: readonly AddonPackageReference[];
|
|
14
|
+
/** The resource path of the addon manifest a consumer project loads the plugin from. */
|
|
15
|
+
export declare const ADDON_PLUGIN_CFG_RESOURCE = "res://addons/godot_mcp/plugin.cfg";
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// The NuGet PackageReferences a consumer's Godot C# project MUST declare so the
|
|
2
|
+
// `addons/godot_mcp/` sources compile into the project assembly (Godot globs every
|
|
3
|
+
// `*.cs` under the project into one assembly — see the addon README
|
|
4
|
+
// "Consumer-install story"). `install-plugin` writes these into the generated
|
|
5
|
+
// consumer `.csproj` so a from-scratch terminal install actually builds.
|
|
6
|
+
//
|
|
7
|
+
// SINGLE SOURCE OF TRUTH: these values mirror the addon's own reused pins in
|
|
8
|
+
// `Godot-MCP.csproj` (`com.IvanMurzak.ReflectorNet`, `com.IvanMurzak.McpPlugin`).
|
|
9
|
+
// They are NOT a bump of those pins — they are the SAME values, copied so the
|
|
10
|
+
// scaffold installs exactly what the addon was built against. A parity test
|
|
11
|
+
// (`cli/tests/addon-deps-parity.test.ts`) reads `Godot-MCP.csproj` and FAILS the
|
|
12
|
+
// build if these constants ever drift from the addon's pins, so the scaffold can
|
|
13
|
+
// never silently install a mismatched version.
|
|
14
|
+
//
|
|
15
|
+
// No top-level side effects; pure data + pure string transforms only.
|
|
16
|
+
/**
|
|
17
|
+
* The exact NuGet `PackageReference`s the consumer's project `.csproj` needs,
|
|
18
|
+
* single-sourced from the addon's `Godot-MCP.csproj` pins. Order matches the
|
|
19
|
+
* addon csproj (ReflectorNet first, then McpPlugin).
|
|
20
|
+
*/
|
|
21
|
+
export const ADDON_PACKAGE_REFERENCES = [
|
|
22
|
+
{ id: 'com.IvanMurzak.ReflectorNet', version: '5.3.1' },
|
|
23
|
+
{ id: 'com.IvanMurzak.McpPlugin', version: '6.10.0' },
|
|
24
|
+
];
|
|
25
|
+
/** The resource path of the addon manifest a consumer project loads the plugin from. */
|
|
26
|
+
export const ADDON_PLUGIN_CFG_RESOURCE = 'res://addons/godot_mcp/plugin.cfg';
|
|
27
|
+
//# sourceMappingURL=addon-deps.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"addon-deps.js","sourceRoot":"","sources":["../../src/utils/addon-deps.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,mFAAmF;AACnF,oEAAoE;AACpE,8EAA8E;AAC9E,yEAAyE;AACzE,EAAE;AACF,6EAA6E;AAC7E,kFAAkF;AAClF,8EAA8E;AAC9E,4EAA4E;AAC5E,iFAAiF;AACjF,iFAAiF;AACjF,+CAA+C;AAC/C,EAAE;AACF,sEAAsE;AAUtE;;;;GAIG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAqC;IACxE,EAAE,EAAE,EAAE,6BAA6B,EAAE,OAAO,EAAE,OAAO,EAAE;IACvD,EAAE,EAAE,EAAE,0BAA0B,EAAE,OAAO,EAAE,QAAQ,EAAE;CAC7C,CAAC;AAEX,wFAAwF;AACxF,MAAM,CAAC,MAAM,yBAAyB,GAAG,mCAAmC,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/** GitHub-release host the addon zip is downloaded from. NOTHING else is trusted. */
|
|
2
|
+
export declare const TRUSTED_DOWNLOAD_HOST = "github.com";
|
|
3
|
+
/** The `owner/repo` the addon releases live under. */
|
|
4
|
+
export declare const ADDON_RELEASE_REPO = "IvanMurzak/Godot-MCP";
|
|
5
|
+
/**
|
|
6
|
+
* The release-asset name for an addon version: `godot-mcp-addon-<version>.zip`.
|
|
7
|
+
* Matches the asset the release workflow attaches (`release.yml` → "Package addon
|
|
8
|
+
* zip": `zip_name="godot-mcp-addon-${version}.zip"`). The `<version>` is the bare
|
|
9
|
+
* version WITHOUT a leading `v` (the `v` only appears in the tag). Pure.
|
|
10
|
+
*/
|
|
11
|
+
export declare function addonAssetName(version: string): string;
|
|
12
|
+
/**
|
|
13
|
+
* The git release TAG for an addon version: the version with a leading `v`
|
|
14
|
+
* (`0.11.1` → `v0.11.1`). The release workflow tags every release `v<version>`
|
|
15
|
+
* (`release.yml` → `tag=v${version}`); an already-`v`-prefixed input is passed
|
|
16
|
+
* through unchanged so a caller cannot double-prefix. Pure.
|
|
17
|
+
*/
|
|
18
|
+
export declare function releaseTag(version: string): string;
|
|
19
|
+
/** Drop a single leading `v`/`V` from a version string. Pure. */
|
|
20
|
+
export declare function stripLeadingV(version: string): string;
|
|
21
|
+
/**
|
|
22
|
+
* The download URL for an addon version's zip:
|
|
23
|
+
* `https://github.com/IvanMurzak/Godot-MCP/releases/download/v<version>/godot-mcp-addon-<version>.zip`.
|
|
24
|
+
* Mirrors `GodotMcpServerView.DownloadUrl`. Pure string build. The host is always
|
|
25
|
+
* `github.com` by construction; `assertTrustedDownloadUrl` re-checks a
|
|
26
|
+
* caller-supplied URL before any network call.
|
|
27
|
+
*/
|
|
28
|
+
export declare function addonDownloadUrl(version: string): string;
|
|
29
|
+
/**
|
|
30
|
+
* Fail-closed host trust check: throw unless `url` is an HTTPS URL whose host is
|
|
31
|
+
* EXACTLY `github.com` (no subdomains, no `github.com.evil.test`, no http). This
|
|
32
|
+
* is the security boundary the task requires — reject non-github hosts. Returns
|
|
33
|
+
* the parsed URL on success. Pure (throws on the unhappy path; the caller turns
|
|
34
|
+
* it into a structured failure so nothing escapes the public boundary).
|
|
35
|
+
*/
|
|
36
|
+
export declare function assertTrustedDownloadUrl(url: string): URL;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// Pure helpers for resolving WHERE the `addons/godot_mcp/` files come from when
|
|
2
|
+
// `install-plugin` materializes them: the trusted GitHub-release download URL and
|
|
3
|
+
// the host-trust check. Mirrors the addon's own trusted-source pattern in
|
|
4
|
+
// `addons/godot_mcp/Runtime/Connection/GodotMcpServerView.cs` (github.com only,
|
|
5
|
+
// `releases/download/v<version>/<asset>`). No side effects; unit-testable.
|
|
6
|
+
/** GitHub-release host the addon zip is downloaded from. NOTHING else is trusted. */
|
|
7
|
+
export const TRUSTED_DOWNLOAD_HOST = 'github.com';
|
|
8
|
+
/** The `owner/repo` the addon releases live under. */
|
|
9
|
+
export const ADDON_RELEASE_REPO = 'IvanMurzak/Godot-MCP';
|
|
10
|
+
/**
|
|
11
|
+
* The release-asset name for an addon version: `godot-mcp-addon-<version>.zip`.
|
|
12
|
+
* Matches the asset the release workflow attaches (`release.yml` → "Package addon
|
|
13
|
+
* zip": `zip_name="godot-mcp-addon-${version}.zip"`). The `<version>` is the bare
|
|
14
|
+
* version WITHOUT a leading `v` (the `v` only appears in the tag). Pure.
|
|
15
|
+
*/
|
|
16
|
+
export function addonAssetName(version) {
|
|
17
|
+
return `godot-mcp-addon-${stripLeadingV(version)}.zip`;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* The git release TAG for an addon version: the version with a leading `v`
|
|
21
|
+
* (`0.11.1` → `v0.11.1`). The release workflow tags every release `v<version>`
|
|
22
|
+
* (`release.yml` → `tag=v${version}`); an already-`v`-prefixed input is passed
|
|
23
|
+
* through unchanged so a caller cannot double-prefix. Pure.
|
|
24
|
+
*/
|
|
25
|
+
export function releaseTag(version) {
|
|
26
|
+
const v = (version ?? '').trim();
|
|
27
|
+
return v.startsWith('v') ? v : `v${v}`;
|
|
28
|
+
}
|
|
29
|
+
/** Drop a single leading `v`/`V` from a version string. Pure. */
|
|
30
|
+
export function stripLeadingV(version) {
|
|
31
|
+
const v = (version ?? '').trim();
|
|
32
|
+
return /^v/i.test(v) ? v.slice(1) : v;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* The download URL for an addon version's zip:
|
|
36
|
+
* `https://github.com/IvanMurzak/Godot-MCP/releases/download/v<version>/godot-mcp-addon-<version>.zip`.
|
|
37
|
+
* Mirrors `GodotMcpServerView.DownloadUrl`. Pure string build. The host is always
|
|
38
|
+
* `github.com` by construction; `assertTrustedDownloadUrl` re-checks a
|
|
39
|
+
* caller-supplied URL before any network call.
|
|
40
|
+
*/
|
|
41
|
+
export function addonDownloadUrl(version) {
|
|
42
|
+
const bare = stripLeadingV(version);
|
|
43
|
+
return `https://${TRUSTED_DOWNLOAD_HOST}/${ADDON_RELEASE_REPO}/releases/download/${releaseTag(version)}/${addonAssetName(bare)}`;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Fail-closed host trust check: throw unless `url` is an HTTPS URL whose host is
|
|
47
|
+
* EXACTLY `github.com` (no subdomains, no `github.com.evil.test`, no http). This
|
|
48
|
+
* is the security boundary the task requires — reject non-github hosts. Returns
|
|
49
|
+
* the parsed URL on success. Pure (throws on the unhappy path; the caller turns
|
|
50
|
+
* it into a structured failure so nothing escapes the public boundary).
|
|
51
|
+
*/
|
|
52
|
+
export function assertTrustedDownloadUrl(url) {
|
|
53
|
+
let parsed;
|
|
54
|
+
try {
|
|
55
|
+
parsed = new URL(url);
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
throw new Error(`Refusing to download addon: malformed URL "${url}".`);
|
|
59
|
+
}
|
|
60
|
+
if (parsed.protocol !== 'https:') {
|
|
61
|
+
throw new Error(`Refusing to download addon: only https is allowed, got "${parsed.protocol}" (${url}).`);
|
|
62
|
+
}
|
|
63
|
+
if (parsed.hostname.toLowerCase() !== TRUSTED_DOWNLOAD_HOST) {
|
|
64
|
+
throw new Error(`Refusing to download addon from untrusted host "${parsed.hostname}". Only ${TRUSTED_DOWNLOAD_HOST} is trusted.`);
|
|
65
|
+
}
|
|
66
|
+
return parsed;
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=addon-source.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"addon-source.js","sourceRoot":"","sources":["../../src/utils/addon-source.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,kFAAkF;AAClF,0EAA0E;AAC1E,gFAAgF;AAChF,2EAA2E;AAE3E,qFAAqF;AACrF,MAAM,CAAC,MAAM,qBAAqB,GAAG,YAAY,CAAC;AAElD,sDAAsD;AACtD,MAAM,CAAC,MAAM,kBAAkB,GAAG,sBAAsB,CAAC;AAEzD;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,OAAe;IAC5C,OAAO,mBAAmB,aAAa,CAAC,OAAO,CAAC,MAAM,CAAC;AACzD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,UAAU,CAAC,OAAe;IACxC,MAAM,CAAC,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACjC,OAAO,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;AACzC,CAAC;AAED,iEAAiE;AACjE,MAAM,UAAU,aAAa,CAAC,OAAe;IAC3C,MAAM,CAAC,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACjC,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACxC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAe;IAC9C,MAAM,IAAI,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;IACpC,OAAO,WAAW,qBAAqB,IAAI,kBAAkB,sBAAsB,UAAU,CAAC,OAAO,CAAC,IAAI,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC;AACnI,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,wBAAwB,CAAC,GAAW;IAClD,IAAI,MAAW,CAAC;IAChB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;IACxB,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,8CAA8C,GAAG,IAAI,CAAC,CAAC;IACzE,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CACb,2DAA2D,MAAM,CAAC,QAAQ,MAAM,GAAG,IAAI,CACxF,CAAC;IACJ,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,CAAC,WAAW,EAAE,KAAK,qBAAqB,EAAE,CAAC;QAC5D,MAAM,IAAI,KAAK,CACb,mDAAmD,MAAM,CAAC,QAAQ,WAAW,qBAAqB,cAAc,CACjH,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { type AddonPackageReference } from './addon-deps.js';
|
|
2
|
+
/**
|
|
3
|
+
* Idempotently reconcile a Godot consumer `.csproj`'s `<PackageReference>`s so it
|
|
4
|
+
* declares exactly the addon's two required NuGet pins (see `addon-deps.ts`).
|
|
5
|
+
*
|
|
6
|
+
* Pure: operates on the csproj TEXT and returns the new text + what changed; never
|
|
7
|
+
* touches the filesystem. Exported for unit tests. Handles, idempotently:
|
|
8
|
+
* - a project with NO `<ItemGroup>` at all (appends one before `</Project>`);
|
|
9
|
+
* - a project that already declares both pins at the right version (no change);
|
|
10
|
+
* - a project that declares one or both at a DIFFERENT version (reconciles in place);
|
|
11
|
+
* - a project that declares only one of the two (adds the missing one).
|
|
12
|
+
*
|
|
13
|
+
* It deliberately does a minimal, well-scoped text edit rather than a full XML
|
|
14
|
+
* parse/serialize, to preserve the rest of the consumer's csproj formatting
|
|
15
|
+
* verbatim. The `<PackageReference Include="..." />` shape it reads/writes is the
|
|
16
|
+
* single self-closing form the scaffold and the addon README both use.
|
|
17
|
+
*/
|
|
18
|
+
export type CsprojPatchChange = {
|
|
19
|
+
id: string;
|
|
20
|
+
action: 'added';
|
|
21
|
+
version: string;
|
|
22
|
+
} | {
|
|
23
|
+
id: string;
|
|
24
|
+
action: 'updated';
|
|
25
|
+
from: string;
|
|
26
|
+
version: string;
|
|
27
|
+
} | {
|
|
28
|
+
id: string;
|
|
29
|
+
action: 'unchanged';
|
|
30
|
+
version: string;
|
|
31
|
+
};
|
|
32
|
+
export interface CsprojPatchResult {
|
|
33
|
+
/** The new csproj text (identical to input when nothing changed). */
|
|
34
|
+
text: string;
|
|
35
|
+
/** True when the text was modified. */
|
|
36
|
+
changed: boolean;
|
|
37
|
+
/** One entry per required package describing what happened to it. */
|
|
38
|
+
changes: CsprojPatchChange[];
|
|
39
|
+
}
|
|
40
|
+
export declare function addAddonPackageReferences(csprojText: string, requiredRefs?: readonly AddonPackageReference[]): CsprojPatchResult;
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { ADDON_PACKAGE_REFERENCES } from './addon-deps.js';
|
|
2
|
+
/** Escape a string for use inside a RegExp source. */
|
|
3
|
+
function escapeRegExp(value) {
|
|
4
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Match an existing `<PackageReference Include="<id>" Version="<ver>" />` element
|
|
8
|
+
* for a specific package id, capturing the whole element and its version, in
|
|
9
|
+
* either attribute order (`Include` before or after `Version`). The element may
|
|
10
|
+
* also be a `<PackageReference ...></PackageReference>` open/close pair.
|
|
11
|
+
*/
|
|
12
|
+
function packageRefRegex(id) {
|
|
13
|
+
const escId = escapeRegExp(id);
|
|
14
|
+
// <PackageReference ... Include="id" ... Version="x" ... /> (Include before Version)
|
|
15
|
+
// or Version before Include. Two alternations cover both orders; either may end
|
|
16
|
+
// with a self-close `/>` or an explicit `></PackageReference>`.
|
|
17
|
+
return new RegExp(`<PackageReference\\b[^>]*?\\bInclude\\s*=\\s*"${escId}"[^>]*?\\bVersion\\s*=\\s*"([^"]*)"[^>]*?(?:/>|></PackageReference>)` +
|
|
18
|
+
`|` +
|
|
19
|
+
`<PackageReference\\b[^>]*?\\bVersion\\s*=\\s*"([^"]*)"[^>]*?\\bInclude\\s*=\\s*"${escId}"[^>]*?(?:/>|></PackageReference>)`, 'i');
|
|
20
|
+
}
|
|
21
|
+
/** Render the canonical self-closing element for a required reference. */
|
|
22
|
+
function renderRef(ref) {
|
|
23
|
+
return `<PackageReference Include="${ref.id}" Version="${ref.version}" />`;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Detect the indentation used by the FIRST existing `<PackageReference>` (or fall
|
|
27
|
+
* back to 4 spaces) so appended/inserted elements match the consumer's style.
|
|
28
|
+
*/
|
|
29
|
+
function detectIndent(text) {
|
|
30
|
+
const m = text.match(/\n([ \t]*)<PackageReference\b/);
|
|
31
|
+
return m ? m[1] : ' ';
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Detect the dominant line ending of the csproj so inserted/appended XML matches
|
|
35
|
+
* it (a CRLF csproj should not gain bare-LF lines). Returns `\r\n` when CRLF
|
|
36
|
+
* line endings outnumber bare-LF ones, else `\n`.
|
|
37
|
+
*/
|
|
38
|
+
function detectEol(text) {
|
|
39
|
+
const crlf = (text.match(/\r\n/g) ?? []).length;
|
|
40
|
+
const lf = (text.match(/\n/g) ?? []).length - crlf;
|
|
41
|
+
return crlf > lf ? '\r\n' : '\n';
|
|
42
|
+
}
|
|
43
|
+
export function addAddonPackageReferences(csprojText, requiredRefs = ADDON_PACKAGE_REFERENCES) {
|
|
44
|
+
const changes = [];
|
|
45
|
+
let text = csprojText;
|
|
46
|
+
const indent = detectIndent(text);
|
|
47
|
+
const eol = detectEol(text);
|
|
48
|
+
// First pass: reconcile any references that already exist (possibly at a
|
|
49
|
+
// different version). Collect the ones still missing for the append pass.
|
|
50
|
+
const missing = [];
|
|
51
|
+
for (const ref of requiredRefs) {
|
|
52
|
+
const re = packageRefRegex(ref.id);
|
|
53
|
+
const match = text.match(re);
|
|
54
|
+
if (!match) {
|
|
55
|
+
missing.push(ref);
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
const existingVersion = match[1] ?? match[2] ?? '';
|
|
59
|
+
if (existingVersion === ref.version) {
|
|
60
|
+
changes.push({ id: ref.id, action: 'unchanged', version: ref.version });
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
// Reconcile in place: replace the whole element with the canonical pin.
|
|
64
|
+
text = text.replace(re, renderRef(ref));
|
|
65
|
+
changes.push({ id: ref.id, action: 'updated', from: existingVersion, version: ref.version });
|
|
66
|
+
}
|
|
67
|
+
// Second pass: add the missing references. Prefer an existing <ItemGroup> that
|
|
68
|
+
// already holds a <PackageReference> (group them together); else append a fresh
|
|
69
|
+
// <ItemGroup> just before </Project>.
|
|
70
|
+
if (missing.length > 0) {
|
|
71
|
+
const block = missing.map((ref) => `${indent}${renderRef(ref)}`).join(eol);
|
|
72
|
+
const pkgItemGroupClose = findPackageReferenceItemGroupClose(text);
|
|
73
|
+
if (pkgItemGroupClose !== -1) {
|
|
74
|
+
// Insert the missing refs just before that ItemGroup's closing tag.
|
|
75
|
+
text = `${text.slice(0, pkgItemGroupClose)}${block}${eol}${text.slice(pkgItemGroupClose)}`;
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
// No PackageReference ItemGroup — append a new one before </Project>.
|
|
79
|
+
const groupIndent = indent.length >= 2 ? indent.slice(0, Math.floor(indent.length / 2)) : ' ';
|
|
80
|
+
const newGroup = `${groupIndent}<ItemGroup>${eol}${block}${eol}${groupIndent}</ItemGroup>${eol}`;
|
|
81
|
+
const closeIdx = text.lastIndexOf('</Project>');
|
|
82
|
+
if (closeIdx === -1) {
|
|
83
|
+
// Not a recognizable csproj; append best-effort at EOF.
|
|
84
|
+
text = `${text}${eol}${newGroup}`;
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
text = `${text.slice(0, closeIdx)}${newGroup}${text.slice(closeIdx)}`;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
for (const ref of missing) {
|
|
91
|
+
changes.push({ id: ref.id, action: 'added', version: ref.version });
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
// Restore the required-order in `changes` to match `requiredRefs` for stable output.
|
|
95
|
+
const orderedChanges = requiredRefs
|
|
96
|
+
.map((ref) => changes.find((c) => c.id === ref.id))
|
|
97
|
+
.filter((c) => c !== undefined);
|
|
98
|
+
return {
|
|
99
|
+
text,
|
|
100
|
+
changed: orderedChanges.some((c) => c.action !== 'unchanged'),
|
|
101
|
+
changes: orderedChanges,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Return the index of the `</ItemGroup>` that closes the FIRST `<ItemGroup>`
|
|
106
|
+
* containing a `<PackageReference>`, or -1 when none exists. Used to group the
|
|
107
|
+
* added pins with the consumer's existing package references.
|
|
108
|
+
*/
|
|
109
|
+
function findPackageReferenceItemGroupClose(text) {
|
|
110
|
+
const itemGroupRe = /<ItemGroup\b[^>]*>([\s\S]*?)<\/ItemGroup>/gi;
|
|
111
|
+
let m;
|
|
112
|
+
while ((m = itemGroupRe.exec(text)) !== null) {
|
|
113
|
+
if (/<PackageReference\b/i.test(m[1])) {
|
|
114
|
+
// The close tag starts at the end of the match minus its length.
|
|
115
|
+
const closeTag = '</ItemGroup>';
|
|
116
|
+
return m.index + m[0].length - closeTag.length;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return -1;
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=csproj-deps.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"csproj-deps.js","sourceRoot":"","sources":["../../src/utils/csproj-deps.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal, dependency-free ZIP reader for the addon-install path. Parses the ZIP
|
|
3
|
+
* central directory and inflates each entry (STORED `0` + DEFLATE `8` — the only
|
|
4
|
+
* two compression methods the GitHub release `zip -r` produces). Pure: takes the
|
|
5
|
+
* archive bytes, returns `{ path, bytes }` entries; performs NO filesystem writes
|
|
6
|
+
* (the caller decides where the files land, after path-safety checks).
|
|
7
|
+
*
|
|
8
|
+
* This avoids adding a native/3rd-party unzip dependency to the lean `godot-cli`
|
|
9
|
+
* package while staying cross-platform (no shelling out to a system `unzip`).
|
|
10
|
+
* Exported for unit tests.
|
|
11
|
+
*/
|
|
12
|
+
export interface ZipEntry {
|
|
13
|
+
/** The entry's path inside the archive, using forward slashes. */
|
|
14
|
+
path: string;
|
|
15
|
+
/** Decompressed bytes. Empty for directory entries. */
|
|
16
|
+
bytes: Buffer;
|
|
17
|
+
/** True when the entry is a directory (path ends with `/`). */
|
|
18
|
+
isDirectory: boolean;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Parse a ZIP archive buffer into its entries. Throws a descriptive Error on a
|
|
22
|
+
* malformed archive (the caller wraps this into a structured failure — it never
|
|
23
|
+
* propagates past the library's public boundary).
|
|
24
|
+
*/
|
|
25
|
+
export declare function parseZip(buffer: Buffer): ZipEntry[];
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import * as zlib from 'zlib';
|
|
2
|
+
// ZIP signatures.
|
|
3
|
+
const EOCD_SIGNATURE = 0x06054b50; // End Of Central Directory
|
|
4
|
+
const CDH_SIGNATURE = 0x02014b50; // Central Directory Header
|
|
5
|
+
const LFH_SIGNATURE = 0x04034b50; // Local File Header
|
|
6
|
+
/**
|
|
7
|
+
* Parse a ZIP archive buffer into its entries. Throws a descriptive Error on a
|
|
8
|
+
* malformed archive (the caller wraps this into a structured failure — it never
|
|
9
|
+
* propagates past the library's public boundary).
|
|
10
|
+
*/
|
|
11
|
+
export function parseZip(buffer) {
|
|
12
|
+
const eocdOffset = findEndOfCentralDirectory(buffer);
|
|
13
|
+
if (eocdOffset === -1) {
|
|
14
|
+
throw new Error('Invalid zip: End Of Central Directory record not found.');
|
|
15
|
+
}
|
|
16
|
+
const entryCount = buffer.readUInt16LE(eocdOffset + 10);
|
|
17
|
+
const centralDirOffset = buffer.readUInt32LE(eocdOffset + 16);
|
|
18
|
+
const entries = [];
|
|
19
|
+
let ptr = centralDirOffset;
|
|
20
|
+
for (let i = 0; i < entryCount; i++) {
|
|
21
|
+
if (buffer.readUInt32LE(ptr) !== CDH_SIGNATURE) {
|
|
22
|
+
throw new Error(`Invalid zip: bad central directory header at entry ${i}.`);
|
|
23
|
+
}
|
|
24
|
+
const compressionMethod = buffer.readUInt16LE(ptr + 10);
|
|
25
|
+
const compressedSize = buffer.readUInt32LE(ptr + 20);
|
|
26
|
+
const fileNameLength = buffer.readUInt16LE(ptr + 28);
|
|
27
|
+
const extraFieldLength = buffer.readUInt16LE(ptr + 30);
|
|
28
|
+
const commentLength = buffer.readUInt16LE(ptr + 32);
|
|
29
|
+
const localHeaderOffset = buffer.readUInt32LE(ptr + 42);
|
|
30
|
+
const fileName = buffer.toString('utf8', ptr + 46, ptr + 46 + fileNameLength);
|
|
31
|
+
const bytes = readLocalEntry(buffer, localHeaderOffset, compressionMethod, compressedSize);
|
|
32
|
+
entries.push({
|
|
33
|
+
path: fileName.replace(/\\/g, '/'),
|
|
34
|
+
bytes,
|
|
35
|
+
isDirectory: fileName.endsWith('/'),
|
|
36
|
+
});
|
|
37
|
+
ptr += 46 + fileNameLength + extraFieldLength + commentLength;
|
|
38
|
+
}
|
|
39
|
+
return entries;
|
|
40
|
+
}
|
|
41
|
+
/** Read + decompress a single entry given its central-directory metadata. */
|
|
42
|
+
function readLocalEntry(buffer, localHeaderOffset, compressionMethod, compressedSize) {
|
|
43
|
+
if (buffer.readUInt32LE(localHeaderOffset) !== LFH_SIGNATURE) {
|
|
44
|
+
throw new Error('Invalid zip: bad local file header.');
|
|
45
|
+
}
|
|
46
|
+
// The local header repeats the name/extra lengths; the data starts after them.
|
|
47
|
+
const lfhNameLength = buffer.readUInt16LE(localHeaderOffset + 26);
|
|
48
|
+
const lfhExtraLength = buffer.readUInt16LE(localHeaderOffset + 28);
|
|
49
|
+
const dataStart = localHeaderOffset + 30 + lfhNameLength + lfhExtraLength;
|
|
50
|
+
const compressed = buffer.subarray(dataStart, dataStart + compressedSize);
|
|
51
|
+
if (compressionMethod === 0) {
|
|
52
|
+
// STORED — no compression.
|
|
53
|
+
return Buffer.from(compressed);
|
|
54
|
+
}
|
|
55
|
+
if (compressionMethod === 8) {
|
|
56
|
+
// DEFLATE (raw, no zlib header).
|
|
57
|
+
return zlib.inflateRawSync(compressed);
|
|
58
|
+
}
|
|
59
|
+
throw new Error(`Unsupported zip compression method ${compressionMethod}.`);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Locate the End Of Central Directory record by scanning backwards from EOF for
|
|
63
|
+
* its signature (the trailing comment is almost always empty, so it is usually
|
|
64
|
+
* the last 22 bytes — but we scan to be safe).
|
|
65
|
+
*/
|
|
66
|
+
function findEndOfCentralDirectory(buffer) {
|
|
67
|
+
const minEocdSize = 22;
|
|
68
|
+
if (buffer.length < minEocdSize)
|
|
69
|
+
return -1;
|
|
70
|
+
// Max comment length is 0xFFFF; scan that far back at most.
|
|
71
|
+
const scanStart = Math.max(0, buffer.length - minEocdSize - 0xffff);
|
|
72
|
+
for (let i = buffer.length - minEocdSize; i >= scanStart; i--) {
|
|
73
|
+
if (buffer.readUInt32LE(i) === EOCD_SIGNATURE) {
|
|
74
|
+
return i;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return -1;
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=unzip.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unzip.js","sourceRoot":"","sources":["../../src/utils/unzip.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "godot-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.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",
|