@f5-sales-demo/xcsh 19.51.4 → 19.51.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/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [19.51.5] - 2026-06-26
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
- Sign + notarize the embedded native addon (`pi_natives.*.node`) in `build-sign-macos` **before** it is embedded into the compiled binary. xcsh extracts the embedded `.node` to `~/.xcsh/natives/<ver>/` at runtime; previously that extracted copy was ad-hoc-signed, so managed/MDM Macs blocked the `dlopen` ("could not verify it is free of malware"). The addon is now Developer-ID-signed with hardened runtime and notarized, so Gatekeeper's online check passes it without manual approval.
|
|
9
|
+
|
|
5
10
|
## [19.51.4] - 2026-06-26
|
|
6
11
|
|
|
7
12
|
### Added
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@f5-sales-demo/xcsh",
|
|
4
|
-
"version": "19.51.
|
|
4
|
+
"version": "19.51.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",
|
|
@@ -54,13 +54,13 @@
|
|
|
54
54
|
"dependencies": {
|
|
55
55
|
"@agentclientprotocol/sdk": "0.16.1",
|
|
56
56
|
"@mozilla/readability": "^0.6",
|
|
57
|
-
"@f5-sales-demo/xcsh-stats": "19.51.
|
|
58
|
-
"@f5-sales-demo/pi-agent-core": "19.51.
|
|
59
|
-
"@f5-sales-demo/pi-ai": "19.51.
|
|
60
|
-
"@f5-sales-demo/pi-natives": "19.51.
|
|
61
|
-
"@f5-sales-demo/pi-resource-management": "19.51.
|
|
62
|
-
"@f5-sales-demo/pi-tui": "19.51.
|
|
63
|
-
"@f5-sales-demo/pi-utils": "19.51.
|
|
57
|
+
"@f5-sales-demo/xcsh-stats": "19.51.4",
|
|
58
|
+
"@f5-sales-demo/pi-agent-core": "19.51.4",
|
|
59
|
+
"@f5-sales-demo/pi-ai": "19.51.4",
|
|
60
|
+
"@f5-sales-demo/pi-natives": "19.51.4",
|
|
61
|
+
"@f5-sales-demo/pi-resource-management": "19.51.4",
|
|
62
|
+
"@f5-sales-demo/pi-tui": "19.51.4",
|
|
63
|
+
"@f5-sales-demo/pi-utils": "19.51.4",
|
|
64
64
|
"@sinclair/typebox": "^0.34",
|
|
65
65
|
"@xterm/headless": "^6.0",
|
|
66
66
|
"ajv": "^8.20",
|
|
@@ -17,17 +17,17 @@ export interface BuildInfo {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export const BUILD_INFO: BuildInfo = {
|
|
20
|
-
"version": "19.51.
|
|
21
|
-
"commit": "
|
|
22
|
-
"shortCommit": "
|
|
20
|
+
"version": "19.51.4",
|
|
21
|
+
"commit": "4219192c5e072c0d7d4a54148b38b27b47d520f8",
|
|
22
|
+
"shortCommit": "4219192",
|
|
23
23
|
"branch": "main",
|
|
24
|
-
"tag": "v19.51.
|
|
25
|
-
"commitDate": "2026-06-
|
|
26
|
-
"buildDate": "2026-06-
|
|
24
|
+
"tag": "v19.51.5",
|
|
25
|
+
"commitDate": "2026-06-27T00:31:04Z",
|
|
26
|
+
"buildDate": "2026-06-27T01:00:15.899Z",
|
|
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.51.
|
|
31
|
+
"commitUrl": "https://github.com/f5-sales-demo/xcsh/commit/4219192c5e072c0d7d4a54148b38b27b47d520f8",
|
|
32
|
+
"releaseUrl": "https://github.com/f5-sales-demo/xcsh/releases/tag/v19.51.4"
|
|
33
33
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Container, Input, matchesKey, Spacer, Text, TruncatedText } from "@f5-sales-demo/pi-tui";
|
|
2
2
|
import type { XCSHContext } from "../../services/xcsh-context";
|
|
3
|
-
import { deriveTenantFromUrl } from "../../services/xcsh-env";
|
|
3
|
+
import { deriveTenantFromUrl, isSensitiveEnvKey, XCSH_CONSOLE_PASSWORD, XCSH_USERNAME } from "../../services/xcsh-env";
|
|
4
4
|
import { theme } from "../theme/theme";
|
|
5
5
|
import { matchesAppInterrupt } from "../utils/keybinding-matchers";
|
|
6
6
|
import { DynamicBorder } from "./dynamic-border";
|
|
@@ -28,18 +28,57 @@ export function validateWizardName(name: string): string | null {
|
|
|
28
28
|
return null;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
type WizardStep =
|
|
31
|
+
type WizardStep =
|
|
32
|
+
| "url"
|
|
33
|
+
| "token"
|
|
34
|
+
| "name"
|
|
35
|
+
| "validating"
|
|
36
|
+
| "namespace"
|
|
37
|
+
| "username"
|
|
38
|
+
| "password"
|
|
39
|
+
| "confirm"
|
|
40
|
+
| "activate";
|
|
32
41
|
|
|
33
42
|
interface WizardState {
|
|
34
43
|
url: string;
|
|
35
44
|
token: string;
|
|
36
45
|
name: string;
|
|
37
46
|
namespace: string;
|
|
47
|
+
/** Web-console login username (optional) — stored as the XCSH_USERNAME env var. */
|
|
48
|
+
username: string;
|
|
49
|
+
/** Web-console login password (optional) — stored as the XCSH_CONSOLE_PASSWORD env var. */
|
|
50
|
+
password: string;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Build the XCSHContext the wizard will persist from its collected state.
|
|
55
|
+
*
|
|
56
|
+
* The optional web-console credentials become generic env vars (XCSH_USERNAME /
|
|
57
|
+
* XCSH_CONSOLE_PASSWORD); any secret-looking key (the password) is auto-marked
|
|
58
|
+
* sensitive so it is masked in `/context show` and redacted on export. Exported
|
|
59
|
+
* so the persistence shape is unit-testable without driving the TUI.
|
|
60
|
+
*/
|
|
61
|
+
export function buildWizardContext(state: WizardState): XCSHContext {
|
|
62
|
+
const context: XCSHContext = {
|
|
63
|
+
name: state.name,
|
|
64
|
+
apiUrl: state.url,
|
|
65
|
+
apiToken: state.token,
|
|
66
|
+
defaultNamespace: state.namespace,
|
|
67
|
+
};
|
|
68
|
+
const env: Record<string, string> = {};
|
|
69
|
+
if (state.username) env[XCSH_USERNAME] = state.username;
|
|
70
|
+
if (state.password) env[XCSH_CONSOLE_PASSWORD] = state.password;
|
|
71
|
+
if (Object.keys(env).length > 0) {
|
|
72
|
+
context.env = env;
|
|
73
|
+
const sensitiveKeys = Object.keys(env).filter(isSensitiveEnvKey);
|
|
74
|
+
if (sensitiveKeys.length > 0) context.sensitiveKeys = sensitiveKeys;
|
|
75
|
+
}
|
|
76
|
+
return context;
|
|
38
77
|
}
|
|
39
78
|
|
|
40
79
|
export class ContextAddWizard extends Container {
|
|
41
80
|
#currentStep: WizardStep = "url";
|
|
42
|
-
#state: WizardState = { url: "", token: "", name: "", namespace: "default" };
|
|
81
|
+
#state: WizardState = { url: "", token: "", name: "", namespace: "default", username: "", password: "" };
|
|
43
82
|
#contentContainer: Container;
|
|
44
83
|
#inputField: Input | null = null;
|
|
45
84
|
#selectedIndex = 0;
|
|
@@ -104,6 +143,12 @@ export class ContextAddWizard extends Container {
|
|
|
104
143
|
case "namespace":
|
|
105
144
|
this.#renderNamespaceStep();
|
|
106
145
|
break;
|
|
146
|
+
case "username":
|
|
147
|
+
this.#renderUsernameStep();
|
|
148
|
+
break;
|
|
149
|
+
case "password":
|
|
150
|
+
this.#renderPasswordStep();
|
|
151
|
+
break;
|
|
107
152
|
case "confirm":
|
|
108
153
|
this.#renderConfirmStep();
|
|
109
154
|
break;
|
|
@@ -139,6 +184,7 @@ export class ContextAddWizard extends Container {
|
|
|
139
184
|
this.#contentContainer.addChild(new Spacer(1));
|
|
140
185
|
|
|
141
186
|
this.#inputField = new Input();
|
|
187
|
+
this.#inputField.setMasked(true);
|
|
142
188
|
this.#inputField.setValue(this.#state.token);
|
|
143
189
|
this.#contentContainer.addChild(this.#inputField);
|
|
144
190
|
this.#contentContainer.addChild(new Spacer(1));
|
|
@@ -288,8 +334,41 @@ export class ContextAddWizard extends Container {
|
|
|
288
334
|
this.#contentContainer.addChild(new Text(theme.fg("muted", "[Enter to continue, Esc to go back]"), 0, 0));
|
|
289
335
|
}
|
|
290
336
|
|
|
337
|
+
#renderUsernameStep(): void {
|
|
338
|
+
this.#contentContainer.addChild(new Text(theme.fg("contentAccent", "Step 6: Web-Console Username")));
|
|
339
|
+
this.#contentContainer.addChild(new Spacer(1));
|
|
340
|
+
this.#contentContainer.addChild(new Text("Enter the web-console login username (optional):", 0, 0));
|
|
341
|
+
this.#contentContainer.addChild(new Spacer(1));
|
|
342
|
+
|
|
343
|
+
this.#inputField = new Input();
|
|
344
|
+
this.#inputField.setValue(this.#state.username);
|
|
345
|
+
this.#contentContainer.addChild(this.#inputField);
|
|
346
|
+
this.#contentContainer.addChild(new Spacer(1));
|
|
347
|
+
|
|
348
|
+
this.#contentContainer.addChild(
|
|
349
|
+
new Text(theme.fg("muted", "[Enter to continue (empty to skip), Esc to go back]"), 0, 0),
|
|
350
|
+
);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
#renderPasswordStep(): void {
|
|
354
|
+
this.#contentContainer.addChild(new Text(theme.fg("contentAccent", "Step 7: Web-Console Password")));
|
|
355
|
+
this.#contentContainer.addChild(new Spacer(1));
|
|
356
|
+
this.#contentContainer.addChild(new Text("Enter the web-console login password (optional):", 0, 0));
|
|
357
|
+
this.#contentContainer.addChild(new Spacer(1));
|
|
358
|
+
|
|
359
|
+
this.#inputField = new Input();
|
|
360
|
+
this.#inputField.setMasked(true);
|
|
361
|
+
this.#inputField.setValue(this.#state.password);
|
|
362
|
+
this.#contentContainer.addChild(this.#inputField);
|
|
363
|
+
this.#contentContainer.addChild(new Spacer(1));
|
|
364
|
+
|
|
365
|
+
this.#contentContainer.addChild(
|
|
366
|
+
new Text(theme.fg("muted", "[Enter to continue (empty to skip), Esc to go back]"), 0, 0),
|
|
367
|
+
);
|
|
368
|
+
}
|
|
369
|
+
|
|
291
370
|
#renderConfirmStep(): void {
|
|
292
|
-
this.#contentContainer.addChild(new Text(theme.fg("contentAccent", "Step
|
|
371
|
+
this.#contentContainer.addChild(new Text(theme.fg("contentAccent", "Step 8: Confirm")));
|
|
293
372
|
this.#contentContainer.addChild(new Spacer(1));
|
|
294
373
|
|
|
295
374
|
// Summary table
|
|
@@ -298,6 +377,12 @@ export class ContextAddWizard extends Container {
|
|
|
298
377
|
const masked = this.#state.token.length > 4 ? `${"*".repeat(8)}${this.#state.token.slice(-4)}` : "****";
|
|
299
378
|
this.#contentContainer.addChild(new Text(`Token: ${masked}`, 0, 0));
|
|
300
379
|
this.#contentContainer.addChild(new Text(`Namespace: ${this.#state.namespace}`, 0, 0));
|
|
380
|
+
if (this.#state.username) {
|
|
381
|
+
this.#contentContainer.addChild(new Text(`Username: ${this.#state.username}`, 0, 0));
|
|
382
|
+
}
|
|
383
|
+
if (this.#state.password) {
|
|
384
|
+
this.#contentContainer.addChild(new Text(`Console Password: ${"*".repeat(8)}`, 0, 0));
|
|
385
|
+
}
|
|
301
386
|
this.#contentContainer.addChild(new Spacer(1));
|
|
302
387
|
|
|
303
388
|
this.#contentContainer.addChild(new Text("Save this context?", 0, 0));
|
|
@@ -318,7 +403,7 @@ export class ContextAddWizard extends Container {
|
|
|
318
403
|
}
|
|
319
404
|
|
|
320
405
|
#renderActivateStep(): void {
|
|
321
|
-
this.#contentContainer.addChild(new Text(theme.fg("contentAccent", "Step
|
|
406
|
+
this.#contentContainer.addChild(new Text(theme.fg("contentAccent", "Step 9: Activate")));
|
|
322
407
|
this.#contentContainer.addChild(new Spacer(1));
|
|
323
408
|
this.#contentContainer.addChild(new Text("Activate this context now?", 0, 0));
|
|
324
409
|
this.#contentContainer.addChild(new Spacer(1));
|
|
@@ -436,6 +521,19 @@ export class ContextAddWizard extends Container {
|
|
|
436
521
|
}
|
|
437
522
|
case "namespace": {
|
|
438
523
|
this.#state.namespace = value || "default";
|
|
524
|
+
this.#currentStep = "username";
|
|
525
|
+
break;
|
|
526
|
+
}
|
|
527
|
+
case "username": {
|
|
528
|
+
// Trimmed: usernames never carry meaningful surrounding whitespace.
|
|
529
|
+
this.#state.username = value;
|
|
530
|
+
this.#currentStep = "password";
|
|
531
|
+
break;
|
|
532
|
+
}
|
|
533
|
+
case "password": {
|
|
534
|
+
// Preserve the password exactly as typed — do NOT use the trimmed
|
|
535
|
+
// `value`, since a password may legitimately contain whitespace.
|
|
536
|
+
this.#state.password = this.#inputField.getValue();
|
|
439
537
|
this.#currentStep = "confirm";
|
|
440
538
|
this.#selectedIndex = 0;
|
|
441
539
|
break;
|
|
@@ -477,12 +575,7 @@ export class ContextAddWizard extends Container {
|
|
|
477
575
|
return;
|
|
478
576
|
}
|
|
479
577
|
case "activate": {
|
|
480
|
-
const context
|
|
481
|
-
name: this.#state.name,
|
|
482
|
-
apiUrl: this.#state.url,
|
|
483
|
-
apiToken: this.#state.token,
|
|
484
|
-
defaultNamespace: this.#state.namespace,
|
|
485
|
-
};
|
|
578
|
+
const context = buildWizardContext(this.#state);
|
|
486
579
|
this.#onCompleteCallback(context, this.#selectedIndex === 0);
|
|
487
580
|
return;
|
|
488
581
|
}
|
|
@@ -521,9 +614,15 @@ export class ContextAddWizard extends Container {
|
|
|
521
614
|
case "namespace":
|
|
522
615
|
this.#currentStep = "name";
|
|
523
616
|
break;
|
|
524
|
-
case "
|
|
617
|
+
case "username":
|
|
525
618
|
this.#currentStep = "namespace";
|
|
526
619
|
break;
|
|
620
|
+
case "password":
|
|
621
|
+
this.#currentStep = "username";
|
|
622
|
+
break;
|
|
623
|
+
case "confirm":
|
|
624
|
+
this.#currentStep = "password";
|
|
625
|
+
break;
|
|
527
626
|
case "activate":
|
|
528
627
|
this.#currentStep = "confirm";
|
|
529
628
|
break;
|