@f5xc-salesdemos/xcsh 19.15.0 → 19.15.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": "19.15.0",
4
+ "version": "19.15.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",
@@ -50,12 +50,12 @@
50
50
  "dependencies": {
51
51
  "@agentclientprotocol/sdk": "0.16.1",
52
52
  "@mozilla/readability": "^0.6",
53
- "@f5xc-salesdemos/xcsh-stats": "19.15.0",
54
- "@f5xc-salesdemos/pi-agent-core": "19.15.0",
55
- "@f5xc-salesdemos/pi-ai": "19.15.0",
56
- "@f5xc-salesdemos/pi-natives": "19.15.0",
57
- "@f5xc-salesdemos/pi-tui": "19.15.0",
58
- "@f5xc-salesdemos/pi-utils": "19.15.0",
53
+ "@f5xc-salesdemos/xcsh-stats": "19.15.2",
54
+ "@f5xc-salesdemos/pi-agent-core": "19.15.2",
55
+ "@f5xc-salesdemos/pi-ai": "19.15.2",
56
+ "@f5xc-salesdemos/pi-natives": "19.15.2",
57
+ "@f5xc-salesdemos/pi-tui": "19.15.2",
58
+ "@f5xc-salesdemos/pi-utils": "19.15.2",
59
59
  "@sinclair/typebox": "^0.34",
60
60
  "@xterm/headless": "^6.0",
61
61
  "ajv": "^8.20",
@@ -17,17 +17,17 @@ export interface BuildInfo {
17
17
  }
18
18
 
19
19
  export const BUILD_INFO: BuildInfo = {
20
- "version": "19.15.0",
21
- "commit": "16f2b4bafacdf1eefeebfb12409b529cf1aa3354",
22
- "shortCommit": "16f2b4b",
20
+ "version": "19.15.2",
21
+ "commit": "64103505bda7d95e1a15c5002b3ad1ac3d8e0c9c",
22
+ "shortCommit": "6410350",
23
23
  "branch": "main",
24
- "tag": "v19.15.0",
25
- "commitDate": "2026-06-08T02:19:41Z",
26
- "buildDate": "2026-06-08T02:48:16.108Z",
24
+ "tag": "v19.15.2",
25
+ "commitDate": "2026-06-08T03:42:17Z",
26
+ "buildDate": "2026-06-08T04:04:32.761Z",
27
27
  "dirty": true,
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/16f2b4bafacdf1eefeebfb12409b529cf1aa3354",
32
- "releaseUrl": "https://github.com/f5xc-salesdemos/xcsh/releases/tag/v19.15.0"
31
+ "commitUrl": "https://github.com/f5xc-salesdemos/xcsh/commit/64103505bda7d95e1a15c5002b3ad1ac3d8e0c9c",
32
+ "releaseUrl": "https://github.com/f5xc-salesdemos/xcsh/releases/tag/v19.15.2"
33
33
  };
@@ -8,6 +8,8 @@ export interface ProfileCollector {
8
8
  readonly id: string;
9
9
  /** Human-readable name */
10
10
  readonly name: string;
11
+ /** Fields this collector is the authoritative source for. Overwrites even pre-existing values. */
12
+ readonly authoritativeFields?: readonly string[];
11
13
  /** Check if this collector can run (binary exists, platform ok, etc.) */
12
14
  available(): Promise<boolean>;
13
15
  /** Run the collector and return partial profile fields to merge */
@@ -147,7 +147,12 @@ export async function seedProfile(): Promise<UserProfile> {
147
147
  const META_FIELDS = new Set(["sources", "observations", "updatedAt", "_fieldOwnership"]);
148
148
  const FORBIDDEN_KEYS = new Set(["__proto__", "constructor", "prototype"]);
149
149
 
150
- export function reconcileProfile(target: UserProfile, source: Partial<UserProfile>, sourceId: string): void {
150
+ export function reconcileProfile(
151
+ target: UserProfile,
152
+ source: Partial<UserProfile>,
153
+ sourceId: string,
154
+ authoritativeFields?: ReadonlySet<string>,
155
+ ): void {
151
156
  const ownership = target._fieldOwnership ?? {};
152
157
 
153
158
  for (const [key, value] of Object.entries(source)) {
@@ -160,7 +165,8 @@ export function reconcileProfile(target: UserProfile, source: Partial<UserProfil
160
165
 
161
166
  if (currentOwner === "user") continue;
162
167
  if (currentOwner && currentOwner !== sourceId) continue;
163
- if (!currentOwner && target[k] !== undefined && target[k] !== null) continue;
168
+ const isAuthoritative = authoritativeFields?.has(k) ?? false;
169
+ if (!currentOwner && !isAuthoritative && target[k] !== undefined && target[k] !== null) continue;
164
170
 
165
171
  Object.defineProperty(target, k, { value, writable: true, enumerable: true, configurable: true });
166
172
  if (!currentOwner) {
@@ -183,7 +189,10 @@ export async function reconcileFromCollectors(): Promise<UserProfile> {
183
189
  continue;
184
190
  }
185
191
  const partial = await collector.collect();
186
- reconcileProfile(profile, partial, collector.id);
192
+ const authoritative = collector.authoritativeFields?.length
193
+ ? new Set(collector.authoritativeFields)
194
+ : undefined;
195
+ reconcileProfile(profile, partial, collector.id, authoritative);
187
196
  (profile.sources as Record<string, string>)[collector.id] = new Date().toISOString();
188
197
  logger.debug(`Profile collector '${collector.id}' reconciled`);
189
198
  } catch (err: unknown) {
@@ -21,7 +21,7 @@ export interface OutputBlockOptions {
21
21
  sections?: Array<{ label?: string; lines: string[] }>;
22
22
  width: number;
23
23
  applyBg?: boolean;
24
- /** Override the state-derived border color. Use sparingly only for branded core tools. */
24
+ /** Override the state-derived border color. Always takes precedence, including on error. Use for branded core tools. */
25
25
  borderColor?: ThemeColor;
26
26
  }
27
27
 
@@ -39,14 +39,11 @@ export function renderOutputBlock(options: OutputBlockOptions, theme: Theme): st
39
39
  const v = theme.boxSharp.vertical;
40
40
  const cap = h.repeat(3);
41
41
  const lineWidth = Math.max(0, width);
42
- // Border colors: error→error (red), warning→warning, running/pending→spinnerAccent, success→dim.
43
- // borderColorOverride (from options) takes precedence for non-error states on F5-branded tools (e.g. XC-API);
44
- // override is always cleared on error so all tools show a consistent error border; use F5_TOOL_BORDER_COLOR.
42
+ // borderColorOverride (F5 brand chrome) always takes precedence;
43
+ // built-in tools without an override use dim borders regardless of error state.
45
44
  const resolvedBorderColor: ThemeColor =
46
- state === "error"
47
- ? "error"
48
- : (borderColorOverride ??
49
- (state === "warning" ? "warning" : state === "running" || state === "pending" ? "spinnerAccent" : "dim"));
45
+ borderColorOverride ??
46
+ (state === "warning" ? "warning" : state === "running" || state === "pending" ? "spinnerAccent" : "dim");
50
47
  const border = (text: string) => theme.fg(resolvedBorderColor, text);
51
48
  const bgFn = (() => {
52
49
  if (!state || !applyBg) return undefined;