@f5xc-salesdemos/xcsh 18.24.0 → 18.25.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": "@f5xc-salesdemos/xcsh",
4
- "version": "18.24.0",
4
+ "version": "18.25.2",
5
5
  "description": "Coding agent CLI with read, bash, edit, write tools and session management",
6
6
  "homepage": "https://github.com/f5xc-salesdemos/xcsh",
7
7
  "author": "Can Boluk",
@@ -47,12 +47,12 @@
47
47
  "dependencies": {
48
48
  "@agentclientprotocol/sdk": "0.16.1",
49
49
  "@mozilla/readability": "^0.6",
50
- "@f5xc-salesdemos/xcsh-stats": "18.24.0",
51
- "@f5xc-salesdemos/pi-agent-core": "18.24.0",
52
- "@f5xc-salesdemos/pi-ai": "18.24.0",
53
- "@f5xc-salesdemos/pi-natives": "18.24.0",
54
- "@f5xc-salesdemos/pi-tui": "18.24.0",
55
- "@f5xc-salesdemos/pi-utils": "18.24.0",
50
+ "@f5xc-salesdemos/xcsh-stats": "18.25.2",
51
+ "@f5xc-salesdemos/pi-agent-core": "18.25.2",
52
+ "@f5xc-salesdemos/pi-ai": "18.25.2",
53
+ "@f5xc-salesdemos/pi-natives": "18.25.2",
54
+ "@f5xc-salesdemos/pi-tui": "18.25.2",
55
+ "@f5xc-salesdemos/pi-utils": "18.25.2",
56
56
  "@sinclair/typebox": "^0.34",
57
57
  "@xterm/headless": "^6.0",
58
58
  "ajv": "^8.18",
@@ -17,17 +17,17 @@ export interface BuildInfo {
17
17
  }
18
18
 
19
19
  export const BUILD_INFO: BuildInfo = {
20
- "version": "18.24.0",
21
- "commit": "dac603ea95ed2b8256eede56654936b456cdf596",
22
- "shortCommit": "dac603e",
20
+ "version": "18.25.2",
21
+ "commit": "abd4234179059ccda04559a3a8611a93ce52f98b",
22
+ "shortCommit": "abd4234",
23
23
  "branch": "main",
24
- "tag": "v18.24.0",
25
- "commitDate": "2026-04-29T05:28:17Z",
26
- "buildDate": "2026-04-29T05:49:28.785Z",
24
+ "tag": "v18.25.2",
25
+ "commitDate": "2026-04-29T07:33:34Z",
26
+ "buildDate": "2026-04-29T07:59:50.398Z",
27
27
  "dirty": false,
28
28
  "prNumber": "",
29
29
  "repoUrl": "https://github.com/f5xc-salesdemos/xcsh",
30
30
  "repoSlug": "f5xc-salesdemos/xcsh",
31
- "commitUrl": "https://github.com/f5xc-salesdemos/xcsh/commit/dac603ea95ed2b8256eede56654936b456cdf596",
32
- "releaseUrl": "https://github.com/f5xc-salesdemos/xcsh/releases/tag/v18.24.0"
31
+ "commitUrl": "https://github.com/f5xc-salesdemos/xcsh/commit/abd4234179059ccda04559a3a8611a93ce52f98b",
32
+ "releaseUrl": "https://github.com/f5xc-salesdemos/xcsh/releases/tag/v18.25.2"
33
33
  };
@@ -180,6 +180,7 @@ export class ContextService {
180
180
  #apiClient: F5XCApiClient | null = null;
181
181
  #revalidationTimer: NodeJS.Timeout | null = null;
182
182
  #lastTokenHealth: TokenHealth = "ok";
183
+ #previousContextName: string | null = null;
183
184
 
184
185
  private constructor(configDir: string) {
185
186
  this.#configDir = configDir;
@@ -330,6 +331,7 @@ export class ContextService {
330
331
  ContextService.#instance.#apiClient = null;
331
332
  ContextService.#instance.#lastTokenHealth = "ok";
332
333
  ContextService.#instance.stopRevalidation();
334
+ ContextService.#instance.#previousContextName = null;
333
335
  }
334
336
  ContextService.#instance = null;
335
337
  // Clear listeners to prevent cross-test contamination. Each createAgentSession() call
@@ -340,6 +342,10 @@ export class ContextService {
340
342
  ContextService.#onTokenHealthChangeListeners = [];
341
343
  }
342
344
 
345
+ get previousContextName(): string | null {
346
+ return this.#previousContextName;
347
+ }
348
+
343
349
  get contextsDir(): string {
344
350
  return path.join(this.#configDir, "contexts");
345
351
  }
@@ -439,6 +445,9 @@ export class ContextService {
439
445
  // NFR-402: write active_context first — if it fails, don't update settings
440
446
  this.#atomicWrite(this.activeContextPath, name);
441
447
 
448
+ if (this.#activeContext && this.#activeContext.name !== name) {
449
+ this.#previousContextName = this.#activeContext.name;
450
+ }
442
451
  this.#activeContext = context;
443
452
  this.#applyToSettings(context);
444
453
  this.#credentialSource = hasEnvOverride() ? "mixed" : "context";
@@ -456,6 +465,13 @@ export class ContextService {
456
465
  return context;
457
466
  }
458
467
 
468
+ async activatePrevious(): Promise<F5XCContext> {
469
+ if (!this.#previousContextName) {
470
+ throw new ContextError("No previous context. Switch contexts first with /context activate <name>.");
471
+ }
472
+ return this.activate(this.#previousContextName);
473
+ }
474
+
459
475
  async listContexts(): Promise<F5XCContext[]> {
460
476
  const files = this.#listContextFiles();
461
477
  const contexts: F5XCContext[] = [];
@@ -506,6 +522,9 @@ export class ContextService {
506
522
  }
507
523
  fs.unlinkSync(contextPath);
508
524
  this.#contextsCache = this.#contextsCache.filter(p => p.name !== name);
525
+ if (this.#previousContextName === name) {
526
+ this.#previousContextName = null;
527
+ }
509
528
  }
510
529
 
511
530
  /**
@@ -806,6 +825,9 @@ export class ContextService {
806
825
  this.#contextsCache = this.#contextsCache
807
826
  .map(p => (p.name === oldName ? { ...p, name: newName } : p))
808
827
  .sort((a, b) => a.name.localeCompare(b.name));
828
+ if (this.#previousContextName === oldName) {
829
+ this.#previousContextName = newName;
830
+ }
809
831
  if (wasActive && this.#activeContext) {
810
832
  this.#activeContext = { ...this.#activeContext, name: newName };
811
833
  for (const cb of ContextService.#onContextChangeListeners) {