@f5xc-salesdemos/xcsh 18.77.3 → 18.77.5
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 +7 -7
- package/src/internal-urls/api-catalog-resolve.ts +6 -0
- package/src/internal-urls/build-info.generated.ts +8 -8
- package/src/modes/components/assistant-message.ts +7 -4
- package/src/modes/controllers/event-controller.ts +3 -0
- package/src/prompts/system/system-prompt.md +2 -0
- package/src/tools/xcsh-api.ts +29 -2
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@f5xc-salesdemos/xcsh",
|
|
4
|
-
"version": "18.77.
|
|
4
|
+
"version": "18.77.5",
|
|
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.77.
|
|
52
|
-
"@f5xc-salesdemos/pi-agent-core": "18.77.
|
|
53
|
-
"@f5xc-salesdemos/pi-ai": "18.77.
|
|
54
|
-
"@f5xc-salesdemos/pi-natives": "18.77.
|
|
55
|
-
"@f5xc-salesdemos/pi-tui": "18.77.
|
|
56
|
-
"@f5xc-salesdemos/pi-utils": "18.77.
|
|
51
|
+
"@f5xc-salesdemos/xcsh-stats": "18.77.5",
|
|
52
|
+
"@f5xc-salesdemos/pi-agent-core": "18.77.5",
|
|
53
|
+
"@f5xc-salesdemos/pi-ai": "18.77.5",
|
|
54
|
+
"@f5xc-salesdemos/pi-natives": "18.77.5",
|
|
55
|
+
"@f5xc-salesdemos/pi-tui": "18.77.5",
|
|
56
|
+
"@f5xc-salesdemos/pi-utils": "18.77.5",
|
|
57
57
|
"@sinclair/typebox": "^0.34",
|
|
58
58
|
"@xterm/headless": "^6.0",
|
|
59
59
|
"ajv": "^8.18",
|
|
@@ -249,6 +249,12 @@ function renderCatalogDetail(cat: ApiCatalogCategory, index: ApiCatalogIndex, op
|
|
|
249
249
|
sections.push(`Required fields: ${op.minimumPayload.requiredFields.join(", ")}`);
|
|
250
250
|
sections.push("", "```json", JSON.stringify(op.minimumPayload.json, null, 2), "```");
|
|
251
251
|
}
|
|
252
|
+
// Universal reference format hint — shown even in compact mode
|
|
253
|
+
if (op.method.toUpperCase() === "POST" || op.method.toUpperCase() === "PUT") {
|
|
254
|
+
sections.push(
|
|
255
|
+
'Object references: `{"namespace": "$F5XC_NAMESPACE", "name": "<name>"}`. Pool arrays: `[{"pool": {"namespace": "$F5XC_NAMESPACE", "name": "<name>"}, "weight": 1, "priority": 1}]`.',
|
|
256
|
+
);
|
|
257
|
+
}
|
|
252
258
|
|
|
253
259
|
// Field Constraints (Tier 2) — skipped in compact mode, deduped when identical across operations
|
|
254
260
|
if (op.fieldMetadata && Object.keys(op.fieldMetadata).length > 0 && !options?.compact) {
|
|
@@ -17,17 +17,17 @@ export interface BuildInfo {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export const BUILD_INFO: BuildInfo = {
|
|
20
|
-
"version": "18.77.
|
|
21
|
-
"commit": "
|
|
22
|
-
"shortCommit": "
|
|
20
|
+
"version": "18.77.5",
|
|
21
|
+
"commit": "9d5df6ccedc2df7a8dfd59c21489a8b208804e27",
|
|
22
|
+
"shortCommit": "9d5df6c",
|
|
23
23
|
"branch": "main",
|
|
24
|
-
"tag": "v18.77.
|
|
25
|
-
"commitDate": "2026-05-
|
|
26
|
-
"buildDate": "2026-05-
|
|
24
|
+
"tag": "v18.77.5",
|
|
25
|
+
"commitDate": "2026-05-24T00:50:34Z",
|
|
26
|
+
"buildDate": "2026-05-24T01:18:57.755Z",
|
|
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/
|
|
32
|
-
"releaseUrl": "https://github.com/f5xc-salesdemos/xcsh/releases/tag/v18.77.
|
|
31
|
+
"commitUrl": "https://github.com/f5xc-salesdemos/xcsh/commit/9d5df6ccedc2df7a8dfd59c21489a8b208804e27",
|
|
32
|
+
"releaseUrl": "https://github.com/f5xc-salesdemos/xcsh/releases/tag/v18.77.5"
|
|
33
33
|
};
|
|
@@ -146,10 +146,13 @@ export class AssistantMessageComponent extends Container {
|
|
|
146
146
|
.some(c => (c.type === "text" && c.text.trim()) || (c.type === "thinking" && c.thinking.trim()));
|
|
147
147
|
|
|
148
148
|
if (this.hideThinkingBlock) {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
149
|
+
if (!message.stopReason) {
|
|
150
|
+
this.#contentContainer.addChild(
|
|
151
|
+
new Text(theme.italic(theme.fg("thinkingText", "Thinking...")), 0, 0),
|
|
152
|
+
);
|
|
153
|
+
if (hasVisibleContentAfter) {
|
|
154
|
+
this.#contentContainer.addChild(new Spacer(1));
|
|
155
|
+
}
|
|
153
156
|
}
|
|
154
157
|
} else {
|
|
155
158
|
// Thinking traces in thinkingText color, italic
|
|
@@ -240,6 +240,9 @@ export class EventController {
|
|
|
240
240
|
? { ...content.arguments, __partialJson: content.partialJson }
|
|
241
241
|
: content.arguments;
|
|
242
242
|
if (!this.ctx.pendingTools.has(content.id)) {
|
|
243
|
+
if (content.name === "todo_write" && !settings.get("todo.verbose")) {
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
243
246
|
this.#resetReadGroup();
|
|
244
247
|
this.ctx.chatContainer.addChild(new Spacer(1));
|
|
245
248
|
const tool = this.ctx.session.getToolByName(content.name);
|
|
@@ -263,6 +263,8 @@ Most tools resolve custom protocol URLs to internal resources (not web URLs):
|
|
|
263
263
|
Do not issue a follow-up GET to verify — the response body is the verification.
|
|
264
264
|
Only issue a GET if the user explicitly asks to read current state, or if the
|
|
265
265
|
initial call returned a non-2xx status.
|
|
266
|
+
For xcsh_api mutations, the 200 response satisfies the "verify the effect" requirement — do not GET the resource again.
|
|
267
|
+
For CREATE, you **MUST NOT** GET referenced dependencies (origin pools, firewalls) to verify they exist — include them by name. For UPDATE, GET the target resource for its current spec, but you **MUST NOT** GET other referenced resources.
|
|
266
268
|
|
|
267
269
|
**Namespace discovery** — when the user asks what resources exist in a namespace
|
|
268
270
|
(e.g. "what's in my namespace", "list everything configured", "show all resources"),
|
package/src/tools/xcsh-api.ts
CHANGED
|
@@ -502,7 +502,7 @@ export class XcshApiTool implements AgentTool<typeof xcshApiSchema, XcshApiToolD
|
|
|
502
502
|
}
|
|
503
503
|
|
|
504
504
|
sections.push(
|
|
505
|
-
"\nInventory complete.
|
|
505
|
+
"\nInventory complete. All listed resources exist and are valid references for mutations. No further API calls needed.",
|
|
506
506
|
);
|
|
507
507
|
const batchTotalItems = relevantData.reduce((sum, r) => sum + (r.itemCount ?? 0), 0);
|
|
508
508
|
const text = sections.join("\n");
|
|
@@ -546,7 +546,7 @@ export class XcshApiTool implements AgentTool<typeof xcshApiSchema, XcshApiToolD
|
|
|
546
546
|
return `Access denied${ctxHint}. The API token may lack the required role or permission for this operation. Check the token's role assignments in the F5 XC console.`;
|
|
547
547
|
case 404: {
|
|
548
548
|
const ns = process.env.F5XC_NAMESPACE ?? this.#contextEnv.get("F5XC_NAMESPACE") ?? "default";
|
|
549
|
-
return `Resource not found in namespace \`${ns}\`${ctxHint}.
|
|
549
|
+
return `Resource not found in namespace \`${ns}\`${ctxHint}. Verify the resource name, or use POST to create it.`;
|
|
550
550
|
}
|
|
551
551
|
case 409:
|
|
552
552
|
return `Resource already exists${ctxHint}. Use PUT to replace the existing resource, or DELETE it first before creating a new one.`;
|
|
@@ -701,6 +701,33 @@ export class XcshApiTool implements AgentTool<typeof xcshApiSchema, XcshApiToolD
|
|
|
701
701
|
}
|
|
702
702
|
return this.#errorResult(`${statusLine}\n\n${bodyText}\n\n${errorCodePrefix}${guidance}`, detail);
|
|
703
703
|
}
|
|
704
|
+
// Mutation stop signals + cache invalidation: reduce post-mutation verification GETs
|
|
705
|
+
if (response.status >= 200 && response.status < 300 && params.method !== "GET") {
|
|
706
|
+
// Invalidate batch cache so subsequent namespace queries reflect the mutation
|
|
707
|
+
const nsMatch = resolvedPath.match(/\/api\/config\/namespaces\/([^/]+)\//);
|
|
708
|
+
if (nsMatch?.[1]) {
|
|
709
|
+
const nsCachePath = `${os.tmpdir()}/xcsh-batch-${nsMatch[1]}.json`;
|
|
710
|
+
await Bun.write(nsCachePath, JSON.stringify({ ts: 0 })).catch(() => {});
|
|
711
|
+
}
|
|
712
|
+
// Append stop signal to prevent unnecessary verification GETs
|
|
713
|
+
const verb = params.method === "DELETE" ? "Deleted" : params.method === "POST" ? "Created" : "Updated";
|
|
714
|
+
// POST returns the full resource; PUT/DELETE return {}.
|
|
715
|
+
// Only claim response contains the resource for POST to avoid misleading the model.
|
|
716
|
+
const resourceHint =
|
|
717
|
+
params.method === "POST"
|
|
718
|
+
? "The response above contains the complete resource. No verification GET is needed. Reference this resource by name in subsequent mutations immediately."
|
|
719
|
+
: "No verification GET is needed.";
|
|
720
|
+
|
|
721
|
+
return {
|
|
722
|
+
content: [
|
|
723
|
+
{
|
|
724
|
+
type: "text",
|
|
725
|
+
text: `${statusLine}\n\n${bodyText}\n\n${verb} ${resolvedPath} successfully. ${resourceHint}`,
|
|
726
|
+
},
|
|
727
|
+
],
|
|
728
|
+
details: detail,
|
|
729
|
+
};
|
|
730
|
+
}
|
|
704
731
|
|
|
705
732
|
return {
|
|
706
733
|
content: [{ type: "text", text: `${statusLine}\n\n${bodyText}` }],
|