@f5-sales-demo/xcsh 19.62.13 → 19.63.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 +8 -8
- package/src/deprecations.ts +87 -0
- package/src/internal-urls/api-spec-resolve.ts +15 -3
- package/src/internal-urls/branding-index.generated.ts +31 -0
- package/src/internal-urls/build-info.generated.ts +8 -8
- package/src/prompts/system/system-prompt.md +5 -1
- package/src/system-prompt.ts +12 -0
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.63.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.63.0",
|
|
60
|
+
"@f5-sales-demo/pi-agent-core": "19.63.0",
|
|
61
|
+
"@f5-sales-demo/pi-ai": "19.63.0",
|
|
62
|
+
"@f5-sales-demo/pi-natives": "19.63.0",
|
|
63
|
+
"@f5-sales-demo/pi-resource-management": "19.63.0",
|
|
64
|
+
"@f5-sales-demo/pi-tui": "19.63.0",
|
|
65
|
+
"@f5-sales-demo/pi-utils": "19.63.0",
|
|
66
66
|
"@sinclair/typebox": "^0.34",
|
|
67
67
|
"@xterm/headless": "^6.0",
|
|
68
68
|
"ajv": "^8.20",
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// Behavioral deprecation guardrails, derived from the single source of truth
|
|
2
|
+
// (api-specs-enriched/config/branding.yaml → branding-index.generated.ts).
|
|
3
|
+
//
|
|
4
|
+
// This module is the ONE seam every surface consumes so deprecation facts are
|
|
5
|
+
// authored once and never hand-duplicated:
|
|
6
|
+
// - the always-on system prompt (renderDeprecationGuardrails)
|
|
7
|
+
// - the xcsh://branding/* protocol (via xcsh-protocol.ts, same generated data)
|
|
8
|
+
// - the CLI-Quick-Start renderer (isDisallowedCliCommand / getDeprecatedClis)
|
|
9
|
+
|
|
10
|
+
import { BRANDING_DEPRECATIONS } from "./internal-urls/branding-index.generated";
|
|
11
|
+
|
|
12
|
+
interface DeprecationEntry {
|
|
13
|
+
deprecated: Record<string, string>;
|
|
14
|
+
canonical: Record<string, string>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const DEPRECATIONS = BRANDING_DEPRECATIONS as unknown as Record<string, DeprecationEntry>;
|
|
18
|
+
|
|
19
|
+
/** Markers that identify a command as targeting the F5 XC API. */
|
|
20
|
+
const F5XC_API_MARKERS = [
|
|
21
|
+
"f5xc_api_url",
|
|
22
|
+
"f5xc_api_token",
|
|
23
|
+
"apitoken",
|
|
24
|
+
".volterra.io",
|
|
25
|
+
".volterra.us",
|
|
26
|
+
"console.ves",
|
|
27
|
+
"/api/config/",
|
|
28
|
+
"/api/data/",
|
|
29
|
+
"/api/web/",
|
|
30
|
+
"/api/shape/",
|
|
31
|
+
"/api/ml/",
|
|
32
|
+
"/api/register/",
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
// xcsh-native guidance substituted wherever a deprecated command would appear.
|
|
36
|
+
// Intentionally does NOT echo the deprecated tool name — the substitution exists
|
|
37
|
+
// precisely so that name never reaches the user through this surface.
|
|
38
|
+
export const XCSH_NATIVE_API_GUIDANCE =
|
|
39
|
+
"Use the `xcsh_api` tool for F5 Distributed Cloud API calls — the spec's legacy CLI example is not supported in xcsh.";
|
|
40
|
+
|
|
41
|
+
/** Deprecated CLI commands, sourced from branding deprecation data (e.g. ["vesctl"]). */
|
|
42
|
+
export function getDeprecatedClis(): string[] {
|
|
43
|
+
const clis = new Set<string>();
|
|
44
|
+
for (const entry of Object.values(DEPRECATIONS)) {
|
|
45
|
+
const command = entry.deprecated?.command;
|
|
46
|
+
if (command) clis.add(command.trim().toLowerCase());
|
|
47
|
+
}
|
|
48
|
+
return [...clis];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* True if a command must never be surfaced as an instruction: it invokes a
|
|
53
|
+
* deprecated CLI (e.g. vesctl), or it is a raw `curl` against the F5 XC API.
|
|
54
|
+
*/
|
|
55
|
+
export function isDisallowedCliCommand(command: string): boolean {
|
|
56
|
+
const lower = command.trim().toLowerCase();
|
|
57
|
+
if (!lower) return false;
|
|
58
|
+
const leadingToken = lower.split(/\s+/)[0] ?? "";
|
|
59
|
+
if (getDeprecatedClis().includes(leadingToken)) return true;
|
|
60
|
+
if (leadingToken === "curl" && F5XC_API_MARKERS.some(marker => lower.includes(marker))) return true;
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Concise, always-on deprecation block for the system prompt. Concrete values
|
|
66
|
+
* come from the embedded branding data; the behavioral rules are stable prose.
|
|
67
|
+
*/
|
|
68
|
+
export function renderDeprecationGuardrails(): string {
|
|
69
|
+
const cli = DEPRECATIONS.cli;
|
|
70
|
+
const apiDocs = DEPRECATIONS.api_documentation;
|
|
71
|
+
const brand = DEPRECATIONS.product_brand;
|
|
72
|
+
|
|
73
|
+
const vesctl = cli?.deprecated.command ?? "vesctl";
|
|
74
|
+
const xcshCmd = cli?.canonical.command ?? "xcsh";
|
|
75
|
+
const legacyApiUrl = apiDocs?.deprecated.url ?? "https://docs.cloud.f5.com/docs-v2/api";
|
|
76
|
+
const enrichedUrl = apiDocs?.canonical.url ?? "https://f5-sales-demo.github.io/api-specs-enriched/en/";
|
|
77
|
+
const deadBrand = brand?.deprecated.name ?? "Volterra";
|
|
78
|
+
const currentBrand = brand?.canonical.name ?? "F5 Distributed Cloud";
|
|
79
|
+
|
|
80
|
+
return [
|
|
81
|
+
"These deprecations are non-negotiable. Full detail lives at `xcsh://branding` and `xcsh://branding/volterra`, but the rules below apply even when that protocol is never consulted.",
|
|
82
|
+
"",
|
|
83
|
+
`- **Never use \`${vesctl}\`.** It is the abandoned, unsupported legacy CLI; \`${xcshCmd}\` is its modern replacement. Never propose, generate, or run \`${vesctl}\`. For F5 XC API calls use the \`xcsh_api\` tool (never raw \`curl\`); for console automation use \`catalog_workflow_runner\`.`,
|
|
84
|
+
`- **The legacy API docs are deprecated.** Never link or fetch \`${legacyApiUrl}\`. The canonical API reference is \`${enrichedUrl}\`, and the enriched specs are already embedded in this binary — prefer \`xcsh://api-catalog/\` and \`xcsh://api-spec/\` before fetching anything.`,
|
|
85
|
+
`- **"${deadBrand}" is a retired brand name.** The product is **${currentBrand}**; never write "${deadBrand}" as a product name or recommend ${deadBrand}-labeled tooling. BUT \`volterra_*\` API keys, \`*.volterra.io\`/\`*.volterra.us\` hostnames, and schema identifiers are **required functional identifiers** — use them verbatim, exactly as the API expects. Only the brand name is dead, not the identifiers.`,
|
|
86
|
+
].join("\n");
|
|
87
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isDisallowedCliCommand, XCSH_NATIVE_API_GUIDANCE } from "../deprecations";
|
|
1
2
|
import type {
|
|
2
3
|
ApiSpecDomainEnrichments,
|
|
3
4
|
ApiSpecDomainEntry,
|
|
@@ -265,16 +266,27 @@ function renderDomainDetail(domain: string, entry: ApiSpecDomainEntry, spec: Ope
|
|
|
265
266
|
if (entry.cliMetadata?.quickStart?.command) {
|
|
266
267
|
const cli = entry.cliMetadata;
|
|
267
268
|
sections.push("", "## CLI Quick Start", "");
|
|
268
|
-
|
|
269
|
+
// Never surface a deprecated CLI (e.g. vesctl) or raw curl against the F5 XC
|
|
270
|
+
// API as an instruction — even if the upstream spec carries one. Substitute
|
|
271
|
+
// xcsh-native guidance instead.
|
|
272
|
+
if (isDisallowedCliCommand(cli.quickStart.command)) {
|
|
273
|
+
sections.push(`${cli.quickStart.description} — ${XCSH_NATIVE_API_GUIDANCE}`);
|
|
274
|
+
} else {
|
|
275
|
+
sections.push(`\`${cli.quickStart.command}\` — ${cli.quickStart.description}`);
|
|
276
|
+
}
|
|
269
277
|
const validWorkflows = cli.commonWorkflows?.filter(wf => wf.name) ?? [];
|
|
270
278
|
if (validWorkflows.length > 0) {
|
|
271
279
|
sections.push("", "### Common Workflows");
|
|
272
280
|
for (const wf of validWorkflows) {
|
|
273
|
-
|
|
281
|
+
const allowedCommands = (wf.commands ?? []).filter(cmd => !isDisallowedCliCommand(cmd));
|
|
282
|
+
if (allowedCommands.length > 0) {
|
|
274
283
|
sections.push("", `**${wf.name}:**`);
|
|
275
|
-
for (const cmd of
|
|
284
|
+
for (const cmd of allowedCommands) {
|
|
276
285
|
sections.push(`- \`${cmd}\``);
|
|
277
286
|
}
|
|
287
|
+
} else if (wf.commands?.length) {
|
|
288
|
+
// Every command in this workflow was deprecated/disallowed.
|
|
289
|
+
sections.push("", `**${wf.name}:** ${XCSH_NATIVE_API_GUIDANCE}`);
|
|
278
290
|
} else {
|
|
279
291
|
sections.push(`- ${wf.name}`);
|
|
280
292
|
}
|
|
@@ -56,6 +56,37 @@ export const BRANDING_DEPRECATIONS = {
|
|
|
56
56
|
url: "https://f5-sales-demo.github.io/terraform-provider-xcsh/",
|
|
57
57
|
},
|
|
58
58
|
},
|
|
59
|
+
cli: {
|
|
60
|
+
deprecated: {
|
|
61
|
+
command: "vesctl",
|
|
62
|
+
status: "abandoned",
|
|
63
|
+
note: "Legacy Volterra CLI, abandoned years ago and unsupported. xcsh must never propose, generate, or run vesctl. High risk of AI model recommendation due to training-data prevalence.\n",
|
|
64
|
+
},
|
|
65
|
+
canonical: {
|
|
66
|
+
command: "xcsh",
|
|
67
|
+
note: "xcsh is the modern, supported replacement for vesctl. For F5 XC API calls use the xcsh_api tool (never curl); for console automation use the catalog_workflow_runner tool.\n",
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
api_documentation: {
|
|
71
|
+
deprecated: {
|
|
72
|
+
url: "https://docs.cloud.f5.com/docs-v2/api",
|
|
73
|
+
note: "Legacy F5 XC API documentation set. Deprecated — never link or fetch it for API references.\n",
|
|
74
|
+
},
|
|
75
|
+
canonical: {
|
|
76
|
+
url: "https://f5-sales-demo.github.io/api-specs-enriched/en/",
|
|
77
|
+
note: "Enriched API specs are embedded in the xcsh binary — prefer xcsh://api-catalog/ and xcsh://api-spec/ before fetching any URL.\n",
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
product_brand: {
|
|
81
|
+
deprecated: {
|
|
82
|
+
name: "Volterra",
|
|
83
|
+
note: 'Volterra was the company F5 acquired; the brand is retired. Never use "Volterra" as a product name in prose or recommend Volterra-labeled tooling.\n',
|
|
84
|
+
},
|
|
85
|
+
canonical: {
|
|
86
|
+
name: "F5 Distributed Cloud",
|
|
87
|
+
note: "volterra_* API keys, *.volterra.io / *.volterra.us hostnames, and schema identifiers are required functional identifiers — use them verbatim; only the product/brand name is deprecated, not these identifiers.\n",
|
|
88
|
+
},
|
|
89
|
+
},
|
|
59
90
|
} as const;
|
|
60
91
|
|
|
61
92
|
export const BRANDING_GLOSSARY = {
|
|
@@ -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.63.0",
|
|
21
|
+
"commit": "d363d9f8ae94d36d0088aab8932d1952d7f2c4d5",
|
|
22
|
+
"shortCommit": "d363d9f",
|
|
23
23
|
"branch": "main",
|
|
24
|
-
"tag": "v19.
|
|
25
|
-
"commitDate": "2026-07-
|
|
26
|
-
"buildDate": "2026-07-
|
|
24
|
+
"tag": "v19.63.0",
|
|
25
|
+
"commitDate": "2026-07-14T14:23:41Z",
|
|
26
|
+
"buildDate": "2026-07-14T14:50:44.521Z",
|
|
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/d363d9f8ae94d36d0088aab8932d1952d7f2c4d5",
|
|
32
|
+
"releaseUrl": "https://github.com/f5-sales-demo/xcsh/releases/tag/v19.63.0"
|
|
33
33
|
};
|
|
@@ -408,7 +408,11 @@ If that also 404s, the product has no documentation — acknowledge this to the
|
|
|
408
408
|
and answers the question, OR when T3 and T5 have been checked without resolution.
|
|
409
409
|
Only then is web search permitted — label external results as supplementary.
|
|
410
410
|
|
|
411
|
-
##
|
|
411
|
+
## Deprecation guardrails
|
|
412
|
+
|
|
413
|
+
%%DEPRECATION_GUARDRAILS%%
|
|
414
|
+
|
|
415
|
+
### Terraform provider
|
|
412
416
|
|
|
413
417
|
HARD OVERRIDE — F5 Distributed Cloud Terraform Provider:
|
|
414
418
|
- NEVER reference, recommend, or generate Terraform code using:
|
package/src/system-prompt.ts
CHANGED
|
@@ -11,11 +11,15 @@ import { $ } from "bun";
|
|
|
11
11
|
import { contextFileCapability } from "./capability/context-file";
|
|
12
12
|
import { systemPromptCapability } from "./capability/system-prompt";
|
|
13
13
|
import type { SkillsSettings } from "./config/settings";
|
|
14
|
+
import { renderDeprecationGuardrails } from "./deprecations";
|
|
14
15
|
import { type ContextFile, loadCapability, type SystemPrompt as SystemPromptFile } from "./discovery";
|
|
15
16
|
import { isApplicableToContext, loadSkills, type Skill } from "./extensibility/skills";
|
|
16
17
|
import customSystemPromptTemplate from "./prompts/system/custom-system-prompt.md" with { type: "text" };
|
|
17
18
|
import systemPromptTemplate from "./prompts/system/system-prompt.md" with { type: "text" };
|
|
18
19
|
|
|
20
|
+
/** Sentinel in system-prompt.md replaced with the rendered deprecation guardrails. */
|
|
21
|
+
const DEPRECATION_GUARDRAILS_MARKER = "%%DEPRECATION_GUARDRAILS%%";
|
|
22
|
+
|
|
19
23
|
let _buildMeta: { version: string; repoSlug: string } | null = null;
|
|
20
24
|
|
|
21
25
|
function getBuildMeta(): { version: string; repoSlug: string } {
|
|
@@ -694,6 +698,14 @@ export async function buildSystemPrompt(options: BuildSystemPromptOptions = {}):
|
|
|
694
698
|
};
|
|
695
699
|
let rendered = prompt.render(resolvedCustomPrompt ? customSystemPromptTemplate : systemPromptTemplate, data);
|
|
696
700
|
|
|
701
|
+
// Deprecation guardrails are always-on: replace the section marker in the default
|
|
702
|
+
// template, or append when the active template has none (e.g. a fully custom system
|
|
703
|
+
// prompt), so the rules apply on every code path — not only when xcsh:// is consulted.
|
|
704
|
+
const deprecationGuardrails = renderDeprecationGuardrails();
|
|
705
|
+
rendered = rendered.includes(DEPRECATION_GUARDRAILS_MARKER)
|
|
706
|
+
? rendered.replace(DEPRECATION_GUARDRAILS_MARKER, deprecationGuardrails)
|
|
707
|
+
: `${rendered}\n\n## Deprecation guardrails\n\n${deprecationGuardrails}`;
|
|
708
|
+
|
|
697
709
|
// When autoqa is active the report_tool_issue tool is in the tool set — nudge the agent.
|
|
698
710
|
if (toolNames.includes("report_tool_issue")) {
|
|
699
711
|
rendered +=
|