@f5-sales-demo/xcsh 19.81.0 → 19.81.2

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.81.0",
4
+ "version": "19.81.2",
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.0",
60
- "@f5-sales-demo/pi-agent-core": "19.81.0",
61
- "@f5-sales-demo/pi-ai": "19.81.0",
62
- "@f5-sales-demo/pi-natives": "19.81.0",
63
- "@f5-sales-demo/pi-resource-management": "19.81.0",
64
- "@f5-sales-demo/pi-tui": "19.81.0",
65
- "@f5-sales-demo/pi-utils": "19.81.0",
59
+ "@f5-sales-demo/xcsh-stats": "19.81.2",
60
+ "@f5-sales-demo/pi-agent-core": "19.81.2",
61
+ "@f5-sales-demo/pi-ai": "19.81.2",
62
+ "@f5-sales-demo/pi-natives": "19.81.2",
63
+ "@f5-sales-demo/pi-resource-management": "19.81.2",
64
+ "@f5-sales-demo/pi-tui": "19.81.2",
65
+ "@f5-sales-demo/pi-utils": "19.81.2",
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.10.0",
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.10.0";
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.10.0",
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,
@@ -1,5 +1,5 @@
1
1
  {
2
- "contractVersion": "1.10.0",
2
+ "contractVersion": "1.11.0",
3
3
  "schemas": {
4
4
  "chat_request": {
5
5
  "type": "object",
@@ -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 discovery range, lowest first. */
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 = PORT_RANGE_START; p <= PORT_RANGE_END; p++) out.push(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
- for (const candidate of portCandidates()) {
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 ${PORT_RANGE_START}-${PORT_RANGE_END} — is another app on the range?`);
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
- const bridge = await deps.startBridgeServer(undefined, tls ? { tls } : undefined);
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 = `[System: You are xcsh, an AI assistant for the F5 Distributed Cloud console, running as a Chrome browser side panel — not a terminal CLI.
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 = `[System: You are xcsh, an AI assistant running as a task pane inside Microsoft Excel — not a terminal CLI. You help the user with the OPEN workbook using the Excel host tools available to you.
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 = `[System: You are xcsh, an AI assistant running as a task pane inside Microsoft PowerPoint — not a terminal CLI. You help the user with the OPEN presentation using the PowerPoint host tools available to you.
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 = `[System: You are xcsh, an AI assistant running as a task pane inside Microsoft Word — not a terminal CLI. You help the user with the OPEN document using the Word host tools available to you.
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
 
@@ -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.0",
21
- "commit": "49eeba707c688fa7aea7e8eb4289762002c87dc9",
22
- "shortCommit": "49eeba7",
20
+ "version": "19.81.2",
21
+ "commit": "551f4607c417658e861efa41ecb4ddf60fed2826",
22
+ "shortCommit": "551f460",
23
23
  "branch": "main",
24
- "tag": "v19.81.0",
25
- "commitDate": "2026-07-23T07:03:42Z",
26
- "buildDate": "2026-07-23T07:33:53.401Z",
24
+ "tag": "v19.81.2",
25
+ "commitDate": "2026-07-23T12:26:32Z",
26
+ "buildDate": "2026-07-23T12:48:41.664Z",
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/49eeba707c688fa7aea7e8eb4289762002c87dc9",
32
- "releaseUrl": "https://github.com/f5-sales-demo/xcsh/releases/tag/v19.81.0"
31
+ "commitUrl": "https://github.com/f5-sales-demo/xcsh/commit/551f4607c417658e861efa41ecb4ddf60fed2826",
32
+ "releaseUrl": "https://github.com/f5-sales-demo/xcsh/releases/tag/v19.81.2"
33
33
  };