@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.
|
|
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.
|
|
60
|
-
"@f5-sales-demo/pi-agent-core": "19.
|
|
61
|
-
"@f5-sales-demo/pi-ai": "19.
|
|
62
|
-
"@f5-sales-demo/pi-natives": "19.
|
|
63
|
-
"@f5-sales-demo/pi-resource-management": "19.
|
|
64
|
-
"@f5-sales-demo/pi-tui": "19.
|
|
65
|
-
"@f5-sales-demo/pi-utils": "19.
|
|
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.
|
|
21
|
-
"commit": "
|
|
22
|
-
"shortCommit": "
|
|
20
|
+
"version": "19.74.0",
|
|
21
|
+
"commit": "c6fc2dd6c16c816e5857edc7e892837405dead7a",
|
|
22
|
+
"shortCommit": "c6fc2dd",
|
|
23
23
|
"branch": "main",
|
|
24
|
-
"tag": "v19.
|
|
25
|
-
"commitDate": "2026-07-
|
|
26
|
-
"buildDate": "2026-07-
|
|
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/
|
|
32
|
-
"releaseUrl": "https://github.com/f5-sales-demo/xcsh/releases/tag/v19.
|
|
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
|
+
});
|
package/src/system-prompt.ts
CHANGED
|
@@ -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,
|