genexus-mcp 3.2.3 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli/lib/update-check.js +77 -26
- package/cli/run.test.js +58 -7
- package/package.json +1 -1
- package/publish/GxMcp.Gateway.deps.json +2 -2
- package/publish/GxMcp.Gateway.dll +0 -0
- package/publish/GxMcp.Gateway.exe +0 -0
- package/publish/config.json +8 -8
- package/publish/gxmcp-manifest.json +10 -15
- package/publish/gxmcp-sbom.json +4 -4
- package/publish/tool_definitions.json +1 -1
- package/publish/worker/GxMcp.Worker.exe +0 -0
- package/publish/nexus-ide.vsix +0 -0
package/cli/lib/update-check.js
CHANGED
|
@@ -44,7 +44,10 @@ function readCache() {
|
|
|
44
44
|
try {
|
|
45
45
|
const raw = fs.readFileSync(getCacheFile(), 'utf8');
|
|
46
46
|
const data = JSON.parse(raw);
|
|
47
|
-
if (data && typeof data === 'object'
|
|
47
|
+
if (data && typeof data === 'object'
|
|
48
|
+
&& (data.package === undefined || data.package === NPM_PACKAGE)
|
|
49
|
+
&& (data.channel === undefined || validateChannel(data.channel))
|
|
50
|
+
&& parseSemver(data.latestVersion)) return data;
|
|
48
51
|
} catch {
|
|
49
52
|
}
|
|
50
53
|
return null;
|
|
@@ -54,7 +57,9 @@ function writeCache(data) {
|
|
|
54
57
|
try {
|
|
55
58
|
const file = getCacheFile();
|
|
56
59
|
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
57
|
-
|
|
60
|
+
const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
|
|
61
|
+
fs.writeFileSync(tmp, JSON.stringify({ package: NPM_PACKAGE, channel: 'latest', ...data }), 'utf8');
|
|
62
|
+
fs.renameSync(tmp, file);
|
|
58
63
|
} catch {
|
|
59
64
|
}
|
|
60
65
|
}
|
|
@@ -65,22 +70,42 @@ function stripV(v) {
|
|
|
65
70
|
|
|
66
71
|
function parseSemver(v) {
|
|
67
72
|
const s = stripV(v);
|
|
68
|
-
const m = /^(\d
|
|
73
|
+
const m = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9A-Za-z-][0-9A-Za-z-]*))*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$/.exec(s);
|
|
69
74
|
if (!m) return null;
|
|
70
|
-
return
|
|
75
|
+
return { valid: true, major: Number(m[1]), minor: Number(m[2]), patch: Number(m[3]),
|
|
76
|
+
prerelease: m[4] ? m[4].split('.') : [], build: m[5] ? m[5].split('.') : [] };
|
|
71
77
|
}
|
|
72
78
|
|
|
73
79
|
function compareSemver(a, b) {
|
|
74
80
|
const pa = parseSemver(a);
|
|
75
81
|
const pb = parseSemver(b);
|
|
76
|
-
if (!pa || !pb) return
|
|
77
|
-
for (
|
|
78
|
-
if (pa[
|
|
79
|
-
if (pa[
|
|
82
|
+
if (!pa || !pb) return null;
|
|
83
|
+
for (const key of ['major', 'minor', 'patch']) {
|
|
84
|
+
if (pa[key] > pb[key]) return 1;
|
|
85
|
+
if (pa[key] < pb[key]) return -1;
|
|
86
|
+
}
|
|
87
|
+
if (pa.prerelease.length === 0 && pb.prerelease.length > 0) return 1;
|
|
88
|
+
if (pa.prerelease.length > 0 && pb.prerelease.length === 0) return -1;
|
|
89
|
+
for (let i = 0; i < Math.max(pa.prerelease.length, pb.prerelease.length); i += 1) {
|
|
90
|
+
if (i >= pa.prerelease.length) return -1;
|
|
91
|
+
if (i >= pb.prerelease.length) return 1;
|
|
92
|
+
const left = pa.prerelease[i];
|
|
93
|
+
const right = pb.prerelease[i];
|
|
94
|
+
if (left === right) continue;
|
|
95
|
+
const leftNum = /^\d+$/.test(left);
|
|
96
|
+
const rightNum = /^\d+$/.test(right);
|
|
97
|
+
if (leftNum && rightNum) return Number(left) > Number(right) ? 1 : -1;
|
|
98
|
+
if (leftNum !== rightNum) return leftNum ? -1 : 1;
|
|
99
|
+
return left > right ? 1 : -1;
|
|
80
100
|
}
|
|
81
101
|
return 0;
|
|
82
102
|
}
|
|
83
103
|
|
|
104
|
+
function validateChannel(channel) {
|
|
105
|
+
const value = typeof channel === 'string' ? channel.trim() : '';
|
|
106
|
+
return /^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(value) ? value : null;
|
|
107
|
+
}
|
|
108
|
+
|
|
84
109
|
function httpGetJson(url) {
|
|
85
110
|
return new Promise((resolve) => {
|
|
86
111
|
let req;
|
|
@@ -112,13 +137,14 @@ function httpGetJson(url) {
|
|
|
112
137
|
// api.github.com. Falls back to the GitHub releases API only for the default
|
|
113
138
|
// channel. The release URL is derived from the version (no API call needed).
|
|
114
139
|
async function fetchLatestRelease(opts = {}) {
|
|
115
|
-
const channel = (opts && opts.channel) || 'latest';
|
|
140
|
+
const channel = validateChannel((opts && opts.channel) || 'latest');
|
|
141
|
+
if (!channel) return null;
|
|
116
142
|
|
|
117
143
|
// 1. npm registry dist-tags (lightweight: just the tag → version map).
|
|
118
144
|
const tags = await httpGetJson(`https://registry.npmjs.org/-/package/${NPM_PACKAGE}/dist-tags`);
|
|
119
145
|
if (tags && typeof tags === 'object') {
|
|
120
146
|
const v = stripV(tags[channel] || '');
|
|
121
|
-
if (v) return { latestVersion: v, releaseUrl: releaseUrlForVersion(v), source: 'npm' };
|
|
147
|
+
if (parseSemver(v)) return { latestVersion: v, releaseUrl: releaseUrlForVersion(v), source: 'npm' };
|
|
122
148
|
// Channel not found on npm — for non-default channels, that's a definitive "no".
|
|
123
149
|
if (channel !== 'latest') return null;
|
|
124
150
|
}
|
|
@@ -128,7 +154,7 @@ async function fetchLatestRelease(opts = {}) {
|
|
|
128
154
|
const rel = await httpGetJson(`https://api.github.com/repos/${REPO}/releases/latest`);
|
|
129
155
|
if (rel && typeof rel === 'object') {
|
|
130
156
|
const tag = stripV(rel.tag_name || '');
|
|
131
|
-
if (tag) {
|
|
157
|
+
if (parseSemver(tag)) {
|
|
132
158
|
const url = typeof rel.html_url === 'string' ? rel.html_url : releaseUrlForVersion(tag);
|
|
133
159
|
return { latestVersion: tag, releaseUrl: url, source: 'github' };
|
|
134
160
|
}
|
|
@@ -157,7 +183,7 @@ function maybePrintCachedBanner(_opts) {
|
|
|
157
183
|
const current = getPackageVersion();
|
|
158
184
|
if (!current) return;
|
|
159
185
|
const cache = readCache();
|
|
160
|
-
if (!cache || !cache.latestVersion) return;
|
|
186
|
+
if (!cache || !cache.latestVersion || (cache.channel && cache.channel !== 'latest')) return;
|
|
161
187
|
if (compareSemver(cache.latestVersion, current) > 0) {
|
|
162
188
|
try {
|
|
163
189
|
process.stderr.write(formatBanner(current, cache.latestVersion, cache.releaseUrl || null));
|
|
@@ -253,27 +279,29 @@ function detectInstallMethod() {
|
|
|
253
279
|
// The method-appropriate upgrade plan. `auto` means no manual install step is
|
|
254
280
|
// needed (the npx launcher fetches @latest on the next client start).
|
|
255
281
|
function upgradePlanFor(method, channel) {
|
|
256
|
-
const
|
|
282
|
+
const resolvedChannel = channel || 'latest';
|
|
283
|
+
const tag = resolvedChannel !== 'latest' ? `@${resolvedChannel}` : '@latest';
|
|
257
284
|
if (method === 'npx-latest') {
|
|
258
285
|
return {
|
|
259
286
|
method,
|
|
287
|
+
channel: resolvedChannel,
|
|
260
288
|
auto: true,
|
|
261
289
|
steps: [
|
|
262
|
-
|
|
263
|
-
'Just fully restart your AI client — it will pick up the
|
|
290
|
+
`Your clients launch via \`npx ${NPM_PACKAGE}${tag}\`, which fetches the newest ${resolvedChannel} version on each start.`,
|
|
291
|
+
'Just fully restart your AI client — it will pick up the selected channel automatically.'
|
|
264
292
|
],
|
|
265
|
-
|
|
266
|
-
applyCommand: { exe: process.platform === 'win32' ? 'npm.cmd' : 'npm', args: ['cache', 'clean', '--force'] },
|
|
293
|
+
applyCommand: null,
|
|
267
294
|
restartRequired: true
|
|
268
295
|
};
|
|
269
296
|
}
|
|
270
297
|
if (method === 'fixed-path') {
|
|
271
298
|
return {
|
|
272
299
|
method,
|
|
300
|
+
channel: resolvedChannel,
|
|
273
301
|
auto: false,
|
|
274
302
|
steps: [
|
|
275
|
-
|
|
276
|
-
`Re-run the installer
|
|
303
|
+
`Your install runs the gateway from a fixed path (corporate install); npm ${tag} will not update that artifact.`,
|
|
304
|
+
`Re-run the fixed-path installer for the resolved ${resolvedChannel} release artifact${resolvedChannel === 'latest' ? '' : ` from channel \`${resolvedChannel}\``}: ${INSTALL_ONE_LINER}`,
|
|
277
305
|
'Then fully restart your AI client.'
|
|
278
306
|
],
|
|
279
307
|
applyCommand: null, // self-stage is a future enhancement; installer is the path
|
|
@@ -284,6 +312,7 @@ function upgradePlanFor(method, channel) {
|
|
|
284
312
|
const tag = channel && channel !== 'latest' ? `@${channel}` : '@latest';
|
|
285
313
|
return {
|
|
286
314
|
method,
|
|
315
|
+
channel: resolvedChannel,
|
|
287
316
|
auto: false,
|
|
288
317
|
steps: [
|
|
289
318
|
'Antigravity launches the gateway executable bundled with the npm package, so each MCP handshake skips npx.',
|
|
@@ -297,6 +326,7 @@ function upgradePlanFor(method, channel) {
|
|
|
297
326
|
// npm-global
|
|
298
327
|
return {
|
|
299
328
|
method: 'npm-global',
|
|
329
|
+
channel: resolvedChannel,
|
|
300
330
|
auto: false,
|
|
301
331
|
steps: [
|
|
302
332
|
`Run: npm install -g ${NPM_PACKAGE}${tag}`,
|
|
@@ -307,23 +337,37 @@ function upgradePlanFor(method, channel) {
|
|
|
307
337
|
};
|
|
308
338
|
}
|
|
309
339
|
|
|
310
|
-
function runCommand(exe, args) {
|
|
340
|
+
function runCommand(exe, args, options = {}) {
|
|
311
341
|
return new Promise((resolve) => {
|
|
312
342
|
let child;
|
|
343
|
+
let settled = false;
|
|
344
|
+
const finish = (result) => { if (!settled) { settled = true; resolve(result); } };
|
|
313
345
|
try {
|
|
314
346
|
child = spawn(exe, args, { stdio: 'inherit', windowsHide: true });
|
|
315
347
|
} catch (err) {
|
|
316
|
-
|
|
348
|
+
finish({ ok: false, code: null, error: err && err.message ? err.message : 'spawn failed' });
|
|
317
349
|
return;
|
|
318
350
|
}
|
|
319
|
-
|
|
320
|
-
|
|
351
|
+
let timedOut = false;
|
|
352
|
+
const timeoutMs = Number.isFinite(options.timeoutMs) ? Math.max(1, options.timeoutMs) : 120000;
|
|
353
|
+
const timer = setTimeout(() => {
|
|
354
|
+
timedOut = true;
|
|
355
|
+
try { child.kill(); } catch { /* process may have exited */ }
|
|
356
|
+
}, timeoutMs);
|
|
357
|
+
child.on('error', (err) => { clearTimeout(timer); finish({ ok: false, code: null, error: err && err.message ? err.message : 'spawn failed', timedOut }); });
|
|
358
|
+
child.on('exit', (code, signal) => {
|
|
359
|
+
clearTimeout(timer);
|
|
360
|
+
finish({ ok: !timedOut && code === 0, code: timedOut ? -1 : code, signal: signal || null, timedOut });
|
|
361
|
+
});
|
|
321
362
|
});
|
|
322
363
|
}
|
|
323
364
|
|
|
324
365
|
async function handleUpdate(options, ctx) {
|
|
325
366
|
const opts = options || {};
|
|
326
|
-
const channel = opts.channel || 'latest';
|
|
367
|
+
const channel = validateChannel(opts.channel || 'latest');
|
|
368
|
+
if (!channel) {
|
|
369
|
+
return { exitCode: ctx.EXIT_CODES.USAGE, envelope: { error: { code: 'invalid_channel', message: 'Channel must contain only letters, numbers, dots, underscores, or hyphens.' } } };
|
|
370
|
+
}
|
|
327
371
|
const current = getPackageVersion();
|
|
328
372
|
const result = await fetchLatestRelease({ channel });
|
|
329
373
|
const mismatches = detectClientExeDrift();
|
|
@@ -346,8 +390,13 @@ async function handleUpdate(options, ctx) {
|
|
|
346
390
|
};
|
|
347
391
|
}
|
|
348
392
|
|
|
349
|
-
writeCache({ checkedAt: Date.now(), latestVersion: result.latestVersion, releaseUrl: result.releaseUrl, source: result.source || null });
|
|
393
|
+
writeCache({ checkedAt: Date.now(), latestVersion: result.latestVersion, releaseUrl: result.releaseUrl, source: result.source || null, channel });
|
|
350
394
|
|
|
395
|
+
const currentSemver = parseSemver(current || '0.0.0');
|
|
396
|
+
const latestSemver = parseSemver(result.latestVersion);
|
|
397
|
+
if (!latestSemver || !currentSemver) {
|
|
398
|
+
return { exitCode: ctx.EXIT_CODES.OK, envelope: { ok: { current, latest: result.latestVersion, channel, updateAvailable: false, invalidVersion: true }, help: ['Could not compare versions because the installed or published version is invalid semver.'] } };
|
|
399
|
+
}
|
|
351
400
|
const updateAvailable = compareSemver(result.latestVersion, current || '0.0.0') > 0;
|
|
352
401
|
const plan = upgradePlanFor(install.method, channel);
|
|
353
402
|
|
|
@@ -433,5 +482,7 @@ module.exports = {
|
|
|
433
482
|
getPackageVersion,
|
|
434
483
|
detectInstallMethod,
|
|
435
484
|
upgradePlanFor,
|
|
436
|
-
fetchLatestRelease
|
|
485
|
+
fetchLatestRelease,
|
|
486
|
+
validateChannel,
|
|
487
|
+
runCommand
|
|
437
488
|
};
|
package/cli/run.test.js
CHANGED
|
@@ -6,7 +6,14 @@ const path = require('node:path');
|
|
|
6
6
|
const os = require('node:os');
|
|
7
7
|
const fs = require('node:fs');
|
|
8
8
|
const { renderOutput } = require('./lib/output');
|
|
9
|
-
const {
|
|
9
|
+
const {
|
|
10
|
+
compareSemver,
|
|
11
|
+
parseSemver,
|
|
12
|
+
validateChannel,
|
|
13
|
+
detectInstallMethod,
|
|
14
|
+
upgradePlanFor,
|
|
15
|
+
runCommand
|
|
16
|
+
} = require('./lib/update-check');
|
|
10
17
|
const {
|
|
11
18
|
detectClientInstalled,
|
|
12
19
|
readJsonFileSafe,
|
|
@@ -1727,12 +1734,37 @@ test('clients remove drops both OpenCode config shapes and legacy key', () => {
|
|
|
1727
1734
|
fs.rmSync(tempRoot, { recursive: true, force: true });
|
|
1728
1735
|
});
|
|
1729
1736
|
|
|
1730
|
-
test('
|
|
1731
|
-
assert.
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
assert.equal(compareSemver('
|
|
1737
|
+
test('strict semver compares prerelease precedence and ignores build metadata', () => {
|
|
1738
|
+
assert.deepEqual(parseSemver('v1.2.3-alpha.1+build.7'), {
|
|
1739
|
+
valid: true, major: 1, minor: 2, patch: 3,
|
|
1740
|
+
prerelease: ['alpha', '1'], build: ['build', '7']
|
|
1741
|
+
});
|
|
1742
|
+
assert.equal(compareSemver('1.0.0-alpha', '1.0.0-alpha.1'), -1);
|
|
1743
|
+
assert.equal(compareSemver('1.0.0', '1.0.0-rc.1'), 1);
|
|
1744
|
+
assert.equal(compareSemver('1.0.0+one', '1.0.0+two'), 0);
|
|
1745
|
+
});
|
|
1746
|
+
|
|
1747
|
+
test('semver and channel validation are explicit for malformed input', () => {
|
|
1748
|
+
assert.equal(parseSemver('1.2'), null);
|
|
1749
|
+
assert.equal(parseSemver('1.2.3-01'), null);
|
|
1750
|
+
assert.equal(compareSemver('garbage', '1.0.0'), null);
|
|
1751
|
+
assert.equal(validateChannel('latest'), 'latest');
|
|
1752
|
+
assert.equal(validateChannel('next-2026'), 'next-2026');
|
|
1753
|
+
assert.equal(validateChannel('bad channel'), null);
|
|
1754
|
+
assert.equal(validateChannel(''), null);
|
|
1755
|
+
});
|
|
1756
|
+
|
|
1757
|
+
test('npx update plan does not use npm cache clean as an update', () => {
|
|
1758
|
+
const plan = upgradePlanFor('npx-latest', 'latest');
|
|
1759
|
+
assert.equal(plan.applyCommand, null);
|
|
1760
|
+
assert.equal(plan.auto, true);
|
|
1761
|
+
});
|
|
1762
|
+
|
|
1763
|
+
test('runCommand reports exit code and kills timed out child', async () => {
|
|
1764
|
+
const result = await runCommand(process.execPath, ['-e', 'setTimeout(() => {}, 1000)'], { timeoutMs: 30 });
|
|
1765
|
+
assert.equal(result.ok, false);
|
|
1766
|
+
assert.equal(result.timedOut, true);
|
|
1767
|
+
assert.equal(typeof result.code, 'number');
|
|
1736
1768
|
});
|
|
1737
1769
|
|
|
1738
1770
|
test('detectInstallMethod returns fixed-path when GENEXUS_MCP_GATEWAY_EXE is set', () => {
|
|
@@ -1748,6 +1780,25 @@ test('detectInstallMethod returns fixed-path when GENEXUS_MCP_GATEWAY_EXE is set
|
|
|
1748
1780
|
}
|
|
1749
1781
|
});
|
|
1750
1782
|
|
|
1783
|
+
test('upgradePlanFor carries the selected channel through every install method', () => {
|
|
1784
|
+
const npx = upgradePlanFor('npx-latest', 'next');
|
|
1785
|
+
assert.equal(npx.channel, 'next');
|
|
1786
|
+
assert.match(npx.steps.join(' '), /npx genexus-mcp@next/);
|
|
1787
|
+
assert.doesNotMatch(npx.steps.join(' '), /@latest/);
|
|
1788
|
+
|
|
1789
|
+
const npm = upgradePlanFor('npm-global', 'next');
|
|
1790
|
+
assert.equal(npm.channel, 'next');
|
|
1791
|
+
assert.deepEqual(npm.applyCommand.args, ['install', '-g', 'genexus-mcp@next']);
|
|
1792
|
+
|
|
1793
|
+
const fixed = upgradePlanFor('fixed-path', 'next');
|
|
1794
|
+
assert.equal(fixed.channel, 'next');
|
|
1795
|
+
assert.match(fixed.steps.join(' '), /next/);
|
|
1796
|
+
assert.doesNotMatch(fixed.steps.join(' '), /npm @latest/);
|
|
1797
|
+
|
|
1798
|
+
const direct = upgradePlanFor('package-direct', 'next');
|
|
1799
|
+
assert.equal(direct.channel, 'next');
|
|
1800
|
+
});
|
|
1801
|
+
|
|
1751
1802
|
test('upgradePlanFor encodes the per-method upgrade strategy', () => {
|
|
1752
1803
|
const npx = upgradePlanFor('npx-latest', 'latest');
|
|
1753
1804
|
assert.equal(npx.auto, true, 'npx@latest auto-updates on restart');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "genexus-mcp",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.3.0",
|
|
4
4
|
"mcpName": "io.github.lennix1337/genexus",
|
|
5
5
|
"description": "GeneXus 17, GeneXus 18 MCP server — read, edit, and analyze Knowledge Base objects directly from Claude, Cursor, and other AI agents over the Model Context Protocol.",
|
|
6
6
|
"keywords": [
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"targets": {
|
|
8
8
|
".NETCoreApp,Version=v10.0": {},
|
|
9
9
|
".NETCoreApp,Version=v10.0/win-x64": {
|
|
10
|
-
"GxMcp.Gateway/3.
|
|
10
|
+
"GxMcp.Gateway/3.3.0": {
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"Newtonsoft.Json": "13.0.3",
|
|
13
13
|
"System.Management": "10.0.5",
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
}
|
|
67
67
|
},
|
|
68
68
|
"libraries": {
|
|
69
|
-
"GxMcp.Gateway/3.
|
|
69
|
+
"GxMcp.Gateway/3.3.0": {
|
|
70
70
|
"type": "project",
|
|
71
71
|
"serviceable": false,
|
|
72
72
|
"sha512": ""
|
|
Binary file
|
|
Binary file
|
package/publish/config.json
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
{
|
|
2
|
+
"GatewayMode": "stdio-isolated",
|
|
2
3
|
"Server": {
|
|
4
|
+
"EmitStructuredContent": false,
|
|
5
|
+
"McpStdio": true,
|
|
6
|
+
"WorkerIdleTimeoutMinutes": 5,
|
|
3
7
|
"TerseResponses": true,
|
|
4
8
|
"HttpPort": 0,
|
|
5
|
-
"
|
|
6
|
-
"SessionIdleTimeoutMinutes": 10,
|
|
7
|
-
"McpStdio": true,
|
|
8
|
-
"EmitStructuredContent": false
|
|
9
|
+
"SessionIdleTimeoutMinutes": 10
|
|
9
10
|
},
|
|
10
11
|
"ConfigSchemaVersion": 2,
|
|
11
|
-
"GatewayMode": "stdio-isolated",
|
|
12
|
-
"Environment": {
|
|
13
|
-
"ResolutionPolicy": "strict"
|
|
14
|
-
},
|
|
15
12
|
"GeneXus": {
|
|
16
13
|
"WorkerExecutable": "worker\\\\GxMcp.Worker.exe",
|
|
17
14
|
"InstallationPath": "C:\\Program Files (x86)\\GeneXus\\GeneXus18"
|
|
15
|
+
},
|
|
16
|
+
"Environment": {
|
|
17
|
+
"ResolutionPolicy": "strict"
|
|
18
18
|
}
|
|
19
19
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": "gxmcp-release-manifest/1",
|
|
3
|
-
"version": "3.
|
|
4
|
-
"sourceCommit": "
|
|
3
|
+
"version": "3.3.0",
|
|
4
|
+
"sourceCommit": "6d2f307d10ca718c6dbec8682c0a1678eb90818b",
|
|
5
5
|
"sourceCommitPolicy": "exact-tag",
|
|
6
|
-
"generatedAtUtc": "2026-09-
|
|
6
|
+
"generatedAtUtc": "2026-09-11T03:19:49.1965424Z",
|
|
7
7
|
"runtime": {
|
|
8
8
|
"gateway": "net10.0-windows",
|
|
9
9
|
"worker": "net48-x86",
|
|
@@ -15,33 +15,28 @@
|
|
|
15
15
|
"2026-07-28"
|
|
16
16
|
],
|
|
17
17
|
"schema": "tool_definitions.json",
|
|
18
|
-
"schemaSha256": "
|
|
18
|
+
"schemaSha256": "5624f61d5e5cabd8cd1beb4f05aa1925735e407814aeafa17e860c1601dd867c",
|
|
19
19
|
"provenance": "gxmcp-sbom.json",
|
|
20
20
|
"artifacts": [
|
|
21
21
|
{
|
|
22
22
|
"path": "gxmcp-sbom.json",
|
|
23
23
|
"size": 590,
|
|
24
|
-
"sha256": "
|
|
24
|
+
"sha256": "cdbc21566af312db105a3c964a9df0462dd2cf473f80efa21d8605307ea893a9"
|
|
25
25
|
},
|
|
26
26
|
{
|
|
27
27
|
"path": "GxMcp.Gateway.exe",
|
|
28
28
|
"size": 162304,
|
|
29
|
-
"sha256": "
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
"path": "nexus-ide.vsix",
|
|
33
|
-
"size": 1318670,
|
|
34
|
-
"sha256": "199d49959a1b5a5de20511a0b9a312955499d8c216fe66a4ed39c1f2e17d39ee"
|
|
29
|
+
"sha256": "e75f60b4cbd28abcaf15d4dd80f1e966b79f078b4155b29f035501686414837b"
|
|
35
30
|
},
|
|
36
31
|
{
|
|
37
32
|
"path": "tool_definitions.json",
|
|
38
|
-
"size":
|
|
39
|
-
"sha256": "
|
|
33
|
+
"size": 111992,
|
|
34
|
+
"sha256": "5624f61d5e5cabd8cd1beb4f05aa1925735e407814aeafa17e860c1601dd867c"
|
|
40
35
|
},
|
|
41
36
|
{
|
|
42
37
|
"path": "worker/GxMcp.Worker.exe",
|
|
43
|
-
"size":
|
|
44
|
-
"sha256": "
|
|
38
|
+
"size": 3082240,
|
|
39
|
+
"sha256": "d66461633c93c8e82a957b15aca6706ac87a1ea6433ae6bc7c855d1180548e1b"
|
|
45
40
|
}
|
|
46
41
|
]
|
|
47
42
|
}
|
package/publish/gxmcp-sbom.json
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": "gxmcp-provenance/1",
|
|
3
|
-
"version": "3.
|
|
4
|
-
"sourceCommit": "
|
|
3
|
+
"version": "3.3.0",
|
|
4
|
+
"sourceCommit": "6d2f307d10ca718c6dbec8682c0a1678eb90818b",
|
|
5
5
|
"sourceCommitPolicy": "exact-tag",
|
|
6
6
|
"components": [
|
|
7
7
|
{
|
|
8
8
|
"name": "genexus-mcp",
|
|
9
9
|
"lockfile": "package-lock.json",
|
|
10
10
|
"size": 39914,
|
|
11
|
-
"sha256": "
|
|
11
|
+
"sha256": "778573945c8e74dc124ea99ed313ea99ab45b44aa600977f8094afd18fa8b9af"
|
|
12
12
|
},
|
|
13
13
|
{
|
|
14
14
|
"name": "nexus-ide",
|
|
15
15
|
"lockfile": "src/nexus-ide/package-lock.json",
|
|
16
16
|
"size": 274983,
|
|
17
|
-
"sha256": "
|
|
17
|
+
"sha256": "ed6d742540a8e833f2c2ad5c51f46be23a97e2d80b892d71891f5f61f5f4728c"
|
|
18
18
|
}
|
|
19
19
|
]
|
|
20
20
|
}
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
{"name":"genexus_transfer","description":"Real XPZ export/import over the SDK's IKnowledgeManagerService — dependency-aware, IDE Export/Import parity (NOT the filesystem copy genexus_io/kb_import do). action=export (targets[]+outputFile; includeDependencies=true exports transitive closure) | inspect (explore an .xpz, read-only) | import (apply into KB; dryRun defaults true=preview via ExploreExport; dryRun=false requires confirm=true).","inputSchema":{"type":"object","required":["action"],"properties":{"action":{"type":"string","enum":["export","inspect","import"],"description":"XPZ export, inspection, or import operation to perform."},"targets":{"type":"array","items":{"type":"string"},"description":"export: object names to export."},"outputFile":{"type":"string","description":"export: absolute .xpz output path."},"includeDependencies":{"type":"boolean","description":"export: compute transitive dependency closure (Calls, Tables) and export all referenced objects.","default":false},"file":{"type":"string","description":"inspect/import: absolute .xpz path."},"type":{"type":"string","description":"export: disambiguate object type."},"dryRun":{"type":"boolean","description":"import: true (default) previews; false applies (needs confirm)."},"confirm":{"type":"boolean","description":"import with dryRun=false: required."},"kb":{"type":"string","description":"KB alias."}},"examples":[{"action":"export","targets":["Customer"],"outputFile":"C:\\tmp\\cust.xpz"},{"action":"export","targets":["Customer"],"outputFile":"C:\\tmp\\cust_full.xpz","includeDependencies":true},{"action":"inspect","file":"C:\\tmp\\cust.xpz"}]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":false}},
|
|
49
49
|
{"name":"genexus_deploy","description":"Deploy application over the SDK. action=list_targets (read-only, default) enumerates deployment target types (IDeploymentTargetService); action=deploy (destructive, confirm=true) runs IDeploymentService.Deploy(model).","inputSchema":{"type":"object","properties":{"action":{"type":"string","enum":["list_targets","deploy"],"description":"Deployment-target or deployment execution operation to perform."},"confirm":{"type":"boolean","description":"deploy: required (builds + ships the app)."},"kb":{"type":"string","description":"KB alias."}},"examples":[{"action":"list_targets"},{"action":"deploy","confirm":true}]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":false}},
|
|
50
50
|
{"name":"genexus_generator_reference","description":"Native typed .NET generator references used by GxExternalReference. list and dry-run actions are read-only. add/remove validate a managed assembly when a path is supplied, require optimistic baseVersion for changes, save only the native GeneratorsPart, reread it, and restore the complete generator-property snapshot on verification failure. No lifecycle action runs implicitly.","inputSchema":{"type":"object","additionalProperties":false,"required":["action","environment","generator"],"properties":{"action":{"type":"string","enum":["list","dry_run_add","add","dry_run_remove","remove"],"description":"Typed .NET generator-reference operation to perform."},"environment":{"type":"string","description":"Active GeneXus Environment name; the tool never switches environments."},"generator":{"type":"string","description":"Generator display name, e.g. Default (.NET)."},"assembly":{"type":"string","description":"Assembly file name for add/remove, e.g. SpreadsheetLibrary.dll."},"assemblyPath":{"type":"string","description":"Absolute path or KB-relative path used to validate a managed assembly. Required for add unless found in a standard model/bin location."},"baseVersion":{"type":"string","description":"Optimistic token returned by list or a dry-run. Required for a real state change."},"dryRun":{"type":"boolean","default":false,"description":"Force add/remove to remain read-only."},"rollbackOnFailure":{"type":"boolean","default":true,"description":"Restore and verify the complete prior generator-property snapshot if save/reread diverges."},"kb":{"type":"string","description":"KB alias."}},"examples":[{"action":"list","environment":".Net Environment","generator":"Default (.NET)"},{"action":"dry_run_add","environment":".Net Environment","generator":"Default (.NET)","assembly":"SpreadsheetLibrary.dll","assemblyPath":"C:\\KBs\\Sample\\CSharpModel\\web\\bin\\SpreadsheetLibrary.dll"},{"action":"add","environment":".Net Environment","generator":"Default (.NET)","assembly":"SpreadsheetLibrary.dll","assemblyPath":"C:\\KBs\\Sample\\CSharpModel\\web\\bin\\SpreadsheetLibrary.dll","baseVersion":"sha256:<token>","rollbackOnFailure":true}]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":false}},
|
|
51
|
-
{"name":"genexus_wwp","description":"Typed WorkWithPlus action, tab, and
|
|
51
|
+
{"name":"genexus_wwp","description":"Typed WorkWithPlus action, tab, grid, and native structural edits with dryRun, optimistic concurrency, exact snapshots, post-save reread, projection verification, and rollback. No lifecycle operation is implicit. Settings: embedded and separate WWP templates, paged reads and exact table-class dryRun; saves remain blocked.","inputSchema":{"type":"object","required":["action"],"properties":{"action":{"type":"string","enum":["list","add_action","update_action","move_action","remove_action","add_tab","move_tab","remove_tab","add_grid_attribute","replace_web_component_with_user_action","settings_templates","settings_read","settings_edit"],"description":"WorkWithPlus action-group, tab, grid-attribute, or explicit native structural operation to perform."},"name":{"type":"string","description":"Transaction, WebPanel, or WorkWithPlus<Object> host."},"group":{"type":"string","description":"Action group name. add_action creates it when absent; update/remove use it as a filter."},"actionName":{"type":"string","description":"Action name."},"attribute":{"type":"string","description":"add_grid_attribute: GeneXus Attribute name."},"caption":{"type":"string","description":"Action caption. For a DropDownComponent pass the GeneXus expression used for the closed button, for example &Context.EmpresaDescricao."},"procedure":{"type":"string","description":"add/update: associated Procedure; existence is validated against the KB."},"selection":{"type":"string","enum":["single","multiple"],"description":"add/update: execution scope for grid actions."},"enabledWhen":{"type":"string","description":"Availability condition stored verbatim; expression semantics are not validated."},"icon":{"type":"string","description":"add/update: button icon."},"description":{"type":"string","description":"add/update: tooltip or description."},"confirm":{"type":"boolean","description":"Confirmation prompt; required to delete unless dryRun."},"buttonClass":{"type":"string","description":"add/update: theme button class."},"position":{"type":"integer","minimum":0,"description":"Zero-based action or tab index."},"toGroup":{"type":"string","description":"move_action: destination group (created when absent)."},"fromGroup":{"type":"string","description":"move_action: source group (optional; searched across groups when omitted)."},"dryRun":{"type":"boolean","description":"Return a typed diff and versionToken without mutation."},"controlName":{"type":"string","description":"Tab ControlName."},"title":{"type":"string","description":"add_tab: tab title."},"children":{"type":"array","description":"add_tab controls; flat children are wrapped in a responsive table.","items":{"$ref":"#/$defs/wwpControl"}},"sourceName":{"type":"string","description":"replace_web_component_with_user_action: existing WebComponent name."},"userActionName":{"type":"string","description":"replace_web_component_with_user_action: resulting UserAction name; defaults to sourceName."},"tablePath":{"type":"string","description":"replace_web_component_with_user_action: full breadcrumb including the source node, for example TableHeader > TableUserRole > EmpresaSelector."},"gxobject":{"type":"string","description":"replace_web_component_with_user_action: existing WebComponent Gxobject to retain; it must match the current node."},"controlType":{"type":"string","enum":["DropDownComponent"],"description":"replace_web_component_with_user_action: resulting UserAction ControlType."},"webComponentLoad":{"type":"string","enum":["On Web Panel load","On first click","On every click"],"description":"DropDownComponent load timing."},"trigger":{"type":"string","enum":["Click","Hover"],"description":"DropDownComponent trigger."},"baseVersion":{"type":"string","description":"Optimistic-concurrency token returned by dryRun/read."},"expectedVersion":{"type":"string","description":"Alias for baseVersion."},"versionToken":{"type":"string","description":"Backward-compatible alias for baseVersion."},"kb":{"type":"string","description":"KB alias."},"template":{"description":"Settings catalog path, wwp:<template-guid>, or unique template name.","type":"string"},"limit":{"type":"integer","minimum":0,"description":"Settings nodes per page; offset=0, limit=0 includes full separate-template XML."},"guid":{"type":"string","description":"Pattern Settings object GUID for settings_* actions."},"nodePath":{"description":"Settings node path returned by settings_read.","type":"string"},"entityKey":{"type":"string"},"value":{"type":"string"},"property":{"description":"Exact SDK property name.","type":"string"},"offset":{"minimum":0,"type":"integer"}},"$defs":{"wwpControl":{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["variable","userAction","table"]},"name":{"type":"string"},"caption":{"type":"string"},"description":{"type":"string"},"basicType":{"type":"string"},"length":{"type":"integer","minimum":1},"decimals":{"type":"integer","minimum":0},"controlType":{"type":"string"},"controlValues":{"type":"string"},"controlEmptyItem":{"type":"boolean"},"controlEmptyItemText":{"type":"string"},"columns":{"type":"integer","minimum":1},"themeClass":{"type":"string"},"children":{"type":"array","items":{"$ref":"#/$defs/wwpControl"}}},"additionalProperties":false}},"examples":[{"action":"list","name":"SampleOrderWW"},{"action":"add_action","name":"SampleOrderWW","group":"Operations","actionName":"Retry","procedure":"RetrySampleOrder","selection":"multiple","dryRun":true},{"action":"add_tab","name":"SamplePanel","controlName":"Details","title":"Details","children":[{"type":"variable","name":"Status","basicType":"VarChar","length":40},{"type":"userAction","name":"Refresh","caption":"Refresh"}],"dryRun":true},{"action":"add_grid_attribute","name":"SampleOrderWW","attribute":"SampleOrderStatus","caption":"Status","dryRun":true},{"action":"replace_web_component_with_user_action","name":"WorkWithPlusWorkWithPlusMasterPage","sourceName":"EmpresaSelector","userActionName":"EmpresaSelector","tablePath":"TableHeader > TableUserRole > EmpresaSelector","gxobject":"WWP_MasterPageEmpresaSelectorWC","controlType":"DropDownComponent","caption":"&Context.EmpresaDescricao","webComponentLoad":"On every click","trigger":"Click","dryRun":true}]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":false}},
|
|
52
52
|
{"name":"genexus_kb_diff","description":"Gateway-only filesystem comparison of two KB directories. Requires kbA and kbB aliases or paths; no active KB selection is used.","inputSchema":{"type":"object","required":["kbA","kbB"],"properties":{"kbA":{"type":"string"},"kbB":{"type":"string"}},"examples":[{"kbA":"development","kbB":"staging"}]},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false}},
|
|
53
53
|
{"name":"genexus_kb_import","description":"Gateway-only filesystem copy of one object between two KB directories. Requires source and object identity; run lifecycle index afterwards.","inputSchema":{"type":"object","required":["from","name","type"],"properties":{"from":{"type":"string"},"name":{"type":"string"},"type":{"type":"string"},"to":{"type":"string"}},"examples":[{"from":"C:\\KBs\\source","to":"C:\\KBs\\target","name":"Customer","type":"Transaction"}]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":false}},
|
|
54
54
|
{"name":"genexus_sandbox","description":"Gateway-only filesystem sandbox management; clone or remove a KB directory without SDK dispatch.","inputSchema":{"type":"object","required":["action","name"],"properties":{"action":{"type":"string","enum":["create","remove"]},"name":{"type":"string"},"from":{"type":"string"},"overwrite":{"type":"boolean"}},"examples":[{"action":"create","name":"probe","from":"C:\\KBs\\base"},{"action":"remove","name":"probe"}]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":false}},
|
|
Binary file
|
package/publish/nexus-ide.vsix
DELETED
|
Binary file
|