@f5xc-salesdemos/xcsh 18.35.2 → 18.35.3
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": "18.35.
|
|
4
|
+
"version": "18.35.3",
|
|
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",
|
|
@@ -48,12 +48,12 @@
|
|
|
48
48
|
"dependencies": {
|
|
49
49
|
"@agentclientprotocol/sdk": "0.16.1",
|
|
50
50
|
"@mozilla/readability": "^0.6",
|
|
51
|
-
"@f5xc-salesdemos/xcsh-stats": "18.35.
|
|
52
|
-
"@f5xc-salesdemos/pi-agent-core": "18.35.
|
|
53
|
-
"@f5xc-salesdemos/pi-ai": "18.35.
|
|
54
|
-
"@f5xc-salesdemos/pi-natives": "18.35.
|
|
55
|
-
"@f5xc-salesdemos/pi-tui": "18.35.
|
|
56
|
-
"@f5xc-salesdemos/pi-utils": "18.35.
|
|
51
|
+
"@f5xc-salesdemos/xcsh-stats": "18.35.3",
|
|
52
|
+
"@f5xc-salesdemos/pi-agent-core": "18.35.3",
|
|
53
|
+
"@f5xc-salesdemos/pi-ai": "18.35.3",
|
|
54
|
+
"@f5xc-salesdemos/pi-natives": "18.35.3",
|
|
55
|
+
"@f5xc-salesdemos/pi-tui": "18.35.3",
|
|
56
|
+
"@f5xc-salesdemos/pi-utils": "18.35.3",
|
|
57
57
|
"@sinclair/typebox": "^0.34",
|
|
58
58
|
"@xterm/headless": "^6.0",
|
|
59
59
|
"ajv": "^8.18",
|
|
@@ -17,17 +17,17 @@ export interface BuildInfo {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export const BUILD_INFO: BuildInfo = {
|
|
20
|
-
"version": "18.35.
|
|
21
|
-
"commit": "
|
|
22
|
-
"shortCommit": "
|
|
20
|
+
"version": "18.35.3",
|
|
21
|
+
"commit": "32785b70f062fe1930d72a355fc5d72bedb29128",
|
|
22
|
+
"shortCommit": "32785b7",
|
|
23
23
|
"branch": "main",
|
|
24
|
-
"tag": "v18.35.
|
|
25
|
-
"commitDate": "2026-05-
|
|
26
|
-
"buildDate": "2026-05-04T00:
|
|
24
|
+
"tag": "v18.35.3",
|
|
25
|
+
"commitDate": "2026-05-04T00:13:26Z",
|
|
26
|
+
"buildDate": "2026-05-04T00:32:30.792Z",
|
|
27
27
|
"dirty": false,
|
|
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/v18.35.
|
|
31
|
+
"commitUrl": "https://github.com/f5xc-salesdemos/xcsh/commit/32785b70f062fe1930d72a355fc5d72bedb29128",
|
|
32
|
+
"releaseUrl": "https://github.com/f5xc-salesdemos/xcsh/releases/tag/v18.35.3"
|
|
33
33
|
};
|
|
@@ -196,13 +196,22 @@ Most tools resolve custom protocol URLs to internal resources (not web URLs):
|
|
|
196
196
|
|
|
197
197
|
When the user needs to **make an API call** (create, read, update, delete):
|
|
198
198
|
|
|
199
|
-
1. `xcsh://api-catalog/?resource={resource_name}` → get endpoint path, method,
|
|
200
|
-
payload JSON,
|
|
199
|
+
1. `xcsh://api-catalog/?resource={resource_name}&compact=true` → get endpoint path, method,
|
|
200
|
+
minimum payload JSON, OneOf recommendations, and response summary
|
|
201
201
|
2. Call `xcsh_api` tool with `method`, `path`, `params` (all `{placeholder}` substitutions), and `payload`
|
|
202
202
|
|
|
203
|
+
When the resource type and required parameters are clear, your **first output
|
|
204
|
+
MUST be the catalog tool call** — do not preface with explanation or deliberation.
|
|
205
|
+
If required parameters (e.g., namespace) are ambiguous, ask first.
|
|
206
|
+
|
|
203
207
|
The `xcsh_api` tool handles authentication, URL construction, and HTTP execution.
|
|
204
208
|
Never construct curl commands for F5 XC API calls — use `xcsh_api` instead.
|
|
205
209
|
|
|
210
|
+
After `xcsh_api` returns a 200 or 201 response, report the result immediately.
|
|
211
|
+
Do not issue a follow-up GET to verify — the response body is the verification.
|
|
212
|
+
Only issue a GET if the user explicitly asks to read current state, or if the
|
|
213
|
+
initial call returned a non-2xx status.
|
|
214
|
+
|
|
206
215
|
If the resource name is unknown, search first:
|
|
207
216
|
`xcsh://api-catalog/?search={term}` → find the matching category, then read it.
|
|
208
217
|
|
|
@@ -7,3 +7,5 @@ Pass all path `{placeholder}` values via `params`, e.g. `{ namespace: "default",
|
|
|
7
7
|
Body is sent for all methods except GET when `payload` is provided — including DELETE operations that require a body.
|
|
8
8
|
|
|
9
9
|
Use this tool after reading the API catalog to get the endpoint path and payload structure.
|
|
10
|
+
|
|
11
|
+
API calls to the same F5 XC tenant reuse a single TLS connection — sequential calls are faster than parallel calls. Do not issue multiple xcsh_api calls in the same turn; issue them one at a time.
|
package/src/tools/xcsh-api.ts
CHANGED
|
@@ -25,6 +25,7 @@ export interface XcshApiToolDetails {
|
|
|
25
25
|
status: number;
|
|
26
26
|
url: string;
|
|
27
27
|
method: string;
|
|
28
|
+
requestId: string;
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
type XcshApiResult = AgentToolResult<XcshApiToolDetails> & { isError?: boolean };
|
|
@@ -35,21 +36,31 @@ export class XcshApiTool implements AgentTool<typeof xcshApiSchema, XcshApiToolD
|
|
|
35
36
|
readonly description: string;
|
|
36
37
|
readonly parameters = xcshApiSchema;
|
|
37
38
|
|
|
39
|
+
#apiBase: string;
|
|
40
|
+
#apiToken: string;
|
|
41
|
+
|
|
38
42
|
constructor(_session: ToolSession) {
|
|
39
43
|
this.description = prompt.render(xcshApiDescription);
|
|
44
|
+
this.#apiBase = (process.env.F5XC_API_URL ?? "").replace(/\/+$/, "");
|
|
45
|
+
this.#apiToken = process.env.F5XC_API_TOKEN ?? "";
|
|
46
|
+
|
|
47
|
+
if (this.#apiBase && this.#apiToken) {
|
|
48
|
+
fetch(`${this.#apiBase}/api/web/namespaces`, {
|
|
49
|
+
method: "HEAD",
|
|
50
|
+
headers: { Authorization: `APIToken ${this.#apiToken}` },
|
|
51
|
+
}).catch(() => {});
|
|
52
|
+
}
|
|
40
53
|
}
|
|
41
54
|
|
|
42
55
|
async execute(_toolCallId: string, params: XcshApiParams): Promise<XcshApiResult> {
|
|
43
|
-
|
|
44
|
-
if (!apiUrl) {
|
|
56
|
+
if (!this.#apiBase) {
|
|
45
57
|
return {
|
|
46
58
|
content: [{ type: "text", text: "Error: F5XC_API_URL environment variable is not set." }],
|
|
47
59
|
isError: true,
|
|
48
60
|
};
|
|
49
61
|
}
|
|
50
62
|
|
|
51
|
-
|
|
52
|
-
if (!apiToken) {
|
|
63
|
+
if (!this.#apiToken) {
|
|
53
64
|
return {
|
|
54
65
|
content: [{ type: "text", text: "Error: F5XC_API_TOKEN environment variable is not set." }],
|
|
55
66
|
isError: true,
|
|
@@ -63,13 +74,19 @@ export class XcshApiTool implements AgentTool<typeof xcshApiSchema, XcshApiToolD
|
|
|
63
74
|
}
|
|
64
75
|
}
|
|
65
76
|
|
|
66
|
-
const url = `${
|
|
77
|
+
const url = `${this.#apiBase}${resolvedPath}`;
|
|
78
|
+
const requestId = crypto.randomUUID();
|
|
67
79
|
const headers: Record<string, string> = {
|
|
68
|
-
Authorization: `APIToken ${apiToken}`,
|
|
80
|
+
Authorization: `APIToken ${this.#apiToken}`,
|
|
69
81
|
Accept: "application/json",
|
|
82
|
+
"X-Request-ID": requestId,
|
|
70
83
|
};
|
|
71
84
|
|
|
72
|
-
const init: RequestInit = {
|
|
85
|
+
const init: RequestInit = {
|
|
86
|
+
method: params.method,
|
|
87
|
+
headers,
|
|
88
|
+
signal: AbortSignal.timeout(30_000),
|
|
89
|
+
};
|
|
73
90
|
|
|
74
91
|
if (params.payload && params.method !== "GET") {
|
|
75
92
|
headers["Content-Type"] = "application/json";
|
|
@@ -78,21 +95,12 @@ export class XcshApiTool implements AgentTool<typeof xcshApiSchema, XcshApiToolD
|
|
|
78
95
|
|
|
79
96
|
try {
|
|
80
97
|
const response = await fetch(url, init);
|
|
81
|
-
const
|
|
82
|
-
let bodyText: string;
|
|
83
|
-
|
|
84
|
-
if (contentType.includes("application/json")) {
|
|
85
|
-
const json = await response.json();
|
|
86
|
-
bodyText = JSON.stringify(json, null, 2);
|
|
87
|
-
} else {
|
|
88
|
-
bodyText = await response.text();
|
|
89
|
-
}
|
|
90
|
-
|
|
98
|
+
const bodyText = await response.text();
|
|
91
99
|
const statusLine = `${response.status} ${response.statusText}`;
|
|
92
100
|
|
|
93
101
|
return {
|
|
94
102
|
content: [{ type: "text", text: `${statusLine}\n\n${bodyText}` }],
|
|
95
|
-
details: { status: response.status, url, method: params.method },
|
|
103
|
+
details: { status: response.status, url, method: params.method, requestId },
|
|
96
104
|
...(response.status >= 400 ? { isError: true } : {}),
|
|
97
105
|
};
|
|
98
106
|
} catch (err) {
|