@f5xc-salesdemos/xcsh 19.6.0 → 19.8.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@f5xc-salesdemos/xcsh",
4
- "version": "19.6.0",
4
+ "version": "19.8.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.6.0",
54
- "@f5xc-salesdemos/pi-agent-core": "19.6.0",
55
- "@f5xc-salesdemos/pi-ai": "19.6.0",
56
- "@f5xc-salesdemos/pi-natives": "19.6.0",
57
- "@f5xc-salesdemos/pi-tui": "19.6.0",
58
- "@f5xc-salesdemos/pi-utils": "19.6.0",
53
+ "@f5xc-salesdemos/xcsh-stats": "19.8.0",
54
+ "@f5xc-salesdemos/pi-agent-core": "19.8.0",
55
+ "@f5xc-salesdemos/pi-ai": "19.8.0",
56
+ "@f5xc-salesdemos/pi-natives": "19.8.0",
57
+ "@f5xc-salesdemos/pi-tui": "19.8.0",
58
+ "@f5xc-salesdemos/pi-utils": "19.8.0",
59
59
  "@sinclair/typebox": "^0.34",
60
60
  "@xterm/headless": "^6.0",
61
61
  "ajv": "^8.20",
@@ -0,0 +1,50 @@
1
+ import type { MarketplacePluginEntry } from "./types";
2
+
3
+ const cache = new Map<string, boolean>();
4
+
5
+ export async function checkPrerequisite(detectCmd: string): Promise<boolean> {
6
+ const cached = cache.get(detectCmd);
7
+ if (cached !== undefined) return cached;
8
+
9
+ try {
10
+ const [cmd, ...args] = detectCmd.split(/\s+/);
11
+ const proc = Bun.spawn([cmd!, ...args], {
12
+ stdout: "ignore",
13
+ stderr: "ignore",
14
+ });
15
+ const exitCode = await proc.exited;
16
+ const available = exitCode === 0;
17
+ cache.set(detectCmd, available);
18
+ return available;
19
+ } catch {
20
+ cache.set(detectCmd, false);
21
+ return false;
22
+ }
23
+ }
24
+
25
+ export async function checkAllPrerequisites(
26
+ plugins: MarketplacePluginEntry[],
27
+ ): Promise<Map<string, { available: boolean; missing: string[] }>> {
28
+ const results = new Map<string, { available: boolean; missing: string[] }>();
29
+
30
+ for (const plugin of plugins) {
31
+ if (!plugin.prerequisites || plugin.prerequisites.length === 0) {
32
+ results.set(plugin.name, { available: true, missing: [] });
33
+ continue;
34
+ }
35
+
36
+ const missing: string[] = [];
37
+ for (const prereq of plugin.prerequisites) {
38
+ const ok = await checkPrerequisite(prereq.detectCmd);
39
+ if (!ok) missing.push(prereq.tool);
40
+ }
41
+
42
+ results.set(plugin.name, { available: missing.length === 0, missing });
43
+ }
44
+
45
+ return results;
46
+ }
47
+
48
+ export function clearPrerequisiteCache(): void {
49
+ cache.clear();
50
+ }
@@ -89,6 +89,8 @@ export interface MarketplacePluginEntry {
89
89
  tags?: string[];
90
90
  strict?: boolean;
91
91
  defaultEnabled?: boolean;
92
+ recommended?: boolean;
93
+ prerequisites?: Array<{ tool: string; installCmd: string; detectCmd: string }>;
92
94
  commands?: string | string[];
93
95
  agents?: string | string[];
94
96
  hooks?: string | Record<string, unknown>;
@@ -17,17 +17,17 @@ export interface BuildInfo {
17
17
  }
18
18
 
19
19
  export const BUILD_INFO: BuildInfo = {
20
- "version": "19.6.0",
21
- "commit": "8505c9827499b1e269615db372fec4132b61c506",
22
- "shortCommit": "8505c98",
20
+ "version": "19.8.0",
21
+ "commit": "ea6c3e825dbbdf4e3e471bbe3a22dc503e00f30e",
22
+ "shortCommit": "ea6c3e8",
23
23
  "branch": "main",
24
- "tag": "v19.6.0",
25
- "commitDate": "2026-06-04T18:26:24Z",
26
- "buildDate": "2026-06-04T18:51:12.169Z",
24
+ "tag": "v19.8.0",
25
+ "commitDate": "2026-06-05T00:33:42Z",
26
+ "buildDate": "2026-06-05T00:57:39.846Z",
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/8505c9827499b1e269615db372fec4132b61c506",
32
- "releaseUrl": "https://github.com/f5xc-salesdemos/xcsh/releases/tag/v19.6.0"
31
+ "commitUrl": "https://github.com/f5xc-salesdemos/xcsh/commit/ea6c3e825dbbdf4e3e471bbe3a22dc503e00f30e",
32
+ "releaseUrl": "https://github.com/f5xc-salesdemos/xcsh/releases/tag/v19.8.0"
33
33
  };
@@ -62,6 +62,8 @@ function catalogToDashboard(entry: MarketplacePluginEntry, marketplace: string):
62
62
  installed: false,
63
63
  enabled: false,
64
64
  hasUpdate: false,
65
+ recommended: entry.recommended,
66
+ prerequisites: entry.prerequisites,
65
67
  };
66
68
  }
67
69
 
@@ -98,6 +100,8 @@ export async function loadAllPlugins(mgr: MarketplaceManager, npmMgr: PluginMana
98
100
  const existing = plugins.find(p => p.id === pluginId);
99
101
  if (existing) {
100
102
  existing.displayName = existing.displayName || entry.displayName;
103
+ existing.recommended = existing.recommended || entry.recommended;
104
+ existing.prerequisites = existing.prerequisites || entry.prerequisites;
101
105
  existing.description = existing.description || entry.description;
102
106
  existing.category = existing.category || entry.category;
103
107
  existing.tags = existing.tags || entry.tags;
@@ -126,10 +130,14 @@ export async function loadAllPlugins(mgr: MarketplaceManager, npmMgr: PluginMana
126
130
  export function buildTabs(plugins: DashboardPlugin[]): PluginTab[] {
127
131
  const tabs: PluginTab[] = [];
128
132
  const installedCount = plugins.filter(p => p.installed).length;
133
+ const recommendedCount = plugins.filter(p => !p.installed && p.recommended).length;
129
134
  const discoverCount = plugins.filter(p => !p.installed).length;
130
135
  const updatesCount = plugins.filter(p => p.hasUpdate).length;
131
136
 
132
137
  tabs.push({ id: "installed", label: "Installed", count: installedCount });
138
+ if (recommendedCount > 0) {
139
+ tabs.push({ id: "recommended", label: "Recommended", count: recommendedCount });
140
+ }
133
141
  if (discoverCount > 0) {
134
142
  tabs.push({ id: "discover", label: "Discover", count: discoverCount });
135
143
  }
@@ -143,6 +151,8 @@ export function filterByTab(plugins: DashboardPlugin[], tabId: PluginTabId): Das
143
151
  switch (tabId) {
144
152
  case "installed":
145
153
  return plugins.filter(p => p.installed);
154
+ case "recommended":
155
+ return plugins.filter(p => !p.installed && p.recommended);
146
156
  case "discover":
147
157
  return plugins.filter(p => !p.installed);
148
158
  case "updates":
@@ -18,9 +18,11 @@ export interface DashboardPlugin {
18
18
  shadowedBy?: "project";
19
19
  hasUpdate: boolean;
20
20
  updateVersion?: string;
21
+ recommended?: boolean;
22
+ prerequisites?: Array<{ tool: string; installCmd: string; detectCmd: string }>;
21
23
  }
22
24
 
23
- export type PluginTabId = "installed" | "discover" | "updates";
25
+ export type PluginTabId = "installed" | "recommended" | "discover" | "updates";
24
26
 
25
27
  export interface PluginTab {
26
28
  id: PluginTabId;
@@ -875,6 +875,7 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<BuiltinSlashCommandSpec> = [
875
875
  { name: "discover", description: "Browse available plugins", usage: "[marketplace]" },
876
876
  { name: "list", description: "List all installed plugins" },
877
877
  { name: "validate", description: "Validate marketplace or plugin manifest", usage: "[path]" },
878
+ { name: "setup", description: "Guided setup for recommended plugins" },
878
879
  { name: "help", description: "Show usage guide" },
879
880
  ],
880
881
  allowArgs: true,
@@ -969,7 +970,6 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<BuiltinSlashCommandSpec> = [
969
970
  }
970
971
  break;
971
972
  }
972
- case "list":
973
973
  default: {
974
974
  const marketplaces = await mgr.listMarketplaces();
975
975
  if (marketplaces.length === 0) {
@@ -1162,6 +1162,80 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<BuiltinSlashCommandSpec> = [
1162
1162
  }
1163
1163
  break;
1164
1164
  }
1165
+ // ── Setup (guided recommended plugin install) ──
1166
+ case "setup": {
1167
+ const { checkPrerequisite } = await import("../extensibility/plugins/marketplace/prerequisites");
1168
+ const allPlugins = await mgr.listAvailablePlugins();
1169
+ const recommended = allPlugins.filter(p => p.recommended);
1170
+ if (recommended.length === 0) {
1171
+ runtime.ctx.showStatus("No recommended plugins found in configured marketplaces");
1172
+ break;
1173
+ }
1174
+
1175
+ const installed = await mgr.listInstalledPlugins();
1176
+ const installedIds = new Set(installed.map(p => p.id));
1177
+ const toInstall = recommended.filter(
1178
+ p => !Array.from(installedIds).some(id => id.startsWith(`${p.name}@`)),
1179
+ );
1180
+
1181
+ if (toInstall.length === 0) {
1182
+ runtime.ctx.showStatus("All recommended plugins are already installed");
1183
+ break;
1184
+ }
1185
+
1186
+ const lines: string[] = ["Recommended plugins setup:\n"];
1187
+ let installedCount = 0;
1188
+ let skippedCount = 0;
1189
+ const skippedReasons: string[] = [];
1190
+
1191
+ for (const plugin of toInstall) {
1192
+ if (plugin.prerequisites && plugin.prerequisites.length > 0) {
1193
+ const missing: string[] = [];
1194
+ for (const prereq of plugin.prerequisites) {
1195
+ const ok = await checkPrerequisite(prereq.detectCmd);
1196
+ if (!ok) missing.push(`${prereq.tool} (${prereq.installCmd})`);
1197
+ }
1198
+ if (missing.length > 0) {
1199
+ lines.push(` ⊘ ${plugin.displayName || plugin.name} — missing: ${missing.join(", ")}`);
1200
+ skippedCount++;
1201
+ skippedReasons.push(...missing);
1202
+ continue;
1203
+ }
1204
+ }
1205
+
1206
+ const marketplaces = await mgr.listMarketplaces();
1207
+ let installed = false;
1208
+ for (const mkt of marketplaces) {
1209
+ const available = await mgr.listAvailablePlugins(mkt.name);
1210
+ if (available.some(a => a.name === plugin.name)) {
1211
+ try {
1212
+ await mgr.installPlugin(plugin.name, mkt.name);
1213
+ lines.push(` + ${plugin.displayName || plugin.name} — installed`);
1214
+ installedCount++;
1215
+ installed = true;
1216
+ } catch (err) {
1217
+ lines.push(
1218
+ ` ! ${plugin.displayName || plugin.name} — ${err instanceof Error ? err.message : String(err)}`,
1219
+ );
1220
+ skippedCount++;
1221
+ }
1222
+ break;
1223
+ }
1224
+ }
1225
+ if (!installed && skippedCount === 0) {
1226
+ lines.push(` ? ${plugin.displayName || plugin.name} — not found in any marketplace`);
1227
+ skippedCount++;
1228
+ }
1229
+ }
1230
+
1231
+ lines.push("");
1232
+ lines.push(`Installed ${installedCount}/${toInstall.length} recommended plugin(s)`);
1233
+ if (skippedCount > 0) {
1234
+ lines.push(`${skippedCount} skipped — install missing tools and run /plugin setup again`);
1235
+ }
1236
+ runtime.ctx.showStatus(lines.join("\n"));
1237
+ break;
1238
+ }
1165
1239
  // ── Help ──
1166
1240
  case "help": {
1167
1241
  runtime.ctx.showStatus(
@@ -1180,6 +1254,7 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<BuiltinSlashCommandSpec> = [
1180
1254
  " /plugin upgrade [name@marketplace] Upgrade plugin(s)",
1181
1255
  " /plugin list List installed plugins",
1182
1256
  " /plugin validate [path] Validate marketplace or plugin",
1257
+ " /plugin setup Guided setup for recommended plugins",
1183
1258
  "",
1184
1259
  "Quick start:",
1185
1260
  " /plugin marketplace add f5xc-salesdemos/marketplace",