@f5-sales-demo/xcsh 19.73.0 → 19.74.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": "@f5-sales-demo/xcsh",
4
- "version": "19.73.0",
4
+ "version": "19.74.0",
5
5
  "description": "Coding agent CLI with read, bash, edit, write tools and session management",
6
6
  "homepage": "https://github.com/f5-sales-demo/xcsh",
7
7
  "author": "Can Boluk",
@@ -56,13 +56,13 @@
56
56
  "dependencies": {
57
57
  "@agentclientprotocol/sdk": "0.16.1",
58
58
  "@mozilla/readability": "^0.6",
59
- "@f5-sales-demo/xcsh-stats": "19.73.0",
60
- "@f5-sales-demo/pi-agent-core": "19.73.0",
61
- "@f5-sales-demo/pi-ai": "19.73.0",
62
- "@f5-sales-demo/pi-natives": "19.73.0",
63
- "@f5-sales-demo/pi-resource-management": "19.73.0",
64
- "@f5-sales-demo/pi-tui": "19.73.0",
65
- "@f5-sales-demo/pi-utils": "19.73.0",
59
+ "@f5-sales-demo/xcsh-stats": "19.74.0",
60
+ "@f5-sales-demo/pi-agent-core": "19.74.0",
61
+ "@f5-sales-demo/pi-ai": "19.74.0",
62
+ "@f5-sales-demo/pi-natives": "19.74.0",
63
+ "@f5-sales-demo/pi-resource-management": "19.74.0",
64
+ "@f5-sales-demo/pi-tui": "19.74.0",
65
+ "@f5-sales-demo/pi-utils": "19.74.0",
66
66
  "@sinclair/typebox": "^0.34",
67
67
  "@xterm/headless": "^6.0",
68
68
  "ajv": "^8.20",
@@ -17,17 +17,17 @@ export interface BuildInfo {
17
17
  }
18
18
 
19
19
  export const BUILD_INFO: BuildInfo = {
20
- "version": "19.73.0",
21
- "commit": "3f32c968ef8b2a0c9fabbc1be3fbe5c7395a7dc9",
22
- "shortCommit": "3f32c96",
20
+ "version": "19.74.0",
21
+ "commit": "c6fc2dd6c16c816e5857edc7e892837405dead7a",
22
+ "shortCommit": "c6fc2dd",
23
23
  "branch": "main",
24
- "tag": "v19.73.0",
25
- "commitDate": "2026-07-22T04:58:36Z",
26
- "buildDate": "2026-07-22T05:24:54.248Z",
24
+ "tag": "v19.74.0",
25
+ "commitDate": "2026-07-22T05:55:19Z",
26
+ "buildDate": "2026-07-22T06:19:41.705Z",
27
27
  "dirty": true,
28
28
  "prNumber": "",
29
29
  "repoUrl": "https://github.com/f5-sales-demo/xcsh",
30
30
  "repoSlug": "f5-sales-demo/xcsh",
31
- "commitUrl": "https://github.com/f5-sales-demo/xcsh/commit/3f32c968ef8b2a0c9fabbc1be3fbe5c7395a7dc9",
32
- "releaseUrl": "https://github.com/f5-sales-demo/xcsh/releases/tag/v19.73.0"
31
+ "commitUrl": "https://github.com/f5-sales-demo/xcsh/commit/c6fc2dd6c16c816e5857edc7e892837405dead7a",
32
+ "releaseUrl": "https://github.com/f5-sales-demo/xcsh/releases/tag/v19.74.0"
33
33
  };
@@ -306,6 +306,9 @@ Most tools resolve custom protocol URLs to internal resources (not web URLs):
306
306
  - `xcsh://console/<resource>` — console route pattern, menu path, and available operations.
307
307
  - `xcsh://console/<resource>/<operation>` — the exact ordered UI steps (selectors) for that operation.
308
308
  - `xcsh://extension` — Chrome extension bridge tool API reference: which tool to use (click, typeahead, input, navigation) for each automation task.
309
+ {{#if hasPlugins}}
310
+ Installed plugins expose capabilities, schemas, and executable helpers on demand. Read `xcsh://plugin` to list installed plugins and `xcsh://plugin/<name>` for a plugin's summary and how to go deeper — pull this in only when a task matches a plugin's domain.
311
+ {{/if}}
309
312
 
310
313
  ### Presentation profile
311
314
 
@@ -0,0 +1,38 @@
1
+ import { beforeAll, describe, expect, test } from "bun:test";
2
+ import * as path from "node:path";
3
+ import { prompt } from "@f5-sales-demo/pi-utils";
4
+ import { registerCodingAgentPromptHelpers } from "./config/prompt-templates";
5
+
6
+ // L0 of the MEDDPICC progressive-hints ladder: a single framework-agnostic line
7
+ // telling the agent that installed plugins expose capabilities/schemas via
8
+ // `xcsh://plugin/<name>`. It is gated on the `hasPlugins` render variable that
9
+ // `buildSystemPrompt` computes from discovered plugin roots.
10
+ //
11
+ // Seam: the Handlebars-compile path (`prompt.render(template, data)`) — the same
12
+ // seam every other conditional-rendering assertion in this package uses. It is
13
+ // deterministic (no dependency on what is installed under the real home dir) and
14
+ // exercises the exact template conditional this task adds. `buildSystemPrompt`
15
+ // resolves plugins from `os.homedir()` and takes no `home` override, so a
16
+ // true-case fixture through it would be non-deterministic.
17
+
18
+ const systemPromptPath = path.resolve(import.meta.dir, "prompts/system/system-prompt.md");
19
+
20
+ describe("L0 plugin-capability pointer", () => {
21
+ beforeAll(() => {
22
+ registerCodingAgentPromptHelpers();
23
+ });
24
+
25
+ test("renders the generic pointer when a plugin is present, naming no plugin", async () => {
26
+ const template = await Bun.file(systemPromptPath).text();
27
+ const rendered = prompt.render(template, { hasPlugins: true });
28
+ expect(rendered).toContain("xcsh://plugin");
29
+ // Generic/reusable: it must not name any specific plugin.
30
+ expect(rendered).not.toContain("meddpicc");
31
+ });
32
+
33
+ test("omits the pointer entirely when no plugins are present", async () => {
34
+ const template = await Bun.file(systemPromptPath).text();
35
+ const rendered = prompt.render(template, { hasPlugins: false });
36
+ expect(rendered).not.toContain("xcsh://plugin");
37
+ });
38
+ });
@@ -13,6 +13,7 @@ import { systemPromptCapability } from "./capability/system-prompt";
13
13
  import type { SkillsSettings } from "./config/settings";
14
14
  import { renderDeprecationGuardrails } from "./deprecations";
15
15
  import { type ContextFile, loadCapability, type SystemPrompt as SystemPromptFile } from "./discovery";
16
+ import { listXcshPluginRoots } from "./discovery/helpers";
16
17
  import { isApplicableToContext, loadSkills, type Skill } from "./extensibility/skills";
17
18
  import customSystemPromptTemplate from "./prompts/system/custom-system-prompt.md" with { type: "text" };
18
19
  import systemPromptTemplate from "./prompts/system/system-prompt.md" with { type: "text" };
@@ -555,6 +556,13 @@ export async function buildSystemPrompt(options: BuildSystemPromptOptions = {}):
555
556
  ? loadSkills({ ...mergedSkillsSettings, cwd: resolvedCwd }).then(result => result.skills)
556
557
  : Promise.resolve([]);
557
558
 
559
+ // L0 plugin-capability pointer: gate a generic `xcsh://plugin` hint on ≥1
560
+ // discoverable plugin. Discovery is cached and reads one small registry file,
561
+ // so this is effectively free; it fails safe to `false` (no hint) on error.
562
+ const hasPluginsPromise: Promise<boolean> = listXcshPluginRoots(os.homedir(), resolvedCwd)
563
+ .then(result => result.roots.length > 0)
564
+ .catch(() => false);
565
+
558
566
  return Promise.all([
559
567
  resolvePromptInput(customPrompt, "system prompt"),
560
568
  resolvePromptInput(appendSystemPrompt, "append system prompt"),
@@ -562,6 +570,7 @@ export async function buildSystemPrompt(options: BuildSystemPromptOptions = {}):
562
570
  contextFilesPromise,
563
571
  agentsMdSearchPromise,
564
572
  skillsPromise,
573
+ hasPluginsPromise,
565
574
  ]).then(
566
575
  ([
567
576
  resolvedCustomPrompt,
@@ -570,6 +579,7 @@ export async function buildSystemPrompt(options: BuildSystemPromptOptions = {}):
570
579
  contextFiles,
571
580
  agentsMdSearch,
572
581
  skills,
582
+ hasPlugins,
573
583
  ]) => ({
574
584
  resolvedCustomPrompt,
575
585
  resolvedAppendPrompt,
@@ -577,6 +587,7 @@ export async function buildSystemPrompt(options: BuildSystemPromptOptions = {}):
577
587
  contextFiles,
578
588
  agentsMdSearch,
579
589
  skills,
590
+ hasPlugins,
580
591
  }),
581
592
  );
582
593
  })();
@@ -601,6 +612,7 @@ export async function buildSystemPrompt(options: BuildSystemPromptOptions = {}):
601
612
  files: [],
602
613
  };
603
614
  let skills: Skill[] = providedSkills ?? [];
615
+ let hasPlugins = false;
604
616
 
605
617
  if (prepResult.type === "timeout") {
606
618
  logger.warn("System prompt preparation timed out; using minimal startup context", {
@@ -623,6 +635,7 @@ export async function buildSystemPrompt(options: BuildSystemPromptOptions = {}):
623
635
  contextFiles = dedupeExactContextFiles(prepResult.value.contextFiles);
624
636
  agentsMdSearch = prepResult.value.agentsMdSearch;
625
637
  skills = prepResult.value.skills;
638
+ hasPlugins = prepResult.value.hasPlugins;
626
639
  }
627
640
 
628
641
  const date = new Date().toISOString().slice(0, 10);
@@ -679,6 +692,7 @@ export async function buildSystemPrompt(options: BuildSystemPromptOptions = {}):
679
692
  agentsMdSearch,
680
693
  skills: contextFilteredSkills,
681
694
  rules: rules ?? [],
695
+ hasPlugins,
682
696
  alwaysApplyRules: injectedAlwaysApplyRules,
683
697
  date,
684
698
  dateTime,