genexus-mcp 2.0.4 → 2.1.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 +155 -132
- package/cli/commands/axi.js +423 -32
- package/cli/index.js +48 -1
- package/cli/lib/config.js +219 -18
- package/cli/run.test.js +256 -0
- package/package.json +1 -1
- package/publish/GxMcp.Gateway.deps.json +125 -0
- package/publish/GxMcp.Gateway.dll +0 -0
- package/publish/GxMcp.Gateway.exe +0 -0
- package/publish/GxMcp.Gateway.pdb +0 -0
- package/publish/GxMcp.Gateway.runtimeconfig.json +20 -0
- package/publish/Newtonsoft.Json.dll +0 -0
- package/publish/System.CodeDom.dll +0 -0
- package/publish/System.Management.dll +0 -0
- package/publish/System.Security.Permissions.dll +0 -0
- package/publish/System.Windows.Extensions.dll +0 -0
- package/publish/config.json +19 -0
- package/publish/runtimes/win/lib/net8.0/System.Management.dll +0 -0
- package/publish/runtimes/win/lib/net8.0/System.Windows.Extensions.dll +0 -0
- package/publish/start_mcp.bat +22 -0
- package/publish/tool_definitions.json +1027 -0
- package/publish/web.config +12 -0
- package/publish/worker/Definitions/APIDefinition.xml +427 -0
- package/publish/worker/Definitions/APILanguageAttributes.xml +13 -0
- package/publish/worker/Definitions/APILanguageColorsDefinition.xml +247 -0
- package/publish/worker/Definitions/ATTDefinition.xml +12943 -0
- package/publish/worker/Definitions/BASEDefinition.xml +60 -0
- package/publish/worker/Definitions/ContextDefinition.xml +43 -0
- package/publish/worker/Definitions/ControlDefinition.xml +34677 -0
- package/publish/worker/Definitions/ControlsPEMs.xml +3852 -0
- package/publish/worker/Definitions/DATASELECTORDefinition.xml +117 -0
- package/publish/worker/Definitions/DK.Frm.Functions.psx +199 -0
- package/publish/worker/Definitions/DK.Trn.Rules.Functions.psx +77 -0
- package/publish/worker/Definitions/DK.Trn.Rules.psx +205 -0
- package/publish/worker/Definitions/DPRVDefinition.xml +1132 -0
- package/publish/worker/Definitions/DPrv.Rules.psx +30 -0
- package/publish/worker/Definitions/DPrv.Source.Functions.psx +2274 -0
- package/publish/worker/Definitions/DashboardDefinition.xml +49 -0
- package/publish/worker/Definitions/DeployDefinition.xml +151 -0
- package/publish/worker/Definitions/DesignSystemDefinition.xml +106 -0
- package/publish/worker/Definitions/DocumentationPartDefinition.xml +139 -0
- package/publish/worker/Definitions/EXODefinition.xml +1877 -0
- package/publish/worker/Definitions/EXOITEMDefinition.xml +5 -0
- package/publish/worker/Definitions/EXOMETHDefinition.xml +1236 -0
- package/publish/worker/Definitions/EXOPARAMDefinition.xml +883 -0
- package/publish/worker/Definitions/EXOPROPDefinition.xml +4620 -0
- package/publish/worker/Definitions/FILEDefinition.xml +223 -0
- package/publish/worker/Definitions/FORMCLASSDefinition.xml +133 -0
- package/publish/worker/Definitions/FormObjDefinition.xml +22921 -0
- package/publish/worker/Definitions/Frm.Functions.psx +1677 -0
- package/publish/worker/Definitions/Functions.psx +2117 -0
- package/publish/worker/Definitions/GRPDefinition.xml +78 -0
- package/publish/worker/Definitions/GXPMCommonDefinition.xml +8700 -0
- package/publish/worker/Definitions/Gxplorer_CommonDefinition.xml +5980 -0
- package/publish/worker/Definitions/GxpmConditions.xml +238 -0
- package/publish/worker/Definitions/HelpGenSettingsDefinition.xml +318 -0
- package/publish/worker/Definitions/IDXDefinition.xml +54 -0
- package/publish/worker/Definitions/IMAGEDefinition.xml +121 -0
- package/publish/worker/Definitions/KBDefinition.xml +696 -0
- package/publish/worker/Definitions/LNGDefinition.xml +558 -0
- package/publish/worker/Definitions/MBRDefinition.xml +131 -0
- package/publish/worker/Definitions/MBROPTIONDefinition.xml +211 -0
- package/publish/worker/Definitions/MNUDefinition.xml +334 -0
- package/publish/worker/Definitions/MNUOPTIONDefinition.xml +51 -0
- package/publish/worker/Definitions/MiniAppDefinition.xml +91 -0
- package/publish/worker/Definitions/ModelDefinition.xml +3518 -0
- package/publish/worker/Definitions/ModuleInfoDefinition.xml +113 -0
- package/publish/worker/Definitions/PALETTEDefinition.xml +66 -0
- package/publish/worker/Definitions/PRCDefinition.xml +2453 -0
- package/publish/worker/Definitions/Prc.Rules.Functions.psx +1925 -0
- package/publish/worker/Definitions/Prc.Rules.psx +393 -0
- package/publish/worker/Definitions/Prc.Source.Functions.psx +2308 -0
- package/publish/worker/Definitions/RPTDefinition.xml +2123 -0
- package/publish/worker/Definitions/RuntimeContextDefinition.xml +43 -0
- package/publish/worker/Definitions/SD.Conditions.Functions.psx +1336 -0
- package/publish/worker/Definitions/SD.Rules.psx +67 -0
- package/publish/worker/Definitions/SD.Source.Functions.psx +1562 -0
- package/publish/worker/Definitions/SDTDefinition.xml +176 -0
- package/publish/worker/Definitions/SDTITEMDefinition.xml +13239 -0
- package/publish/worker/Definitions/SDTLEVELDefinition.xml +384 -0
- package/publish/worker/Definitions/SINGLEIMAGEDefinition.xml +388 -0
- package/publish/worker/Definitions/STENCILDefinition.xml +73 -0
- package/publish/worker/Definitions/SYNCDefinition.xml +410 -0
- package/publish/worker/Definitions/SuperAppDefinition.xml +180 -0
- package/publish/worker/Definitions/Sync.Rules.psx +191 -0
- package/publish/worker/Definitions/TBDDefinition.xml +99 -0
- package/publish/worker/Definitions/TBLDefinition.xml +302 -0
- package/publish/worker/Definitions/TRNDefinition.xml +5640 -0
- package/publish/worker/Definitions/ThemeDefinition.xml +60769 -0
- package/publish/worker/Definitions/TransactionAttributeDefinition.xml +25 -0
- package/publish/worker/Definitions/TransactionLevelDefinition.xml +48 -0
- package/publish/worker/Definitions/Trn.Rules.Functions.psx +2237 -0
- package/publish/worker/Definitions/Trn.Rules.psx +560 -0
- package/publish/worker/Definitions/Trn.Source.Functions.psx +2154 -0
- package/publish/worker/Definitions/UrlRewriteDefinition.xml +66 -0
- package/publish/worker/Definitions/UserControlDefinition.xml +146 -0
- package/publish/worker/Definitions/WBPDefinition.xml +1874 -0
- package/publish/worker/Definitions/WKPDefinition.xml +1813 -0
- package/publish/worker/Definitions/Wbp.Conditions.Functions.psx +2032 -0
- package/publish/worker/Definitions/Wbp.Rules.Functions.psx +2170 -0
- package/publish/worker/Definitions/Wbp.Rules.psx +336 -0
- package/publish/worker/Definitions/Wbp.Source.Functions.psx +2344 -0
- package/publish/worker/Definitions/Wrk.Conditions.Functions.psx +1909 -0
- package/publish/worker/Definitions/Wrk.Rules.Functions.psx +1937 -0
- package/publish/worker/Definitions/Wrk.Rules.psx +453 -0
- package/publish/worker/Definitions/Wrk.Source.Functions.psx +2224 -0
- package/publish/worker/Definitions/XFLDefinition.xml +246 -0
- package/publish/worker/Definitions/cobolDefinition.xml +2074 -0
- package/publish/worker/Definitions/conditions.xml +251 -0
- package/publish/worker/Definitions/conditionsSD.xml +236 -0
- package/publish/worker/Definitions/csharpDefinition.xml +3527 -0
- package/publish/worker/Definitions/csharpwinDefinition.xml +2979 -0
- package/publish/worker/Definitions/dataprovider.xml +254 -0
- package/publish/worker/Definitions/ds_AS400NATIVEDefinition.xml +2167 -0
- package/publish/worker/Definitions/ds_DAMENGDefinition.xml +2546 -0
- package/publish/worker/Definitions/ds_DB2400Definition.xml +2209 -0
- package/publish/worker/Definitions/ds_DB2COMMONSERVERSDefinition.xml +2394 -0
- package/publish/worker/Definitions/ds_DBFCDXDefinition.xml +5 -0
- package/publish/worker/Definitions/ds_DBFIDXDefinition.xml +5 -0
- package/publish/worker/Definitions/ds_HANADefinition.xml +1821 -0
- package/publish/worker/Definitions/ds_INFORMIXDefinition.xml +2498 -0
- package/publish/worker/Definitions/ds_MYSQLDefinition.xml +2222 -0
- package/publish/worker/Definitions/ds_ORACLEDefinition.xml +2915 -0
- package/publish/worker/Definitions/ds_POSTGRESQLDefinition.xml +2206 -0
- package/publish/worker/Definitions/ds_SERVICEDefinition.xml +710 -0
- package/publish/worker/Definitions/ds_SQLCEDefinition.xml +822 -0
- package/publish/worker/Definitions/ds_SQLITEDefinition.xml +1075 -0
- package/publish/worker/Definitions/ds_SQLSERVERDefinition.xml +2481 -0
- package/publish/worker/Definitions/dv_AS400NATIVEDefinition.xml +53 -0
- package/publish/worker/Definitions/dv_DAMENGDefinition.xml +53 -0
- package/publish/worker/Definitions/dv_DB2400Definition.xml +47 -0
- package/publish/worker/Definitions/dv_DB2COMMONSERVERSDefinition.xml +47 -0
- package/publish/worker/Definitions/dv_DBFCDXDefinition.xml +47 -0
- package/publish/worker/Definitions/dv_DBFIDXDefinition.xml +47 -0
- package/publish/worker/Definitions/dv_HANADefinition.xml +53 -0
- package/publish/worker/Definitions/dv_INFORMIXDefinition.xml +53 -0
- package/publish/worker/Definitions/dv_MYSQLDefinition.xml +53 -0
- package/publish/worker/Definitions/dv_ORACLEDefinition.xml +53 -0
- package/publish/worker/Definitions/dv_POSTGRESQLDefinition.xml +53 -0
- package/publish/worker/Definitions/dv_SERVICEDefinition.xml +47 -0
- package/publish/worker/Definitions/dv_SQLCEDefinition.xml +48 -0
- package/publish/worker/Definitions/dv_SQLITEDefinition.xml +47 -0
- package/publish/worker/Definitions/dv_SQLSERVERDefinition.xml +53 -0
- package/publish/worker/Definitions/dvi_AS400NATIVEDefinition.xml +53 -0
- package/publish/worker/Definitions/dvi_DAMENGDefinition.xml +53 -0
- package/publish/worker/Definitions/dvi_DB2400Definition.xml +47 -0
- package/publish/worker/Definitions/dvi_DB2COMMONSERVERSDefinition.xml +47 -0
- package/publish/worker/Definitions/dvi_DBFCDXDefinition.xml +51 -0
- package/publish/worker/Definitions/dvi_DBFIDXDefinition.xml +47 -0
- package/publish/worker/Definitions/dvi_HANADefinition.xml +53 -0
- package/publish/worker/Definitions/dvi_INFORMIXDefinition.xml +53 -0
- package/publish/worker/Definitions/dvi_MYSQLDefinition.xml +53 -0
- package/publish/worker/Definitions/dvi_ORACLEDefinition.xml +53 -0
- package/publish/worker/Definitions/dvi_POSTGRESQLDefinition.xml +53 -0
- package/publish/worker/Definitions/dvi_SERVICEDefinition.xml +47 -0
- package/publish/worker/Definitions/dvi_SQLCEDefinition.xml +48 -0
- package/publish/worker/Definitions/dvi_SQLITEDefinition.xml +47 -0
- package/publish/worker/Definitions/dvi_SQLSERVERDefinition.xml +53 -0
- package/publish/worker/Definitions/events.xml +340 -0
- package/publish/worker/Definitions/eventsSD.xml +331 -0
- package/publish/worker/Definitions/exportDefinition.xml +123 -0
- package/publish/worker/Definitions/formula.xml +215 -0
- package/publish/worker/Definitions/gxtypes.xml +24099 -0
- package/publish/worker/Definitions/importDefinition.xml +148 -0
- package/publish/worker/Definitions/javaDefinition.xml +4733 -0
- package/publish/worker/Definitions/kbInfoDefinition.xml +43 -0
- package/publish/worker/Definitions/netcoreDefinition.xml +3506 -0
- package/publish/worker/Definitions/netmobileDefinition.xml +1559 -0
- package/publish/worker/Definitions/procedures.xml +292 -0
- package/publish/worker/Definitions/rpgDefinition.xml +2083 -0
- package/publish/worker/Definitions/rubyDefinition.xml +1358 -0
- package/publish/worker/Definitions/rules.xml +279 -0
- package/publish/worker/Definitions/rulesSD.xml +253 -0
- package/publish/worker/Definitions/sdpatternsDefinition.xml +3509 -0
- package/publish/worker/Definitions/smartdeviceDefinition.xml +897 -0
- package/publish/worker/Definitions/trn_src.xml +335 -0
- package/publish/worker/Definitions/vfpDefinition.xml +2372 -0
- package/publish/worker/Definitions/vfpcsDefinition.xml +2631 -0
- package/publish/worker/GxMcp.Worker.exe +0 -0
- package/publish/worker/GxMcp.Worker.exe.config +76 -0
- package/publish/worker/GxMcp.Worker.pdb +0 -0
- package/publish/worker/Newtonsoft.Json.dll +0 -0
package/cli/commands/axi.js
CHANGED
|
@@ -10,7 +10,15 @@ const {
|
|
|
10
10
|
directoryLooksLikeKnowledgeBase,
|
|
11
11
|
createConfigFile,
|
|
12
12
|
patchClientConfig,
|
|
13
|
-
|
|
13
|
+
unpatchClientConfig,
|
|
14
|
+
getLocalAppDataCacheDir,
|
|
15
|
+
readGeneXusVersionFromInstall,
|
|
16
|
+
discoverGeneXusInstallation,
|
|
17
|
+
discoverKnowledgeBase,
|
|
18
|
+
readKbCatalog,
|
|
19
|
+
addKbToConfig,
|
|
20
|
+
removeKbFromConfig,
|
|
21
|
+
switchActiveKb
|
|
14
22
|
} = require('../lib/config');
|
|
15
23
|
|
|
16
24
|
function parseFieldSelection(raw) {
|
|
@@ -127,10 +135,8 @@ function buildStatusData(cwd) {
|
|
|
127
135
|
return { ready, configFound, gatewayExeFound, kbLooksValid, configPath, gatewayExePath, kbPath, gxPath, configSource };
|
|
128
136
|
}
|
|
129
137
|
|
|
130
|
-
async function
|
|
131
|
-
|
|
132
|
-
return { status: 'fail', detail: 'Gateway executable does not exist for spawn probe.' };
|
|
133
|
-
}
|
|
138
|
+
async function spawnGatewayProbe({ env = process.env, spawnHoldMs, timeoutMs, label, successDetail }) {
|
|
139
|
+
const gatewayExePath = getGatewayExePath();
|
|
134
140
|
|
|
135
141
|
return await new Promise((resolve) => {
|
|
136
142
|
let done = false;
|
|
@@ -144,38 +150,41 @@ async function probeGatewaySpawn(gatewayExePath) {
|
|
|
144
150
|
const child = spawn(gatewayExePath, ['--axi-spawn-probe'], {
|
|
145
151
|
stdio: 'ignore',
|
|
146
152
|
windowsHide: true,
|
|
147
|
-
env
|
|
153
|
+
env
|
|
148
154
|
});
|
|
149
155
|
|
|
150
156
|
child.once('error', (err) => {
|
|
151
|
-
finish({ status: 'fail', detail:
|
|
157
|
+
finish({ status: 'fail', detail: `${label} failed: ${err.message}` });
|
|
152
158
|
});
|
|
153
159
|
|
|
154
160
|
child.once('spawn', () => {
|
|
155
161
|
setTimeout(() => {
|
|
156
|
-
try {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
}
|
|
160
|
-
finish({ status: 'pass', detail: 'Gateway process can be spawned (probe launched and terminated).' });
|
|
161
|
-
}, 180);
|
|
162
|
+
try { child.kill(); } catch { }
|
|
163
|
+
finish({ status: 'pass', detail: successDetail });
|
|
164
|
+
}, spawnHoldMs);
|
|
162
165
|
});
|
|
163
166
|
|
|
164
167
|
setTimeout(() => {
|
|
165
168
|
if (!done) {
|
|
166
|
-
try {
|
|
167
|
-
|
|
168
|
-
} catch {
|
|
169
|
-
}
|
|
170
|
-
finish({ status: 'warn', detail: 'Spawn probe timed out; process was force-stopped.' });
|
|
169
|
+
try { child.kill(); } catch { }
|
|
170
|
+
finish({ status: 'warn', detail: `${label} timed out; process was force-stopped.` });
|
|
171
171
|
}
|
|
172
|
-
},
|
|
172
|
+
}, timeoutMs);
|
|
173
173
|
} catch (err) {
|
|
174
|
-
finish({ status: 'fail', detail:
|
|
174
|
+
finish({ status: 'fail', detail: `${label} threw: ${err.message}` });
|
|
175
175
|
}
|
|
176
176
|
});
|
|
177
177
|
}
|
|
178
178
|
|
|
179
|
+
async function probeGatewaySpawn() {
|
|
180
|
+
return spawnGatewayProbe({
|
|
181
|
+
spawnHoldMs: 180,
|
|
182
|
+
timeoutMs: 900,
|
|
183
|
+
label: 'Spawn probe',
|
|
184
|
+
successDetail: 'Gateway process can be spawned (probe launched and terminated).'
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
|
|
179
188
|
function resolveMcpBaseUrl(cwd) {
|
|
180
189
|
const configPath = resolveConfigPathNoMutate(cwd);
|
|
181
190
|
const fallback = 'http://127.0.0.1:5000/mcp';
|
|
@@ -339,7 +348,7 @@ async function handleDoctor(options, ctx) {
|
|
|
339
348
|
];
|
|
340
349
|
|
|
341
350
|
if (options.full) {
|
|
342
|
-
const probe = await probeGatewaySpawn(
|
|
351
|
+
const probe = await probeGatewaySpawn();
|
|
343
352
|
checks.push({ id: 'gateway_spawn_probe', status: probe.status, detail: probe.detail });
|
|
344
353
|
} else {
|
|
345
354
|
checks.push({ id: 'gateway_spawn_probe', status: 'warn', detail: 'Spawn probe skipped by default. Run doctor with --full.' });
|
|
@@ -795,20 +804,72 @@ async function handleInit(options, ctx) {
|
|
|
795
804
|
return runInteractiveInit({ ...ctx, options });
|
|
796
805
|
}
|
|
797
806
|
|
|
798
|
-
|
|
807
|
+
const resolution = {
|
|
808
|
+
kb: { value: options.kb || null, source: options.kb ? 'flag' : null },
|
|
809
|
+
gx: { value: options.gx || null, source: options.gx ? 'flag' : null }
|
|
810
|
+
};
|
|
811
|
+
|
|
812
|
+
if (!resolution.kb.value) {
|
|
813
|
+
const fromCwd = discoverKnowledgeBase(ctx.cwd);
|
|
814
|
+
if (fromCwd) {
|
|
815
|
+
resolution.kb.value = fromCwd;
|
|
816
|
+
resolution.kb.source = 'cwd';
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
if (!resolution.gx.value) {
|
|
821
|
+
const fromDisco = discoverGeneXusInstallation();
|
|
822
|
+
if (fromDisco) {
|
|
823
|
+
resolution.gx.value = fromDisco;
|
|
824
|
+
resolution.gx.source = 'auto-discovery';
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
if (!resolution.kb.value || !resolution.gx.value) {
|
|
829
|
+
const missing = [];
|
|
830
|
+
if (!resolution.kb.value) missing.push('--kb (and current directory is not a GeneXus KB)');
|
|
831
|
+
if (!resolution.gx.value) missing.push('--gx (and no GeneXus installation was auto-discovered)');
|
|
799
832
|
return {
|
|
800
833
|
exitCode: ctx.EXIT_CODES.USAGE,
|
|
801
|
-
envelope: usageEnvelope(
|
|
834
|
+
envelope: usageEnvelope(
|
|
835
|
+
`Cannot resolve required paths: ${missing.join('; ')}. Pass flags explicitly or run from inside a KB folder.`,
|
|
836
|
+
ctx.EXIT_CODES.USAGE
|
|
837
|
+
)
|
|
802
838
|
};
|
|
803
839
|
}
|
|
804
840
|
|
|
805
841
|
try {
|
|
806
|
-
const created = createConfigFile(
|
|
842
|
+
const created = createConfigFile(resolution.kb.value, resolution.gx.value);
|
|
843
|
+
const kbName = path.basename(resolution.kb.value);
|
|
844
|
+
addKbToConfig(created.targetConfigPath, kbName, resolution.kb.value);
|
|
845
|
+
|
|
807
846
|
let patchResult = { patched: [], failed: [] };
|
|
808
847
|
if (options.writeClients) {
|
|
809
848
|
patchResult = patchClientConfig(created.targetConfigPath);
|
|
810
849
|
}
|
|
811
850
|
|
|
851
|
+
const verification = await runPostInitVerification({
|
|
852
|
+
cwd: ctx.cwd,
|
|
853
|
+
includeSmoke: !options.noSmoke,
|
|
854
|
+
ctx
|
|
855
|
+
});
|
|
856
|
+
|
|
857
|
+
let warm = null;
|
|
858
|
+
if (options.warm) {
|
|
859
|
+
warm = await warmGateway({ configPath: created.targetConfigPath });
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
const help = [];
|
|
863
|
+
if (patchResult.patched.length === 0 && !options.writeClients) {
|
|
864
|
+
help.push('Run `genexus-mcp init --kb "<kbPath>" --gx "<geneXusPath>" --write-clients` to patch supported clients.');
|
|
865
|
+
}
|
|
866
|
+
if (verification.summary.fail > 0 || verification.summary.warn > 0) {
|
|
867
|
+
help.push('Some verification checks did not pass. Run `genexus-mcp doctor --full --mcp-smoke` for details.');
|
|
868
|
+
}
|
|
869
|
+
if (options.noSmoke) {
|
|
870
|
+
help.push('MCP protocol smoke was skipped (--no-smoke). Re-run `genexus-mcp doctor --mcp-smoke` to validate end-to-end.');
|
|
871
|
+
}
|
|
872
|
+
|
|
812
873
|
return {
|
|
813
874
|
exitCode: ctx.EXIT_CODES.OK,
|
|
814
875
|
envelope: {
|
|
@@ -818,14 +879,23 @@ async function handleInit(options, ctx) {
|
|
|
818
879
|
configPath: created.targetConfigPath,
|
|
819
880
|
configFound: true,
|
|
820
881
|
noOp: !created.changed,
|
|
821
|
-
clientsPatchedCount: patchResult.patched.length
|
|
882
|
+
clientsPatchedCount: patchResult.patched.length,
|
|
883
|
+
resolved: {
|
|
884
|
+
kb: { path: resolution.kb.value, source: resolution.kb.source },
|
|
885
|
+
gx: { path: resolution.gx.value, source: resolution.gx.source }
|
|
886
|
+
},
|
|
887
|
+
verification: {
|
|
888
|
+
summary: verification.summary,
|
|
889
|
+
checks: verification.checks
|
|
890
|
+
},
|
|
891
|
+
warm: warm || null
|
|
822
892
|
},
|
|
823
|
-
help
|
|
824
|
-
? ['Run `genexus-mcp init --kb "<kbPath>" --gx "<geneXusPath>" --write-clients` to patch supported clients.']
|
|
825
|
-
: [],
|
|
893
|
+
help,
|
|
826
894
|
meta: {
|
|
827
895
|
patchedClients: patchResult.patched,
|
|
828
|
-
failedClients: patchResult.failed
|
|
896
|
+
failedClients: patchResult.failed,
|
|
897
|
+
smokeSkipped: !!options.noSmoke,
|
|
898
|
+
warmed: !!warm && warm.status === 'pass'
|
|
829
899
|
}
|
|
830
900
|
}
|
|
831
901
|
};
|
|
@@ -837,6 +907,301 @@ async function handleInit(options, ctx) {
|
|
|
837
907
|
}
|
|
838
908
|
}
|
|
839
909
|
|
|
910
|
+
async function warmGateway({ configPath }) {
|
|
911
|
+
return spawnGatewayProbe({
|
|
912
|
+
env: { ...process.env, GX_CONFIG_PATH: configPath },
|
|
913
|
+
spawnHoldMs: 1500,
|
|
914
|
+
timeoutMs: 12000,
|
|
915
|
+
label: 'Warm spawn',
|
|
916
|
+
successDetail: 'Gateway warmed (worker process kicked).'
|
|
917
|
+
});
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
async function runPostInitVerification({ cwd, includeSmoke, ctx }) {
|
|
921
|
+
const doctorResult = await handleDoctor(
|
|
922
|
+
{ full: false, mcpSmoke: !!includeSmoke, fields: null, limit: 100 },
|
|
923
|
+
{ cwd, EXIT_CODES: ctx.EXIT_CODES }
|
|
924
|
+
);
|
|
925
|
+
|
|
926
|
+
const { checks, summary } = doctorResult.envelope.ok;
|
|
927
|
+
return { checks, summary };
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
async function handleWhoami(options, ctx) {
|
|
931
|
+
const data = buildStatusData(ctx.cwd);
|
|
932
|
+
|
|
933
|
+
if (!data.configFound) {
|
|
934
|
+
return {
|
|
935
|
+
exitCode: ctx.EXIT_CODES.OK,
|
|
936
|
+
envelope: {
|
|
937
|
+
ok: {
|
|
938
|
+
connected: false,
|
|
939
|
+
reason: 'No GeneXus MCP configuration was found in the current context.'
|
|
940
|
+
},
|
|
941
|
+
help: [
|
|
942
|
+
'Run `genexus-mcp init --kb "<kbPath>" --gx "<geneXusPath>"` to configure.',
|
|
943
|
+
'Or run `genexus-mcp init --interactive` for a guided setup.'
|
|
944
|
+
]
|
|
945
|
+
}
|
|
946
|
+
};
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
const kbPath = data.kbPath;
|
|
950
|
+
const gxPath = data.gxPath;
|
|
951
|
+
const kbName = kbPath ? path.basename(kbPath) : null;
|
|
952
|
+
const kbExists = !!(kbPath && fs.existsSync(kbPath));
|
|
953
|
+
const kbValid = data.kbLooksValid;
|
|
954
|
+
const gxVersion = readGeneXusVersionFromInstall(gxPath);
|
|
955
|
+
|
|
956
|
+
const ok = {
|
|
957
|
+
connected: true,
|
|
958
|
+
kb: {
|
|
959
|
+
name: kbName,
|
|
960
|
+
path: kbPath,
|
|
961
|
+
exists: kbExists,
|
|
962
|
+
looksValid: kbValid
|
|
963
|
+
},
|
|
964
|
+
geneXus: {
|
|
965
|
+
installationPath: gxPath,
|
|
966
|
+
version: gxVersion
|
|
967
|
+
},
|
|
968
|
+
config: {
|
|
969
|
+
path: data.configPath,
|
|
970
|
+
source: data.configSource
|
|
971
|
+
}
|
|
972
|
+
};
|
|
973
|
+
|
|
974
|
+
const help = [];
|
|
975
|
+
if (!kbExists) help.push('Configured KB path does not exist on disk.');
|
|
976
|
+
if (kbExists && !kbValid) help.push('KB path exists but does not look like a GeneXus KB (no `.gxw` or `KnowledgeBase.Connection`).');
|
|
977
|
+
if (!gxVersion) help.push('Could not read GeneXus version from installation folder (no version.txt detected).');
|
|
978
|
+
|
|
979
|
+
return { exitCode: ctx.EXIT_CODES.OK, envelope: { ok, help } };
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
async function promptYesNo(question) {
|
|
983
|
+
return new Promise((resolve) => {
|
|
984
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stderr });
|
|
985
|
+
rl.question(`${question} [y/N]: `, (answer) => {
|
|
986
|
+
rl.close();
|
|
987
|
+
const trimmed = (answer || '').trim().toLowerCase();
|
|
988
|
+
resolve(trimmed === 'y' || trimmed === 'yes');
|
|
989
|
+
});
|
|
990
|
+
});
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
async function handleUninstall(options, ctx) {
|
|
994
|
+
const data = buildStatusData(ctx.cwd);
|
|
995
|
+
const cacheDir = getLocalAppDataCacheDir();
|
|
996
|
+
const cacheDirExists = !!(cacheDir && fs.existsSync(cacheDir));
|
|
997
|
+
const localConfigPath = data.configPath;
|
|
998
|
+
const hasLocalConfig = !!localConfigPath && fs.existsSync(localConfigPath);
|
|
999
|
+
|
|
1000
|
+
const plan = {
|
|
1001
|
+
clientEntries: 'Remove `mcpServers.genexus` from any detected AI client config.',
|
|
1002
|
+
cacheDir: cacheDirExists ? `Delete ${cacheDir}` : 'No cache directory present.',
|
|
1003
|
+
localConfig: hasLocalConfig ? `Delete ${localConfigPath}` : 'No local config.json detected.'
|
|
1004
|
+
};
|
|
1005
|
+
|
|
1006
|
+
if (!options.yes) {
|
|
1007
|
+
process.stderr.write('\n[genexus-mcp uninstall] The following actions will be performed:\n');
|
|
1008
|
+
process.stderr.write(` - ${plan.clientEntries}\n`);
|
|
1009
|
+
process.stderr.write(` - ${plan.cacheDir}\n`);
|
|
1010
|
+
process.stderr.write(` - ${plan.localConfig}\n\n`);
|
|
1011
|
+
const confirmed = await promptYesNo('Proceed?');
|
|
1012
|
+
if (!confirmed) {
|
|
1013
|
+
return {
|
|
1014
|
+
exitCode: ctx.EXIT_CODES.OK,
|
|
1015
|
+
envelope: {
|
|
1016
|
+
ok: { action: 'uninstall', cancelled: true, plan },
|
|
1017
|
+
help: ['Pass --yes to skip the interactive confirmation.']
|
|
1018
|
+
}
|
|
1019
|
+
};
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
const unpatch = unpatchClientConfig();
|
|
1024
|
+
|
|
1025
|
+
let cacheRemoved = false;
|
|
1026
|
+
let cacheError = null;
|
|
1027
|
+
if (cacheDirExists) {
|
|
1028
|
+
try {
|
|
1029
|
+
fs.rmSync(cacheDir, { recursive: true, force: true });
|
|
1030
|
+
cacheRemoved = true;
|
|
1031
|
+
} catch (err) {
|
|
1032
|
+
cacheError = err && err.message ? err.message : 'Unknown error removing cache dir';
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
let configRemoved = false;
|
|
1037
|
+
let configError = null;
|
|
1038
|
+
if (hasLocalConfig) {
|
|
1039
|
+
try {
|
|
1040
|
+
fs.unlinkSync(localConfigPath);
|
|
1041
|
+
configRemoved = true;
|
|
1042
|
+
} catch (err) {
|
|
1043
|
+
configError = err && err.message ? err.message : 'Unknown error removing config.json';
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
const help = [];
|
|
1048
|
+
if (cacheError) help.push(`Cache removal failed: ${cacheError}`);
|
|
1049
|
+
if (configError) help.push(`Local config removal failed: ${configError}`);
|
|
1050
|
+
if (unpatch.failed.length > 0) help.push(`Some client configs could not be updated (see meta.failedClients).`);
|
|
1051
|
+
if (unpatch.removed.length > 0) help.push('Restart your AI clients to release any stale MCP connections.');
|
|
1052
|
+
|
|
1053
|
+
return {
|
|
1054
|
+
exitCode: ctx.EXIT_CODES.OK,
|
|
1055
|
+
envelope: {
|
|
1056
|
+
ok: {
|
|
1057
|
+
action: 'uninstall',
|
|
1058
|
+
cancelled: false,
|
|
1059
|
+
removedClients: unpatch.removed,
|
|
1060
|
+
cacheRemoved,
|
|
1061
|
+
cacheDir: cacheDir || null,
|
|
1062
|
+
configRemoved,
|
|
1063
|
+
configPath: localConfigPath || null
|
|
1064
|
+
},
|
|
1065
|
+
help,
|
|
1066
|
+
meta: {
|
|
1067
|
+
skippedClients: unpatch.skipped,
|
|
1068
|
+
failedClients: unpatch.failed
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
};
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
async function handleKb(subcommand, options, ctx) {
|
|
1075
|
+
const data = buildStatusData(ctx.cwd);
|
|
1076
|
+
if (!data.configPath) {
|
|
1077
|
+
return {
|
|
1078
|
+
exitCode: ctx.EXIT_CODES.ERROR,
|
|
1079
|
+
envelope: operationalErrorEnvelope(
|
|
1080
|
+
'No GeneXus MCP config.json found. Run `genexus-mcp init` first.',
|
|
1081
|
+
ctx.EXIT_CODES.ERROR,
|
|
1082
|
+
['Run `genexus-mcp init --kb "<path>" --gx "<path>"` to create one.']
|
|
1083
|
+
)
|
|
1084
|
+
};
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
const configPath = data.configPath;
|
|
1088
|
+
|
|
1089
|
+
if (subcommand === 'list') {
|
|
1090
|
+
const catalog = readKbCatalog(configPath);
|
|
1091
|
+
const entries = Object.entries(catalog.kbs).map(([name, p]) => ({
|
|
1092
|
+
name,
|
|
1093
|
+
path: p,
|
|
1094
|
+
active: name === catalog.activeKb,
|
|
1095
|
+
exists: fs.existsSync(p)
|
|
1096
|
+
}));
|
|
1097
|
+
if (entries.length === 0 && catalog.kbPath) {
|
|
1098
|
+
entries.push({ name: '(legacy)', path: catalog.kbPath, active: true, exists: fs.existsSync(catalog.kbPath) });
|
|
1099
|
+
}
|
|
1100
|
+
return {
|
|
1101
|
+
exitCode: ctx.EXIT_CODES.OK,
|
|
1102
|
+
envelope: {
|
|
1103
|
+
ok: {
|
|
1104
|
+
activeKb: catalog.activeKb,
|
|
1105
|
+
kbs: entries,
|
|
1106
|
+
returned: entries.length,
|
|
1107
|
+
total: entries.length
|
|
1108
|
+
},
|
|
1109
|
+
help: entries.length === 0
|
|
1110
|
+
? ['No KBs registered. Run `genexus-mcp kb add --name <name> --kb <path>` to register one.']
|
|
1111
|
+
: []
|
|
1112
|
+
}
|
|
1113
|
+
};
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
if (subcommand === 'add') {
|
|
1117
|
+
if (!options.name || !options.kb) {
|
|
1118
|
+
return {
|
|
1119
|
+
exitCode: ctx.EXIT_CODES.USAGE,
|
|
1120
|
+
envelope: usageEnvelope('`kb add` requires --name and --kb.', ctx.EXIT_CODES.USAGE)
|
|
1121
|
+
};
|
|
1122
|
+
}
|
|
1123
|
+
const catalog = addKbToConfig(configPath, options.name, options.kb);
|
|
1124
|
+
return {
|
|
1125
|
+
exitCode: ctx.EXIT_CODES.OK,
|
|
1126
|
+
envelope: {
|
|
1127
|
+
ok: {
|
|
1128
|
+
action: 'kb.add',
|
|
1129
|
+
name: options.name,
|
|
1130
|
+
path: options.kb,
|
|
1131
|
+
activeKb: catalog.activeKb,
|
|
1132
|
+
registeredCount: Object.keys(catalog.kbs).length
|
|
1133
|
+
},
|
|
1134
|
+
help: catalog.activeKb === options.name
|
|
1135
|
+
? ['Restart your AI client to pick up the new active KB.']
|
|
1136
|
+
: [`KB registered. Run \`genexus-mcp kb switch --name ${options.name}\` to make it active.`]
|
|
1137
|
+
}
|
|
1138
|
+
};
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
if (subcommand === 'remove') {
|
|
1142
|
+
if (!options.name) {
|
|
1143
|
+
return {
|
|
1144
|
+
exitCode: ctx.EXIT_CODES.USAGE,
|
|
1145
|
+
envelope: usageEnvelope('`kb remove` requires --name.', ctx.EXIT_CODES.USAGE)
|
|
1146
|
+
};
|
|
1147
|
+
}
|
|
1148
|
+
const { catalog, removed } = removeKbFromConfig(configPath, options.name);
|
|
1149
|
+
if (!removed) {
|
|
1150
|
+
return {
|
|
1151
|
+
exitCode: ctx.EXIT_CODES.OK,
|
|
1152
|
+
envelope: {
|
|
1153
|
+
ok: { action: 'kb.remove', name: options.name, removed: false },
|
|
1154
|
+
help: [`KB '${options.name}' was not registered. Run \`genexus-mcp kb list\` to see available names.`]
|
|
1155
|
+
}
|
|
1156
|
+
};
|
|
1157
|
+
}
|
|
1158
|
+
return {
|
|
1159
|
+
exitCode: ctx.EXIT_CODES.OK,
|
|
1160
|
+
envelope: {
|
|
1161
|
+
ok: {
|
|
1162
|
+
action: 'kb.remove',
|
|
1163
|
+
name: options.name,
|
|
1164
|
+
removed: true,
|
|
1165
|
+
activeKb: catalog.activeKb,
|
|
1166
|
+
registeredCount: Object.keys(catalog.kbs).length
|
|
1167
|
+
},
|
|
1168
|
+
help: ['Restart your AI client to apply changes.']
|
|
1169
|
+
}
|
|
1170
|
+
};
|
|
1171
|
+
}
|
|
1172
|
+
|
|
1173
|
+
if (subcommand === 'switch') {
|
|
1174
|
+
const result = switchActiveKb(configPath, { name: options.name, path: options.kb });
|
|
1175
|
+
if (!result.ok) {
|
|
1176
|
+
return {
|
|
1177
|
+
exitCode: ctx.EXIT_CODES.USAGE,
|
|
1178
|
+
envelope: usageEnvelope(result.reason, ctx.EXIT_CODES.USAGE)
|
|
1179
|
+
};
|
|
1180
|
+
}
|
|
1181
|
+
return {
|
|
1182
|
+
exitCode: ctx.EXIT_CODES.OK,
|
|
1183
|
+
envelope: {
|
|
1184
|
+
ok: {
|
|
1185
|
+
action: 'kb.switch',
|
|
1186
|
+
activeKb: result.switchedTo.name,
|
|
1187
|
+
kbPath: result.switchedTo.path
|
|
1188
|
+
},
|
|
1189
|
+
help: [
|
|
1190
|
+
'Restart your AI client (or run `genexus_lifecycle action=stop-worker` via MCP) so the worker reloads with the new KB.'
|
|
1191
|
+
]
|
|
1192
|
+
}
|
|
1193
|
+
};
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
return {
|
|
1197
|
+
exitCode: ctx.EXIT_CODES.USAGE,
|
|
1198
|
+
envelope: usageEnvelope(
|
|
1199
|
+
`Unknown kb subcommand '${subcommand}'. Use list, add, remove, or switch.`,
|
|
1200
|
+
ctx.EXIT_CODES.USAGE
|
|
1201
|
+
)
|
|
1202
|
+
};
|
|
1203
|
+
}
|
|
1204
|
+
|
|
840
1205
|
function commandHelpMap() {
|
|
841
1206
|
return {
|
|
842
1207
|
axi: {
|
|
@@ -864,8 +1229,31 @@ function commandHelpMap() {
|
|
|
864
1229
|
examples: ['genexus-mcp config show', 'genexus-mcp config show --full --format json']
|
|
865
1230
|
},
|
|
866
1231
|
init: {
|
|
867
|
-
usage: 'genexus-mcp init --kb <path> --gx <path> [--write-clients] [--format ...] OR genexus-mcp init --interactive',
|
|
868
|
-
examples: [
|
|
1232
|
+
usage: 'genexus-mcp init [--kb <path>] [--gx <path>] [--write-clients] [--no-smoke] [--warm] [--format ...] OR genexus-mcp init --interactive',
|
|
1233
|
+
examples: [
|
|
1234
|
+
'genexus-mcp init # zero-config: auto-discovers GX from registry/Program Files and KB from cwd',
|
|
1235
|
+
'genexus-mcp init --kb "C:\\KBs\\MyKB" --gx "C:\\Program Files (x86)\\GeneXus\\GeneXus18"',
|
|
1236
|
+
'genexus-mcp init --interactive',
|
|
1237
|
+
'genexus-mcp init --kb <path> --gx <path> --no-smoke'
|
|
1238
|
+
]
|
|
1239
|
+
},
|
|
1240
|
+
whoami: {
|
|
1241
|
+
usage: 'genexus-mcp whoami [--format toon|json|text]',
|
|
1242
|
+
examples: ['genexus-mcp whoami', 'genexus-mcp whoami --format json']
|
|
1243
|
+
},
|
|
1244
|
+
uninstall: {
|
|
1245
|
+
usage: 'genexus-mcp uninstall [--yes] [--format toon|json|text]',
|
|
1246
|
+
examples: ['genexus-mcp uninstall', 'genexus-mcp uninstall --yes --format json']
|
|
1247
|
+
},
|
|
1248
|
+
kb: {
|
|
1249
|
+
usage: 'genexus-mcp kb <list|add|remove|switch> [--name <name>] [--kb <path>] [--format ...]',
|
|
1250
|
+
examples: [
|
|
1251
|
+
'genexus-mcp kb list',
|
|
1252
|
+
'genexus-mcp kb add --name sales --kb "C:\\KBs\\SalesProd"',
|
|
1253
|
+
'genexus-mcp kb switch --name sales',
|
|
1254
|
+
'genexus-mcp kb switch --kb "C:\\KBs\\NewKB" # auto-registers by folder name',
|
|
1255
|
+
'genexus-mcp kb remove --name sales'
|
|
1256
|
+
]
|
|
869
1257
|
},
|
|
870
1258
|
llm: {
|
|
871
1259
|
usage: 'genexus-mcp llm help [--full] [--fields f1,f2] [--format toon|json|text]',
|
|
@@ -939,7 +1327,7 @@ async function handleHelp(targetCommand, ctx) {
|
|
|
939
1327
|
bin: binPath,
|
|
940
1328
|
command: 'genexus-mcp',
|
|
941
1329
|
description: 'GeneXus MCP launcher and AXI-oriented utility CLI',
|
|
942
|
-
commands: ['home', 'axi home', 'status', 'doctor', 'tools list', 'config show', 'layout status', 'layout run', 'layout inspect', 'init', 'llm help', 'update', 'help'],
|
|
1330
|
+
commands: ['home', 'axi home', 'status', 'doctor', 'tools list', 'config show', 'layout status', 'layout run', 'layout inspect', 'init', 'whoami', 'uninstall', 'kb list', 'kb add', 'kb remove', 'kb switch', 'llm help', 'update', 'help'],
|
|
943
1331
|
defaults: { format: 'toon', limit: 100 }
|
|
944
1332
|
},
|
|
945
1333
|
help: [
|
|
@@ -1042,6 +1430,9 @@ module.exports = {
|
|
|
1042
1430
|
handleToolsList,
|
|
1043
1431
|
handleConfigShow,
|
|
1044
1432
|
handleInit,
|
|
1433
|
+
handleWhoami,
|
|
1434
|
+
handleUninstall,
|
|
1435
|
+
handleKb,
|
|
1045
1436
|
handleHome,
|
|
1046
1437
|
handleLlmHelp,
|
|
1047
1438
|
handleLayout,
|
package/cli/index.js
CHANGED
|
@@ -15,6 +15,9 @@ const {
|
|
|
15
15
|
handleToolsList,
|
|
16
16
|
handleConfigShow,
|
|
17
17
|
handleInit,
|
|
18
|
+
handleWhoami,
|
|
19
|
+
handleUninstall,
|
|
20
|
+
handleKb,
|
|
18
21
|
handleHome,
|
|
19
22
|
handleLlmHelp,
|
|
20
23
|
handleLayout,
|
|
@@ -37,6 +40,10 @@ const GLOBAL_DEFAULTS = {
|
|
|
37
40
|
interactive: false,
|
|
38
41
|
writeClients: false,
|
|
39
42
|
mcpSmoke: false,
|
|
43
|
+
noSmoke: false,
|
|
44
|
+
warm: false,
|
|
45
|
+
yes: false,
|
|
46
|
+
name: null,
|
|
40
47
|
limit: 100,
|
|
41
48
|
query: null,
|
|
42
49
|
quiet: false,
|
|
@@ -44,7 +51,7 @@ const GLOBAL_DEFAULTS = {
|
|
|
44
51
|
help: false
|
|
45
52
|
};
|
|
46
53
|
|
|
47
|
-
const KNOWN_COMMANDS = new Set(['status', 'doctor', 'tools', 'config', 'init', 'setup', 'help', 'home', 'axi', 'llm', 'layout', 'update']);
|
|
54
|
+
const KNOWN_COMMANDS = new Set(['status', 'doctor', 'tools', 'config', 'init', 'setup', 'whoami', 'uninstall', 'kb', 'help', 'home', 'axi', 'llm', 'layout', 'update']);
|
|
48
55
|
|
|
49
56
|
function parseArgs(argv) {
|
|
50
57
|
const result = {
|
|
@@ -99,6 +106,11 @@ function parseArgs(argv) {
|
|
|
99
106
|
tokens.shift();
|
|
100
107
|
}
|
|
101
108
|
|
|
109
|
+
if (result.command === 'kb' && ['list', 'add', 'remove', 'switch'].includes(tokens[0])) {
|
|
110
|
+
result.subcommand = tokens[0];
|
|
111
|
+
tokens.shift();
|
|
112
|
+
}
|
|
113
|
+
|
|
102
114
|
if (result.command === 'layout' && (tokens[0] === 'status' || tokens[0] === 'run' || tokens[0] === 'inspect')) {
|
|
103
115
|
result.subcommand = tokens[0];
|
|
104
116
|
tokens.shift();
|
|
@@ -148,6 +160,12 @@ function parseArgs(argv) {
|
|
|
148
160
|
else result.unknownFlags.push('--gx requires a value');
|
|
149
161
|
break;
|
|
150
162
|
}
|
|
163
|
+
case 'name': {
|
|
164
|
+
const val = takeValue();
|
|
165
|
+
if (val) result.options.name = val;
|
|
166
|
+
else result.unknownFlags.push('--name requires a value');
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
151
169
|
case 'limit': {
|
|
152
170
|
const val = takeValue();
|
|
153
171
|
if (!val) {
|
|
@@ -238,6 +256,15 @@ function parseArgs(argv) {
|
|
|
238
256
|
case 'mcp-smoke':
|
|
239
257
|
result.options.mcpSmoke = true;
|
|
240
258
|
break;
|
|
259
|
+
case 'no-smoke':
|
|
260
|
+
result.options.noSmoke = true;
|
|
261
|
+
break;
|
|
262
|
+
case 'warm':
|
|
263
|
+
result.options.warm = true;
|
|
264
|
+
break;
|
|
265
|
+
case 'yes':
|
|
266
|
+
result.options.yes = true;
|
|
267
|
+
break;
|
|
241
268
|
case 'quiet':
|
|
242
269
|
result.options.quiet = true;
|
|
243
270
|
break;
|
|
@@ -333,6 +360,9 @@ function resolveMetaCommand(parsed, targetHelp) {
|
|
|
333
360
|
if (parsed.subcommand === 'inspect') return 'layout.inspect';
|
|
334
361
|
return 'layout.status';
|
|
335
362
|
}
|
|
363
|
+
if (parsed.command === 'kb') {
|
|
364
|
+
return parsed.subcommand ? `kb.${parsed.subcommand}` : 'kb';
|
|
365
|
+
}
|
|
336
366
|
if (parsed.command === 'update') return 'update';
|
|
337
367
|
return parsed.command || 'unknown';
|
|
338
368
|
}
|
|
@@ -444,6 +474,23 @@ async function main(argv) {
|
|
|
444
474
|
case 'init':
|
|
445
475
|
result = await handleInit(parsed.options, ctx);
|
|
446
476
|
break;
|
|
477
|
+
case 'whoami':
|
|
478
|
+
result = await handleWhoami(parsed.options, ctx);
|
|
479
|
+
break;
|
|
480
|
+
case 'uninstall':
|
|
481
|
+
result = await handleUninstall(parsed.options, ctx);
|
|
482
|
+
break;
|
|
483
|
+
case 'kb':
|
|
484
|
+
if (!parsed.subcommand || !['list', 'add', 'remove', 'switch'].includes(parsed.subcommand)) {
|
|
485
|
+
writeStructured(
|
|
486
|
+
process.stdout,
|
|
487
|
+
withCommandMeta(usageEnvelope('kb requires subcommand `list`, `add`, `remove`, or `switch`.', EXIT_CODES.USAGE), resolveMetaCommand(parsed)),
|
|
488
|
+
parsed.options.format
|
|
489
|
+
);
|
|
490
|
+
return EXIT_CODES.USAGE;
|
|
491
|
+
}
|
|
492
|
+
result = await handleKb(parsed.subcommand, parsed.options, ctx);
|
|
493
|
+
break;
|
|
447
494
|
case 'update':
|
|
448
495
|
result = await handleUpdate(parsed.options, ctx);
|
|
449
496
|
break;
|