godot-cli 0.14.0 → 0.16.1
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 +116 -17
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +1 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/install-plugin.js +5 -1
- package/dist/commands/install-plugin.js.map +1 -1
- package/dist/commands/login.d.ts +2 -0
- package/dist/commands/login.js +38 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/open.js +8 -1
- package/dist/commands/open.js.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/install-extension.js +3 -1
- package/dist/lib/install-extension.js.map +1 -1
- package/dist/lib/install-plugin.js +23 -11
- package/dist/lib/install-plugin.js.map +1 -1
- package/dist/lib/types.d.ts +8 -2
- package/dist/utils/addon-deps.d.ts +23 -0
- package/dist/utils/addon-deps.js +15 -0
- package/dist/utils/addon-deps.js.map +1 -1
- package/dist/utils/agents.js +1 -1
- package/dist/utils/agents.js.map +1 -1
- package/dist/utils/auth.d.ts +42 -0
- package/dist/utils/auth.js +113 -0
- package/dist/utils/auth.js.map +1 -0
- package/dist/utils/browser.d.ts +5 -0
- package/dist/utils/browser.js +50 -0
- package/dist/utils/browser.js.map +1 -0
- package/dist/utils/cloud-login.d.ts +19 -0
- package/dist/utils/cloud-login.js +65 -0
- package/dist/utils/cloud-login.js.map +1 -0
- package/dist/utils/connection.d.ts +20 -5
- package/dist/utils/connection.js +39 -6
- package/dist/utils/connection.js.map +1 -1
- package/dist/utils/credentials.d.ts +36 -0
- package/dist/utils/credentials.js +99 -0
- package/dist/utils/credentials.js.map +1 -0
- package/dist/utils/csproj-deps.d.ts +37 -1
- package/dist/utils/csproj-deps.js +104 -5
- package/dist/utils/csproj-deps.js.map +1 -1
- package/dist/utils/extension-install.d.ts +7 -1
- package/dist/utils/extension-install.js +36 -10
- package/dist/utils/extension-install.js.map +1 -1
- package/dist/utils/extensions-catalog.d.ts +19 -0
- package/dist/utils/extensions-catalog.js +177 -1
- package/dist/utils/extensions-catalog.js.map +1 -1
- package/package.json +2 -1
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
/**
|
|
4
|
+
* Project-local cloud credentials the CLI persists after a successful `login`.
|
|
5
|
+
*
|
|
6
|
+
* Stored SEPARATELY from `.godot-mcp/features.json` (the committable feature
|
|
7
|
+
* override list) because a bearer token must never be committed: `writeCredentials`
|
|
8
|
+
* drops a `.gitignore` alongside so `credentials.json` is ignored while the
|
|
9
|
+
* sibling `features.json` stays version-controllable.
|
|
10
|
+
*
|
|
11
|
+
* `godot-cli login` writes it; `godot-cli open --mode Cloud` (and the direct
|
|
12
|
+
* tool-call path in `connection.ts`) read the token back so no manual `--token`
|
|
13
|
+
* is needed. The addon's own live config still lives in `user://` — this file is
|
|
14
|
+
* purely the CLI's in-project pickup surface, mirroring the Unity CLI's
|
|
15
|
+
* `cloudToken` config field.
|
|
16
|
+
*/
|
|
17
|
+
export const CREDENTIALS_RELATIVE_PATH = '.godot-mcp/credentials.json';
|
|
18
|
+
export function getCredentialsPath(projectPath) {
|
|
19
|
+
return path.join(projectPath, CREDENTIALS_RELATIVE_PATH);
|
|
20
|
+
}
|
|
21
|
+
/** Read the credentials file. Returns null when absent; throws on malformed JSON. */
|
|
22
|
+
export function readCredentials(projectPath) {
|
|
23
|
+
const credentialsPath = getCredentialsPath(projectPath);
|
|
24
|
+
if (!fs.existsSync(credentialsPath)) {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
const json = fs.readFileSync(credentialsPath, 'utf-8');
|
|
28
|
+
try {
|
|
29
|
+
return JSON.parse(json);
|
|
30
|
+
}
|
|
31
|
+
catch (err) {
|
|
32
|
+
if (err instanceof SyntaxError) {
|
|
33
|
+
throw new SyntaxError(`Malformed JSON in credentials file: ${credentialsPath}\n${err.message}`);
|
|
34
|
+
}
|
|
35
|
+
throw err;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Write the credentials file, creating the `.godot-mcp/` directory if needed and
|
|
40
|
+
* ensuring `credentials.json` is git-ignored so the token is never committed.
|
|
41
|
+
*/
|
|
42
|
+
export function writeCredentials(projectPath, credentials) {
|
|
43
|
+
const credentialsPath = getCredentialsPath(projectPath);
|
|
44
|
+
const dir = path.dirname(credentialsPath);
|
|
45
|
+
if (!fs.existsSync(dir)) {
|
|
46
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
47
|
+
}
|
|
48
|
+
// Owner-only perms: the file holds a raw cloud bearer token, so it must not be
|
|
49
|
+
// group/world-readable on a shared machine. `mode` only applies when the file is
|
|
50
|
+
// CREATED, so also chmod on overwrite (best-effort — no-op/again-fine on Windows).
|
|
51
|
+
fs.writeFileSync(credentialsPath, JSON.stringify(credentials, null, 2) + '\n', { mode: 0o600 });
|
|
52
|
+
try {
|
|
53
|
+
fs.chmodSync(credentialsPath, 0o600);
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
// Best-effort only — never fail the login over a chmod (e.g. Windows ACLs).
|
|
57
|
+
}
|
|
58
|
+
ensureGitignored(dir, 'credentials.json');
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Convenience reader for the persisted cloud token. Swallows a missing or
|
|
62
|
+
* malformed file (returns undefined) so a broken credentials file can never
|
|
63
|
+
* crash `open` / `run-tool`; `login` re-authenticates and overwrites it.
|
|
64
|
+
*/
|
|
65
|
+
export function readCloudToken(projectPath) {
|
|
66
|
+
let credentials;
|
|
67
|
+
try {
|
|
68
|
+
credentials = readCredentials(projectPath);
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
const token = credentials?.cloudToken;
|
|
74
|
+
return typeof token === 'string' && token.trim().length > 0 ? token : undefined;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Ensure `<dir>/.gitignore` ignores `entry`, so the secret is not committed.
|
|
78
|
+
* Idempotent: creates the file when absent, appends the line only when missing.
|
|
79
|
+
* Best-effort — a failure here never blocks persisting the token.
|
|
80
|
+
*/
|
|
81
|
+
function ensureGitignored(dir, entry) {
|
|
82
|
+
try {
|
|
83
|
+
const gitignorePath = path.join(dir, '.gitignore');
|
|
84
|
+
if (!fs.existsSync(gitignorePath)) {
|
|
85
|
+
fs.writeFileSync(gitignorePath, `${entry}\n`);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
const existing = fs.readFileSync(gitignorePath, 'utf-8');
|
|
89
|
+
const lines = existing.split(/\r?\n/).map((l) => l.trim());
|
|
90
|
+
if (!lines.includes(entry)) {
|
|
91
|
+
const prefix = existing.length > 0 && !existing.endsWith('\n') ? '\n' : '';
|
|
92
|
+
fs.appendFileSync(gitignorePath, `${prefix}${entry}\n`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
// Best-effort only — never fail the login over a .gitignore write.
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=credentials.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credentials.js","sourceRoot":"","sources":["../../src/utils/credentials.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type AddonPackageReference } from './addon-deps.js';
|
|
1
|
+
import { type AddonPackageReference, type AddonEmbeddedResource } from './addon-deps.js';
|
|
2
2
|
/**
|
|
3
3
|
* Idempotently reconcile a Godot consumer `.csproj`'s `<PackageReference>`s so it
|
|
4
4
|
* declares exactly the addon's two required NuGet pins (see `addon-deps.ts`).
|
|
@@ -37,4 +37,40 @@ export interface CsprojPatchResult {
|
|
|
37
37
|
/** One entry per required package describing what happened to it. */
|
|
38
38
|
changes: CsprojPatchChange[];
|
|
39
39
|
}
|
|
40
|
+
export type CsprojEmbedChange = {
|
|
41
|
+
include: string;
|
|
42
|
+
action: 'added';
|
|
43
|
+
logicalName: string;
|
|
44
|
+
} | {
|
|
45
|
+
include: string;
|
|
46
|
+
action: 'updated';
|
|
47
|
+
from: string;
|
|
48
|
+
logicalName: string;
|
|
49
|
+
} | {
|
|
50
|
+
include: string;
|
|
51
|
+
action: 'unchanged';
|
|
52
|
+
logicalName: string;
|
|
53
|
+
};
|
|
54
|
+
export interface CsprojEmbedResult {
|
|
55
|
+
/** The new csproj text (identical to input when nothing changed). */
|
|
56
|
+
text: string;
|
|
57
|
+
/** True when the text was modified. */
|
|
58
|
+
changed: boolean;
|
|
59
|
+
/** One entry per required embedded resource describing what happened to it. */
|
|
60
|
+
changes: CsprojEmbedChange[];
|
|
61
|
+
}
|
|
40
62
|
export declare function addAddonPackageReferences(csprojText: string, requiredRefs?: readonly AddonPackageReference[]): CsprojPatchResult;
|
|
63
|
+
/**
|
|
64
|
+
* Idempotently reconcile a Godot consumer `.csproj`'s `<EmbeddedResource>`s so it
|
|
65
|
+
* declares exactly the addon's required embeds (see `addon-deps.ts`
|
|
66
|
+
* `ADDON_EMBEDDED_RESOURCES`). Pure (operates on csproj TEXT, never touches the
|
|
67
|
+
* filesystem) and exported for unit tests. Sibling of `addAddonPackageReferences`.
|
|
68
|
+
* Handles, idempotently:
|
|
69
|
+
* - a project with NO `<EmbeddedResource>` ItemGroup (groups into one, else appends
|
|
70
|
+
* a fresh `<ItemGroup>` before `</Project>`);
|
|
71
|
+
* - a project that already embeds the resource with the right LogicalName (no change);
|
|
72
|
+
* - a project that embeds the same Include with a DIFFERENT LogicalName (reconciles
|
|
73
|
+
* in place);
|
|
74
|
+
* Re-running `install-plugin` therefore never duplicates the `<EmbeddedResource>`.
|
|
75
|
+
*/
|
|
76
|
+
export declare function addAddonEmbeddedResources(csprojText: string, requiredResources?: readonly AddonEmbeddedResource[]): CsprojEmbedResult;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ADDON_PACKAGE_REFERENCES } from './addon-deps.js';
|
|
1
|
+
import { ADDON_PACKAGE_REFERENCES, ADDON_EMBEDDED_RESOURCES, } from './addon-deps.js';
|
|
2
2
|
/** Escape a string for use inside a RegExp source. */
|
|
3
3
|
function escapeRegExp(value) {
|
|
4
4
|
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
@@ -18,16 +18,32 @@ function packageRefRegex(id) {
|
|
|
18
18
|
`|` +
|
|
19
19
|
`<PackageReference\\b[^>]*?\\bVersion\\s*=\\s*"([^"]*)"[^>]*?\\bInclude\\s*=\\s*"${escId}"[^>]*?(?:/>|></PackageReference>)`, 'i');
|
|
20
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* Match an existing `<EmbeddedResource ... Include="<include>" ... />` element for a
|
|
23
|
+
* specific file path, capturing the whole element (in either attribute order, and
|
|
24
|
+
* whether self-closed `/>` or an explicit `></EmbeddedResource>` pair). The
|
|
25
|
+
* `LogicalName` is extracted from the captured element text separately so the regex
|
|
26
|
+
* stays order-agnostic and tolerant of an absent `LogicalName`.
|
|
27
|
+
*/
|
|
28
|
+
function embeddedResourceRegex(include) {
|
|
29
|
+
const escInclude = escapeRegExp(include);
|
|
30
|
+
return new RegExp(`<EmbeddedResource\\b[^>]*?\\bInclude\\s*=\\s*"${escInclude}"[^>]*?(?:/>|></EmbeddedResource>)`, 'i');
|
|
31
|
+
}
|
|
21
32
|
/** Render the canonical self-closing element for a required reference. */
|
|
22
33
|
function renderRef(ref) {
|
|
23
34
|
return `<PackageReference Include="${ref.id}" Version="${ref.version}" />`;
|
|
24
35
|
}
|
|
36
|
+
/** Render the canonical self-closing element for a required embedded resource. */
|
|
37
|
+
function renderEmbed(res) {
|
|
38
|
+
return `<EmbeddedResource Include="${res.include}" LogicalName="${res.logicalName}" />`;
|
|
39
|
+
}
|
|
25
40
|
/**
|
|
26
|
-
* Detect the indentation used by the FIRST existing `<PackageReference>`
|
|
27
|
-
* back to 4 spaces) so appended/inserted elements
|
|
41
|
+
* Detect the indentation used by the FIRST existing `<PackageReference>` /
|
|
42
|
+
* `<EmbeddedResource>` (or fall back to 4 spaces) so appended/inserted elements
|
|
43
|
+
* match the consumer's style.
|
|
28
44
|
*/
|
|
29
45
|
function detectIndent(text) {
|
|
30
|
-
const m = text.match(/\n([ \t]*)<PackageReference\b/);
|
|
46
|
+
const m = text.match(/\n([ \t]*)<(?:PackageReference|EmbeddedResource)\b/);
|
|
31
47
|
return m ? m[1] : ' ';
|
|
32
48
|
}
|
|
33
49
|
/**
|
|
@@ -101,16 +117,99 @@ export function addAddonPackageReferences(csprojText, requiredRefs = ADDON_PACKA
|
|
|
101
117
|
changes: orderedChanges,
|
|
102
118
|
};
|
|
103
119
|
}
|
|
120
|
+
/**
|
|
121
|
+
* Idempotently reconcile a Godot consumer `.csproj`'s `<EmbeddedResource>`s so it
|
|
122
|
+
* declares exactly the addon's required embeds (see `addon-deps.ts`
|
|
123
|
+
* `ADDON_EMBEDDED_RESOURCES`). Pure (operates on csproj TEXT, never touches the
|
|
124
|
+
* filesystem) and exported for unit tests. Sibling of `addAddonPackageReferences`.
|
|
125
|
+
* Handles, idempotently:
|
|
126
|
+
* - a project with NO `<EmbeddedResource>` ItemGroup (groups into one, else appends
|
|
127
|
+
* a fresh `<ItemGroup>` before `</Project>`);
|
|
128
|
+
* - a project that already embeds the resource with the right LogicalName (no change);
|
|
129
|
+
* - a project that embeds the same Include with a DIFFERENT LogicalName (reconciles
|
|
130
|
+
* in place);
|
|
131
|
+
* Re-running `install-plugin` therefore never duplicates the `<EmbeddedResource>`.
|
|
132
|
+
*/
|
|
133
|
+
export function addAddonEmbeddedResources(csprojText, requiredResources = ADDON_EMBEDDED_RESOURCES) {
|
|
134
|
+
const changes = [];
|
|
135
|
+
let text = csprojText;
|
|
136
|
+
const indent = detectIndent(text);
|
|
137
|
+
const eol = detectEol(text);
|
|
138
|
+
// First pass: reconcile any embeds that already exist (possibly with a different
|
|
139
|
+
// LogicalName). Collect the ones still missing for the append pass.
|
|
140
|
+
const missing = [];
|
|
141
|
+
for (const res of requiredResources) {
|
|
142
|
+
const re = embeddedResourceRegex(res.include);
|
|
143
|
+
const match = text.match(re);
|
|
144
|
+
if (!match) {
|
|
145
|
+
missing.push(res);
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
const logicalMatch = match[0].match(/\bLogicalName\s*=\s*"([^"]*)"/i);
|
|
149
|
+
const existingLogical = logicalMatch ? logicalMatch[1] : '';
|
|
150
|
+
if (existingLogical === res.logicalName) {
|
|
151
|
+
changes.push({ include: res.include, action: 'unchanged', logicalName: res.logicalName });
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
// Reconcile in place: replace the whole element with the canonical embed.
|
|
155
|
+
text = text.replace(re, renderEmbed(res));
|
|
156
|
+
changes.push({ include: res.include, action: 'updated', from: existingLogical, logicalName: res.logicalName });
|
|
157
|
+
}
|
|
158
|
+
// Second pass: add the missing embeds. Prefer an existing <ItemGroup> that already
|
|
159
|
+
// holds an <EmbeddedResource> (group them together); else append a fresh
|
|
160
|
+
// <ItemGroup> just before </Project>. Deliberately NOT grouped with the
|
|
161
|
+
// PackageReference ItemGroup — the addon's own csproj keeps the two in separate
|
|
162
|
+
// groups, and this keeps the scaffold's layout identical.
|
|
163
|
+
if (missing.length > 0) {
|
|
164
|
+
const block = missing.map((res) => `${indent}${renderEmbed(res)}`).join(eol);
|
|
165
|
+
const embedItemGroupClose = findItemGroupCloseContaining(text, /<EmbeddedResource\b/i);
|
|
166
|
+
if (embedItemGroupClose !== -1) {
|
|
167
|
+
text = `${text.slice(0, embedItemGroupClose)}${block}${eol}${text.slice(embedItemGroupClose)}`;
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
const groupIndent = indent.length >= 2 ? indent.slice(0, Math.floor(indent.length / 2)) : ' ';
|
|
171
|
+
const newGroup = `${groupIndent}<ItemGroup>${eol}${block}${eol}${groupIndent}</ItemGroup>${eol}`;
|
|
172
|
+
const closeIdx = text.lastIndexOf('</Project>');
|
|
173
|
+
if (closeIdx === -1) {
|
|
174
|
+
text = `${text}${eol}${newGroup}`;
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
text = `${text.slice(0, closeIdx)}${newGroup}${text.slice(closeIdx)}`;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
for (const res of missing) {
|
|
181
|
+
changes.push({ include: res.include, action: 'added', logicalName: res.logicalName });
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
// Restore required-order in `changes` to match `requiredResources` for stable output.
|
|
185
|
+
const orderedChanges = requiredResources
|
|
186
|
+
.map((res) => changes.find((c) => c.include === res.include))
|
|
187
|
+
.filter((c) => c !== undefined);
|
|
188
|
+
return {
|
|
189
|
+
text,
|
|
190
|
+
changed: orderedChanges.some((c) => c.action !== 'unchanged'),
|
|
191
|
+
changes: orderedChanges,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
104
194
|
/**
|
|
105
195
|
* Return the index of the `</ItemGroup>` that closes the FIRST `<ItemGroup>`
|
|
106
196
|
* containing a `<PackageReference>`, or -1 when none exists. Used to group the
|
|
107
197
|
* added pins with the consumer's existing package references.
|
|
108
198
|
*/
|
|
109
199
|
function findPackageReferenceItemGroupClose(text) {
|
|
200
|
+
return findItemGroupCloseContaining(text, /<PackageReference\b/i);
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Return the index of the `</ItemGroup>` that closes the FIRST `<ItemGroup>` whose
|
|
204
|
+
* body matches `childTagRe`, or -1 when none exists. Used to group an added element
|
|
205
|
+
* with the consumer's existing items of the same kind. `childTagRe` MUST NOT be a
|
|
206
|
+
* global regex (a stateful `lastIndex` would corrupt the `.test` below).
|
|
207
|
+
*/
|
|
208
|
+
function findItemGroupCloseContaining(text, childTagRe) {
|
|
110
209
|
const itemGroupRe = /<ItemGroup\b[^>]*>([\s\S]*?)<\/ItemGroup>/gi;
|
|
111
210
|
let m;
|
|
112
211
|
while ((m = itemGroupRe.exec(text)) !== null) {
|
|
113
|
-
if (
|
|
212
|
+
if (childTagRe.test(m[1])) {
|
|
114
213
|
// The close tag starts at the end of the match minus its length.
|
|
115
214
|
const closeTag = '</ItemGroup>';
|
|
116
215
|
return m.index + m[0].length - closeTag.length;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"csproj-deps.js","sourceRoot":"","sources":["../../src/utils/csproj-deps.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"csproj-deps.js","sourceRoot":"","sources":["../../src/utils/csproj-deps.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import type { ExtensionDescriptor } from './extensions-catalog.js';
|
|
2
2
|
export type ExtensionInstallAction = 'add' | 'update' | 'noop';
|
|
3
|
+
/**
|
|
4
|
+
* The MSBuild floating-version marker written for an UNPINNED (null/empty-version) descriptor.
|
|
5
|
+
* A versionless `<PackageReference Include="x" />` fails NuGet restore with NU1015, so the
|
|
6
|
+
* "float to latest" intent is materialized as `Version="*"`. Mirrors C# `ExtensionInstallPlanner.FloatVersion`.
|
|
7
|
+
*/
|
|
8
|
+
export declare const FLOAT_VERSION = "*";
|
|
3
9
|
export interface ExtensionInstallPlan {
|
|
4
10
|
/** The add / update / no-op decision. */
|
|
5
11
|
action: ExtensionInstallAction;
|
|
@@ -9,7 +15,7 @@ export interface ExtensionInstallPlan {
|
|
|
9
15
|
packageId: string;
|
|
10
16
|
/** Version currently referenced: `null` when not installed; `''` when referenced without a version. */
|
|
11
17
|
fromVersion: string | null;
|
|
12
|
-
/** The descriptor's
|
|
18
|
+
/** The version the plan writes: the descriptor's pin when set, `"*"` (the float marker) when unpinned and a reference is added or self-healed, `null` only on a no-op. */
|
|
13
19
|
toVersion: string | null;
|
|
14
20
|
}
|
|
15
21
|
/** Thrown by {@link planExtensionInstall} on a genuinely unparseable `.csproj` (the lib turns it into a structured failure). */
|
|
@@ -6,19 +6,30 @@
|
|
|
6
6
|
//
|
|
7
7
|
// Parity contract (verified by `cli/tests/extension-install.test.ts` against the
|
|
8
8
|
// SAME scenario set as `Godot-MCP.Tests/ExtensionInstallTests.cs`):
|
|
9
|
-
// - absent reference
|
|
10
|
-
// - present, descriptor newer
|
|
11
|
-
// - present, no version, pinned
|
|
12
|
-
// - present,
|
|
13
|
-
// -
|
|
9
|
+
// - absent reference → ADD (append; Version="<pin>" when pinned, Version="*" when unpinned/floating)
|
|
10
|
+
// - present, descriptor newer → UPDATE (bump version, honoring attr vs child form)
|
|
11
|
+
// - present, no version, pinned → UPDATE (set the descriptor's pin)
|
|
12
|
+
// - present, no version, unpinned → UPDATE (SELF-HEAL the NU1015-prone versionless reference to Version="*")
|
|
13
|
+
// - present, equal/newer → NO-OP
|
|
14
|
+
// - descriptor unpinned, present with a version → NO-OP (never downgrade a concrete pin to "*")
|
|
14
15
|
// - version compare is numeric + tolerant (1.10.0 > 1.2.0; trailing 0; suffix-tolerant)
|
|
15
16
|
//
|
|
17
|
+
// A versionless `<PackageReference Include="x" />` fails NuGet restore with NU1015, so an
|
|
18
|
+
// unpinned (null-version) descriptor's "float to latest" intent is materialized as
|
|
19
|
+
// `Version="*"` — mirroring the C# planner's `FloatVersion` constant byte-for-byte.
|
|
20
|
+
//
|
|
16
21
|
// The C# planner uses System.Xml.Linq; this uses scoped text edits (like the CLI's
|
|
17
22
|
// existing `csproj-deps.ts`) so the consumer's formatting is preserved verbatim. The
|
|
18
23
|
// add/update/no-op DECISION and the resulting parsed PackageReferences are identical.
|
|
19
24
|
//
|
|
20
25
|
// No top-level side effects; pure string transforms only.
|
|
21
26
|
import { hasVersion } from './extensions-catalog.js';
|
|
27
|
+
/**
|
|
28
|
+
* The MSBuild floating-version marker written for an UNPINNED (null/empty-version) descriptor.
|
|
29
|
+
* A versionless `<PackageReference Include="x" />` fails NuGet restore with NU1015, so the
|
|
30
|
+
* "float to latest" intent is materialized as `Version="*"`. Mirrors C# `ExtensionInstallPlanner.FloatVersion`.
|
|
31
|
+
*/
|
|
32
|
+
export const FLOAT_VERSION = '*';
|
|
22
33
|
/** Thrown by {@link planExtensionInstall} on a genuinely unparseable `.csproj` (the lib turns it into a structured failure). */
|
|
23
34
|
export class CsprojParseError extends Error {
|
|
24
35
|
}
|
|
@@ -110,9 +121,10 @@ function detectEol(text) {
|
|
|
110
121
|
return crlf > lf ? '\r\n' : '\n';
|
|
111
122
|
}
|
|
112
123
|
function renderRef(descriptor) {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
124
|
+
// Always emit a Version: the descriptor's pin when set, else the "*" float marker. A versionless
|
|
125
|
+
// reference fails NuGet restore with NU1015. Byte-equal to the C# planner's AppendPackageReference.
|
|
126
|
+
const version = hasVersion(descriptor) ? descriptor.version : FLOAT_VERSION;
|
|
127
|
+
return `<PackageReference Include="${descriptor.packageId}" Version="${version}" />`;
|
|
116
128
|
}
|
|
117
129
|
/** Index of the `</ItemGroup>` closing the FIRST `<ItemGroup>` holding a `<PackageReference>`, or -1. */
|
|
118
130
|
function findPackageReferenceItemGroupClose(text) {
|
|
@@ -184,13 +196,27 @@ export function planExtensionInstall(descriptor, csprojText) {
|
|
|
184
196
|
resultingCsproj: appendReference(csprojText, descriptor),
|
|
185
197
|
packageId: descriptor.packageId,
|
|
186
198
|
fromVersion: null,
|
|
187
|
-
toVersion: hasVersion(descriptor) ? descriptor.version :
|
|
199
|
+
toVersion: hasVersion(descriptor) ? descriptor.version : FLOAT_VERSION,
|
|
188
200
|
};
|
|
189
201
|
}
|
|
190
202
|
const element = match[0];
|
|
191
203
|
const currentVersion = readElementVersion(element);
|
|
192
|
-
// Descriptor pins no version →
|
|
204
|
+
// Descriptor pins no version → it wants a FLOATING reference (Version="*").
|
|
193
205
|
if (!hasVersion(descriptor)) {
|
|
206
|
+
// SELF-HEAL: an existing reference with NO version is NU1015-prone — upgrade it to "*".
|
|
207
|
+
// But NEVER downgrade a concrete consumer pin (or an existing "*") to "*": leave any
|
|
208
|
+
// already-versioned reference untouched (no-op), since the consumer's pin is authoritative.
|
|
209
|
+
if (currentVersion === '') {
|
|
210
|
+
const healedElement = setElementVersion(element, FLOAT_VERSION);
|
|
211
|
+
return {
|
|
212
|
+
action: 'update',
|
|
213
|
+
// Function replacement so any `$` in the marker is never treated as a replacement pattern.
|
|
214
|
+
resultingCsproj: csprojText.replace(elementRe, () => healedElement),
|
|
215
|
+
packageId: descriptor.packageId,
|
|
216
|
+
fromVersion: currentVersion,
|
|
217
|
+
toVersion: FLOAT_VERSION,
|
|
218
|
+
};
|
|
219
|
+
}
|
|
194
220
|
return {
|
|
195
221
|
action: 'noop',
|
|
196
222
|
resultingCsproj: csprojText,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extension-install.js","sourceRoot":"","sources":["../../src/utils/extension-install.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,sEAAsE;AACtE,kFAAkF;AAClF,mFAAmF;AACnF,iEAAiE;AACjE,EAAE;AACF,iFAAiF;AACjF,oEAAoE;AACpE,
|
|
1
|
+
{"version":3,"file":"extension-install.js","sourceRoot":"","sources":["../../src/utils/extension-install.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,10 +3,28 @@ export interface ExtensionTool {
|
|
|
3
3
|
readonly name: string;
|
|
4
4
|
readonly description: string;
|
|
5
5
|
}
|
|
6
|
+
/**
|
|
7
|
+
* The third-party Godot addon a CLASS-B extension wraps — mirrors the JSON
|
|
8
|
+
* `addonRequired` block. Class-A extensions (which wrap a BUILT-IN Godot feature)
|
|
9
|
+
* OMIT this entirely (`addonRequired` is absent / `undefined`). When present it is
|
|
10
|
+
* pure presentation metadata so the dock/app/CLI can surface "requires the <name>
|
|
11
|
+
* addon" + a link; it does NOT affect install logic (the package is still installed
|
|
12
|
+
* by `packageId` alone — the addon is the consumer's own runtime responsibility).
|
|
13
|
+
* `name` is the anchor; `assetLibId` (the Godot AssetLib id, stored as a string),
|
|
14
|
+
* `repo`, and `license` are optional.
|
|
15
|
+
*/
|
|
16
|
+
export interface ExtensionAddonRequirement {
|
|
17
|
+
readonly name: string;
|
|
18
|
+
readonly assetLibId: string | null;
|
|
19
|
+
readonly repo: string | null;
|
|
20
|
+
readonly license: string | null;
|
|
21
|
+
}
|
|
6
22
|
/**
|
|
7
23
|
* One installable extension — the CLI analog of the C# `GodotExtensionDescriptor`.
|
|
8
24
|
* `packageId` is the INSTALL IDENTITY (the `<PackageReference Include="...">`).
|
|
9
25
|
* `version` is `null` for a floating (unpinned) reference.
|
|
26
|
+
* `addonRequired` is present ONLY for CLASS-B (addon-dependent) extensions; Class-A
|
|
27
|
+
* entries omit it.
|
|
10
28
|
*/
|
|
11
29
|
export interface ExtensionDescriptor {
|
|
12
30
|
readonly name: string;
|
|
@@ -15,6 +33,7 @@ export interface ExtensionDescriptor {
|
|
|
15
33
|
readonly version: string | null;
|
|
16
34
|
readonly gitUrl: string | null;
|
|
17
35
|
readonly tools: readonly ExtensionTool[];
|
|
36
|
+
readonly addonRequired?: ExtensionAddonRequirement | null;
|
|
18
37
|
}
|
|
19
38
|
/**
|
|
20
39
|
* The extension catalog, single-sourced from `addons/godot_mcp/extensions.catalog.json`.
|