@f5-sales-demo/xcsh 19.87.0 → 19.88.0
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/extension-bridge-tools.ts +43 -11
- package/src/browser/headless-bridge.ts +9 -6
- package/src/browser/host-profiles.ts +19 -3
- package/src/extensibility/extensions/loader.ts +18 -6
- package/src/internal-urls/build-info.generated.ts +8 -8
- package/src/sdk.ts +14 -1
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@f5-sales-demo/xcsh",
|
|
4
|
-
"version": "19.
|
|
4
|
+
"version": "19.88.0",
|
|
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.
|
|
60
|
-
"@f5-sales-demo/pi-agent-core": "19.
|
|
61
|
-
"@f5-sales-demo/pi-ai": "19.
|
|
62
|
-
"@f5-sales-demo/pi-natives": "19.
|
|
63
|
-
"@f5-sales-demo/pi-resource-management": "19.
|
|
64
|
-
"@f5-sales-demo/pi-tui": "19.
|
|
65
|
-
"@f5-sales-demo/pi-utils": "19.
|
|
59
|
+
"@f5-sales-demo/xcsh-stats": "19.88.0",
|
|
60
|
+
"@f5-sales-demo/pi-agent-core": "19.88.0",
|
|
61
|
+
"@f5-sales-demo/pi-ai": "19.88.0",
|
|
62
|
+
"@f5-sales-demo/pi-natives": "19.88.0",
|
|
63
|
+
"@f5-sales-demo/pi-resource-management": "19.88.0",
|
|
64
|
+
"@f5-sales-demo/pi-tui": "19.88.0",
|
|
65
|
+
"@f5-sales-demo/pi-utils": "19.88.0",
|
|
66
66
|
"@sinclair/typebox": "^0.34",
|
|
67
67
|
"@xterm/headless": "^6.0",
|
|
68
68
|
"ajv": "^8.20",
|
|
@@ -100,16 +100,48 @@ export const BROWSER_TOOL_NAMES: readonly string[] = [
|
|
|
100
100
|
|
|
101
101
|
/**
|
|
102
102
|
* Builtin agent tools scoped into the headless OFFICE bridge (`xcsh office serve`).
|
|
103
|
-
* The Office task pane drives a document (Excel/PowerPoint/Word), NOT a browser, so
|
|
104
|
-
* it must get NONE of the {@link BROWSER_TOOL_NAMES} — those would be hallucinated
|
|
105
|
-
* against a host with no browser to drive. The document's own tools arrive at
|
|
106
|
-
* runtime over the bridge via `set_host_tools`; this list is only the minimal
|
|
107
|
-
* general-purpose, host-neutral builtin toolset a document assistant can safely use.
|
|
108
103
|
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
104
|
+
* FULL CLI-PARITY tool set (minus browser automation): the Office pane is a full
|
|
105
|
+
* local xcsh agent, so it gets the same general-purpose native tools the CLI has —
|
|
106
|
+
* `bash` (so it can shell out to `az`, `gh`, terraform, git, …), the file tools
|
|
107
|
+
* (`read`/`write`/`edit`), search (`grep`), plus planning (`todo_write`,
|
|
108
|
+
* `task`) and `calc`. (File-finding is covered by `bash`; the builtin `find`
|
|
109
|
+
* tool is omitted because its name collides with a browser tool.) The document's own Excel/PowerPoint/Word tools arrive at
|
|
110
|
+
* runtime over the bridge via `set_host_tools`.
|
|
111
|
+
*
|
|
112
|
+
* DELIBERATELY EXCLUDED:
|
|
113
|
+
* - Every {@link BROWSER_TOOL_NAMES} entry — there is no browser to drive in a
|
|
114
|
+
* document pane, so navigate/click/screenshot would only be hallucinated.
|
|
115
|
+
* - `ask` (needs interactive stdin → would hang headless), `python` (spawns a
|
|
116
|
+
* kernel → startup cost), `ssh`/`debug`/`notebook`/`browser`/`get_page_context`.
|
|
117
|
+
*
|
|
118
|
+
* SAFETY: the headless session pairs this with the bundled `sandbox-guard`
|
|
119
|
+
* extension (see headless-bridge.ts `bundledExtensions`), which confines the file
|
|
120
|
+
* tools + the shell's working dir to the launch cwd subtree — the CLI's own model.
|
|
121
|
+
* `az`/`gh` still run (network actions aren't filesystem-confined); credentials must
|
|
122
|
+
* already exist for the process user. There is no per-tool approval prompt — the
|
|
123
|
+
* local trusted bridge auto-runs tools exactly as the CLI does.
|
|
124
|
+
*
|
|
125
|
+
* THREAT MODEL (reviewed + accepted, 2026-07-24): the pane's agent auto-reads
|
|
126
|
+
* document content, which could be adversarial (a prompt-injected customer .xlsx)
|
|
127
|
+
* and steer it into shell/`az`/`gh` calls; the filesystem sandbox blocks file
|
|
128
|
+
* damage outside cwd but NOT network/cloud actions. This is the same exposure the
|
|
129
|
+
* xcsh CLI already carries (no approval system anywhere). The operator explicitly
|
|
130
|
+
* chose full CLI parity + FS sandbox over a bash approval gate, mitigating in
|
|
131
|
+
* practice by only opening trusted documents. If untrusted files become common,
|
|
132
|
+
* revisit with a per-shell approval round-trip (host_tool_call-style frame).
|
|
133
|
+
*
|
|
134
|
+
* NOTE: an EMPTY list cannot express "no builtin tools" — createTools treats `[]` as
|
|
135
|
+
* "unscoped" and returns the FULL registry (including browser tools). So this is an
|
|
136
|
+
* explicit curated array, not `[]`.
|
|
114
137
|
*/
|
|
115
|
-
export const OFFICE_TOOL_NAMES: readonly string[] = [
|
|
138
|
+
export const OFFICE_TOOL_NAMES: readonly string[] = [
|
|
139
|
+
"read",
|
|
140
|
+
"write",
|
|
141
|
+
"edit",
|
|
142
|
+
"bash",
|
|
143
|
+
"grep",
|
|
144
|
+
"todo_write",
|
|
145
|
+
"task",
|
|
146
|
+
"calc",
|
|
147
|
+
];
|
|
@@ -134,12 +134,10 @@ export async function startHeadlessChatBridge(deps: HeadlessBridgeDeps = default
|
|
|
134
134
|
// selectProvider() reuses a dead bridge. The caller (startOfficeServe) treats
|
|
135
135
|
// the rethrow as a non-fatal "pane only" fallback.
|
|
136
136
|
try {
|
|
137
|
-
// Create ONE headless Office session
|
|
138
|
-
// (OFFICE_TOOL_NAMES
|
|
139
|
-
//
|
|
140
|
-
//
|
|
141
|
-
// The document's own tools (Excel/Word/PowerPoint) arrive at runtime via
|
|
142
|
-
// set_host_tools; chat over xcsh's configured provider needs no browser tooling.
|
|
137
|
+
// Create ONE headless Office session with the full CLI-parity builtin set
|
|
138
|
+
// (OFFICE_TOOL_NAMES: bash/read/write/edit/grep/find/… — NO browser tools, which
|
|
139
|
+
// would be hallucinated in a document task pane). The document's own tools
|
|
140
|
+
// (Excel/Word/PowerPoint) arrive at runtime via set_host_tools.
|
|
143
141
|
const { session } = await deps.createAgentSession({
|
|
144
142
|
cwd,
|
|
145
143
|
hasUI: false,
|
|
@@ -149,6 +147,11 @@ export async function startHeadlessChatBridge(deps: HeadlessBridgeDeps = default
|
|
|
149
147
|
enableMCP: false,
|
|
150
148
|
enableLsp: false,
|
|
151
149
|
disableExtensionDiscovery: true,
|
|
150
|
+
// …but DO load the bundled filesystem sandbox: the pane runs full CLI-parity
|
|
151
|
+
// tools (bash/read/write), so it needs the CLI's safety net confining file
|
|
152
|
+
// tools + the shell's cwd to the launch directory subtree (sandbox.enabled
|
|
153
|
+
// defaults true). Without this, a discovery-disabled session ran ungated.
|
|
154
|
+
bundledExtensions: ["sandbox-guard"],
|
|
152
155
|
});
|
|
153
156
|
|
|
154
157
|
const chatHandler = new deps.ChatHandlerCtor(bridge, session);
|
|
@@ -85,6 +85,19 @@ SAFETY — NEVER DO THESE:
|
|
|
85
85
|
|
|
86
86
|
`;
|
|
87
87
|
|
|
88
|
+
/**
|
|
89
|
+
* Shared tail for every Office (document) profile: the pane is a FULL local xcsh
|
|
90
|
+
* agent — same native tools as the CLI — plus the one safety rule that shelling
|
|
91
|
+
* out makes necessary (don't let the agent kill its own bridge). Interpolated into
|
|
92
|
+
* each document profile so the three stay in sync (DRY).
|
|
93
|
+
*/
|
|
94
|
+
const OFFICE_NATIVE_TOOLS_NOTE = `
|
|
95
|
+
NATIVE TOOLS: Beyond the document host tools, you have xcsh's full local toolset — \`bash\` (run shell commands, including CLIs like \`az\`, \`gh\`, \`terraform\`, \`git\` when installed and authenticated), file tools (\`read\`/\`write\`/\`edit\`), and \`grep\` — plus any skills available in this workspace. Reach for them when the task genuinely needs them (pull live data with a CLI, read a local file the user points you at). Prefer the document host tools for document work. Your file tools and shell are confined to the folder xcsh was launched from.
|
|
96
|
+
|
|
97
|
+
SAFETY:
|
|
98
|
+
- NEVER kill, stop, inspect, or manage the xcsh \`office serve\` process, its bridge ports, or any xcsh process — that bridge IS you; ending it ends the session.
|
|
99
|
+
- NEVER run \`lsof\`/\`fuser\`/\`kill\`/\`pkill\` against the bridge ports or use the shell to manage xcsh itself.`;
|
|
100
|
+
|
|
88
101
|
/**
|
|
89
102
|
* Excel task-pane self-awareness prompt. The assistant works the OPEN workbook
|
|
90
103
|
* via host tools (arriving at runtime over the bridge), thinking in cells,
|
|
@@ -95,7 +108,7 @@ You are still xcsh, the F5 Distributed Cloud technical coworker defined in your
|
|
|
95
108
|
|
|
96
109
|
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.
|
|
97
110
|
|
|
98
|
-
CONTEXT:
|
|
111
|
+
CONTEXT: Your workspace centers on the open workbook. Think in cells, ranges, and — above all — FORMULAS and their dependencies:
|
|
99
112
|
- Preserve formula relationships. When you change a cell, let dependent cells recompute; do not overwrite a formula with its current value unless asked.
|
|
100
113
|
- Warn the user before overwriting existing cell contents.
|
|
101
114
|
- Cite specific cells and ranges precisely (e.g. A1, Sheet1!B2:B10) so the user can follow along.
|
|
@@ -105,6 +118,7 @@ TOOLS: Discover the workbook before you answer, then reach for the tool that mat
|
|
|
105
118
|
- Use \`read_table\` for structured Excel Tables (it tracks the real extent), \`get_formulas\` to see the formulas behind cells, \`get_cell_metadata\` for cell types/number formats, and \`read_named_range\` to read a defined name.
|
|
106
119
|
- Use \`sort_filter_table\` to sort or filter a Table by column.
|
|
107
120
|
- Use \`read_range\`/\`write_range\` for arbitrary cell ranges (bare or sheet-qualified like Sheet2!A1:B10), and \`list_sheets\` when you only need the tab names.
|
|
121
|
+
${OFFICE_NATIVE_TOOLS_NOTE}
|
|
108
122
|
|
|
109
123
|
BEHAVIOR:
|
|
110
124
|
- Respond concisely with markdown. The task pane is narrow — avoid long code blocks.
|
|
@@ -123,7 +137,7 @@ You are still xcsh, the F5 Distributed Cloud technical coworker defined in your
|
|
|
123
137
|
|
|
124
138
|
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.
|
|
125
139
|
|
|
126
|
-
CONTEXT:
|
|
140
|
+
CONTEXT: Your workspace centers on the open presentation. Think in slides, shapes, and the slide master:
|
|
127
141
|
- Conform any new content to the deck's existing template, fonts, and colors — do not introduce a different look.
|
|
128
142
|
- Make pinpoint, per-slide edits. Do NOT regenerate the whole deck to change one thing.
|
|
129
143
|
- Refer to slides by number so the user can follow along.
|
|
@@ -132,6 +146,7 @@ TOOLS: Discover the deck before you answer, then reach for the tool that matches
|
|
|
132
146
|
- Call \`get_presentation_info\` FIRST to discover all slides, their layouts, and shape counts before answering — do not guess the structure.
|
|
133
147
|
- Use \`read_slide_shapes\` to see all shapes on a slide with their text + position, \`read_slide_layout\` for the layout/master applied to a slide, and \`modify_shape_text\` to edit the text of a named shape.
|
|
134
148
|
- Use \`read_slides\` for a quick text-only scan of the whole deck, and \`add_text_box\`/\`add_slide\` to create new content.
|
|
149
|
+
${OFFICE_NATIVE_TOOLS_NOTE}
|
|
135
150
|
|
|
136
151
|
BEHAVIOR:
|
|
137
152
|
- Respond concisely with markdown. The task pane is narrow — avoid long code blocks.
|
|
@@ -151,7 +166,7 @@ You are still xcsh, the F5 Distributed Cloud technical coworker defined in your
|
|
|
151
166
|
|
|
152
167
|
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.
|
|
153
168
|
|
|
154
|
-
CONTEXT:
|
|
169
|
+
CONTEXT: Your workspace centers on the open document. Think in paragraphs, the current selection, comments, and tracked changes:
|
|
155
170
|
- Preserve the document's styles and numbering — do not flatten formatting.
|
|
156
171
|
- Describe your edits so the user can review them, and prefer changes the user can accept or reject.
|
|
157
172
|
- When the user refers to "the selection" (or "this"), act on the current selection.
|
|
@@ -161,6 +176,7 @@ TOOLS: Discover the document before you answer, then reach for the tool that mat
|
|
|
161
176
|
- Use \`read_paragraphs\` for styled paragraph content, \`read_selection\` for the current selection, \`get_comments\` for comments, and \`get_tracked_changes\` for revisions.
|
|
162
177
|
- Use \`read_document\` when you need the full plain text.
|
|
163
178
|
- Use \`insert_paragraph\` to add content at a specific location (start, end, or before/after the selection), and \`insert_text\` for inline text within a paragraph.
|
|
179
|
+
${OFFICE_NATIVE_TOOLS_NOTE}
|
|
164
180
|
|
|
165
181
|
BEHAVIOR:
|
|
166
182
|
- Respond concisely with markdown. The task pane is narrow — avoid long code blocks.
|
|
@@ -336,8 +336,17 @@ export async function loadExtensionFromFactory(
|
|
|
336
336
|
|
|
337
337
|
/**
|
|
338
338
|
* Load extensions from paths.
|
|
339
|
+
*
|
|
340
|
+
* `bundledExtensionNames` opts specific bundled extensions (e.g. `["sandbox-guard"]`)
|
|
341
|
+
* into a session that has otherwise disabled discovery — the headless bridges use
|
|
342
|
+
* this to keep the CLI's filesystem safety net without paying for full discovery.
|
|
339
343
|
*/
|
|
340
|
-
export async function loadExtensions(
|
|
344
|
+
export async function loadExtensions(
|
|
345
|
+
paths: string[],
|
|
346
|
+
cwd: string,
|
|
347
|
+
eventBus?: EventBus,
|
|
348
|
+
bundledExtensionNames: readonly string[] = [],
|
|
349
|
+
): Promise<LoadExtensionsResult> {
|
|
341
350
|
const extensions: Extension[] = [];
|
|
342
351
|
const errors: Array<{ path: string; error: string }> = [];
|
|
343
352
|
const resolvedEventBus = eventBus ?? new EventBus();
|
|
@@ -356,11 +365,14 @@ export async function loadExtensions(paths: string[], cwd: string, eventBus?: Ev
|
|
|
356
365
|
}
|
|
357
366
|
}
|
|
358
367
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
368
|
+
const result: LoadExtensionsResult = { extensions, errors, runtime };
|
|
369
|
+
|
|
370
|
+
if (bundledExtensionNames.length > 0) {
|
|
371
|
+
const allow = new Set(bundledExtensionNames);
|
|
372
|
+
await loadBundledExtensions(result, cwd, resolvedEventBus, name => !allow.has(name));
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
return result;
|
|
364
376
|
}
|
|
365
377
|
|
|
366
378
|
interface ExtensionManifest {
|
|
@@ -17,17 +17,17 @@ export interface BuildInfo {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export const BUILD_INFO: BuildInfo = {
|
|
20
|
-
"version": "19.
|
|
21
|
-
"commit": "
|
|
22
|
-
"shortCommit": "
|
|
20
|
+
"version": "19.88.0",
|
|
21
|
+
"commit": "4e87c996191e7c88ae503cedded3afee98177587",
|
|
22
|
+
"shortCommit": "4e87c99",
|
|
23
23
|
"branch": "main",
|
|
24
|
-
"tag": "v19.
|
|
25
|
-
"commitDate": "2026-07-
|
|
26
|
-
"buildDate": "2026-07-
|
|
24
|
+
"tag": "v19.88.0",
|
|
25
|
+
"commitDate": "2026-07-24T18:57:08Z",
|
|
26
|
+
"buildDate": "2026-07-24T19:23:46.325Z",
|
|
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.
|
|
31
|
+
"commitUrl": "https://github.com/f5-sales-demo/xcsh/commit/4e87c996191e7c88ae503cedded3afee98177587",
|
|
32
|
+
"releaseUrl": "https://github.com/f5-sales-demo/xcsh/releases/tag/v19.88.0"
|
|
33
33
|
};
|
package/src/sdk.ts
CHANGED
|
@@ -188,6 +188,12 @@ export interface CreateAgentSessionOptions {
|
|
|
188
188
|
additionalExtensionPaths?: string[];
|
|
189
189
|
/** Disable extension discovery (explicit paths still load). */
|
|
190
190
|
disableExtensionDiscovery?: boolean;
|
|
191
|
+
/**
|
|
192
|
+
* Bundled extensions to load even when discovery is disabled (e.g.
|
|
193
|
+
* `["sandbox-guard"]`). Lets a headless session keep the CLI's filesystem
|
|
194
|
+
* safety net without paying for full discovery.
|
|
195
|
+
*/
|
|
196
|
+
bundledExtensions?: string[];
|
|
191
197
|
/**
|
|
192
198
|
* Pre-loaded extensions (skips file discovery).
|
|
193
199
|
* @internal Used by CLI when extensions are loaded early to parse custom flags.
|
|
@@ -1238,7 +1244,14 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1238
1244
|
let extensionsResult: LoadExtensionsResult;
|
|
1239
1245
|
if (options.disableExtensionDiscovery) {
|
|
1240
1246
|
const configuredPaths = options.additionalExtensionPaths ?? [];
|
|
1241
|
-
extensionsResult = await logger.time(
|
|
1247
|
+
extensionsResult = await logger.time(
|
|
1248
|
+
"loadExtensions",
|
|
1249
|
+
loadExtensions,
|
|
1250
|
+
configuredPaths,
|
|
1251
|
+
cwd,
|
|
1252
|
+
eventBus,
|
|
1253
|
+
options.bundledExtensions ?? [],
|
|
1254
|
+
);
|
|
1242
1255
|
for (const { path, error } of extensionsResult.errors) {
|
|
1243
1256
|
logger.error("Failed to load extension", { path, error });
|
|
1244
1257
|
}
|