@f5-sales-demo/xcsh 19.102.4 → 19.102.5

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.102.4",
4
+ "version": "19.102.5",
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",
@@ -57,13 +57,13 @@
57
57
  "dependencies": {
58
58
  "@agentclientprotocol/sdk": "1.3.0",
59
59
  "@mozilla/readability": "^0.6",
60
- "@f5-sales-demo/xcsh-stats": "19.102.4",
61
- "@f5-sales-demo/pi-agent-core": "19.102.4",
62
- "@f5-sales-demo/pi-ai": "19.102.4",
63
- "@f5-sales-demo/pi-natives": "19.102.4",
64
- "@f5-sales-demo/pi-resource-management": "19.102.4",
65
- "@f5-sales-demo/pi-tui": "19.102.4",
66
- "@f5-sales-demo/pi-utils": "19.102.4",
60
+ "@f5-sales-demo/xcsh-stats": "19.102.5",
61
+ "@f5-sales-demo/pi-agent-core": "19.102.5",
62
+ "@f5-sales-demo/pi-ai": "19.102.5",
63
+ "@f5-sales-demo/pi-natives": "19.102.5",
64
+ "@f5-sales-demo/pi-resource-management": "19.102.5",
65
+ "@f5-sales-demo/pi-tui": "19.102.5",
66
+ "@f5-sales-demo/pi-utils": "19.102.5",
67
67
  "@sinclair/typebox": "^0.34",
68
68
  "@xterm/headless": "^6.0",
69
69
  "ajv": "^8.20",
@@ -17,17 +17,17 @@ export interface BuildInfo {
17
17
  }
18
18
 
19
19
  export const BUILD_INFO: BuildInfo = {
20
- "version": "19.102.4",
21
- "commit": "5beee843e5cd185c015cf2ca04edf5dde54eadb8",
22
- "shortCommit": "5beee84",
20
+ "version": "19.102.5",
21
+ "commit": "8a63bfb03a98e424c010b4176b65ed5583587dad",
22
+ "shortCommit": "8a63bfb",
23
23
  "branch": "main",
24
- "tag": "v19.102.4",
25
- "commitDate": "2026-07-30T20:21:22Z",
26
- "buildDate": "2026-07-30T20:45:02.127Z",
24
+ "tag": "v19.102.5",
25
+ "commitDate": "2026-07-30T22:33:51Z",
26
+ "buildDate": "2026-07-30T23:00:45.450Z",
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/5beee843e5cd185c015cf2ca04edf5dde54eadb8",
32
- "releaseUrl": "https://github.com/f5-sales-demo/xcsh/releases/tag/v19.102.4"
31
+ "commitUrl": "https://github.com/f5-sales-demo/xcsh/commit/8a63bfb03a98e424c010b4176b65ed5583587dad",
32
+ "releaseUrl": "https://github.com/f5-sales-demo/xcsh/releases/tag/v19.102.5"
33
33
  };
@@ -203,6 +203,12 @@ const COMMAND_BEARING_CONFIG = [
203
203
  // was measured working with its config.yml read-only.
204
204
  path.join(".config", "glab-cli", "aliases.yml"),
205
205
  path.join("Library", "Application Support", "glab-cli", "aliases.yml"),
206
+ // Build configuration that redirects a later build. Protected by *omission* while home was denied —
207
+ // the cache carve-outs grant `.cargo/registry` rather than `.cargo` — so #2637 had to name them. A
208
+ // write here is persistence, not theft: the operator's next build runs what it says. Reads are fine.
209
+ path.join(".cargo", "config.toml"),
210
+ path.join(".gradle", "init.gradle"),
211
+ path.join(".gradle", "init.d"),
206
212
  ];
207
213
 
208
214
  /** Read-only inside home: configuration a tool needs to behave correctly, but must not rewrite. */
@@ -268,9 +274,10 @@ const AGENT_PROFILE_FILES = ["user-profile.json", "computer-profile.json", "sett
268
274
  * unforeseen — `/data`, `/scratch`, a bespoke mount.
269
275
  */
270
276
  const DATA_ROOTS = [
271
- "/Users", // macOS home container: other operators' accounts, /Users/Shared
272
- "/home", // Linux home container
273
- "/root", // Linux superuser home
277
+ // `/Users` and `/home` are deliberately absent: denying the home container denies this operator's own
278
+ // home with it, which is the whole of #2637. Other accounts are 0700, so the filesystem already refuses
279
+ // them; the fence is not here to re-implement file permissions.
280
+ "/root", // Linux superuser home: not this operator's account
274
281
  "/Volumes", // macOS mounts. Per-container, not per-child: /Volumes/Macintosh HD resolves to /,
275
282
  "/mnt", // which `tooBroadToDeny` then rejects, and the kernel resolves such a path before any
276
283
  "/media", // rule matches it — so denying the container cannot deny the boot volume.
@@ -528,8 +535,22 @@ export function buildContainmentFence(options: ContainmentOptions): ContainmentF
528
535
  // rejects, so `/`, `/usr`, `/tmp` and `$TMPDIR` are never denied and operational paths stay
529
536
  // reachable. And it costs nothing below: the workspace is allowed at greater depth, and
530
537
  // `fenceVerdict` takes the deepest match.
531
- if (home !== undefined && home !== workspace) deny.add(home);
538
+ // Home is never denied, and the walk stops there (#2637).
539
+ //
540
+ // This is a professional courtesy, not a prison: an effort to stop *inadvertent* filesystem wandering
541
+ // between customers, for an operator with senior technical skills and the same rights on this machine
542
+ // as the agent acting for them. Denying home outright refused `~/git/STYLE_GUIDE.md` and then needed
543
+ // ~30 carve-outs to make ordinary tooling work again — every one of them evidence the posture was wrong.
544
+ //
545
+ // What the walk still covers is the part that matters: every level between the workspace and home. With
546
+ // the workspace at `~/MEDDPICC/EQUIFAX`, `~/MEDDPICC` is denied so the `ACME` sibling is unreachable,
547
+ // and with `<container>/<tenant>/repo` every level up to home is denied, so the v19.100.1 cross-tenant
548
+ // regression does not return.
549
+ //
550
+ // A session whose folder IS home, or a direct child of it, therefore fences nothing above itself. That
551
+ // is deliberate: if the operator chooses to work in home, that is their filesystem to lay out.
532
552
  for (let ancestor = path.dirname(workspace); ; ancestor = path.dirname(ancestor)) {
553
+ if (ancestor === home) break; // the operator's own account is theirs
533
554
  if (tooBroadToDeny(ancestor, fsRoot)) break;
534
555
  deny.add(ancestor);
535
556
  const next = path.dirname(ancestor);
@@ -629,6 +650,11 @@ export function buildContainmentFence(options: ContainmentOptions): ContainmentF
629
650
  // e.g. /Volumes/Macintosh HD -> /. Skipped for the whole-root list, per the note above.
630
651
  if (!rootScoped.has(resolved) && tooBroadToDeny(resolved, fsRoot)) continue;
631
652
  if (resolved === fsRoot) continue; // never the root the workspace lives on
653
+ // Never a directory that CONTAINS home, because denying it denies home (#2637). Removing `/Users`
654
+ // and `/home` from the static list was not enough: the root enumeration re-adds them, since
655
+ // `Users` is not an operational name. That is what still refused `~/git/STYLE_GUIDE.md` at the
656
+ // kernel while `fenceVerdict` said allow — the unit tests use synthetic roots and could not see it.
657
+ if (home !== undefined && pathIsWithin(resolved, home)) continue;
632
658
  // A deny beats an allow at EQUAL depth, so denying a root that IS the workspace or IS something
633
659
  // the operator granted would not be redundant — it would silently revoke the grant. Deeper is
634
660
  // fine and intended: an ancestor deny with the workspace allowed inside it is the normal shape.