@f5-sales-demo/xcsh 19.81.0 → 19.81.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 +8 -8
- package/src/browser/capabilities.generated.ts +25 -2
- package/src/browser/capabilities.json +9 -1
- package/src/browser/chat-conformance.json +1 -1
- package/src/browser/extension-bridge.ts +52 -6
- package/src/browser/headless-bridge.ts +8 -2
- package/src/browser/host-profiles.ts +16 -8
- package/src/commands/worker.ts +3 -0
- package/src/internal-urls/build-info.generated.ts +8 -8
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@f5-sales-demo/xcsh",
|
|
4
|
-
"version": "19.81.
|
|
4
|
+
"version": "19.81.1",
|
|
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.81.
|
|
60
|
-
"@f5-sales-demo/pi-agent-core": "19.81.
|
|
61
|
-
"@f5-sales-demo/pi-ai": "19.81.
|
|
62
|
-
"@f5-sales-demo/pi-natives": "19.81.
|
|
63
|
-
"@f5-sales-demo/pi-resource-management": "19.81.
|
|
64
|
-
"@f5-sales-demo/pi-tui": "19.81.
|
|
65
|
-
"@f5-sales-demo/pi-utils": "19.81.
|
|
59
|
+
"@f5-sales-demo/xcsh-stats": "19.81.1",
|
|
60
|
+
"@f5-sales-demo/pi-agent-core": "19.81.1",
|
|
61
|
+
"@f5-sales-demo/pi-ai": "19.81.1",
|
|
62
|
+
"@f5-sales-demo/pi-natives": "19.81.1",
|
|
63
|
+
"@f5-sales-demo/pi-resource-management": "19.81.1",
|
|
64
|
+
"@f5-sales-demo/pi-tui": "19.81.1",
|
|
65
|
+
"@f5-sales-demo/pi-utils": "19.81.1",
|
|
66
66
|
"@sinclair/typebox": "^0.34",
|
|
67
67
|
"@xterm/headless": "^6.0",
|
|
68
68
|
"ajv": "^8.20",
|
|
@@ -26,7 +26,7 @@ export interface ExtensionCapabilities {
|
|
|
26
26
|
|
|
27
27
|
export const EXTENSION_CAPABILITIES: ExtensionCapabilities = {
|
|
28
28
|
"version": "0.1.0",
|
|
29
|
-
"contractVersion": "1.
|
|
29
|
+
"contractVersion": "1.11.0",
|
|
30
30
|
"multiPortDiscovery": true,
|
|
31
31
|
"protocol": "tool_request/result",
|
|
32
32
|
"tools": [
|
|
@@ -786,6 +786,29 @@ export const EXTENSION_CAPABILITIES: ExtensionCapabilities = {
|
|
|
786
786
|
}
|
|
787
787
|
],
|
|
788
788
|
"features": {
|
|
789
|
+
"handshake": {
|
|
790
|
+
"serveKind": [
|
|
791
|
+
"office",
|
|
792
|
+
"browser"
|
|
793
|
+
],
|
|
794
|
+
"officePortRange": [
|
|
795
|
+
19242,
|
|
796
|
+
19261
|
|
797
|
+
],
|
|
798
|
+
"officeWssPortRange": [
|
|
799
|
+
19342,
|
|
800
|
+
19361
|
|
801
|
+
],
|
|
802
|
+
"browserPortRange": [
|
|
803
|
+
19222,
|
|
804
|
+
19241
|
|
805
|
+
],
|
|
806
|
+
"browserWssPortRange": [
|
|
807
|
+
19322,
|
|
808
|
+
19341
|
|
809
|
+
],
|
|
810
|
+
"description": "hello_ack advertises serveKind — how the bridge was STARTED (office-serve vs Chrome worker), distinct from the client's announced host. `xcsh office serve` binds the dedicated office port range and advertises serveKind:\"office\"; the Chrome worker binds the browser range and advertises \"browser\". The Office pane scans only the office wss range AND filters on serveKind:\"office\", so it can never adopt a Chrome worker (a serveKind absent/null is treated as ineligible)."
|
|
811
|
+
},
|
|
789
812
|
"explainMode": {
|
|
790
813
|
"tool": "set_explain_mode",
|
|
791
814
|
"default": false,
|
|
@@ -855,6 +878,6 @@ export const EXTENSION_CAPABILITIES: ExtensionCapabilities = {
|
|
|
855
878
|
}
|
|
856
879
|
};
|
|
857
880
|
|
|
858
|
-
export const EXTENSION_CONTRACT_VERSION = "1.
|
|
881
|
+
export const EXTENSION_CONTRACT_VERSION = "1.11.0";
|
|
859
882
|
|
|
860
883
|
export const EXTENSION_TOOL_NAMES: readonly string[] = ["ping","capabilities","reload","debug_exec","detach","set_bridge_port","navigate","login","scroll_to","resize_window","tabs_list","tabs_create","tabs_close","click","click_element","click_xy","type_text","form_input","key_press","select_option","label_select","file_upload","read_ax","get_page_text","query_dom","find","wait_for","assert_text","screenshot","read_console","read_network","diag_suspension","diag_bridges","diag_activation","diag_ttft","capture_login_flow","wait_for_api_response","get_page_context","javascript_tool","browser_batch","set_explain_mode","annotate"];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": "0.1.0",
|
|
3
|
-
"contractVersion": "1.
|
|
3
|
+
"contractVersion": "1.11.0",
|
|
4
4
|
"multiPortDiscovery": true,
|
|
5
5
|
"protocol": "tool_request/result",
|
|
6
6
|
"tools": [
|
|
@@ -703,6 +703,14 @@
|
|
|
703
703
|
}
|
|
704
704
|
],
|
|
705
705
|
"features": {
|
|
706
|
+
"handshake": {
|
|
707
|
+
"serveKind": ["office", "browser"],
|
|
708
|
+
"officePortRange": [19242, 19261],
|
|
709
|
+
"officeWssPortRange": [19342, 19361],
|
|
710
|
+
"browserPortRange": [19222, 19241],
|
|
711
|
+
"browserWssPortRange": [19322, 19341],
|
|
712
|
+
"description": "hello_ack advertises serveKind — how the bridge was STARTED (office-serve vs Chrome worker), distinct from the client's announced host. `xcsh office serve` binds the dedicated office port range and advertises serveKind:\"office\"; the Chrome worker binds the browser range and advertises \"browser\". The Office pane scans only the office wss range AND filters on serveKind:\"office\", so it can never adopt a Chrome worker (a serveKind absent/null is treated as ineligible)."
|
|
713
|
+
},
|
|
706
714
|
"explainMode": {
|
|
707
715
|
"tool": "set_explain_mode",
|
|
708
716
|
"default": false,
|
|
@@ -69,10 +69,37 @@ export function resolvePort(port?: number): number {
|
|
|
69
69
|
return DEFAULT_PORT;
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
/** Inclusive loopback discovery range for auto-selected bridge ports. */
|
|
72
|
+
/** Inclusive loopback discovery range for auto-selected bridge ports (Chrome worker). */
|
|
73
73
|
export const PORT_RANGE_START = 19222;
|
|
74
74
|
export const PORT_RANGE_END = 19241;
|
|
75
75
|
|
|
76
|
+
/**
|
|
77
|
+
* Dedicated loopback ws range for `xcsh office serve` bridges — DISJOINT from the
|
|
78
|
+
* Chrome worker range above. Its paired wss listeners land at +{@link WSS_PORT_OFFSET}
|
|
79
|
+
* (19342–19361). Giving office-serve its own range means a Chrome worker and an
|
|
80
|
+
* office bridge can never contend for a port, so the office pane (which scans only
|
|
81
|
+
* the office wss range) can never adopt a Chrome worker. The Chrome fleet's range
|
|
82
|
+
* is UNCHANGED — zero blast radius on browser automation.
|
|
83
|
+
*/
|
|
84
|
+
export const OFFICE_PORT_RANGE_START = 19242;
|
|
85
|
+
export const OFFICE_PORT_RANGE_END = 19261;
|
|
86
|
+
|
|
87
|
+
/** An inclusive port range for auto-select. */
|
|
88
|
+
export interface PortRange {
|
|
89
|
+
start: number;
|
|
90
|
+
end: number;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** The Chrome-worker auto-select range (the default). */
|
|
94
|
+
export const CHROME_PORT_RANGE: PortRange = { start: PORT_RANGE_START, end: PORT_RANGE_END };
|
|
95
|
+
|
|
96
|
+
/** The office-serve auto-select range. */
|
|
97
|
+
export const OFFICE_PORT_RANGE: PortRange = { start: OFFICE_PORT_RANGE_START, end: OFFICE_PORT_RANGE_END };
|
|
98
|
+
|
|
99
|
+
/** How a bridge was STARTED — its intrinsic scope (distinct from the connecting
|
|
100
|
+
* client's announced host). Echoed in hello_ack so the office pane can filter. */
|
|
101
|
+
export type ServeKind = "office" | "browser";
|
|
102
|
+
|
|
76
103
|
/**
|
|
77
104
|
* Fixed offset from a bound ws port to its paired `wss` port. The wss listener is
|
|
78
105
|
* ADDITIVE: when the bridge binds ws port P (in {@link PORT_RANGE_START}–{@link
|
|
@@ -140,12 +167,14 @@ export interface BridgeListenOpts {
|
|
|
140
167
|
skipOriginCheck?: boolean;
|
|
141
168
|
/** When present, an additive `wss` listener is started on port + {@link WSS_PORT_OFFSET}. */
|
|
142
169
|
tls?: BridgeTls;
|
|
170
|
+
/** Auto-select range for {@link startBridgeServer}; defaults to {@link CHROME_PORT_RANGE}. */
|
|
171
|
+
range?: PortRange;
|
|
143
172
|
}
|
|
144
173
|
|
|
145
|
-
/** Every port in the
|
|
146
|
-
export function portCandidates(): number[] {
|
|
174
|
+
/** Every port in the given range (default {@link CHROME_PORT_RANGE}), lowest first. */
|
|
175
|
+
export function portCandidates(range: PortRange = CHROME_PORT_RANGE): number[] {
|
|
147
176
|
const out: number[] = [];
|
|
148
|
-
for (let p =
|
|
177
|
+
for (let p = range.start; p <= range.end; p++) out.push(p);
|
|
149
178
|
return out;
|
|
150
179
|
}
|
|
151
180
|
|
|
@@ -181,6 +210,10 @@ export class BridgeServer {
|
|
|
181
210
|
/** The client host learned from the `hello` handshake (null until a client
|
|
182
211
|
* announces one; the Chrome extension omits it → stays null → chrome profile). */
|
|
183
212
|
#clientHost: ClientHost | null = null;
|
|
213
|
+
/** How THIS bridge was started (its intrinsic scope). Defaults to "browser" (the
|
|
214
|
+
* Chrome worker); office-serve calls {@link setServeKind}("office"). Echoed in
|
|
215
|
+
* hello_ack so the office pane's discovery filter never adopts a Chrome worker. */
|
|
216
|
+
#serveKind: ServeKind = "browser";
|
|
184
217
|
/** Provider of this process's tenant identity, answering the `hello` handshake. */
|
|
185
218
|
#sessionInfo:
|
|
186
219
|
| (() => {
|
|
@@ -213,6 +246,17 @@ export class BridgeServer {
|
|
|
213
246
|
return this.#clientHost;
|
|
214
247
|
}
|
|
215
248
|
|
|
249
|
+
/** How this bridge was started ("browser" by default; "office" for office-serve). */
|
|
250
|
+
get serveKind(): ServeKind {
|
|
251
|
+
return this.#serveKind;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/** Declare this bridge's intrinsic scope. Called once at startup by the host
|
|
255
|
+
* bootstrap (office-serve → "office"; the Chrome worker → "browser"). */
|
|
256
|
+
setServeKind(kind: ServeKind): void {
|
|
257
|
+
this.#serveKind = kind;
|
|
258
|
+
}
|
|
259
|
+
|
|
216
260
|
/** Number of connected extension clients (channels). */
|
|
217
261
|
get connectedCount(): number {
|
|
218
262
|
return this.#clients.size;
|
|
@@ -412,6 +456,7 @@ export class BridgeServer {
|
|
|
412
456
|
apiUrl: info.apiUrl,
|
|
413
457
|
contextBound: info.contextBound,
|
|
414
458
|
host: this.#clientHost,
|
|
459
|
+
serveKind: this.#serveKind,
|
|
415
460
|
pid: process.pid,
|
|
416
461
|
wssPort: this.wssPort,
|
|
417
462
|
canConfigureProvider: true,
|
|
@@ -488,8 +533,9 @@ export async function startBridgeServer(port?: number, opts?: BridgeListenOpts):
|
|
|
488
533
|
}
|
|
489
534
|
return server;
|
|
490
535
|
}
|
|
491
|
-
|
|
536
|
+
const range = opts?.range ?? CHROME_PORT_RANGE;
|
|
537
|
+
for (const candidate of portCandidates(range)) {
|
|
492
538
|
if (server.listen(candidate, opts)) return server;
|
|
493
539
|
}
|
|
494
|
-
throw new Error(`no free xcsh bridge port in ${
|
|
540
|
+
throw new Error(`no free xcsh bridge port in ${range.start}-${range.end} — is another app on the range?`);
|
|
495
541
|
}
|
|
@@ -20,7 +20,7 @@ import { ContextService } from "../services/xcsh-context";
|
|
|
20
20
|
import { deriveTenantEnv } from "../services/xcsh-env";
|
|
21
21
|
import { resolveBridgeTls } from "./bridge-cert";
|
|
22
22
|
import { ChatHandler } from "./chat-handler";
|
|
23
|
-
import { type BridgeServer, startBridgeServer } from "./extension-bridge";
|
|
23
|
+
import { type BridgeServer, OFFICE_PORT_RANGE, startBridgeServer } from "./extension-bridge";
|
|
24
24
|
import { OFFICE_TOOL_NAMES } from "./extension-bridge-tools";
|
|
25
25
|
import { setSharedBridgeServer } from "./provider";
|
|
26
26
|
|
|
@@ -110,7 +110,13 @@ export async function startHeadlessChatBridge(deps: HeadlessBridgeDeps = default
|
|
|
110
110
|
// Provision the wss cert before binding (warm boot = on-disk cache hit);
|
|
111
111
|
// `undefined` (offline) → the bridge starts ws-only.
|
|
112
112
|
const tls = await deps.resolveBridgeTls();
|
|
113
|
-
|
|
113
|
+
// Office-serve binds the DEDICATED office range (disjoint from the Chrome worker
|
|
114
|
+
// range) so the two can never collide on a port.
|
|
115
|
+
const bridge = await deps.startBridgeServer(undefined, { ...(tls ? { tls } : {}), range: OFFICE_PORT_RANGE });
|
|
116
|
+
// Advertise this bridge's intrinsic scope UNCONDITIONALLY so the office pane's
|
|
117
|
+
// discovery filter (requireServeKind:"office") can adopt it and never a Chrome
|
|
118
|
+
// worker — the starvation-guard the port-isolation UAT pins.
|
|
119
|
+
bridge.setServeKind("office");
|
|
114
120
|
// Reuse this bridge for any in-process selectProvider() (no conflicting second bridge).
|
|
115
121
|
deps.setSharedBridgeServer(bridge);
|
|
116
122
|
bridge.setSessionInfo(sessionInfoForOfficeServe);
|
|
@@ -45,7 +45,8 @@ export interface HostProfile {
|
|
|
45
45
|
* chat (not the CLI TUI). Tells the LLM it's in a Chrome side panel alongside the
|
|
46
46
|
* F5 XC console, what tools it has, and how to behave differently from the CLI.
|
|
47
47
|
*/
|
|
48
|
-
export const CHROME_CHAT_SYSTEM_PROMPT =
|
|
48
|
+
export const CHROME_CHAT_SYSTEM_PROMPT = `<system-directive>
|
|
49
|
+
You are still xcsh, the F5 Distributed Cloud technical coworker defined in your role above; this session is a Chrome side panel alongside the F5 XC console — an additional surface, not a new identity. Keep your xcsh/F5 purpose and adopt this browser context on top of it.
|
|
49
50
|
|
|
50
51
|
CRITICAL: ALWAYS respond with TEXT FIRST. Do NOT jump straight to tool calls. The user sees a chat panel and expects a conversational text response, not silence while tools run in the background. For questions ("what page am I on?", "what is this?"), answer with text using the page context below — no tools needed. Only use tools when the user explicitly asks you to DO something (create, navigate, click, modify).
|
|
51
52
|
|
|
@@ -79,7 +80,8 @@ SAFETY — NEVER DO THESE:
|
|
|
79
80
|
- NEVER kill, stop, or manage processes on port 19222 — that is YOUR OWN bridge. Killing it kills you.
|
|
80
81
|
- NEVER run lsof, fuser, kill, or pkill on the bridge port. You ARE the bridge.
|
|
81
82
|
- NEVER use bash/shell tools to manage xcsh processes, ports, or the debugger connection.
|
|
82
|
-
- NEVER run commands that would terminate your own process or the WebSocket server.
|
|
83
|
+
- NEVER run commands that would terminate your own process or the WebSocket server.
|
|
84
|
+
</system-directive>
|
|
83
85
|
|
|
84
86
|
`;
|
|
85
87
|
|
|
@@ -88,7 +90,8 @@ SAFETY — NEVER DO THESE:
|
|
|
88
90
|
* via host tools (arriving at runtime over the bridge), thinking in cells,
|
|
89
91
|
* ranges, and formula dependencies.
|
|
90
92
|
*/
|
|
91
|
-
const EXCEL_CHAT_SYSTEM_PROMPT =
|
|
93
|
+
const EXCEL_CHAT_SYSTEM_PROMPT = `<system-directive>
|
|
94
|
+
You are still xcsh, the F5 Distributed Cloud technical coworker defined in your role above. This session reaches you through a Microsoft Excel task pane instead of the terminal — an additional surface, not a new identity. Help the F5 SE with the OPEN workbook (often demo data, MEDDPICC sheets, account plans, pricing models) using the Excel host tools available to you. Keep your xcsh/F5 purpose AND adopt the Excel context on top of it.
|
|
92
95
|
|
|
93
96
|
CRITICAL: ALWAYS respond with TEXT FIRST — the user sees a chat pane and expects a conversational reply, not silence while tools run. Answer questions from the data you read; only WRITE to the workbook when the user asks you to.
|
|
94
97
|
|
|
@@ -106,7 +109,8 @@ TOOLS: Discover the workbook before you answer, then reach for the tool that mat
|
|
|
106
109
|
BEHAVIOR:
|
|
107
110
|
- Respond concisely with markdown. The task pane is narrow — avoid long code blocks.
|
|
108
111
|
- Read the workbook to answer questions about its data; do not guess.
|
|
109
|
-
- Make edits only when asked, one clear change at a time, and say what you changed and where.
|
|
112
|
+
- Make edits only when asked, one clear change at a time, and say what you changed and where.
|
|
113
|
+
</system-directive>
|
|
110
114
|
|
|
111
115
|
`;
|
|
112
116
|
|
|
@@ -114,7 +118,8 @@ BEHAVIOR:
|
|
|
114
118
|
* PowerPoint task-pane self-awareness prompt. The assistant works the OPEN
|
|
115
119
|
* presentation via host tools, thinking in slides, shapes, and the slide master.
|
|
116
120
|
*/
|
|
117
|
-
const POWERPOINT_CHAT_SYSTEM_PROMPT =
|
|
121
|
+
const POWERPOINT_CHAT_SYSTEM_PROMPT = `<system-directive>
|
|
122
|
+
You are still xcsh, the F5 Distributed Cloud technical coworker defined in your role above. This session reaches you through a Microsoft PowerPoint task pane instead of the terminal — an additional surface, not a new identity. Help the F5 SE with the OPEN presentation (often a customer deck, demo walkthrough, or QBR) using the PowerPoint host tools available to you. Keep your xcsh/F5 purpose AND adopt the PowerPoint context on top of it.
|
|
118
123
|
|
|
119
124
|
CRITICAL: ALWAYS respond with TEXT FIRST — the user sees a chat pane and expects a conversational reply, not silence while tools run. Answer questions from what you read; only edit the deck when the user asks you to.
|
|
120
125
|
|
|
@@ -131,7 +136,8 @@ TOOLS: Discover the deck before you answer, then reach for the tool that matches
|
|
|
131
136
|
BEHAVIOR:
|
|
132
137
|
- Respond concisely with markdown. The task pane is narrow — avoid long code blocks.
|
|
133
138
|
- Read the presentation to answer questions about it; do not guess.
|
|
134
|
-
- Make edits only when asked, one clear change at a time, and say which slide you changed.
|
|
139
|
+
- Make edits only when asked, one clear change at a time, and say which slide you changed.
|
|
140
|
+
</system-directive>
|
|
135
141
|
|
|
136
142
|
`;
|
|
137
143
|
|
|
@@ -140,7 +146,8 @@ BEHAVIOR:
|
|
|
140
146
|
* via host tools, thinking in paragraphs, the selection, comments, and tracked
|
|
141
147
|
* changes.
|
|
142
148
|
*/
|
|
143
|
-
const WORD_CHAT_SYSTEM_PROMPT =
|
|
149
|
+
const WORD_CHAT_SYSTEM_PROMPT = `<system-directive>
|
|
150
|
+
You are still xcsh, the F5 Distributed Cloud technical coworker defined in your role above. This session reaches you through a Microsoft Word task pane instead of the terminal — an additional surface, not a new identity. Help the F5 SE with the OPEN document (often a proposal, SOW, discovery write-up, or technical brief) using the Word host tools available to you. Keep your xcsh/F5 purpose AND adopt the Word context on top of it.
|
|
144
151
|
|
|
145
152
|
CRITICAL: ALWAYS respond with TEXT FIRST — the user sees a chat pane and expects a conversational reply, not silence while tools run. Answer questions from what you read; only edit the document when the user asks you to.
|
|
146
153
|
|
|
@@ -158,7 +165,8 @@ TOOLS: Discover the document before you answer, then reach for the tool that mat
|
|
|
158
165
|
BEHAVIOR:
|
|
159
166
|
- Respond concisely with markdown. The task pane is narrow — avoid long code blocks.
|
|
160
167
|
- Read the document to answer questions about it; do not guess.
|
|
161
|
-
- Make edits only when asked, one clear change at a time, and say what you changed.
|
|
168
|
+
- Make edits only when asked, one clear change at a time, and say what you changed.
|
|
169
|
+
</system-directive>
|
|
162
170
|
|
|
163
171
|
`;
|
|
164
172
|
|
package/src/commands/worker.ts
CHANGED
|
@@ -152,6 +152,9 @@ export default class Worker extends Command {
|
|
|
152
152
|
`[xcsh worker] extension bridge listening on ws://127.0.0.1:${bridge.port}` +
|
|
153
153
|
(bridge.wssPort ? ` + wss://${LOCALIP_HOST}:${bridge.wssPort}` : ""),
|
|
154
154
|
);
|
|
155
|
+
// This is the Chrome-extension worker: advertise "browser" so the office pane's
|
|
156
|
+
// serveKind filter never adopts it (explicit; "browser" is also the default).
|
|
157
|
+
bridge.setServeKind("browser");
|
|
155
158
|
setSharedBridgeServer(bridge);
|
|
156
159
|
bridge.setSessionInfo(sessionInfoForWorker);
|
|
157
160
|
ContextService.onContextChange(() => bridge.broadcastTenantChanged());
|
|
@@ -17,17 +17,17 @@ export interface BuildInfo {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export const BUILD_INFO: BuildInfo = {
|
|
20
|
-
"version": "19.81.
|
|
21
|
-
"commit": "
|
|
22
|
-
"shortCommit": "
|
|
20
|
+
"version": "19.81.1",
|
|
21
|
+
"commit": "27b80e6050da531bf6f3b60628a89cc63d92cc66",
|
|
22
|
+
"shortCommit": "27b80e6",
|
|
23
23
|
"branch": "main",
|
|
24
|
-
"tag": "v19.81.
|
|
25
|
-
"commitDate": "2026-07-23T07:
|
|
26
|
-
"buildDate": "2026-07-
|
|
24
|
+
"tag": "v19.81.1",
|
|
25
|
+
"commitDate": "2026-07-23T07:58:54Z",
|
|
26
|
+
"buildDate": "2026-07-23T08:35:35.676Z",
|
|
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.81.
|
|
31
|
+
"commitUrl": "https://github.com/f5-sales-demo/xcsh/commit/27b80e6050da531bf6f3b60628a89cc63d92cc66",
|
|
32
|
+
"releaseUrl": "https://github.com/f5-sales-demo/xcsh/releases/tag/v19.81.1"
|
|
33
33
|
};
|