@tronsfey/ucli 0.5.0 → 0.5.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/dist/{client-3I7XBDJU.js → client-LCWUZRZX.js} +94 -4
- package/dist/client-LCWUZRZX.js.map +1 -0
- package/dist/index.js +326 -69
- package/dist/index.js.map +1 -1
- package/dist/{runner-GVYIJNHN.js → runner-HH357SRR.js} +33 -17
- package/dist/{runner-GVYIJNHN.js.map → runner-HH357SRR.js.map} +1 -1
- package/package.json +2 -2
- package/skill.md +92 -8
- package/dist/client-3I7XBDJU.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -166,23 +166,59 @@ var ExitCode = {
|
|
|
166
166
|
SERVER_ERROR: 7
|
|
167
167
|
};
|
|
168
168
|
|
|
169
|
+
// src/lib/output.ts
|
|
170
|
+
var currentMode = "text";
|
|
171
|
+
function setOutputMode(mode) {
|
|
172
|
+
currentMode = mode;
|
|
173
|
+
}
|
|
174
|
+
function isJsonOutput() {
|
|
175
|
+
return currentMode === "json";
|
|
176
|
+
}
|
|
177
|
+
function outputSuccess(data) {
|
|
178
|
+
if (currentMode === "json") {
|
|
179
|
+
console.log(JSON.stringify({ success: true, data }, null, 2));
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
function outputError(code, message, hint) {
|
|
183
|
+
if (currentMode === "json") {
|
|
184
|
+
const envelope = {
|
|
185
|
+
success: false,
|
|
186
|
+
error: { code, message, ...hint ? { hint } : {} }
|
|
187
|
+
};
|
|
188
|
+
console.log(JSON.stringify(envelope, null, 2));
|
|
189
|
+
process.exit(code);
|
|
190
|
+
}
|
|
191
|
+
console.error(`
|
|
192
|
+
\u2716 Error: ${message}`);
|
|
193
|
+
if (hint) console.error(` Hint: ${hint}`);
|
|
194
|
+
process.exit(code);
|
|
195
|
+
}
|
|
196
|
+
|
|
169
197
|
// src/commands/configure.ts
|
|
170
198
|
function registerConfigure(program2) {
|
|
171
199
|
program2.command("configure").description("Configure the OAS Gateway server URL and authentication token").requiredOption("--server <url>", "OAS Gateway server URL (e.g. https://oas.example.com)").requiredOption("--token <jwt>", "Group JWT token issued by the server admin").action(async (opts) => {
|
|
172
200
|
const serverUrl = opts.server.replace(/\/$/, "");
|
|
173
201
|
const token = opts.token;
|
|
174
|
-
|
|
202
|
+
if (!isJsonOutput()) {
|
|
203
|
+
console.log(`Connecting to ${serverUrl}...`);
|
|
204
|
+
}
|
|
175
205
|
const client = new ServerClient({ serverUrl, token });
|
|
176
206
|
try {
|
|
177
207
|
await client.listOAS();
|
|
178
208
|
saveConfig({ serverUrl, token });
|
|
209
|
+
if (isJsonOutput()) {
|
|
210
|
+
outputSuccess({ serverUrl, configured: true });
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
179
213
|
console.log("\u2713 Configuration saved successfully.");
|
|
180
214
|
console.log(` Server: ${serverUrl}`);
|
|
181
215
|
console.log(` Token: ${token.slice(0, 20)}...`);
|
|
182
216
|
} catch (err) {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
217
|
+
outputError(
|
|
218
|
+
ExitCode.CONNECTIVITY_ERROR,
|
|
219
|
+
`Connection failed: ${err.message}`,
|
|
220
|
+
"Check the server URL and token"
|
|
221
|
+
);
|
|
186
222
|
}
|
|
187
223
|
});
|
|
188
224
|
}
|
|
@@ -466,24 +502,24 @@ function registerServices(program2) {
|
|
|
466
502
|
await writeOASListCache(entries, maxTtl);
|
|
467
503
|
}
|
|
468
504
|
}
|
|
505
|
+
const safe = entries.map(({ authConfig, ...rest }) => ({
|
|
506
|
+
...rest,
|
|
507
|
+
authConfig: { type: authConfig["type"] ?? rest.authType }
|
|
508
|
+
}));
|
|
509
|
+
if (isJsonOutput()) {
|
|
510
|
+
outputSuccess(safe);
|
|
511
|
+
return;
|
|
512
|
+
}
|
|
469
513
|
const format = (opts.format ?? "table").toLowerCase();
|
|
470
514
|
if (entries.length === 0) {
|
|
471
515
|
console.log("No services registered in this group.");
|
|
472
516
|
return;
|
|
473
517
|
}
|
|
474
518
|
if (format === "json") {
|
|
475
|
-
const safe = entries.map(({ authConfig, ...rest }) => ({
|
|
476
|
-
...rest,
|
|
477
|
-
authConfig: { type: authConfig["type"] ?? rest.authType }
|
|
478
|
-
}));
|
|
479
519
|
console.log(JSON.stringify(safe, null, 2));
|
|
480
520
|
return;
|
|
481
521
|
}
|
|
482
522
|
if (format === "yaml") {
|
|
483
|
-
const safe = entries.map(({ authConfig, ...rest }) => ({
|
|
484
|
-
...rest,
|
|
485
|
-
authConfig: { type: authConfig["type"] ?? rest.authType }
|
|
486
|
-
}));
|
|
487
523
|
console.log(toYaml(safe));
|
|
488
524
|
return;
|
|
489
525
|
}
|
|
@@ -504,30 +540,30 @@ ${"SERVICE".padEnd(nameWidth)} AUTH DESCRIPTION`);
|
|
|
504
540
|
let entry;
|
|
505
541
|
try {
|
|
506
542
|
entry = await client.getOAS(name);
|
|
507
|
-
} catch
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
543
|
+
} catch {
|
|
544
|
+
outputError(
|
|
545
|
+
ExitCode.NOT_FOUND,
|
|
546
|
+
`Service not found: ${name}`,
|
|
547
|
+
"Run: ucli services list to see available services"
|
|
548
|
+
);
|
|
511
549
|
}
|
|
512
550
|
const help = await getServiceHelp(entry);
|
|
551
|
+
const { authConfig, ...rest } = entry;
|
|
552
|
+
const safe = {
|
|
553
|
+
...rest,
|
|
554
|
+
authConfig: { type: authConfig["type"] ?? rest.authType },
|
|
555
|
+
operationsHelp: help
|
|
556
|
+
};
|
|
557
|
+
if (isJsonOutput()) {
|
|
558
|
+
outputSuccess(safe);
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
513
561
|
const format = (opts.format ?? "table").toLowerCase();
|
|
514
562
|
if (format === "json") {
|
|
515
|
-
const { authConfig, ...rest } = entry;
|
|
516
|
-
const safe = {
|
|
517
|
-
...rest,
|
|
518
|
-
authConfig: { type: authConfig["type"] ?? rest.authType },
|
|
519
|
-
operationsHelp: help
|
|
520
|
-
};
|
|
521
563
|
console.log(JSON.stringify(safe, null, 2));
|
|
522
564
|
return;
|
|
523
565
|
}
|
|
524
566
|
if (format === "yaml") {
|
|
525
|
-
const { authConfig, ...rest } = entry;
|
|
526
|
-
const safe = {
|
|
527
|
-
...rest,
|
|
528
|
-
authConfig: { type: authConfig["type"] ?? rest.authType },
|
|
529
|
-
operationsHelp: help
|
|
530
|
-
};
|
|
531
567
|
console.log(toYaml(safe));
|
|
532
568
|
return;
|
|
533
569
|
}
|
|
@@ -548,13 +584,18 @@ Service: ${entry.name}`);
|
|
|
548
584
|
function registerRun(program2) {
|
|
549
585
|
program2.command("run [service] [args...]").description("Execute an operation on a service").option("--service <name>", "Service name (from `services list`)").option("--operation <id>", "OperationId to execute").option("--params <json>", "JSON string of operation parameters").option("--format <fmt>", "Output format: json | table | yaml", "json").option("--query <jmespath>", "Filter response with JMESPath expression").option("--data <json>", "Request body (JSON string or @filename)").allowUnknownOption(true).action(async (serviceArg, args, opts) => {
|
|
550
586
|
if (serviceArg && opts.service && serviceArg !== opts.service) {
|
|
551
|
-
|
|
552
|
-
|
|
587
|
+
outputError(
|
|
588
|
+
ExitCode.USAGE_ERROR,
|
|
589
|
+
`Conflicting service values: positional "${serviceArg}" and --service "${opts.service}". Use either the positional argument or --service flag, not both.`
|
|
590
|
+
);
|
|
553
591
|
}
|
|
554
592
|
const service = opts.service ?? serviceArg;
|
|
555
593
|
if (!service) {
|
|
556
|
-
|
|
557
|
-
|
|
594
|
+
outputError(
|
|
595
|
+
ExitCode.USAGE_ERROR,
|
|
596
|
+
"Missing service name. Use positional <service> or --service <name>.",
|
|
597
|
+
"Run: ucli services list to see available services"
|
|
598
|
+
);
|
|
558
599
|
}
|
|
559
600
|
const cfg = getConfig();
|
|
560
601
|
const client = new ServerClient(cfg);
|
|
@@ -562,9 +603,11 @@ function registerRun(program2) {
|
|
|
562
603
|
try {
|
|
563
604
|
entry = await client.getOAS(service);
|
|
564
605
|
} catch {
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
606
|
+
outputError(
|
|
607
|
+
ExitCode.NOT_FOUND,
|
|
608
|
+
`Unknown service: ${service}`,
|
|
609
|
+
"Run: ucli services list to see available services"
|
|
610
|
+
);
|
|
568
611
|
}
|
|
569
612
|
const extraArgs = opts.args ?? [];
|
|
570
613
|
const operationArgs = [...args, ...extraArgs];
|
|
@@ -576,8 +619,11 @@ function registerRun(program2) {
|
|
|
576
619
|
try {
|
|
577
620
|
parsed = JSON.parse(opts.params);
|
|
578
621
|
} catch {
|
|
579
|
-
|
|
580
|
-
|
|
622
|
+
outputError(
|
|
623
|
+
ExitCode.USAGE_ERROR,
|
|
624
|
+
"Invalid --params JSON.",
|
|
625
|
+
`Example: --params '{"petId": 1}'`
|
|
626
|
+
);
|
|
581
627
|
}
|
|
582
628
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
583
629
|
for (const [k, v] of Object.entries(parsed)) {
|
|
@@ -600,8 +646,10 @@ function registerRun(program2) {
|
|
|
600
646
|
...query !== void 0 ? { query } : {}
|
|
601
647
|
});
|
|
602
648
|
} catch (err) {
|
|
603
|
-
|
|
604
|
-
|
|
649
|
+
outputError(
|
|
650
|
+
ExitCode.GENERAL_ERROR,
|
|
651
|
+
`Operation failed: ${err.message}`
|
|
652
|
+
);
|
|
605
653
|
}
|
|
606
654
|
});
|
|
607
655
|
}
|
|
@@ -611,7 +659,9 @@ function registerRefresh(program2) {
|
|
|
611
659
|
program2.command("refresh").description("Force-refresh the local OAS cache from the server").option("--service <name>", "Refresh only a specific service").action(async (opts) => {
|
|
612
660
|
const cfg = getConfig();
|
|
613
661
|
const client = new ServerClient(cfg);
|
|
614
|
-
|
|
662
|
+
if (!isJsonOutput()) {
|
|
663
|
+
console.log("Refreshing OAS list from server...");
|
|
664
|
+
}
|
|
615
665
|
if (opts.service) {
|
|
616
666
|
await clearOASCache(opts.service);
|
|
617
667
|
} else {
|
|
@@ -622,6 +672,10 @@ function registerRefresh(program2) {
|
|
|
622
672
|
const maxTtl = Math.min(...entries.map((e) => e.cacheTtl));
|
|
623
673
|
await writeOASListCache(entries, maxTtl);
|
|
624
674
|
}
|
|
675
|
+
if (isJsonOutput()) {
|
|
676
|
+
outputSuccess({ refreshed: entries.length });
|
|
677
|
+
return;
|
|
678
|
+
}
|
|
625
679
|
console.log(`\u2713 Refreshed ${entries.length} service(s).`);
|
|
626
680
|
});
|
|
627
681
|
}
|
|
@@ -696,6 +750,10 @@ DISCOVERY
|
|
|
696
750
|
ucli services info <service>
|
|
697
751
|
Show detailed service info and all available operations.
|
|
698
752
|
|
|
753
|
+
ucli introspect
|
|
754
|
+
Return complete capability manifest in a single call (JSON).
|
|
755
|
+
Ideal for AI agents: includes services, MCP servers, and command reference.
|
|
756
|
+
|
|
699
757
|
ucli help [service]
|
|
700
758
|
Show this guide, or service-specific operations.
|
|
701
759
|
|
|
@@ -708,6 +766,16 @@ EXECUTION
|
|
|
708
766
|
--query <jmespath> Filter response with JMESPath
|
|
709
767
|
--data <json|@file> Request body for POST/PUT/PATCH
|
|
710
768
|
|
|
769
|
+
MCP SERVERS
|
|
770
|
+
ucli mcp list
|
|
771
|
+
List all MCP servers in your group.
|
|
772
|
+
|
|
773
|
+
ucli mcp tools <server>
|
|
774
|
+
List tools available on a MCP server.
|
|
775
|
+
|
|
776
|
+
ucli mcp run <server> <tool> [key=value ...]
|
|
777
|
+
Call a tool on a MCP server.
|
|
778
|
+
|
|
711
779
|
MAINTENANCE
|
|
712
780
|
ucli refresh
|
|
713
781
|
Force-refresh the local OAS cache from the server.
|
|
@@ -722,6 +790,8 @@ SHELL COMPLETIONS
|
|
|
722
790
|
|
|
723
791
|
GLOBAL FLAGS
|
|
724
792
|
--debug Enable verbose debug logging
|
|
793
|
+
--output json Wrap ALL output in structured JSON envelopes
|
|
794
|
+
(for agent/automation consumption)
|
|
725
795
|
-v, --version Show version number
|
|
726
796
|
|
|
727
797
|
ERRORS
|
|
@@ -729,6 +799,11 @@ ERRORS
|
|
|
729
799
|
404 Not Found \u2192 Check service name: ucli services list
|
|
730
800
|
4xx Client Error \u2192 Check operation args: ucli services info <service>
|
|
731
801
|
5xx Server Error \u2192 Retry or run: ucli refresh
|
|
802
|
+
|
|
803
|
+
AI AGENT QUICK START
|
|
804
|
+
1. ucli introspect # discover everything in one call
|
|
805
|
+
2. ucli run <svc> <op> [args] # execute operations
|
|
806
|
+
3. Use --output json globally # get structured { success, data/error } envelopes
|
|
732
807
|
`);
|
|
733
808
|
}
|
|
734
809
|
|
|
@@ -739,8 +814,8 @@ function resolve(mod, name) {
|
|
|
739
814
|
throw new Error(`Cannot resolve export "${name}" from module`);
|
|
740
815
|
}
|
|
741
816
|
async function getMcp2cli() {
|
|
742
|
-
const clientMod = await import("./client-
|
|
743
|
-
const runnerMod = await import("./runner-
|
|
817
|
+
const clientMod = await import("./client-LCWUZRZX.js");
|
|
818
|
+
const runnerMod = await import("./runner-HH357SRR.js");
|
|
744
819
|
return {
|
|
745
820
|
createMcpClient: resolve(clientMod, "createMcpClient"),
|
|
746
821
|
getTools: resolve(runnerMod, "getTools"),
|
|
@@ -810,24 +885,24 @@ function registerMcp(program2) {
|
|
|
810
885
|
const cfg = getConfig();
|
|
811
886
|
const client = new ServerClient(cfg);
|
|
812
887
|
const entries = await client.listMCP();
|
|
888
|
+
const safe = entries.map(({ authConfig, ...rest }) => ({
|
|
889
|
+
...rest,
|
|
890
|
+
authConfig: { type: authConfig.type }
|
|
891
|
+
}));
|
|
892
|
+
if (isJsonOutput()) {
|
|
893
|
+
outputSuccess(safe);
|
|
894
|
+
return;
|
|
895
|
+
}
|
|
813
896
|
if (entries.length === 0) {
|
|
814
897
|
console.log("No MCP servers registered in this group.");
|
|
815
898
|
return;
|
|
816
899
|
}
|
|
817
900
|
const format = (opts.format ?? "table").toLowerCase();
|
|
818
901
|
if (format === "json") {
|
|
819
|
-
const safe = entries.map(({ authConfig, ...rest }) => ({
|
|
820
|
-
...rest,
|
|
821
|
-
authConfig: { type: authConfig.type }
|
|
822
|
-
}));
|
|
823
902
|
console.log(JSON.stringify(safe, null, 2));
|
|
824
903
|
return;
|
|
825
904
|
}
|
|
826
905
|
if (format === "yaml") {
|
|
827
|
-
const safe = entries.map(({ authConfig, ...rest }) => ({
|
|
828
|
-
...rest,
|
|
829
|
-
authConfig: { type: authConfig.type }
|
|
830
|
-
}));
|
|
831
906
|
console.log(toYaml(safe));
|
|
832
907
|
return;
|
|
833
908
|
}
|
|
@@ -848,16 +923,21 @@ ${"SERVER".padEnd(nameWidth)} TRANSPORT DESCRIPTION`);
|
|
|
848
923
|
try {
|
|
849
924
|
entry = await client.getMCP(serverName);
|
|
850
925
|
} catch {
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
926
|
+
outputError(
|
|
927
|
+
ExitCode.NOT_FOUND,
|
|
928
|
+
`Unknown MCP server: ${serverName}`,
|
|
929
|
+
"Run: ucli mcp list to see available servers"
|
|
930
|
+
);
|
|
854
931
|
}
|
|
855
932
|
let tools;
|
|
856
933
|
try {
|
|
857
934
|
tools = await listMcpTools(entry);
|
|
858
935
|
} catch (err) {
|
|
859
|
-
|
|
860
|
-
|
|
936
|
+
outputError(ExitCode.GENERAL_ERROR, `Failed to fetch tools: ${err.message}`);
|
|
937
|
+
}
|
|
938
|
+
if (isJsonOutput()) {
|
|
939
|
+
outputSuccess(tools);
|
|
940
|
+
return;
|
|
861
941
|
}
|
|
862
942
|
if (tools.length === 0) {
|
|
863
943
|
console.log(`No tools found on MCP server "${serverName}".`);
|
|
@@ -888,15 +968,16 @@ Tools on "${serverName}":`);
|
|
|
888
968
|
try {
|
|
889
969
|
entry = await client.getMCP(serverName);
|
|
890
970
|
} catch {
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
971
|
+
outputError(
|
|
972
|
+
ExitCode.NOT_FOUND,
|
|
973
|
+
`Unknown MCP server: ${serverName}`,
|
|
974
|
+
"Run: ucli mcp list to see available servers"
|
|
975
|
+
);
|
|
894
976
|
}
|
|
895
977
|
try {
|
|
896
978
|
await runMcpTool(entry, toolName, args);
|
|
897
979
|
} catch (err) {
|
|
898
|
-
|
|
899
|
-
process.exit(ExitCode.GENERAL_ERROR);
|
|
980
|
+
outputError(ExitCode.GENERAL_ERROR, `Tool execution failed: ${err.message}`);
|
|
900
981
|
}
|
|
901
982
|
});
|
|
902
983
|
}
|
|
@@ -931,8 +1012,11 @@ function registerDoctor(program2) {
|
|
|
931
1012
|
ok: false,
|
|
932
1013
|
detail: "Not configured. Run: ucli configure --server <url> --token <jwt>"
|
|
933
1014
|
});
|
|
934
|
-
|
|
935
|
-
|
|
1015
|
+
outputError(
|
|
1016
|
+
ExitCode.CONFIG_ERROR,
|
|
1017
|
+
"Not configured",
|
|
1018
|
+
"Run: ucli configure --server <url> --token <jwt>"
|
|
1019
|
+
);
|
|
936
1020
|
}
|
|
937
1021
|
let cfg;
|
|
938
1022
|
try {
|
|
@@ -948,8 +1032,11 @@ function registerDoctor(program2) {
|
|
|
948
1032
|
ok: false,
|
|
949
1033
|
detail: `Failed to read config: ${err.message}`
|
|
950
1034
|
});
|
|
951
|
-
|
|
952
|
-
|
|
1035
|
+
outputError(
|
|
1036
|
+
ExitCode.CONFIG_ERROR,
|
|
1037
|
+
`Failed to read config: ${err.message}`,
|
|
1038
|
+
"Run: ucli configure --server <url> --token <jwt>"
|
|
1039
|
+
);
|
|
953
1040
|
}
|
|
954
1041
|
debug(`Checking connectivity to ${cfg.serverUrl}...`);
|
|
955
1042
|
try {
|
|
@@ -985,8 +1072,15 @@ function registerDoctor(program2) {
|
|
|
985
1072
|
detail: `Token rejected: ${msg}`
|
|
986
1073
|
});
|
|
987
1074
|
}
|
|
988
|
-
printResults(results);
|
|
989
1075
|
const allOk = results.every((r) => r.ok);
|
|
1076
|
+
if (isJsonOutput()) {
|
|
1077
|
+
outputSuccess({
|
|
1078
|
+
healthy: allOk,
|
|
1079
|
+
checks: results
|
|
1080
|
+
});
|
|
1081
|
+
process.exit(allOk ? ExitCode.SUCCESS : ExitCode.GENERAL_ERROR);
|
|
1082
|
+
}
|
|
1083
|
+
printResults(results);
|
|
990
1084
|
process.exit(allOk ? ExitCode.SUCCESS : ExitCode.GENERAL_ERROR);
|
|
991
1085
|
});
|
|
992
1086
|
}
|
|
@@ -1026,7 +1120,7 @@ _ucli_completions() {
|
|
|
1026
1120
|
COMPREPLY=()
|
|
1027
1121
|
cur="\${COMP_WORDS[COMP_CWORD]}"
|
|
1028
1122
|
prev="\${COMP_WORDS[COMP_CWORD-1]}"
|
|
1029
|
-
commands="configure services run refresh help mcp doctor completions"
|
|
1123
|
+
commands="configure services run refresh help mcp doctor completions introspect"
|
|
1030
1124
|
|
|
1031
1125
|
case "\${COMP_WORDS[1]}" in
|
|
1032
1126
|
services)
|
|
@@ -1070,6 +1164,7 @@ _ucli() {
|
|
|
1070
1164
|
'mcp:Interact with MCP servers'
|
|
1071
1165
|
'doctor:Check configuration and connectivity'
|
|
1072
1166
|
'completions:Generate shell completion script'
|
|
1167
|
+
'introspect:Return complete capability manifest for AI agents'
|
|
1073
1168
|
)
|
|
1074
1169
|
|
|
1075
1170
|
_arguments -C \\
|
|
@@ -1112,6 +1207,8 @@ complete -c ucli -n __fish_use_subcommand -a mcp -d 'Interact with MCP servers'
|
|
|
1112
1207
|
complete -c ucli -n __fish_use_subcommand -a doctor -d 'Check config and connectivity'
|
|
1113
1208
|
complete -c ucli -n __fish_use_subcommand -a completions -d 'Generate shell completions'
|
|
1114
1209
|
|
|
1210
|
+
complete -c ucli -n __fish_use_subcommand -a introspect -d 'Return capability manifest for AI agents'
|
|
1211
|
+
|
|
1115
1212
|
# services subcommands
|
|
1116
1213
|
complete -c ucli -n '__fish_seen_subcommand_from services' -a list -d 'List services'
|
|
1117
1214
|
complete -c ucli -n '__fish_seen_subcommand_from services' -a info -d 'Show service details'
|
|
@@ -1125,16 +1222,175 @@ complete -c ucli -n '__fish_seen_subcommand_from mcp' -a run -d 'Call a tool'
|
|
|
1125
1222
|
complete -c ucli -n '__fish_seen_subcommand_from completions' -a 'bash zsh fish' -d 'Shell type'`;
|
|
1126
1223
|
}
|
|
1127
1224
|
|
|
1225
|
+
// src/commands/introspect.ts
|
|
1226
|
+
function registerIntrospect(program2) {
|
|
1227
|
+
program2.command("introspect").description("Return a complete capability manifest for AI agent discovery (services, MCP servers, commands)").option("--format <fmt>", "Output format: json | yaml", "json").action(async (opts) => {
|
|
1228
|
+
const cfg = getConfig();
|
|
1229
|
+
const client = new ServerClient(cfg);
|
|
1230
|
+
let oasEntries = [];
|
|
1231
|
+
let mcpEntries = [];
|
|
1232
|
+
try {
|
|
1233
|
+
;
|
|
1234
|
+
[oasEntries, mcpEntries] = await Promise.all([
|
|
1235
|
+
client.listOAS(),
|
|
1236
|
+
client.listMCP()
|
|
1237
|
+
]);
|
|
1238
|
+
} catch (err) {
|
|
1239
|
+
const message = err.message;
|
|
1240
|
+
outputError(
|
|
1241
|
+
ExitCode.CONNECTIVITY_ERROR,
|
|
1242
|
+
`Failed to fetch capabilities: ${message}`,
|
|
1243
|
+
"Check server connectivity with: ucli doctor"
|
|
1244
|
+
);
|
|
1245
|
+
}
|
|
1246
|
+
const manifest = {
|
|
1247
|
+
version: "1",
|
|
1248
|
+
services: oasEntries.map(toIntrospectService),
|
|
1249
|
+
mcpServers: mcpEntries.map(toIntrospectMcpServer),
|
|
1250
|
+
commands: getCommandReference()
|
|
1251
|
+
};
|
|
1252
|
+
const format = (opts.format ?? "json").toLowerCase();
|
|
1253
|
+
if (isJsonOutput()) {
|
|
1254
|
+
outputSuccess(manifest);
|
|
1255
|
+
return;
|
|
1256
|
+
}
|
|
1257
|
+
if (format === "json") {
|
|
1258
|
+
console.log(JSON.stringify(manifest, null, 2));
|
|
1259
|
+
return;
|
|
1260
|
+
}
|
|
1261
|
+
if (format === "yaml") {
|
|
1262
|
+
console.log(toYaml(manifest));
|
|
1263
|
+
return;
|
|
1264
|
+
}
|
|
1265
|
+
console.log(JSON.stringify(manifest, null, 2));
|
|
1266
|
+
});
|
|
1267
|
+
}
|
|
1268
|
+
function toIntrospectService(e) {
|
|
1269
|
+
return {
|
|
1270
|
+
name: e.name,
|
|
1271
|
+
description: e.description,
|
|
1272
|
+
authType: e.authType,
|
|
1273
|
+
remoteUrl: e.remoteUrl,
|
|
1274
|
+
baseEndpoint: e.baseEndpoint,
|
|
1275
|
+
cacheTtl: e.cacheTtl
|
|
1276
|
+
};
|
|
1277
|
+
}
|
|
1278
|
+
function toIntrospectMcpServer(e) {
|
|
1279
|
+
return {
|
|
1280
|
+
name: e.name,
|
|
1281
|
+
description: e.description,
|
|
1282
|
+
transport: e.transport,
|
|
1283
|
+
enabled: e.enabled
|
|
1284
|
+
};
|
|
1285
|
+
}
|
|
1286
|
+
function getCommandReference() {
|
|
1287
|
+
return [
|
|
1288
|
+
{
|
|
1289
|
+
name: "services list",
|
|
1290
|
+
description: "List all OAS services available in the current group",
|
|
1291
|
+
usage: "ucli services list [--format json|table|yaml] [--refresh]",
|
|
1292
|
+
examples: [
|
|
1293
|
+
"ucli services list",
|
|
1294
|
+
"ucli services list --format json",
|
|
1295
|
+
"ucli services list --refresh"
|
|
1296
|
+
]
|
|
1297
|
+
},
|
|
1298
|
+
{
|
|
1299
|
+
name: "services info",
|
|
1300
|
+
description: "Show detailed information and available operations for a service",
|
|
1301
|
+
usage: "ucli services info <name> [--format json|table|yaml]",
|
|
1302
|
+
examples: [
|
|
1303
|
+
"ucli services info payments",
|
|
1304
|
+
"ucli services info payments --format json"
|
|
1305
|
+
]
|
|
1306
|
+
},
|
|
1307
|
+
{
|
|
1308
|
+
name: "run",
|
|
1309
|
+
description: "Execute an operation on an OAS service",
|
|
1310
|
+
usage: "ucli run <service> <operation> [--format json|table|yaml] [--query <jmespath>] [--data <json|@file>] [--params <json>]",
|
|
1311
|
+
examples: [
|
|
1312
|
+
"ucli run payments listTransactions",
|
|
1313
|
+
"ucli run payments getTransaction --transactionId txn_123",
|
|
1314
|
+
`ucli run payments createCharge --data '{"amount": 5000, "currency": "USD"}'`,
|
|
1315
|
+
'ucli run inventory listProducts --query "items[?stock > `0`].name"'
|
|
1316
|
+
]
|
|
1317
|
+
},
|
|
1318
|
+
{
|
|
1319
|
+
name: "mcp list",
|
|
1320
|
+
description: "List all MCP servers available in the current group",
|
|
1321
|
+
usage: "ucli mcp list [--format json|table|yaml]",
|
|
1322
|
+
examples: [
|
|
1323
|
+
"ucli mcp list",
|
|
1324
|
+
"ucli mcp list --format json"
|
|
1325
|
+
]
|
|
1326
|
+
},
|
|
1327
|
+
{
|
|
1328
|
+
name: "mcp tools",
|
|
1329
|
+
description: "List tools available on a MCP server",
|
|
1330
|
+
usage: "ucli mcp tools <server> [--format json|table|yaml]",
|
|
1331
|
+
examples: [
|
|
1332
|
+
"ucli mcp tools weather",
|
|
1333
|
+
"ucli mcp tools weather --format json"
|
|
1334
|
+
]
|
|
1335
|
+
},
|
|
1336
|
+
{
|
|
1337
|
+
name: "mcp run",
|
|
1338
|
+
description: "Call a tool on a MCP server",
|
|
1339
|
+
usage: "ucli mcp run <server> <tool> [key=value ...]",
|
|
1340
|
+
examples: [
|
|
1341
|
+
'ucli mcp run weather get_forecast location="New York"',
|
|
1342
|
+
'ucli mcp run search web_search query="ucli docs" limit=5'
|
|
1343
|
+
]
|
|
1344
|
+
},
|
|
1345
|
+
{
|
|
1346
|
+
name: "introspect",
|
|
1347
|
+
description: "Return complete capability manifest (this command)",
|
|
1348
|
+
usage: "ucli introspect [--format json|yaml]",
|
|
1349
|
+
examples: [
|
|
1350
|
+
"ucli introspect",
|
|
1351
|
+
"ucli introspect --format yaml"
|
|
1352
|
+
]
|
|
1353
|
+
},
|
|
1354
|
+
{
|
|
1355
|
+
name: "refresh",
|
|
1356
|
+
description: "Force-refresh the local OAS cache from the server",
|
|
1357
|
+
usage: "ucli refresh [--service <name>]",
|
|
1358
|
+
examples: [
|
|
1359
|
+
"ucli refresh",
|
|
1360
|
+
"ucli refresh --service payments"
|
|
1361
|
+
]
|
|
1362
|
+
},
|
|
1363
|
+
{
|
|
1364
|
+
name: "doctor",
|
|
1365
|
+
description: "Check configuration, server connectivity, and token validity",
|
|
1366
|
+
usage: "ucli doctor",
|
|
1367
|
+
examples: ["ucli doctor"]
|
|
1368
|
+
},
|
|
1369
|
+
{
|
|
1370
|
+
name: "configure",
|
|
1371
|
+
description: "Configure the server URL and authentication token",
|
|
1372
|
+
usage: "ucli configure --server <url> --token <jwt>",
|
|
1373
|
+
examples: ["ucli configure --server https://oas.example.com --token eyJ..."]
|
|
1374
|
+
}
|
|
1375
|
+
];
|
|
1376
|
+
}
|
|
1377
|
+
|
|
1128
1378
|
// src/index.ts
|
|
1129
1379
|
var require3 = createRequire2(import.meta.url);
|
|
1130
1380
|
var pkg = require3("../package.json");
|
|
1131
1381
|
var program = new Command();
|
|
1132
|
-
program.name("ucli").description(pkg.description).version(pkg.version, "-v, --version").option("--debug", "Enable verbose debug logging").addHelpCommand(false).hook("preAction", (_thisCommand, actionCommand) => {
|
|
1382
|
+
program.name("ucli").description(pkg.description).version(pkg.version, "-v, --version").option("--debug", "Enable verbose debug logging").option("--output <mode>", "Output mode: text | json (json wraps every result in a structured envelope for agent consumption)", "text").addHelpCommand(false).hook("preAction", (_thisCommand, actionCommand) => {
|
|
1133
1383
|
let cmd = actionCommand;
|
|
1134
1384
|
while (cmd) {
|
|
1135
|
-
|
|
1385
|
+
const opts = cmd.opts();
|
|
1386
|
+
if (opts.debug) {
|
|
1136
1387
|
setDebugMode(true);
|
|
1137
|
-
|
|
1388
|
+
}
|
|
1389
|
+
if (opts.output && typeof opts.output === "string") {
|
|
1390
|
+
const mode = opts.output.toLowerCase();
|
|
1391
|
+
if (mode === "json" || mode === "text") {
|
|
1392
|
+
setOutputMode(mode);
|
|
1393
|
+
}
|
|
1138
1394
|
}
|
|
1139
1395
|
cmd = cmd.parent;
|
|
1140
1396
|
}
|
|
@@ -1146,6 +1402,7 @@ registerRefresh(program);
|
|
|
1146
1402
|
registerMcp(program);
|
|
1147
1403
|
registerDoctor(program);
|
|
1148
1404
|
registerCompletions(program);
|
|
1405
|
+
registerIntrospect(program);
|
|
1149
1406
|
registerHelp(program);
|
|
1150
1407
|
program.parse(process.argv);
|
|
1151
1408
|
//# sourceMappingURL=index.js.map
|