@f5xc-salesdemos/xcsh 19.4.0 → 19.5.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/package.json +7 -7
- package/src/extensibility/plugins/marketplace/manager.ts +1 -1
- package/src/internal-urls/build-info.generated.ts +8 -8
- package/src/main.ts +1 -1
- package/src/modes/components/plugin-selector.ts +1 -1
- package/src/slash-commands/builtin-registry.ts +184 -145
- package/src/slash-commands/marketplace-install-parser.ts +1 -1
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@f5xc-salesdemos/xcsh",
|
|
4
|
-
"version": "19.
|
|
4
|
+
"version": "19.5.0",
|
|
5
5
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
|
6
6
|
"homepage": "https://github.com/f5xc-salesdemos/xcsh",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -50,12 +50,12 @@
|
|
|
50
50
|
"dependencies": {
|
|
51
51
|
"@agentclientprotocol/sdk": "0.16.1",
|
|
52
52
|
"@mozilla/readability": "^0.6",
|
|
53
|
-
"@f5xc-salesdemos/xcsh-stats": "19.
|
|
54
|
-
"@f5xc-salesdemos/pi-agent-core": "19.
|
|
55
|
-
"@f5xc-salesdemos/pi-ai": "19.
|
|
56
|
-
"@f5xc-salesdemos/pi-natives": "19.
|
|
57
|
-
"@f5xc-salesdemos/pi-tui": "19.
|
|
58
|
-
"@f5xc-salesdemos/pi-utils": "19.
|
|
53
|
+
"@f5xc-salesdemos/xcsh-stats": "19.5.0",
|
|
54
|
+
"@f5xc-salesdemos/pi-agent-core": "19.5.0",
|
|
55
|
+
"@f5xc-salesdemos/pi-ai": "19.5.0",
|
|
56
|
+
"@f5xc-salesdemos/pi-natives": "19.5.0",
|
|
57
|
+
"@f5xc-salesdemos/pi-tui": "19.5.0",
|
|
58
|
+
"@f5xc-salesdemos/pi-utils": "19.5.0",
|
|
59
59
|
"@sinclair/typebox": "^0.34",
|
|
60
60
|
"@xterm/headless": "^6.0",
|
|
61
61
|
"ajv": "^8.20",
|
|
@@ -719,7 +719,7 @@ export class MarketplaceManager {
|
|
|
719
719
|
} catch (err) {
|
|
720
720
|
if (isEnoent(err)) {
|
|
721
721
|
throw new Error(
|
|
722
|
-
`Marketplace catalog not found at ${entry.catalogPath}. Try: /marketplace update ${entry.name}`,
|
|
722
|
+
`Marketplace catalog not found at ${entry.catalogPath}. Try: /plugin marketplace update ${entry.name}`,
|
|
723
723
|
);
|
|
724
724
|
}
|
|
725
725
|
throw err;
|
|
@@ -17,17 +17,17 @@ export interface BuildInfo {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export const BUILD_INFO: BuildInfo = {
|
|
20
|
-
"version": "19.
|
|
21
|
-
"commit": "
|
|
22
|
-
"shortCommit": "
|
|
20
|
+
"version": "19.5.0",
|
|
21
|
+
"commit": "1845641b31e29a09b04c301d1bcfc297a719c5f9",
|
|
22
|
+
"shortCommit": "1845641",
|
|
23
23
|
"branch": "main",
|
|
24
|
-
"tag": "v19.
|
|
25
|
-
"commitDate": "2026-06-04T16:
|
|
26
|
-
"buildDate": "2026-06-
|
|
24
|
+
"tag": "v19.5.0",
|
|
25
|
+
"commitDate": "2026-06-04T16:42:25Z",
|
|
26
|
+
"buildDate": "2026-06-04T17:10:47.523Z",
|
|
27
27
|
"dirty": true,
|
|
28
28
|
"prNumber": "",
|
|
29
29
|
"repoUrl": "https://github.com/f5xc-salesdemos/xcsh",
|
|
30
30
|
"repoSlug": "f5xc-salesdemos/xcsh",
|
|
31
|
-
"commitUrl": "https://github.com/f5xc-salesdemos/xcsh/commit/
|
|
32
|
-
"releaseUrl": "https://github.com/f5xc-salesdemos/xcsh/releases/tag/v19.
|
|
31
|
+
"commitUrl": "https://github.com/f5xc-salesdemos/xcsh/commit/1845641b31e29a09b04c301d1bcfc297a719c5f9",
|
|
32
|
+
"releaseUrl": "https://github.com/f5xc-salesdemos/xcsh/releases/tag/v19.5.0"
|
|
33
33
|
};
|
package/src/main.ts
CHANGED
|
@@ -749,7 +749,7 @@ export async function runRootCommand(parsed: Args, rawArgs: string[]): Promise<v
|
|
|
749
749
|
await mgr.upgradeAllPlugins();
|
|
750
750
|
logger.debug(`Auto-upgraded ${updates.length} marketplace plugin(s)`);
|
|
751
751
|
} else {
|
|
752
|
-
logger.debug(`${updates.length} marketplace plugin update(s) available \u2014 /
|
|
752
|
+
logger.debug(`${updates.length} marketplace plugin update(s) available \u2014 /plugin upgrade`);
|
|
753
753
|
}
|
|
754
754
|
} catch {
|
|
755
755
|
// Silently ignore — network failure, corrupt data, offline.
|
|
@@ -54,7 +54,7 @@ export class PluginSelectorComponent extends Container {
|
|
|
54
54
|
label: "No plugins available",
|
|
55
55
|
description:
|
|
56
56
|
marketplaceCount === 0
|
|
57
|
-
? "Add a marketplace first: /marketplace add <source>"
|
|
57
|
+
? "Add a marketplace first: /plugin marketplace add <source>"
|
|
58
58
|
: "Configured marketplaces have no plugins",
|
|
59
59
|
});
|
|
60
60
|
}
|
|
@@ -858,37 +858,60 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<BuiltinSlashCommandSpec> = [
|
|
|
858
858
|
handle: shutdownHandler,
|
|
859
859
|
},
|
|
860
860
|
{
|
|
861
|
-
name: "
|
|
862
|
-
|
|
861
|
+
name: "plugin",
|
|
862
|
+
aliases: ["marketplace", "plugins"],
|
|
863
|
+
description: "Manage plugins and marketplace sources",
|
|
863
864
|
subcommands: [
|
|
864
|
-
{ name: "
|
|
865
|
-
{ name: "remove", description: "Remove a marketplace source", usage: "<name>" },
|
|
866
|
-
{ name: "update", description: "Update marketplace catalog(s)", usage: "[name]" },
|
|
867
|
-
{ name: "list", description: "List configured marketplaces" },
|
|
868
|
-
{ name: "discover", description: "Browse available plugins", usage: "[marketplace]" },
|
|
865
|
+
{ name: "marketplace", description: "Manage marketplace sources (add, remove, update, list)" },
|
|
869
866
|
{
|
|
870
867
|
name: "install",
|
|
871
|
-
description: "Install a plugin
|
|
872
|
-
usage: "[--force] [name@marketplace
|
|
868
|
+
description: "Install a plugin",
|
|
869
|
+
usage: "[--force] [--scope user|project] <name@marketplace>",
|
|
873
870
|
},
|
|
874
|
-
{ name: "uninstall", description: "Uninstall a plugin
|
|
875
|
-
{ name: "
|
|
876
|
-
{ name: "
|
|
871
|
+
{ name: "uninstall", description: "Uninstall a plugin", usage: "[--scope user|project] <name@marketplace>" },
|
|
872
|
+
{ name: "enable", description: "Enable a plugin", usage: "[--scope user|project] <name@marketplace>" },
|
|
873
|
+
{ name: "disable", description: "Disable a plugin", usage: "[--scope user|project] <name@marketplace>" },
|
|
874
|
+
{ name: "upgrade", description: "Upgrade plugins", usage: "[--scope user|project] [name@marketplace]" },
|
|
875
|
+
{ name: "discover", description: "Browse available plugins", usage: "[marketplace]" },
|
|
876
|
+
{ name: "list", description: "List all installed plugins" },
|
|
877
|
+
{ name: "validate", description: "Validate marketplace or plugin manifest", usage: "[path]" },
|
|
877
878
|
{ name: "help", description: "Show usage guide" },
|
|
878
879
|
],
|
|
879
880
|
allowArgs: true,
|
|
880
881
|
handle: async (command, runtime) => {
|
|
881
882
|
runtime.ctx.editor.setText("");
|
|
882
883
|
const args = command.args.trim().split(/\s+/);
|
|
883
|
-
const sub = args[0] || "
|
|
884
|
+
const sub = args[0] || "";
|
|
884
885
|
const rest = args.slice(1).join(" ").trim();
|
|
885
886
|
|
|
886
|
-
// /
|
|
887
|
-
if (
|
|
887
|
+
// /plugin (no args) → open interactive dashboard
|
|
888
|
+
if (!sub) {
|
|
889
|
+
runtime.ctx.showPluginDashboard();
|
|
890
|
+
return;
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
// /plugin install (no args) → interactive browser
|
|
894
|
+
if (sub === "install" && !rest) {
|
|
888
895
|
try {
|
|
889
896
|
runtime.ctx.showPluginSelector("install");
|
|
890
897
|
} catch (err) {
|
|
891
|
-
runtime.ctx.showStatus(`
|
|
898
|
+
runtime.ctx.showStatus(`Plugin error: ${err}`);
|
|
899
|
+
}
|
|
900
|
+
return;
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
// /plugin list (no args) → open interactive dashboard
|
|
904
|
+
if (sub === "list" && !rest) {
|
|
905
|
+
runtime.ctx.showPluginDashboard();
|
|
906
|
+
return;
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
// /plugin uninstall (no args) → interactive uninstall selector
|
|
910
|
+
if (sub === "uninstall" && !rest) {
|
|
911
|
+
try {
|
|
912
|
+
runtime.ctx.showPluginSelector("uninstall");
|
|
913
|
+
} catch (err) {
|
|
914
|
+
runtime.ctx.showStatus(`Plugin error: ${err}`);
|
|
892
915
|
}
|
|
893
916
|
return;
|
|
894
917
|
}
|
|
@@ -911,9 +934,63 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<BuiltinSlashCommandSpec> = [
|
|
|
911
934
|
|
|
912
935
|
try {
|
|
913
936
|
switch (sub) {
|
|
937
|
+
// ── Marketplace management (/plugin marketplace add|remove|update|list) ──
|
|
938
|
+
case "marketplace": {
|
|
939
|
+
const mktArgs = rest.split(/\s+/);
|
|
940
|
+
const mktSub = mktArgs[0] || "";
|
|
941
|
+
const mktRest = mktArgs.slice(1).join(" ").trim();
|
|
942
|
+
switch (mktSub) {
|
|
943
|
+
case "add": {
|
|
944
|
+
if (!mktRest) {
|
|
945
|
+
runtime.ctx.showStatus("Usage: /plugin marketplace add <source>");
|
|
946
|
+
return;
|
|
947
|
+
}
|
|
948
|
+
const entry = await mgr.addMarketplace(mktRest);
|
|
949
|
+
runtime.ctx.showStatus(`Added marketplace: ${entry.name}`);
|
|
950
|
+
break;
|
|
951
|
+
}
|
|
952
|
+
case "remove":
|
|
953
|
+
case "rm": {
|
|
954
|
+
if (!mktRest) {
|
|
955
|
+
runtime.ctx.showStatus("Usage: /plugin marketplace remove <name>");
|
|
956
|
+
return;
|
|
957
|
+
}
|
|
958
|
+
await mgr.removeMarketplace(mktRest);
|
|
959
|
+
runtime.ctx.showStatus(`Removed marketplace: ${mktRest}`);
|
|
960
|
+
break;
|
|
961
|
+
}
|
|
962
|
+
case "update": {
|
|
963
|
+
if (mktRest) {
|
|
964
|
+
await mgr.updateMarketplace(mktRest);
|
|
965
|
+
runtime.ctx.showStatus(`Updated marketplace: ${mktRest}`);
|
|
966
|
+
} else {
|
|
967
|
+
const results = await mgr.updateAllMarketplaces();
|
|
968
|
+
runtime.ctx.showStatus(`Updated ${results.length} marketplace(s)`);
|
|
969
|
+
}
|
|
970
|
+
break;
|
|
971
|
+
}
|
|
972
|
+
case "list":
|
|
973
|
+
default: {
|
|
974
|
+
const marketplaces = await mgr.listMarketplaces();
|
|
975
|
+
if (marketplaces.length === 0) {
|
|
976
|
+
runtime.ctx.showStatus(
|
|
977
|
+
"No marketplaces configured.\n\nGet started:\n /plugin marketplace add f5xc-salesdemos/marketplace",
|
|
978
|
+
);
|
|
979
|
+
} else {
|
|
980
|
+
const lines = marketplaces.map(m => ` ${m.name} ${m.sourceUri}`);
|
|
981
|
+
runtime.ctx.showStatus(
|
|
982
|
+
`Marketplaces:\n${lines.join("\n")}\n\nUse /plugin discover to browse plugins`,
|
|
983
|
+
);
|
|
984
|
+
}
|
|
985
|
+
break;
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
break;
|
|
989
|
+
}
|
|
990
|
+
// ── Legacy shorthand: /marketplace add|remove|update → /plugin marketplace ──
|
|
914
991
|
case "add": {
|
|
915
992
|
if (!rest) {
|
|
916
|
-
runtime.ctx.showStatus("Usage: /marketplace add <source>");
|
|
993
|
+
runtime.ctx.showStatus("Usage: /plugin marketplace add <source>");
|
|
917
994
|
return;
|
|
918
995
|
}
|
|
919
996
|
const entry = await mgr.addMarketplace(rest);
|
|
@@ -923,7 +1000,7 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<BuiltinSlashCommandSpec> = [
|
|
|
923
1000
|
case "remove":
|
|
924
1001
|
case "rm": {
|
|
925
1002
|
if (!rest) {
|
|
926
|
-
runtime.ctx.showStatus("Usage: /marketplace remove <name>");
|
|
1003
|
+
runtime.ctx.showStatus("Usage: /plugin marketplace remove <name>");
|
|
927
1004
|
return;
|
|
928
1005
|
}
|
|
929
1006
|
await mgr.removeMarketplace(rest);
|
|
@@ -940,13 +1017,14 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<BuiltinSlashCommandSpec> = [
|
|
|
940
1017
|
}
|
|
941
1018
|
break;
|
|
942
1019
|
}
|
|
1020
|
+
// ── Plugin discovery ──
|
|
943
1021
|
case "discover": {
|
|
944
1022
|
const plugins = await mgr.listAvailablePlugins(rest || undefined);
|
|
945
1023
|
if (plugins.length === 0) {
|
|
946
1024
|
const marketplaces = await mgr.listMarketplaces();
|
|
947
1025
|
if (marketplaces.length === 0) {
|
|
948
1026
|
runtime.ctx.showStatus(
|
|
949
|
-
"No marketplaces configured. Try:\n /marketplace add f5xc-salesdemos/marketplace",
|
|
1027
|
+
"No marketplaces configured. Try:\n /plugin marketplace add f5xc-salesdemos/marketplace",
|
|
950
1028
|
);
|
|
951
1029
|
} else {
|
|
952
1030
|
runtime.ctx.showStatus("No plugins available in configured marketplaces");
|
|
@@ -960,8 +1038,8 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<BuiltinSlashCommandSpec> = [
|
|
|
960
1038
|
}
|
|
961
1039
|
break;
|
|
962
1040
|
}
|
|
1041
|
+
// ── Install ──
|
|
963
1042
|
case "install": {
|
|
964
|
-
// Parse: /marketplace install [--force] [--scope user|project] name@marketplace
|
|
965
1043
|
const parsed = parseMarketplaceInstallArgs(rest);
|
|
966
1044
|
if ("error" in parsed) {
|
|
967
1045
|
runtime.ctx.showStatus(parsed.error);
|
|
@@ -974,15 +1052,11 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<BuiltinSlashCommandSpec> = [
|
|
|
974
1052
|
runtime.ctx.showStatus(`Installed ${name} from ${marketplace}`);
|
|
975
1053
|
break;
|
|
976
1054
|
}
|
|
1055
|
+
// ── Uninstall ──
|
|
977
1056
|
case "uninstall": {
|
|
978
|
-
if (!rest) {
|
|
979
|
-
// No args → open interactive uninstall selector
|
|
980
|
-
runtime.ctx.showPluginSelector("uninstall");
|
|
981
|
-
return;
|
|
982
|
-
}
|
|
983
1057
|
const uninstArgs = parsePluginScopeArgs(
|
|
984
1058
|
rest,
|
|
985
|
-
"Usage: /
|
|
1059
|
+
"Usage: /plugin uninstall [--scope user|project] <name@marketplace>",
|
|
986
1060
|
);
|
|
987
1061
|
if ("error" in uninstArgs) {
|
|
988
1062
|
runtime.ctx.showStatus(uninstArgs.error);
|
|
@@ -992,23 +1066,28 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<BuiltinSlashCommandSpec> = [
|
|
|
992
1066
|
runtime.ctx.showStatus(`Uninstalled ${uninstArgs.pluginId}`);
|
|
993
1067
|
break;
|
|
994
1068
|
}
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
runtime.ctx.showStatus(
|
|
1069
|
+
// ── Enable / Disable ──
|
|
1070
|
+
case "enable":
|
|
1071
|
+
case "disable": {
|
|
1072
|
+
const parsed = parsePluginScopeArgs(
|
|
1073
|
+
rest ?? "",
|
|
1074
|
+
`Usage: /plugin ${sub} [--scope user|project] <name@marketplace>`,
|
|
1075
|
+
);
|
|
1076
|
+
if ("error" in parsed) {
|
|
1077
|
+
runtime.ctx.showStatus(parsed.error);
|
|
1078
|
+
return;
|
|
1004
1079
|
}
|
|
1080
|
+
const isEnable = sub === "enable";
|
|
1081
|
+
await mgr.setPluginEnabled(parsed.pluginId, isEnable, parsed.scope);
|
|
1082
|
+
runtime.ctx.showStatus(`${isEnable ? "Enabled" : "Disabled"} ${parsed.pluginId}`);
|
|
1005
1083
|
break;
|
|
1006
1084
|
}
|
|
1085
|
+
// ── Upgrade ──
|
|
1007
1086
|
case "upgrade": {
|
|
1008
1087
|
if (rest) {
|
|
1009
1088
|
const upArgs = parsePluginScopeArgs(
|
|
1010
1089
|
rest,
|
|
1011
|
-
"Usage: /
|
|
1090
|
+
"Usage: /plugin upgrade [--scope user|project] <name@marketplace>",
|
|
1012
1091
|
);
|
|
1013
1092
|
if ("error" in upArgs) {
|
|
1014
1093
|
runtime.ctx.showStatus(upArgs.error);
|
|
@@ -1019,7 +1098,7 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<BuiltinSlashCommandSpec> = [
|
|
|
1019
1098
|
} else {
|
|
1020
1099
|
const results = await mgr.upgradeAllPlugins();
|
|
1021
1100
|
if (results.length === 0) {
|
|
1022
|
-
runtime.ctx.showStatus("All
|
|
1101
|
+
runtime.ctx.showStatus("All plugins are up to date");
|
|
1023
1102
|
} else {
|
|
1024
1103
|
const lines = results.map(r => ` ${r.pluginId}: ${r.from} -> ${r.to}`);
|
|
1025
1104
|
runtime.ctx.showStatus(`Upgraded ${results.length} plugin(s):\n${lines.join("\n")}`);
|
|
@@ -1027,106 +1106,9 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<BuiltinSlashCommandSpec> = [
|
|
|
1027
1106
|
}
|
|
1028
1107
|
break;
|
|
1029
1108
|
}
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
[
|
|
1033
|
-
"Marketplace commands:",
|
|
1034
|
-
" /marketplace Browse and install plugins",
|
|
1035
|
-
" /marketplace add <source> Add a marketplace (e.g. owner/repo)",
|
|
1036
|
-
" /marketplace remove <name> Remove a marketplace",
|
|
1037
|
-
" /marketplace update [name] Re-fetch catalog(s)",
|
|
1038
|
-
" /marketplace list List configured marketplaces",
|
|
1039
|
-
" /marketplace discover [marketplace] Browse available plugins",
|
|
1040
|
-
" /marketplace install <name@marketplace> Install a plugin",
|
|
1041
|
-
" /marketplace uninstall <name@marketplace> Uninstall a plugin",
|
|
1042
|
-
" /marketplace installed List installed plugins",
|
|
1043
|
-
" /marketplace upgrade [name@marketplace] Upgrade plugin(s)",
|
|
1044
|
-
"",
|
|
1045
|
-
"Quick start:",
|
|
1046
|
-
" /marketplace add f5xc-salesdemos/marketplace",
|
|
1047
|
-
" /marketplace (opens interactive browser)",
|
|
1048
|
-
].join("\n"),
|
|
1049
|
-
);
|
|
1050
|
-
break;
|
|
1051
|
-
}
|
|
1052
|
-
default: {
|
|
1053
|
-
const marketplaces = await mgr.listMarketplaces();
|
|
1054
|
-
if (marketplaces.length === 0) {
|
|
1055
|
-
runtime.ctx.showStatus(
|
|
1056
|
-
"No marketplaces configured.\n\nGet started:\n /marketplace add f5xc-salesdemos/marketplace\n\nThen browse plugins with /marketplace or /marketplace discover",
|
|
1057
|
-
);
|
|
1058
|
-
} else {
|
|
1059
|
-
const lines = marketplaces.map(m => ` ${m.name} ${m.sourceUri}`);
|
|
1060
|
-
runtime.ctx.showStatus(
|
|
1061
|
-
`Marketplaces:\n${lines.join("\n")}\n\nUse /marketplace discover to browse plugins, or /marketplace help for all commands`,
|
|
1062
|
-
);
|
|
1063
|
-
}
|
|
1064
|
-
break;
|
|
1065
|
-
}
|
|
1066
|
-
}
|
|
1067
|
-
} catch (err) {
|
|
1068
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
1069
|
-
runtime.ctx.showStatus(`Marketplace error: ${msg}`);
|
|
1070
|
-
}
|
|
1071
|
-
},
|
|
1072
|
-
},
|
|
1073
|
-
{
|
|
1074
|
-
name: "plugins",
|
|
1075
|
-
description: "View and manage installed plugins",
|
|
1076
|
-
subcommands: [
|
|
1077
|
-
{ name: "list", description: "List all installed plugins (npm + marketplace)" },
|
|
1078
|
-
{ name: "enable", description: "Enable a marketplace plugin", usage: "<name@marketplace>" },
|
|
1079
|
-
{ name: "disable", description: "Disable a marketplace plugin", usage: "<name@marketplace>" },
|
|
1080
|
-
],
|
|
1081
|
-
allowArgs: true,
|
|
1082
|
-
handle: async (command, runtime) => {
|
|
1083
|
-
runtime.ctx.editor.setText("");
|
|
1084
|
-
const args = command.args.trim().split(/\s+/);
|
|
1085
|
-
const sub = args[0] || "";
|
|
1086
|
-
const rest = args.slice(1).join(" ").trim();
|
|
1087
|
-
|
|
1088
|
-
// No args or bare "list" with no further args → open interactive dashboard
|
|
1089
|
-
if (!sub || (sub === "list" && !rest)) {
|
|
1090
|
-
runtime.ctx.showPluginDashboard();
|
|
1091
|
-
return;
|
|
1092
|
-
}
|
|
1093
|
-
|
|
1094
|
-
try {
|
|
1095
|
-
const mgr = new MarketplaceManager({
|
|
1096
|
-
marketplacesRegistryPath: getMarketplacesRegistryPath(),
|
|
1097
|
-
installedRegistryPath: getInstalledPluginsRegistryPath(),
|
|
1098
|
-
projectInstalledRegistryPath: await resolveOrDefaultProjectRegistryPath(
|
|
1099
|
-
runtime.ctx.sessionManager.getCwd(),
|
|
1100
|
-
),
|
|
1101
|
-
marketplacesCacheDir: getMarketplacesCacheDir(),
|
|
1102
|
-
pluginsCacheDir: getPluginsCacheDir(),
|
|
1103
|
-
clearPluginRootsCache: (extraPaths?: readonly string[]) => {
|
|
1104
|
-
const home = os.homedir();
|
|
1105
|
-
invalidateFsCache(path.join(home, getConfigDirName(), "plugins", "installed_plugins.json"));
|
|
1106
|
-
for (const p of extraPaths ?? []) invalidateFsCache(p);
|
|
1107
|
-
clearXcshPluginRootsCache();
|
|
1108
|
-
},
|
|
1109
|
-
});
|
|
1110
|
-
|
|
1111
|
-
switch (sub) {
|
|
1112
|
-
case "enable":
|
|
1113
|
-
case "disable": {
|
|
1114
|
-
const parsed = parsePluginScopeArgs(
|
|
1115
|
-
rest ?? "",
|
|
1116
|
-
`Usage: /plugins ${sub} [--scope user|project] <name@marketplace>`,
|
|
1117
|
-
);
|
|
1118
|
-
if ("error" in parsed) {
|
|
1119
|
-
runtime.ctx.showStatus(parsed.error);
|
|
1120
|
-
return;
|
|
1121
|
-
}
|
|
1122
|
-
const isEnable = sub === "enable";
|
|
1123
|
-
await mgr.setPluginEnabled(parsed.pluginId, isEnable, parsed.scope);
|
|
1124
|
-
runtime.ctx.showStatus(`${isEnable ? "Enabled" : "Disabled"} ${parsed.pluginId}`);
|
|
1125
|
-
break;
|
|
1126
|
-
}
|
|
1127
|
-
case "list": {
|
|
1109
|
+
// ── Installed list ──
|
|
1110
|
+
case "installed": {
|
|
1128
1111
|
const lines: string[] = [];
|
|
1129
|
-
|
|
1130
1112
|
const npm = new PluginManager();
|
|
1131
1113
|
const npmPlugins = await npm.list();
|
|
1132
1114
|
if (npmPlugins.length > 0) {
|
|
@@ -1136,7 +1118,6 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<BuiltinSlashCommandSpec> = [
|
|
|
1136
1118
|
lines.push(` ${p.name}@${p.version}${status}`);
|
|
1137
1119
|
}
|
|
1138
1120
|
}
|
|
1139
|
-
|
|
1140
1121
|
const mktPlugins = await mgr.listInstalledPlugins();
|
|
1141
1122
|
if (mktPlugins.length > 0) {
|
|
1142
1123
|
if (lines.length > 0) lines.push("");
|
|
@@ -1148,7 +1129,6 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<BuiltinSlashCommandSpec> = [
|
|
|
1148
1129
|
lines.push(` ${p.id} v${entry?.version ?? "?"}${status} [${p.scope}]${shadowed}`);
|
|
1149
1130
|
}
|
|
1150
1131
|
}
|
|
1151
|
-
|
|
1152
1132
|
if (lines.length === 0) {
|
|
1153
1133
|
runtime.ctx.showStatus("No plugins installed");
|
|
1154
1134
|
} else {
|
|
@@ -1156,19 +1136,78 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<BuiltinSlashCommandSpec> = [
|
|
|
1156
1136
|
}
|
|
1157
1137
|
break;
|
|
1158
1138
|
}
|
|
1159
|
-
|
|
1139
|
+
// ── Validate ──
|
|
1140
|
+
case "validate": {
|
|
1141
|
+
const targetPath = rest
|
|
1142
|
+
? path.resolve(runtime.ctx.sessionManager.getCwd(), rest)
|
|
1143
|
+
: runtime.ctx.sessionManager.getCwd();
|
|
1144
|
+
const catalogPath = path.join(targetPath, ".xcsh-plugin", "marketplace.json");
|
|
1145
|
+
const pluginPath = path.join(targetPath, ".xcsh-plugin", "plugin.json");
|
|
1146
|
+
const { existsSync } = await import("node:fs");
|
|
1147
|
+
if (existsSync(catalogPath)) {
|
|
1148
|
+
const { parseMarketplaceCatalog } = await import("../extensibility/plugins/marketplace/fetcher");
|
|
1149
|
+
const content = await Bun.file(catalogPath).text();
|
|
1150
|
+
const catalog = parseMarketplaceCatalog(content, catalogPath);
|
|
1151
|
+
runtime.ctx.showStatus(
|
|
1152
|
+
`Marketplace "${catalog.name}" is valid (${catalog.plugins.length} plugin(s))`,
|
|
1153
|
+
);
|
|
1154
|
+
} else if (existsSync(pluginPath)) {
|
|
1155
|
+
const content = await Bun.file(pluginPath).text();
|
|
1156
|
+
const manifest = JSON.parse(content);
|
|
1157
|
+
runtime.ctx.showStatus(`Plugin "${manifest.name ?? path.basename(targetPath)}" manifest is valid`);
|
|
1158
|
+
} else {
|
|
1159
|
+
runtime.ctx.showStatus(
|
|
1160
|
+
`No .xcsh-plugin/marketplace.json or .xcsh-plugin/plugin.json found at ${targetPath}`,
|
|
1161
|
+
);
|
|
1162
|
+
}
|
|
1163
|
+
break;
|
|
1164
|
+
}
|
|
1165
|
+
// ── Help ──
|
|
1166
|
+
case "help": {
|
|
1160
1167
|
runtime.ctx.showStatus(
|
|
1161
|
-
|
|
1162
|
-
"
|
|
1163
|
-
" /
|
|
1164
|
-
" /
|
|
1165
|
-
" /
|
|
1168
|
+
[
|
|
1169
|
+
"Plugin commands:",
|
|
1170
|
+
" /plugin Open plugin dashboard",
|
|
1171
|
+
" /plugin marketplace add <source> Add a marketplace (e.g. owner/repo)",
|
|
1172
|
+
" /plugin marketplace remove <name> Remove a marketplace",
|
|
1173
|
+
" /plugin marketplace update [name] Re-fetch catalog(s)",
|
|
1174
|
+
" /plugin marketplace list List configured marketplaces",
|
|
1175
|
+
" /plugin discover [marketplace] Browse available plugins",
|
|
1176
|
+
" /plugin install <name@marketplace> Install a plugin",
|
|
1177
|
+
" /plugin uninstall <name@marketplace> Uninstall a plugin",
|
|
1178
|
+
" /plugin enable <name@marketplace> Enable a plugin",
|
|
1179
|
+
" /plugin disable <name@marketplace> Disable a plugin",
|
|
1180
|
+
" /plugin upgrade [name@marketplace] Upgrade plugin(s)",
|
|
1181
|
+
" /plugin list List installed plugins",
|
|
1182
|
+
" /plugin validate [path] Validate marketplace or plugin",
|
|
1183
|
+
"",
|
|
1184
|
+
"Quick start:",
|
|
1185
|
+
" /plugin marketplace add f5xc-salesdemos/marketplace",
|
|
1186
|
+
" /plugin (opens plugin dashboard)",
|
|
1187
|
+
"",
|
|
1188
|
+
"Aliases: /marketplace, /plugins",
|
|
1189
|
+
].join("\n"),
|
|
1166
1190
|
);
|
|
1167
1191
|
break;
|
|
1168
1192
|
}
|
|
1193
|
+
default: {
|
|
1194
|
+
const marketplaces = await mgr.listMarketplaces();
|
|
1195
|
+
if (marketplaces.length === 0) {
|
|
1196
|
+
runtime.ctx.showStatus(
|
|
1197
|
+
"No marketplaces configured.\n\nGet started:\n /plugin marketplace add f5xc-salesdemos/marketplace\n\nThen browse plugins with /plugin or /plugin discover",
|
|
1198
|
+
);
|
|
1199
|
+
} else {
|
|
1200
|
+
const lines = marketplaces.map(m => ` ${m.name} ${m.sourceUri}`);
|
|
1201
|
+
runtime.ctx.showStatus(
|
|
1202
|
+
`Marketplaces:\n${lines.join("\n")}\n\nUse /plugin discover to browse plugins, or /plugin help for all commands`,
|
|
1203
|
+
);
|
|
1204
|
+
}
|
|
1205
|
+
break;
|
|
1206
|
+
}
|
|
1169
1207
|
}
|
|
1170
1208
|
} catch (err) {
|
|
1171
|
-
|
|
1209
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1210
|
+
runtime.ctx.showStatus(`Plugin error: ${msg}`);
|
|
1172
1211
|
}
|
|
1173
1212
|
},
|
|
1174
1213
|
},
|