@f5-sales-demo/xcsh 19.58.1 → 19.58.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": "@f5-sales-demo/xcsh",
|
|
4
|
-
"version": "19.58.
|
|
4
|
+
"version": "19.58.3",
|
|
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",
|
|
@@ -55,13 +55,13 @@
|
|
|
55
55
|
"dependencies": {
|
|
56
56
|
"@agentclientprotocol/sdk": "0.16.1",
|
|
57
57
|
"@mozilla/readability": "^0.6",
|
|
58
|
-
"@f5-sales-demo/xcsh-stats": "19.58.
|
|
59
|
-
"@f5-sales-demo/pi-agent-core": "19.58.
|
|
60
|
-
"@f5-sales-demo/pi-ai": "19.58.
|
|
61
|
-
"@f5-sales-demo/pi-natives": "19.58.
|
|
62
|
-
"@f5-sales-demo/pi-resource-management": "19.58.
|
|
63
|
-
"@f5-sales-demo/pi-tui": "19.58.
|
|
64
|
-
"@f5-sales-demo/pi-utils": "19.58.
|
|
58
|
+
"@f5-sales-demo/xcsh-stats": "19.58.3",
|
|
59
|
+
"@f5-sales-demo/pi-agent-core": "19.58.3",
|
|
60
|
+
"@f5-sales-demo/pi-ai": "19.58.3",
|
|
61
|
+
"@f5-sales-demo/pi-natives": "19.58.3",
|
|
62
|
+
"@f5-sales-demo/pi-resource-management": "19.58.3",
|
|
63
|
+
"@f5-sales-demo/pi-tui": "19.58.3",
|
|
64
|
+
"@f5-sales-demo/pi-utils": "19.58.3",
|
|
65
65
|
"@sinclair/typebox": "^0.34",
|
|
66
66
|
"@xterm/headless": "^6.0",
|
|
67
67
|
"ajv": "^8.20",
|
package/src/commands/worker.ts
CHANGED
|
@@ -23,7 +23,7 @@ import { initializeWithSettings } from "../discovery";
|
|
|
23
23
|
import { createAgentSession } from "../sdk";
|
|
24
24
|
import { activateTenantContext } from "../services/session-context-binding";
|
|
25
25
|
import { ContextService } from "../services/xcsh-context";
|
|
26
|
-
import {
|
|
26
|
+
import { deriveTenantEnv } from "../services/xcsh-env";
|
|
27
27
|
|
|
28
28
|
/** Mutable worker identity. Seeded from env at spawn (backward compat); replaced by a
|
|
29
29
|
* late IPC bind on a pre-warmed spare. `null` fields fall back to env, then the "spare"
|
|
@@ -64,17 +64,13 @@ export function sessionInfoForWorker(): {
|
|
|
64
64
|
/* ContextService not initialized — fall through to the tenant key; contextBound stays false. */
|
|
65
65
|
}
|
|
66
66
|
apiUrl = apiUrl ?? process.env.XCSH_API_URL ?? null;
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
const [tenant, env] = raw.split("|");
|
|
75
|
-
return { tenant: tenant || null, env: env || null, apiUrl: null, contextBound, sessionId };
|
|
76
|
-
}
|
|
77
|
-
return { tenant: null, env: null, apiUrl: null, contextBound, sessionId };
|
|
67
|
+
// Prefer the apiUrl-derived key (active context wins), but fall back to the
|
|
68
|
+
// tenant this worker was assigned (IPC bind or spawn env) so an apiUrl whose
|
|
69
|
+
// host we can't parse never blanks a KNOWN tenant — which would make the
|
|
70
|
+
// extension drop the bridge and show "No xcsh running for this tenant" (#1872).
|
|
71
|
+
const tenantKey = boundIdentity?.tenantKey ?? process.env.XCSH_SESSION_TENANT ?? null;
|
|
72
|
+
const { tenant, env } = deriveTenantEnv(apiUrl, tenantKey);
|
|
73
|
+
return { tenant, env, apiUrl, contextBound, sessionId };
|
|
78
74
|
}
|
|
79
75
|
|
|
80
76
|
/** Browser-automation tool set — identical scoping to `main.ts`'s extension path.
|
|
@@ -17,17 +17,17 @@ export interface BuildInfo {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export const BUILD_INFO: BuildInfo = {
|
|
20
|
-
"version": "19.58.
|
|
21
|
-
"commit": "
|
|
22
|
-
"shortCommit": "
|
|
20
|
+
"version": "19.58.3",
|
|
21
|
+
"commit": "1e0e9e203ce3f95f2e4bb1069f4371d9b7529e91",
|
|
22
|
+
"shortCommit": "1e0e9e2",
|
|
23
23
|
"branch": "main",
|
|
24
|
-
"tag": "v19.58.
|
|
25
|
-
"commitDate": "2026-07-
|
|
26
|
-
"buildDate": "2026-07-
|
|
24
|
+
"tag": "v19.58.3",
|
|
25
|
+
"commitDate": "2026-07-05T18:06:30Z",
|
|
26
|
+
"buildDate": "2026-07-05T18:27:55.948Z",
|
|
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.58.
|
|
31
|
+
"commitUrl": "https://github.com/f5-sales-demo/xcsh/commit/1e0e9e203ce3f95f2e4bb1069f4371d9b7529e91",
|
|
32
|
+
"releaseUrl": "https://github.com/f5-sales-demo/xcsh/releases/tag/v19.58.3"
|
|
33
33
|
};
|
package/src/main.ts
CHANGED
|
@@ -815,7 +815,7 @@ export async function runRootCommand(parsed: Args, rawArgs: string[]): Promise<v
|
|
|
815
815
|
// tenant), so the panel can lock its session and route per tenant.
|
|
816
816
|
{
|
|
817
817
|
const { ContextService } = await import("./services/xcsh-context");
|
|
818
|
-
const {
|
|
818
|
+
const { deriveTenantEnv } = await import("./services/xcsh-env");
|
|
819
819
|
const readInfo = () => {
|
|
820
820
|
let apiUrl: string | null = null;
|
|
821
821
|
let contextBound = false;
|
|
@@ -828,15 +828,13 @@ export async function runRootCommand(parsed: Args, rawArgs: string[]): Promise<v
|
|
|
828
828
|
}
|
|
829
829
|
// Fall back to the env override when no context is active (env-only mode).
|
|
830
830
|
apiUrl = apiUrl ?? process.env.XCSH_API_URL ?? null;
|
|
831
|
-
|
|
831
|
+
// Prefer the apiUrl-derived key; fall back to the assigned tenant key so an
|
|
832
|
+
// unparseable apiUrl never blanks a known tenant (#1872). Same contract as
|
|
833
|
+
// the worker path (sessionInfoForWorker).
|
|
834
|
+
const tenantKey = process.env.XCSH_SESSION_TENANT ?? null;
|
|
835
|
+
const { tenant, env } = deriveTenantEnv(apiUrl, tenantKey);
|
|
832
836
|
// Interactive path has no per-tab XCSH_SESSION_ID; workers echo one, this doesn't.
|
|
833
|
-
return {
|
|
834
|
-
tenant: key?.tenant ?? null,
|
|
835
|
-
env: key?.env ?? null,
|
|
836
|
-
apiUrl,
|
|
837
|
-
contextBound,
|
|
838
|
-
sessionId: null,
|
|
839
|
-
};
|
|
837
|
+
return { tenant, env, apiUrl, contextBound, sessionId: null };
|
|
840
838
|
};
|
|
841
839
|
bridgeServer.setSessionInfo(readInfo);
|
|
842
840
|
ContextService.onContextChange(() => bridgeServer?.broadcastTenantChanged());
|
package/src/services/xcsh-env.ts
CHANGED
|
@@ -128,6 +128,31 @@ export function sessionKeyFromUrl(url: string | undefined): SessionKey | null {
|
|
|
128
128
|
return null;
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
+
/**
|
|
132
|
+
* Resolve the `{tenant, env}` a worker advertises to the extension's `hello`
|
|
133
|
+
* handshake. Prefers the session key parsed from `apiUrl` (the live/active
|
|
134
|
+
* context is authoritative) but falls back to the worker's assigned tenant key
|
|
135
|
+
* (`"tenant|env"`, from `boundIdentity.tenantKey` / `XCSH_SESSION_TENANT`) when
|
|
136
|
+
* `apiUrl` is absent OR its host doesn't parse to a key.
|
|
137
|
+
*
|
|
138
|
+
* The fallback is load-bearing (#1872): the extension's `liveTenants` filter
|
|
139
|
+
* keeps a bridge only when BOTH `tenant` and `env` are set, so returning
|
|
140
|
+
* `{tenant:null, env:null}` for a worker that KNOWS its tenant (e.g. an
|
|
141
|
+
* activated context whose stored `apiUrl` isn't `<tenant>.console.ves.volterra.io`)
|
|
142
|
+
* silently drops the bridge and the panel shows "No xcsh running for this tenant".
|
|
143
|
+
*/
|
|
144
|
+
export function deriveTenantEnv(
|
|
145
|
+
apiUrl: string | null,
|
|
146
|
+
tenantKey: string | null | undefined,
|
|
147
|
+
): { tenant: string | null; env: string | null } {
|
|
148
|
+
const key = apiUrl ? sessionKeyFromUrl(apiUrl) : null;
|
|
149
|
+
const [assignedTenant, assignedEnv] = (tenantKey ?? "").split("|");
|
|
150
|
+
return {
|
|
151
|
+
tenant: key?.tenant ?? (assignedTenant || null),
|
|
152
|
+
env: key?.env ?? (assignedEnv || null),
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
|
|
131
156
|
/**
|
|
132
157
|
* Reduce an API URL to its origin (`https://host[:port]`) — the canonical stored
|
|
133
158
|
* form for a context endpoint.
|