@f5xc-salesdemos/xcsh 18.26.0 → 18.27.1
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.
|
|
4
|
+
"version": "18.27.1",
|
|
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",
|
|
@@ -47,12 +47,12 @@
|
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"@agentclientprotocol/sdk": "0.16.1",
|
|
49
49
|
"@mozilla/readability": "^0.6",
|
|
50
|
-
"@f5xc-salesdemos/xcsh-stats": "18.
|
|
51
|
-
"@f5xc-salesdemos/pi-agent-core": "18.
|
|
52
|
-
"@f5xc-salesdemos/pi-ai": "18.
|
|
53
|
-
"@f5xc-salesdemos/pi-natives": "18.
|
|
54
|
-
"@f5xc-salesdemos/pi-tui": "18.
|
|
55
|
-
"@f5xc-salesdemos/pi-utils": "18.
|
|
50
|
+
"@f5xc-salesdemos/xcsh-stats": "18.27.1",
|
|
51
|
+
"@f5xc-salesdemos/pi-agent-core": "18.27.1",
|
|
52
|
+
"@f5xc-salesdemos/pi-ai": "18.27.1",
|
|
53
|
+
"@f5xc-salesdemos/pi-natives": "18.27.1",
|
|
54
|
+
"@f5xc-salesdemos/pi-tui": "18.27.1",
|
|
55
|
+
"@f5xc-salesdemos/pi-utils": "18.27.1",
|
|
56
56
|
"@sinclair/typebox": "^0.34",
|
|
57
57
|
"@xterm/headless": "^6.0",
|
|
58
58
|
"ajv": "^8.18",
|
|
@@ -17,17 +17,17 @@ export interface BuildInfo {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export const BUILD_INFO: BuildInfo = {
|
|
20
|
-
"version": "18.
|
|
21
|
-
"commit": "
|
|
22
|
-
"shortCommit": "
|
|
20
|
+
"version": "18.27.1",
|
|
21
|
+
"commit": "aa8bc582baa89e73ceb7b76059ac706556123411",
|
|
22
|
+
"shortCommit": "aa8bc58",
|
|
23
23
|
"branch": "main",
|
|
24
|
-
"tag": "v18.
|
|
25
|
-
"commitDate": "2026-04-
|
|
26
|
-
"buildDate": "2026-04-
|
|
24
|
+
"tag": "v18.27.1",
|
|
25
|
+
"commitDate": "2026-04-29T22:53:47Z",
|
|
26
|
+
"buildDate": "2026-04-29T23:15:51.283Z",
|
|
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.
|
|
31
|
+
"commitUrl": "https://github.com/f5xc-salesdemos/xcsh/commit/aa8bc582baa89e73ceb7b76059ac706556123411",
|
|
32
|
+
"releaseUrl": "https://github.com/f5xc-salesdemos/xcsh/releases/tag/v18.27.1"
|
|
33
33
|
};
|
|
@@ -14,7 +14,7 @@ const STARTUP_RETRY_DELAY_MS = 500;
|
|
|
14
14
|
|
|
15
15
|
type ContextValidator = (opts: {
|
|
16
16
|
timeoutMs: number;
|
|
17
|
-
}) => Promise<{ status: AuthStatus; latencyMs?: number; errorClass?: "network" | "credential" }>;
|
|
17
|
+
}) => Promise<{ status: AuthStatus; latencyMs?: number; errorClass?: "network" | "credential" | "url_not_found" }>;
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
20
|
* Runs the context validator once with a startup-sized timeout; if the result is `offline`
|
|
@@ -28,7 +28,7 @@ export async function validateContextWithStartupRetry(
|
|
|
28
28
|
retryTimeoutMs?: number;
|
|
29
29
|
retryDelayMs?: number;
|
|
30
30
|
},
|
|
31
|
-
): Promise<{ status: AuthStatus; latencyMs?: number }> {
|
|
31
|
+
): Promise<{ status: AuthStatus; latencyMs?: number; errorClass?: "network" | "credential" | "url_not_found" }> {
|
|
32
32
|
const firstTimeoutMs = options?.firstTimeoutMs ?? STARTUP_FIRST_TIMEOUT_MS;
|
|
33
33
|
const retryTimeoutMs = options?.retryTimeoutMs ?? STARTUP_RETRY_TIMEOUT_MS;
|
|
34
34
|
const retryDelayMs = options?.retryDelayMs ?? STARTUP_RETRY_DELAY_MS;
|
|
@@ -56,6 +56,7 @@ export interface WelcomeContextStatus {
|
|
|
56
56
|
state: ContextCheckState;
|
|
57
57
|
name?: string;
|
|
58
58
|
latencyMs?: number;
|
|
59
|
+
errorClass?: "network" | "credential" | "url_not_found";
|
|
59
60
|
}
|
|
60
61
|
|
|
61
62
|
export interface WelcomeCheckResult {
|
|
@@ -167,7 +168,7 @@ async function checkContextStatus(): Promise<WelcomeContextStatus> {
|
|
|
167
168
|
case "auth_error":
|
|
168
169
|
return { state: "auth_error", name };
|
|
169
170
|
case "offline":
|
|
170
|
-
return { state: "offline", name };
|
|
171
|
+
return { state: "offline", name, errorClass: result.errorClass };
|
|
171
172
|
default:
|
|
172
173
|
return { state: "no_context" };
|
|
173
174
|
}
|
|
@@ -232,6 +232,12 @@ export class WelcomeComponent implements Component {
|
|
|
232
232
|
` ${theme.fg("dim", "Run /context to update")}`,
|
|
233
233
|
];
|
|
234
234
|
case "offline":
|
|
235
|
+
if (this.contextStatus?.errorClass === "url_not_found") {
|
|
236
|
+
return [
|
|
237
|
+
` ${formatStatusIcon("error")} ${theme.fg("muted", n)} ${theme.fg("error", "\u2014 tenant not found")}`,
|
|
238
|
+
` ${theme.fg("dim", "Recreate with /context create or check with /context show")}`,
|
|
239
|
+
];
|
|
240
|
+
}
|
|
235
241
|
return [
|
|
236
242
|
` ${formatStatusIcon("warning")} ${theme.fg("muted", n)} ${theme.fg("warning", "\u2014 unreachable")}`,
|
|
237
243
|
` ${theme.fg("dim", "Check network, /context")}`,
|
|
@@ -114,7 +114,7 @@ export interface ValidationResult {
|
|
|
114
114
|
context: F5XCContext;
|
|
115
115
|
status: AuthStatus;
|
|
116
116
|
latencyMs?: number;
|
|
117
|
-
errorClass?: "network" | "credential";
|
|
117
|
+
errorClass?: "network" | "credential" | "url_not_found";
|
|
118
118
|
}
|
|
119
119
|
|
|
120
120
|
export class ContextError extends Error {
|
|
@@ -915,7 +915,7 @@ export class ContextService {
|
|
|
915
915
|
timeoutMs?: number;
|
|
916
916
|
apiUrl?: string;
|
|
917
917
|
apiToken?: string;
|
|
918
|
-
}): Promise<{ status: AuthStatus; latencyMs?: number; errorClass?: "network" | "credential" }> {
|
|
918
|
+
}): Promise<{ status: AuthStatus; latencyMs?: number; errorClass?: "network" | "credential" | "url_not_found" }> {
|
|
919
919
|
// Use explicit credentials if provided (for non-active contexts or env-backed sessions),
|
|
920
920
|
// otherwise fall back to effective credentials (env override > active context)
|
|
921
921
|
const effectiveUrl = options?.apiUrl ?? process.env[F5XC_API_URL] ?? this.#activeContext?.apiUrl;
|
|
@@ -946,13 +946,23 @@ export class ContextService {
|
|
|
946
946
|
method: "GET",
|
|
947
947
|
headers: { Authorization: `APIToken ${effectiveToken}`, Accept: "application/json" },
|
|
948
948
|
signal: AbortSignal.timeout(timeout),
|
|
949
|
+
redirect: "manual",
|
|
949
950
|
});
|
|
950
951
|
const latencyMs = Math.round(performance.now() - start);
|
|
951
952
|
if (!adHoc) {
|
|
952
953
|
this.#lastAuthLatencyMs = latencyMs;
|
|
953
954
|
this.#lastAuthCheckedAt = checkedAt;
|
|
954
955
|
}
|
|
956
|
+
if (response.type === "opaqueredirect" || (response.status >= 300 && response.status < 400)) {
|
|
957
|
+
if (!adHoc) this.#authStatus = "offline";
|
|
958
|
+
return { status: "offline", latencyMs, errorClass: "url_not_found" };
|
|
959
|
+
}
|
|
955
960
|
if (response.ok) {
|
|
961
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
962
|
+
if (!contentType.includes("application/json")) {
|
|
963
|
+
if (!adHoc) this.#authStatus = "offline";
|
|
964
|
+
return { status: "offline", latencyMs, errorClass: "url_not_found" };
|
|
965
|
+
}
|
|
956
966
|
if (!adHoc) this.#authStatus = "connected";
|
|
957
967
|
return { status: "connected", latencyMs };
|
|
958
968
|
}
|
|
@@ -23,7 +23,7 @@ const r = (s: string) => `${F5_RED}${s}${RESET}`;
|
|
|
23
23
|
export function formatAuthIndicator(
|
|
24
24
|
status: AuthStatus,
|
|
25
25
|
latencyMs?: number,
|
|
26
|
-
errorClass?: "network" | "credential",
|
|
26
|
+
errorClass?: "network" | "credential" | "url_not_found",
|
|
27
27
|
): string {
|
|
28
28
|
const ms = latencyMs !== undefined ? ` (${latencyMs}ms)` : "";
|
|
29
29
|
switch (status) {
|
|
@@ -32,6 +32,9 @@ export function formatAuthIndicator(
|
|
|
32
32
|
case "auth_error":
|
|
33
33
|
return `${formatStatusIcon("error")} Auth Error — check token${ms}`;
|
|
34
34
|
case "offline":
|
|
35
|
+
if (errorClass === "url_not_found") {
|
|
36
|
+
return `${formatStatusIcon("error")} Offline — tenant URL not found${ms}`;
|
|
37
|
+
}
|
|
35
38
|
return `${formatStatusIcon("warning")} Offline — ${errorClass === "credential" ? "auth issue" : "network issue"}${ms}`;
|
|
36
39
|
default:
|
|
37
40
|
return `${formatStatusIcon("unknown")} Unknown`;
|