@f5-sales-demo/xcsh 19.57.0 → 19.57.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.57.0",
4
+ "version": "19.57.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",
@@ -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.57.0",
59
- "@f5-sales-demo/pi-agent-core": "19.57.0",
60
- "@f5-sales-demo/pi-ai": "19.57.0",
61
- "@f5-sales-demo/pi-natives": "19.57.0",
62
- "@f5-sales-demo/pi-resource-management": "19.57.0",
63
- "@f5-sales-demo/pi-tui": "19.57.0",
64
- "@f5-sales-demo/pi-utils": "19.57.0",
58
+ "@f5-sales-demo/xcsh-stats": "19.57.2",
59
+ "@f5-sales-demo/pi-agent-core": "19.57.2",
60
+ "@f5-sales-demo/pi-ai": "19.57.2",
61
+ "@f5-sales-demo/pi-natives": "19.57.2",
62
+ "@f5-sales-demo/pi-resource-management": "19.57.2",
63
+ "@f5-sales-demo/pi-tui": "19.57.2",
64
+ "@f5-sales-demo/pi-utils": "19.57.2",
65
65
  "@sinclair/typebox": "^0.34",
66
66
  "@xterm/headless": "^6.0",
67
67
  "ajv": "^8.20",
@@ -13,7 +13,7 @@
13
13
  * `XCSH_SESSION_TENANT` so it advertises its assigned tenant even before a context
14
14
  * is bound. This lets the extension panel lock onto the right tenant immediately.
15
15
  */
16
- import { getProjectDir, getXCSHConfigDir } from "@f5-sales-demo/pi-utils";
16
+ import { getProjectDir, getXCSHConfigDir, logger } from "@f5-sales-demo/pi-utils";
17
17
  import { Command } from "@f5-sales-demo/pi-utils/cli";
18
18
  import { ChatHandler } from "../browser/chat-handler";
19
19
  import { startBridgeServer } from "../browser/extension-bridge";
@@ -90,6 +90,12 @@ export default class Worker extends Command {
90
90
  static description = "Run a headless extension-bridge worker (no TUI); blocks until SIGTERM";
91
91
 
92
92
  async run(): Promise<void> {
93
+ // Record the per-tab session-boot timeline (parity with main.ts:runRootCommand).
94
+ // Spans only accumulate while recording; nothing prints unless PI_TIMING is set,
95
+ // and each logger.time() returns its wrapped value unchanged — so a normal
96
+ // `xcsh worker` run is behaviorally identical to before.
97
+ logger.startTiming();
98
+
93
99
  process.env.XCSH_BROWSER_PROVIDER = "extension";
94
100
 
95
101
  const cwd = getProjectDir();
@@ -113,7 +119,9 @@ export default class Worker extends Command {
113
119
 
114
120
  // INSTANT-ON: start the bridge before the heavy session init so the extension
115
121
  // can connect immediately. Honors XCSH_BRIDGE_PORT (forced) or auto-selects.
116
- const bridge = await startBridgeServer();
122
+ // session:bridgeListen — time-to-"bridge-ready": the extension can connect and
123
+ // complete the hello/hello_ack handshake once this resolves (INSTANT-ON path).
124
+ const bridge = await logger.time("session:bridgeListen", startBridgeServer);
117
125
  console.error(`[xcsh worker] extension bridge listening on ws://127.0.0.1:${bridge.port}`);
118
126
  setSharedBridgeServer(bridge);
119
127
  bridge.setSessionInfo(sessionInfoForWorker);
@@ -124,7 +132,10 @@ export default class Worker extends Command {
124
132
  // the browser (without this the agent only has catalog_workflow_runner and
125
133
  // merely narrates "Navigating…"). Include their names in the tool scope.
126
134
  const extensionTools = createExtensionBridgeTools(bridge);
127
- const { session } = await createAgentSession({
135
+ // session:createAgentSession the heavy step between bridge-ready and
136
+ // session-ready (model registry, tools, context bootstrap). Wrapped as a span
137
+ // (parity with main.ts:892) so PI_TIMING reveals the per-tab session-load split.
138
+ const { session } = await logger.time("session:createAgentSession", createAgentSession, {
128
139
  cwd,
129
140
  hasUI: false,
130
141
  toolNames: [...new Set([...BROWSER_TOOL_NAMES, ...EXTENSION_AGENT_TOOL_NAMES])],
@@ -139,6 +150,17 @@ export default class Worker extends Command {
139
150
  const chatHandler = new ChatHandler(bridge, session);
140
151
  chatHandler.attach();
141
152
 
153
+ // session-ready. Emit the per-tab boot breakdown when requested (parity with
154
+ // main.ts:1002-1009). PI_TIMING=x prints then exits — used by bench/extension-session.ts
155
+ // to measure total worker cold-start; otherwise this is a no-op.
156
+ if (process.env.PI_TIMING) {
157
+ logger.printTimings();
158
+ if (process.env.PI_TIMING === "x") {
159
+ process.exit(0);
160
+ }
161
+ }
162
+ logger.endTiming();
163
+
142
164
  let shuttingDown = false;
143
165
  const shutdown = () => {
144
166
  if (shuttingDown) return;
@@ -284,7 +284,7 @@ async function loadExtension(
284
284
  const resolvedPath = resolvePath(extensionPath, cwd);
285
285
 
286
286
  try {
287
- const module = await import(resolvedPath);
287
+ const module = await logger.time("ext:loadModule", () => import(resolvedPath));
288
288
  const factory = (module.default ?? module) as ExtensionFactory;
289
289
 
290
290
  if (typeof factory !== "function") {
@@ -295,7 +295,13 @@ async function loadExtension(
295
295
  }
296
296
 
297
297
  const extension = createExtension(extensionPath, resolvedPath);
298
- const api = new ConcreteExtensionAPI(await import("@f5-sales-demo/xcsh"), extension, runtime, cwd, eventBus);
298
+ const api = new ConcreteExtensionAPI(
299
+ await logger.time("ext:barrelImport", () => import("@f5-sales-demo/xcsh")),
300
+ extension,
301
+ runtime,
302
+ cwd,
303
+ eventBus,
304
+ );
299
305
  await factory(api);
300
306
 
301
307
  return { extension, error: null };
@@ -316,7 +322,13 @@ export async function loadExtensionFromFactory(
316
322
  name = "<inline>",
317
323
  ): Promise<Extension> {
318
324
  const extension = createExtension(name, name);
319
- const api = new ConcreteExtensionAPI(await import("@f5-sales-demo/xcsh"), extension, runtime, cwd, eventBus);
325
+ const api = new ConcreteExtensionAPI(
326
+ await logger.time("ext:barrelImport", () => import("@f5-sales-demo/xcsh")),
327
+ extension,
328
+ runtime,
329
+ cwd,
330
+ eventBus,
331
+ );
320
332
  await factory(api);
321
333
  return extension;
322
334
  }
@@ -540,7 +552,9 @@ export async function discoverAndLoadExtensions(
540
552
  };
541
553
 
542
554
  // 1. Discover extension modules via capability API (native .omp/.pi only)
543
- const discovered = await loadCapability<ExtensionModule>(extensionModuleCapability.id, { cwd });
555
+ const discovered = await logger.time("ext:discoverCapability", () =>
556
+ loadCapability<ExtensionModule>(extensionModuleCapability.id, { cwd }),
557
+ );
544
558
  for (const ext of discovered.items) {
545
559
  if (ext._source.provider !== "native") continue;
546
560
  if (isDisabledName(ext.name)) continue;
@@ -548,29 +562,31 @@ export async function discoverAndLoadExtensions(
548
562
  }
549
563
 
550
564
  // 2. Discover extension entry points from installed plugins (node_modules path)
551
- addPaths(await getAllPluginExtensionPaths(cwd));
565
+ addPaths(await logger.time("ext:pluginPaths", () => getAllPluginExtensionPaths(cwd)));
552
566
 
553
567
  // 2b. Discover extension entry points from marketplace-cached plugins
554
- for (const root of getPreloadedPluginRoots()) {
555
- try {
556
- const pkgPath = path.join(root.path, "package.json");
557
- const pkg = await Bun.file(pkgPath).json();
558
- const manifest = pkg?.xcsh ?? pkg?.pi;
559
- const extensions = manifest?.extensions;
560
- if (Array.isArray(extensions)) {
561
- for (const entry of extensions) {
562
- if (typeof entry !== "string") continue;
563
- if (path.isAbsolute(entry) || entry.includes("..")) continue;
564
- const resolved = path.resolve(root.path, entry);
565
- if (!resolved.startsWith(root.path + path.sep) && resolved !== root.path) continue;
566
- if (isDisabledName(getExtensionNameFromPath(resolved))) continue;
567
- addPath(resolved);
568
+ await logger.time("ext:marketplaceRoots", async () => {
569
+ for (const root of getPreloadedPluginRoots()) {
570
+ try {
571
+ const pkgPath = path.join(root.path, "package.json");
572
+ const pkg = await Bun.file(pkgPath).json();
573
+ const manifest = pkg?.xcsh ?? pkg?.pi;
574
+ const extensions = manifest?.extensions;
575
+ if (Array.isArray(extensions)) {
576
+ for (const entry of extensions) {
577
+ if (typeof entry !== "string") continue;
578
+ if (path.isAbsolute(entry) || entry.includes("..")) continue;
579
+ const resolved = path.resolve(root.path, entry);
580
+ if (!resolved.startsWith(root.path + path.sep) && resolved !== root.path) continue;
581
+ if (isDisabledName(getExtensionNameFromPath(resolved))) continue;
582
+ addPath(resolved);
583
+ }
568
584
  }
585
+ } catch {
586
+ // No package.json or invalid — skip
569
587
  }
570
- } catch {
571
- // No package.json or invalid — skip
572
588
  }
573
- }
589
+ });
574
590
 
575
591
  // 3. Explicitly configured paths
576
592
  for (const configuredPath of configuredPaths) {
@@ -601,7 +617,7 @@ export async function discoverAndLoadExtensions(
601
617
  }
602
618
 
603
619
  const resolvedEventBus = eventBus ?? new EventBus();
604
- const result = await loadExtensions(allPaths, cwd, resolvedEventBus);
605
- await loadBundledExtensions(result, cwd, resolvedEventBus, isDisabledName);
620
+ const result = await logger.time("ext:loadLoop", () => loadExtensions(allPaths, cwd, resolvedEventBus));
621
+ await logger.time("ext:loadBundled", () => loadBundledExtensions(result, cwd, resolvedEventBus, isDisabledName));
606
622
  return result;
607
623
  }
@@ -17,17 +17,17 @@ export interface BuildInfo {
17
17
  }
18
18
 
19
19
  export const BUILD_INFO: BuildInfo = {
20
- "version": "19.57.0",
21
- "commit": "9b508d8af3633290ce801f2ca9956dd22df78e30",
22
- "shortCommit": "9b508d8",
20
+ "version": "19.57.2",
21
+ "commit": "642fb826019640261cf1e3c1ec0206581fd9c1fc",
22
+ "shortCommit": "642fb82",
23
23
  "branch": "main",
24
- "tag": "v19.57.0",
25
- "commitDate": "2026-07-04T20:19:08Z",
26
- "buildDate": "2026-07-04T20:54:40.287Z",
24
+ "tag": "v19.57.2",
25
+ "commitDate": "2026-07-04T22:01:28Z",
26
+ "buildDate": "2026-07-04T22:29:54.204Z",
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/9b508d8af3633290ce801f2ca9956dd22df78e30",
32
- "releaseUrl": "https://github.com/f5-sales-demo/xcsh/releases/tag/v19.57.0"
31
+ "commitUrl": "https://github.com/f5-sales-demo/xcsh/commit/642fb826019640261cf1e3c1ec0206581fd9c1fc",
32
+ "releaseUrl": "https://github.com/f5-sales-demo/xcsh/releases/tag/v19.57.2"
33
33
  };