@f5-sales-demo/xcsh 19.105.4 → 19.105.7

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.
Files changed (45) hide show
  1. package/CHANGELOG.md +160 -28
  2. package/package.json +8 -8
  3. package/scripts/generate-api-spec-index.ts +7 -22
  4. package/scripts/generate-console-catalog.ts +2 -1
  5. package/scripts/sanitize-generated-content.ts +141 -0
  6. package/src/cli.ts +0 -3
  7. package/src/config/agent-config-file.ts +34 -0
  8. package/src/config/auto-config.ts +16 -4
  9. package/src/config/settings.ts +4 -2
  10. package/src/discovery/agents-md.ts +2 -2
  11. package/src/discovery/agents.ts +7 -7
  12. package/src/discovery/builtin.ts +14 -14
  13. package/src/discovery/claude-plugins.ts +6 -6
  14. package/src/discovery/claude.ts +10 -10
  15. package/src/discovery/cline.ts +2 -2
  16. package/src/discovery/codex.ts +10 -10
  17. package/src/discovery/cursor.ts +4 -4
  18. package/src/discovery/gemini.ts +7 -7
  19. package/src/discovery/github.ts +3 -3
  20. package/src/discovery/mcp-json.ts +2 -2
  21. package/src/discovery/opencode.ts +7 -7
  22. package/src/discovery/ssh.ts +2 -2
  23. package/src/discovery/vscode.ts +2 -2
  24. package/src/discovery/windsurf.ts +3 -3
  25. package/src/extensibility/extensions/loader.ts +0 -8
  26. package/src/extensibility/extensions/types.ts +0 -4
  27. package/src/internal-urls/build-info-runtime.ts +0 -1
  28. package/src/internal-urls/build-info.generated.ts +8 -8
  29. package/src/internal-urls/console-catalog.generated.ts +1 -1
  30. package/src/internal-urls/index.ts +0 -3
  31. package/src/internal-urls/terraform-resolve.ts +1 -1
  32. package/src/internal-urls/xcsh-protocol.ts +0 -73
  33. package/src/modes/components/model-selector.ts +5 -1
  34. package/src/modes/controllers/selector-controller.ts +3 -2
  35. package/src/modes/interactive-mode.ts +0 -8
  36. package/src/prompts/system/system-prompt.md +63 -26
  37. package/src/prompts/tools/xcsh-api.md +114 -60
  38. package/src/sandbox/containment.ts +3 -6
  39. package/src/sdk.ts +0 -47
  40. package/src/session/compaction/compaction.ts +1 -1
  41. package/src/system-prompt.ts +0 -21
  42. package/src/discovery/language.ts +0 -46
  43. package/src/internal-urls/computer-profile.ts +0 -692
  44. package/src/internal-urls/profile-collectors.ts +0 -371
  45. package/src/internal-urls/user-profile.ts +0 -431
package/CHANGELOG.md CHANGED
@@ -2,8 +2,34 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [19.105.7] - 2026-07-31
6
+
7
+ ### Fixed
8
+
9
+ - Fixed exact `provider/model` searches in `/model` and restricted global agent configuration writes to owner-only permissions ([#2741](https://github.com/f5-sales-demo/xcsh/issues/2741))
10
+
11
+ ## [19.105.6] - 2026-07-31
12
+
13
+ ### Breaking Changes
14
+
15
+ - Removed the `registerProfileCollector()` extension API and the `xcsh://user` and `xcsh://computer` routes. Extensions must no longer register workstation or user identity collectors. ([#2674](https://github.com/f5-sales-demo/xcsh/issues/2674))
16
+
17
+ ### Removed
18
+
19
+ - Removed automatic collection, persistence, and prompt injection of user and workstation profile data, including names, contact details, employer and manager information, addresses, social identifiers, hostnames, and endpoint security inventory. ([#2674](https://github.com/f5-sales-demo/xcsh/issues/2674))
20
+
5
21
  ### Fixed
6
22
 
23
+ - Fixed the checksum-pinned Zig installer on macOS and Windows native release runners and added cross-platform pre-merge validation ([#61](https://github.com/f5-sales-demo/xcsh/issues/61))
24
+
25
+ ## [19.105.5] - 2026-07-31
26
+
27
+ ### Fixed
28
+
29
+ - Added post-publication Homebrew install verification to the release workflow ([#2719](https://github.com/f5-sales-demo/xcsh/issues/2719))
30
+ - Replaced the deprecated Node 20 Zig setup action with a checksum-pinned official installer ([#61](https://github.com/f5-sales-demo/xcsh/issues/61))
31
+ - Invalidated stale release PRs immediately on new `main` pushes, before the full release-creation gate ([#2732](https://github.com/f5-sales-demo/xcsh/issues/2732))
32
+ - Preserved GPT-5.6 Sol High reasoning and token-limit metadata through generated LiteLLM model discovery ([#2729](https://github.com/f5-sales-demo/xcsh/issues/2729))
7
33
  - Regenerated stale same-version release PRs when newer commits have merged into `main` ([#2727](https://github.com/f5-sales-demo/xcsh/issues/2727))
8
34
 
9
35
  ## [19.105.3] - 2026-07-31
@@ -33,16 +59,23 @@
33
59
  ## [19.51.5] - 2026-06-26
34
60
 
35
61
  ### Fixed
36
- - 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.
62
+
63
+ - Sign + notarize the embedded native addon (`pi_natives.*.node`) in `build-sign-macos` **before** it is embedded into
64
+ the compiled binary. xcsh extracts the embedded `.node` to `~/.xcsh/natives/<ver>/` at runtime; previously that
65
+ extracted copy was ad-hoc-signed, so managed/MDM Macs blocked the `dlopen` ("could not verify it is free of
66
+ malware"). The addon is now Developer-ID-signed with hardened runtime and notarized, so Gatekeeper's online check
67
+ passes it without manual approval.
37
68
 
38
69
  ## [19.51.4] - 2026-06-26
39
70
 
40
71
  ### Added
72
+
41
73
  - Deterministic NL→XC console automation: the system prompt mandates the purpose-built `catalog_workflow_runner` console skill (extension-driven) and forbids the generic Puppeteer browser tool for F5 XC console pages; visible Chrome is framed as the flagship showcase, headless as the exception.
42
74
  - Native-messaging host auto-install on console-automation init (idempotent), with a baked-in Web Store URL and fail-fast guidance when the extension is not connected.
43
75
  - Gated, security-clean relay tracing in `chrome-host` for diagnosing the bridge-connect step.
44
76
 
45
77
  ### Fixed
78
+
46
79
  - Native host now uses the compiled `xcsh` binary (not `bun + cli.ts`), which survives Chrome's stripped-env launch.
47
80
  - Re-embedded console catalog/field-metadata with the `urn:xcsh:console:workflow:v1` schema and the tcp-load-balancer / network-interface defect fixes plus label corrections.
48
81
  - Pre-existing biome lint/format issues that were blocking CI.
@@ -67,7 +100,10 @@
67
100
 
68
101
  ### Changed
69
102
 
70
- - Salesforce tools extracted to marketplace plugin: sf_setup, sf_query, sf_org_display, and sf_pipeline_report are now available as an installable plugin (`@f5-sales-demo/xcsh-salesforce`) via the Extension API instead of built-in tools. Install with `xcsh plugin install salesforce`. Context discovery, pipeline reporting, and container-adapted authentication are preserved with full feature parity. ([#1059](https://github.com/f5-sales-demo/xcsh/issues/1059))
103
+ - Salesforce tools extracted to marketplace plugin: sf_setup, sf_query, sf_org_display, and sf_pipeline_report are now
104
+ available as an installable plugin (`@f5-sales-demo/xcsh-salesforce`) via the Extension API instead of built-in
105
+ tools. Install with `xcsh plugin install salesforce`. Context discovery, pipeline reporting, and container-adapted
106
+ authentication are preserved with full feature parity. ([#1059](https://github.com/f5-sales-demo/xcsh/issues/1059))
71
107
 
72
108
  ## [18.75.0] - 2026-05-23
73
109
 
@@ -79,7 +115,11 @@
79
115
 
80
116
  ### Fixed
81
117
 
82
- - Welcome banner cloud provider hints: AWS SSO token expiry now correctly suggests `aws sso login` instead of `aws configure`; Google Cloud check replaced `gcloud auth list` (false positives on expired tokens) with `gcloud auth print-access-token`; F5 XC Context surfaces `errorClass` (network/URL) in hints; GitLab `project_inaccessible` gets its own hint; Salesforce differentiates `session_expired` and `not_configured` hints ([#825](https://github.com/f5-sales-demo/xcsh/issues/825))
118
+ - Welcome banner cloud provider hints: AWS SSO token expiry now correctly suggests `aws sso login` instead of `aws
119
+ configure`; Google Cloud check replaced `gcloud auth list` (false positives on expired tokens) with `gcloud auth
120
+ print-access-token`; F5 XC Context surfaces `errorClass` (network/URL) in hints; GitLab `project_inaccessible` gets
121
+ its own hint; Salesforce differentiates `session_expired` and `not_configured` hints
122
+ ([#825](https://github.com/f5-sales-demo/xcsh/issues/825))
83
123
 
84
124
  ## [18.64.0] - 2026-05-13
85
125
 
@@ -92,7 +132,11 @@
92
132
 
93
133
  ### Changed
94
134
 
95
- - Regenerated API spec index from catalog v2.1.82: http_loadbalancer CRUD verification corrections (6 new server defaults, corrected minimum configs, cross-field dependencies, default_pool inline pool discovery, 5 composable routing approaches) and tcp_loadbalancer minimum config corrections (listen_port, origin_pools_weights, do_not_advertise format, 9 server defaults, forced hash_policy default) ([#753](https://github.com/f5-sales-demo/xcsh/issues/753), [#757](https://github.com/f5-sales-demo/xcsh/issues/757))
135
+ - Regenerated API spec index from catalog v2.1.82: http_loadbalancer CRUD verification corrections (6 new server
136
+ defaults, corrected minimum configs, cross-field dependencies, default_pool inline pool discovery, 5 composable
137
+ routing approaches) and tcp_loadbalancer minimum config corrections (listen_port, origin_pools_weights,
138
+ do_not_advertise format, 9 server defaults, forced hash_policy default)
139
+ ([#753](https://github.com/f5-sales-demo/xcsh/issues/753), [#757](https://github.com/f5-sales-demo/xcsh/issues/757))
96
140
 
97
141
  ## [18.53.0] - 2026-05-09
98
142
 
@@ -156,25 +200,40 @@
156
200
 
157
201
  ### Fixed
158
202
 
159
- - Fixed gutter width propagation in the fallback tool renderer: `#formatToolExecution()` now receives the actual available width at render-time and uses it for line truncation instead of a hardcoded 80-column limit. On narrow terminals (<82 cols) this prevents content wider than the gutter-adjusted viewport; on wide terminals it allows longer output lines. ([#117](https://github.com/f5-sales-demo/xcsh/issues/117))
203
+ - Fixed gutter width propagation in the fallback tool renderer: `#formatToolExecution()` now receives the actual
204
+ available width at render-time and uses it for line truncation instead of a hardcoded 80-column limit. On narrow
205
+ terminals (<82 cols) this prevents content wider than the gutter-adjusted viewport; on wide terminals it allows
206
+ longer output lines. ([#117](https://github.com/f5-sales-demo/xcsh/issues/117))
160
207
  - Fixed `resolveConfigValue` returning literal env var names (e.g. `"LITELLM_API_KEY"`) as API keys when the env var is unset, causing 401 errors on first launch. The resolver now rejects unresolved `ALL_CAPS_WITH_UNDERSCORES` patterns, matching the existing guard in `resolveYamlApiKeyConfig`. ([#241](https://github.com/f5-sales-demo/xcsh/issues/241))
161
208
 
162
209
  ### Changed
163
210
 
164
- - Renamed F5 XC credential system from "profile" to "context" to align with kubectl conventions. The `/profile` command is now `/context`, all types/classes use `Context*` naming (`ContextService`, `ContextStatus`, `F5XCContext`, etc.), on-disk paths changed from `profiles/` to `contexts/` and `active_profile` to `active_context`, and the status-line segment ID is now `context_f5xc`. ([#302](https://github.com/f5-sales-demo/xcsh/issues/302))
211
+ - Renamed F5 XC credential system from "profile" to "context" to align with kubectl conventions. The `/profile` command
212
+ is now `/context`, all types/classes use `Context*` naming (`ContextService`, `ContextStatus`, `F5XCContext`, etc.),
213
+ on-disk paths changed from `profiles/` to `contexts/` and `active_profile` to `active_context`, and the status-line
214
+ segment ID is now `context_f5xc`. ([#302](https://github.com/f5-sales-demo/xcsh/issues/302))
165
215
 
166
216
  ## [18.12.0] - 2026-04-23
167
217
 
168
218
  ### Changed
169
219
 
170
- - **System prompt realigned around the SE coworker primary mission.** The `<role>` block now leads with "technical coworker for F5 Distributed Cloud sales engineers" and names demos, MEDDPICC qualification, customer meeting preparation, and F5 XC product subject-matter expertise as primary activities — technical depth is retained as an explicit enabling credential, not subordinated. `<behavior>` reframes around the **presentation reflex** (confirming a capability before verifying it against current docs) with a conditional clause preserving the **deployment reflex** guard when the task is infrastructure. `<stakes>` leads with customer-facing risk (lost deals, damaged credibility, post-sale trust erosion) and retains infra stakes (outages, security exposures) as a secondary clause.
220
+ - **System prompt realigned around the SE coworker primary mission.** The `<role>` block now leads with "technical
221
+ coworker for F5 Distributed Cloud sales engineers" and names demos, MEDDPICC qualification, customer meeting
222
+ preparation, and F5 XC product subject-matter expertise as primary activities — technical depth is retained as an
223
+ explicit enabling credential, not subordinated. `<behavior>` reframes around the **presentation reflex** (confirming
224
+ a capability before verifying it against current docs) with a conditional clause preserving the **deployment reflex**
225
+ guard when the task is infrastructure. `<stakes>` leads with customer-facing risk (lost deals, damaged credibility,
226
+ post-sale trust erosion) and retains infra stakes (outages, security exposures) as a secondary clause.
171
227
  - **Identity section moved above Workspace in the rendered prompt.** Static behavioral anchors now occupy the highest-attention position at the top of the prompt, and dynamic context-file changes no longer invalidate the cache for static behavioral content.
172
228
  - **Replaced the sea-color epistemic-integrity example** with a bot-defense-SKU vs contract-claim scenario. The three examples now cover SE domain (product claim vs contract reality), infra domain (LB health-check probe layer), and technical domain (mutex race) — diverse and domain-grounded.
173
229
  - **Compressed the `xcsh://` routing instruction** from 3 lines to 2 lines. The redundant trigger-phrase enumeration is removed; the MUST directive is sufficient now that `xcsh://about` also documents the architecture.
174
230
 
175
231
  ### Added
176
232
 
177
- - **`.xcsh/rules/config-integrity.md`** — new scoped rule carrying the dependency-first IaC guidance that previously lived in the always-on `<config-integrity>` block. Fires on `tool:edit` and `tool:write` for `.tf`, `.yaml`, `.yml`, `.json`, `.sh`, `Makefile`, `Dockerfile`, `.toml`. Uses `condition: "."` (always-true regex) so the rules engine registers it — rules without a `condition` are silently dropped.
233
+ - **`.xcsh/rules/config-integrity.md`** — new scoped rule carrying the dependency-first IaC guidance that previously
234
+ lived in the always-on `<config-integrity>` block. Fires on `tool:edit` and `tool:write` for `.tf`, `.yaml`, `.yml`,
235
+ `.json`, `.sh`, `Makefile`, `Dockerfile`, `.toml`. Uses `condition: "."` (always-true regex) so the rules engine
236
+ registers it — rules without a `condition` are silently dropped.
178
237
  - **`xcsh://about` enriched** with `## Lineage` (upstream fork + maintainer), `## Architecture` (package role map), and `## Capabilities` (feature surface summary). On-demand only; zero system-prompt token cost.
179
238
 
180
239
  ### Removed
@@ -187,12 +246,24 @@ Refs: #254, #243.
187
246
 
188
247
  ### Removed
189
248
 
190
- - **All built-in themes except `xcsh-dark` and `xcsh-light` have been removed.** The 99 community themes previously shipped under `packages/coding-agent/src/modes/theme/defaults/` (`dark-ocean`, `dark-dracula`, `titanium`, `anthracite`, etc.), as well as the base `dark` and `light` themes, are no longer included. The hardcoded fallback when a user's theme fails to load now targets `xcsh-dark`. Users on a removed theme will fall back to `xcsh-dark` on next launch. User-authored themes under `~/.xcsh/agent/themes/` are unaffected.
249
+ - **All built-in themes except `xcsh-dark` and `xcsh-light` have been removed.** The 99 community themes previously
250
+ shipped under `packages/coding-agent/src/modes/theme/defaults/` (`dark-ocean`, `dark-dracula`, `titanium`,
251
+ `anthracite`, etc.), as well as the base `dark` and `light` themes, are no longer included. The hardcoded fallback
252
+ when a user's theme fails to load now targets `xcsh-dark`. Users on a removed theme will fall back to `xcsh-dark` on
253
+ next launch. User-authored themes under `~/.xcsh/agent/themes/` are unaffected.
191
254
 
192
255
  ### Changed
193
256
 
194
- - **TUI tool-call outcomes now render as a single colored gutter ball (●).** Inline `✓/✗/⚠` status icons were removed from every tool renderer. A new "warning" outcome (orange ball) signals non-error degraded states such as grep with zero matches, exa with zero results, ast-grep with zero matches, or ask falling back to a headless/empty-questions path. `xcsh-dark` uses `warmAmber` (#ffb347); `xcsh-light` uses `#b85e00` (WCAG AA on white). User-authored themes inherit via the `gutterWarning → warning` fallback chain.
195
- - **`AgentToolResult` and `tool_execution_end` events gain an optional `isWarning?: boolean`** alongside `isError`. Tools that want an orange gutter ball on zero-result or fallback paths set this field (or use the new `ToolResultBuilder.isWarning()` fluent method). Extensions subscribing to `tool_execution_end` and `tool_result` hook events now receive the flag; existing extensions are unaffected. Backwards-compatible unset means "not a warning."
257
+ - **TUI tool-call outcomes now render as a single colored gutter ball (●).** Inline `✓/✗/⚠` status icons were
258
+ removed from every tool renderer. A new "warning" outcome (orange ball) signals non-error degraded states such as
259
+ grep with zero matches, exa with zero results, ast-grep with zero matches, or ask falling back to a
260
+ headless/empty-questions path. `xcsh-dark` uses `warmAmber` (#ffb347); `xcsh-light` uses `#b85e00` (WCAG AA on
261
+ white). User-authored themes inherit via the `gutterWarning → warning` fallback chain.
262
+ - **`AgentToolResult` and `tool_execution_end` events gain an optional `isWarning?: boolean`** alongside `isError`.
263
+ Tools that want an orange gutter ball on zero-result or fallback paths set this field (or use the new
264
+ `ToolResultBuilder.isWarning()` fluent method). Extensions subscribing to `tool_execution_end` and `tool_result` hook
265
+ events now receive the flag; existing extensions are unaffected. Backwards-compatible — unset means "not a
266
+ warning."
196
267
  - **`formatEmptyMessage` and `formatErrorMessage` helpers no longer prepend ⚠/✗ glyphs.** Centralized fix so every tool renderer inherits the glyph-free output without a per-file workaround.
197
268
 
198
269
  Refs: #173.
@@ -201,7 +272,10 @@ Refs: #173.
201
272
 
202
273
  ### Fixed
203
274
 
204
- - Widened the `defaultThinkingLevel` schema enum to include `"off"`, which was already a supported runtime value via `resolveThinkingLevelForModel` but was not declared as a valid schema value. This closes a type-safety gap where programmatic callers (tests, config.yml edits) could set `"off"` without a `SettingValue` type narrowing it. The `/settings` UI dropdown is unchanged; the widening is schema-level only.
275
+ - Widened the `defaultThinkingLevel` schema enum to include `"off"`, which was already a supported runtime value via
276
+ `resolveThinkingLevelForModel` but was not declared as a valid schema value. This closes a type-safety gap where
277
+ programmatic callers (tests, config.yml edits) could set `"off"` without a `SettingValue` type narrowing it. The
278
+ `/settings` UI dropdown is unchanged; the widening is schema-level only.
205
279
 
206
280
  ### Changed
207
281
 
@@ -3892,7 +3966,10 @@ Refs: #173.
3892
3966
 
3893
3967
  ### Fixed
3894
3968
 
3895
- - External edits to `config.yml` are now preserved when omp reloads or saves unrelated settings. Previously, editing config.yml directly (e.g., removing a package from `packages` array) would be silently reverted on next omp startup when automatic setters like `setLastChangelogVersion()` triggered a save. ([#1046](https://github.com/badlogic/pi-mono/pull/1046) by [@nicobailonMD](https://github.com/nicobailonMD))
3969
+ - External edits to `config.yml` are now preserved when omp reloads or saves unrelated settings. Previously, editing
3970
+ config.yml directly (e.g., removing a package from `packages` array) would be silently reverted on next omp startup
3971
+ when automatic setters like `setLastChangelogVersion()` triggered a save.
3972
+ ([#1046](https://github.com/badlogic/pi-mono/pull/1046) by [@nicobailonMD](https://github.com/nicobailonMD))
3896
3973
 
3897
3974
  ## [8.13.0] - 2026-01-29
3898
3975
 
@@ -5042,7 +5119,13 @@ Refs: #173.
5042
5119
  ### Added
5043
5120
 
5044
5121
  - Exported `InteractiveModeOptions` type for programmatic SDK usage
5045
- - Exported additional UI components for extensions: `ArminComponent`, `AssistantMessageComponent`, `BashExecutionComponent`, `BranchSummaryMessageComponent`, `CompactionSummaryMessageComponent`, `CustomEditor`, `CustomMessageComponent`, `FooterComponent`, `ExtensionEditorComponent`, `ExtensionInputComponent`, `ExtensionSelectorComponent`, `LoginDialogComponent`, `ModelSelectorComponent`, `OAuthSelectorComponent`, `SessionSelectorComponent`, `SettingsSelectorComponent`, `ShowImagesSelectorComponent`, `ThemeSelectorComponent`, `ThinkingSelectorComponent`, `ToolExecutionComponent`, `TreeSelectorComponent`, `UserMessageComponent`, `UserMessageSelectorComponent`
5122
+ - Exported additional UI components for extensions: `ArminComponent`, `AssistantMessageComponent`,
5123
+ `BashExecutionComponent`, `BranchSummaryMessageComponent`, `CompactionSummaryMessageComponent`, `CustomEditor`,
5124
+ `CustomMessageComponent`, `FooterComponent`, `ExtensionEditorComponent`, `ExtensionInputComponent`,
5125
+ `ExtensionSelectorComponent`, `LoginDialogComponent`, `ModelSelectorComponent`, `OAuthSelectorComponent`,
5126
+ `SessionSelectorComponent`, `SettingsSelectorComponent`, `ShowImagesSelectorComponent`, `ThemeSelectorComponent`,
5127
+ `ThinkingSelectorComponent`, `ToolExecutionComponent`, `TreeSelectorComponent`, `UserMessageComponent`,
5128
+ `UserMessageSelectorComponent`
5046
5129
  - Exported `renderDiff`, `truncateToVisualLines`, and related types for extension use
5047
5130
  - `setFooter()` and `setHeader()` methods on `ExtensionUIContext` for custom footer/header components
5048
5131
  - `setEditorComponent()` method on `ExtensionUIContext` for custom editor components
@@ -5489,7 +5572,12 @@ Refs: #173.
5489
5572
 
5490
5573
  ### Added
5491
5574
 
5492
- - Added 65 new built-in color themes including dark variants (abyss, aurora, cavern, copper, cosmos, eclipse, ember, equinox, lavender, lunar, midnight, nebula, rainforest, reef, sakura, slate, solstice, starfall, swamp, taiga, terminal, tundra, twilight, volcanic), light variants (aurora-day, canyon, cirrus, coral, dawn, dunes, eucalyptus, frost, glacier, haze, honeycomb, lagoon, lavender, meadow, mint, opal, orchard, paper, prism, sand, savanna, soleil, wetland, zenith), and material themes (alabaster, amethyst, anthracite, basalt, birch, graphite, limestone, mahogany, marble, obsidian, onyx, pearl, porcelain, quartz, sandstone, titanium)
5575
+ - Added 65 new built-in color themes including dark variants (abyss, aurora, cavern, copper, cosmos, eclipse, ember,
5576
+ equinox, lavender, lunar, midnight, nebula, rainforest, reef, sakura, slate, solstice, starfall, swamp, taiga,
5577
+ terminal, tundra, twilight, volcanic), light variants (aurora-day, canyon, cirrus, coral, dawn, dunes, eucalyptus,
5578
+ frost, glacier, haze, honeycomb, lagoon, lavender, meadow, mint, opal, orchard, paper, prism, sand, savanna, soleil,
5579
+ wetland, zenith), and material themes (alabaster, amethyst, anthracite, basalt, birch, graphite, limestone, mahogany,
5580
+ marble, obsidian, onyx, pearl, porcelain, quartz, sandstone, titanium)
5493
5581
 
5494
5582
  ### Fixed
5495
5583
 
@@ -6324,7 +6412,11 @@ Total color count increased from 46 to 50. See [docs/theme.md](docs/theme.md) fo
6324
6412
 
6325
6413
  ### Breaking
6326
6414
 
6327
- - **Session hooks API redesign**: Merged `branch` event into `session` event. `BranchEvent`, `BranchEventResult` types and `pi.on("branch", ...)` removed. Use `pi.on("session", ...)` with `reason: "before_branch" | "branch"` instead. `AgentSession.branch()` returns `{ cancelled }` instead of `{ skipped }`. `AgentSession.reset()` and `switchSession()` now return `boolean` (false if cancelled by hook). RPC commands `reset`, `switch_session`, and `branch` now include `cancelled` in response data. ([#278](https://github.com/badlogic/pi-mono/issues/278))
6415
+ - **Session hooks API redesign**: Merged `branch` event into `session` event. `BranchEvent`, `BranchEventResult` types
6416
+ and `pi.on("branch", ...)` removed. Use `pi.on("session", ...)` with `reason: "before_branch" | "branch"` instead.
6417
+ `AgentSession.branch()` returns `{ cancelled }` instead of `{ skipped }`. `AgentSession.reset()` and
6418
+ `switchSession()` now return `boolean` (false if cancelled by hook). RPC commands `reset`, `switch_session`, and
6419
+ `branch` now include `cancelled` in response data. ([#278](https://github.com/badlogic/pi-mono/issues/278))
6328
6420
 
6329
6421
  ### Added
6330
6422
 
@@ -6480,7 +6572,11 @@ Total color count increased from 46 to 50. See [docs/theme.md](docs/theme.md) fo
6480
6572
 
6481
6573
  - **Subagent example improvements**: Parallel mode now streams updates from all tasks. Chain mode shows all completed steps during streaming. Expanded view uses proper markdown rendering with syntax highlighting. Usage footer shows turn count.
6482
6574
 
6483
- - **Skills standard compliance**: Skills now adhere to the [Agent Skills standard](https://agentskills.io/specification). Validates name (must match parent directory, lowercase, max 64 chars), description (required, max 1024 chars), and frontmatter fields. Warns on violations but remains lenient. Prompt format changed to XML structure. Removed `{baseDir}` placeholder in favor of relative paths. ([#231](https://github.com/badlogic/pi-mono/issues/231))
6575
+ - **Skills standard compliance**: Skills now adhere to the [Agent Skills
6576
+ standard](https://agentskills.io/specification). Validates name (must match parent directory, lowercase, max 64
6577
+ chars), description (required, max 1024 chars), and frontmatter fields. Warns on violations but remains lenient.
6578
+ Prompt format changed to XML structure. Removed `{baseDir}` placeholder in favor of relative paths.
6579
+ ([#231](https://github.com/badlogic/pi-mono/issues/231))
6484
6580
 
6485
6581
  ### Fixed
6486
6582
 
@@ -6545,7 +6641,10 @@ Total color count increased from 46 to 50. See [docs/theme.md](docs/theme.md) fo
6545
6641
 
6546
6642
  ### Fixed
6547
6643
 
6548
- - Fixed Claude models via GitHub Copilot re-answering all previous prompts in multi-turn conversations. The issue was that assistant message content was sent as an array instead of a string, which Copilot's Claude adapter misinterpreted. Also added missing `Openai-Intent: conversation-edits` header and fixed `X-Initiator` logic to check for any assistant/tool message in history. ([#209](https://github.com/badlogic/pi-mono/issues/209))
6644
+ - Fixed Claude models via GitHub Copilot re-answering all previous prompts in multi-turn conversations. The issue was
6645
+ that assistant message content was sent as an array instead of a string, which Copilot's Claude adapter
6646
+ misinterpreted. Also added missing `Openai-Intent: conversation-edits` header and fixed `X-Initiator` logic to check
6647
+ for any assistant/tool message in history. ([#209](https://github.com/badlogic/pi-mono/issues/209))
6549
6648
 
6550
6649
  - Detect image MIME type via file magic (read tool and `@file` attachments), not filename extension.
6551
6650
 
@@ -6633,7 +6732,11 @@ _Dedicated to Peter's shoulder ([@steipete](https://twitter.com/steipete))_
6633
6732
 
6634
6733
  ### Added
6635
6734
 
6636
- - **Inline image rendering**: Terminals supporting Kitty graphics protocol (Kitty, Ghostty, WezTerm) or iTerm2 inline images now render images inline in tool output. Aspect ratio is preserved by querying terminal cell dimensions on startup. Toggle with `/show-images` command or `terminal.showImages` setting. Falls back to text placeholder on unsupported terminals or when disabled. ([#177](https://github.com/badlogic/pi-mono/pull/177) by [@nicobailon](https://github.com/nicobailon))
6735
+ - **Inline image rendering**: Terminals supporting Kitty graphics protocol (Kitty, Ghostty, WezTerm) or iTerm2 inline
6736
+ images now render images inline in tool output. Aspect ratio is preserved by querying terminal cell dimensions on
6737
+ startup. Toggle with `/show-images` command or `terminal.showImages` setting. Falls back to text placeholder on
6738
+ unsupported terminals or when disabled. ([#177](https://github.com/badlogic/pi-mono/pull/177) by
6739
+ [@nicobailon](https://github.com/nicobailon))
6637
6740
 
6638
6741
  - **Gemini 3 Pro thinking levels**: Thinking level selector now works with Gemini 3 Pro models. Minimal/low map to Google's LOW, medium/high map to Google's HIGH. ([#176](https://github.com/badlogic/pi-mono/pull/176) by [@markusylisiurunen](https://github.com/markusylisiurunen))
6639
6742
 
@@ -6669,7 +6772,11 @@ _Dedicated to Peter's shoulder ([@steipete](https://twitter.com/steipete))_
6669
6772
 
6670
6773
  ### Added
6671
6774
 
6672
- - **Skills system**: Auto-discover and load instruction files on-demand. Supports Claude Code (`~/.claude/skills/*/SKILL.md`), Codex CLI (`~/.codex/skills/`), and OMP-native formats (`~/.omp/agent/skills/`, `.omp/skills/`). Skills are listed in system prompt with descriptions, agent loads them via read tool when needed. Supports `{baseDir}` placeholder. Disable with `--no-skills` or `skills.enabled: false` in settings. ([#169](https://github.com/badlogic/pi-mono/issues/169))
6775
+ - **Skills system**: Auto-discover and load instruction files on-demand. Supports Claude Code
6776
+ (`~/.claude/skills/*/SKILL.md`), Codex CLI (`~/.codex/skills/`), and OMP-native formats (`~/.omp/agent/skills/`,
6777
+ `.omp/skills/`). Skills are listed in system prompt with descriptions, agent loads them via read tool when needed.
6778
+ Supports `{baseDir}` placeholder. Disable with `--no-skills` or `skills.enabled: false` in settings.
6779
+ ([#169](https://github.com/badlogic/pi-mono/issues/169))
6673
6780
 
6674
6781
  - **Version flag**: Added `--version` / `-v` flag to display the current version and exit. ([#170](https://github.com/badlogic/pi-mono/pull/170))
6675
6782
 
@@ -6677,7 +6784,11 @@ _Dedicated to Peter's shoulder ([@steipete](https://twitter.com/steipete))_
6677
6784
 
6678
6785
  ### Added
6679
6786
 
6680
- - **Auto-retry on transient errors**: Automatically retries requests when providers return overloaded, rate limit, or server errors (429, 500, 502, 503, 504). Uses exponential backoff (2s, 4s, 8s). Shows retry status in TUI with option to cancel via Escape. Configurable in `settings.json` via `retry.enabled`, `retry.maxRetries`, `retry.baseDelayMs`. RPC mode emits `auto_retry_start` and `auto_retry_end` events. ([#157](https://github.com/badlogic/pi-mono/issues/157))
6787
+ - **Auto-retry on transient errors**: Automatically retries requests when providers return overloaded, rate limit, or
6788
+ server errors (429, 500, 502, 503, 504). Uses exponential backoff (2s, 4s, 8s). Shows retry status in TUI with option
6789
+ to cancel via Escape. Configurable in `settings.json` via `retry.enabled`, `retry.maxRetries`, `retry.baseDelayMs`.
6790
+ RPC mode emits `auto_retry_start` and `auto_retry_end` events.
6791
+ ([#157](https://github.com/badlogic/pi-mono/issues/157))
6681
6792
 
6682
6793
  - **HTML export line numbers**: Read tool calls in HTML exports now display line number ranges (e.g., `file.txt:10-20`) when offset/limit parameters are used, matching the TUI display format. Line numbers appear in yellow color for better visibility. ([#166](https://github.com/badlogic/pi-mono/issues/166))
6683
6794
 
@@ -6703,7 +6814,12 @@ _Dedicated to Peter's shoulder ([@steipete](https://twitter.com/steipete))_
6703
6814
 
6704
6815
  ### Added
6705
6816
 
6706
- - **Hooks system**: TypeScript modules that extend agent behavior by subscribing to lifecycle events. Hooks can intercept tool calls, prompt for confirmation, modify results, and inject messages from external sources. Auto-discovered from `~/.omp/agent/hooks/*.ts` and `.omp/hooks/*.ts`. Thanks to [@nicobailon](https://github.com/nicobailon) for the collaboration on the design and implementation. ([#145](https://github.com/badlogic/pi-mono/issues/145), supersedes [#158](https://github.com/badlogic/pi-mono/pull/158))
6817
+ - **Hooks system**: TypeScript modules that extend agent behavior by subscribing to lifecycle events. Hooks can
6818
+ intercept tool calls, prompt for confirmation, modify results, and inject messages from external sources.
6819
+ Auto-discovered from `~/.omp/agent/hooks/*.ts` and `.omp/hooks/*.ts`. Thanks to
6820
+ [@nicobailon](https://github.com/nicobailon) for the collaboration on the design and implementation.
6821
+ ([#145](https://github.com/badlogic/pi-mono/issues/145), supersedes
6822
+ [#158](https://github.com/badlogic/pi-mono/pull/158))
6707
6823
 
6708
6824
  - **`pi.send()` API**: Hooks can inject messages into the agent session from external sources (file watchers, webhooks, CI systems). If streaming, messages are queued; otherwise a new agent loop starts immediately.
6709
6825
 
@@ -6741,7 +6857,10 @@ _Dedicated to Peter's shoulder ([@steipete](https://twitter.com/steipete))_
6741
6857
 
6742
6858
  ### Breaking Changes
6743
6859
 
6744
- - **New RPC protocol**: The RPC mode (`--mode rpc`) has been completely redesigned with a new JSON protocol. The old protocol is no longer supported. See [`docs/rpc.md`](docs/rpc.md) for the new protocol documentation and [`test/rpc-example.ts`](test/rpc-example.ts) for a working example. Includes `RpcClient` TypeScript class for easy integration. ([#91](https://github.com/badlogic/pi-mono/issues/91))
6860
+ - **New RPC protocol**: The RPC mode (`--mode rpc`) has been completely redesigned with a new JSON protocol. The old
6861
+ protocol is no longer supported. See [`docs/rpc.md`](docs/rpc.md) for the new protocol documentation and
6862
+ [`test/rpc-example.ts`](test/rpc-example.ts) for a working example. Includes `RpcClient` TypeScript class for easy
6863
+ integration. ([#91](https://github.com/badlogic/pi-mono/issues/91))
6745
6864
 
6746
6865
  ### Changed
6747
6866
 
@@ -6751,7 +6870,10 @@ _Dedicated to Peter's shoulder ([@steipete](https://twitter.com/steipete))_
6751
6870
 
6752
6871
  ### Changed
6753
6872
 
6754
- - **Major code refactoring**: Restructured codebase for better maintainability and separation of concerns. Moved files into organized directories (`core/`, `modes/`, `utils/`, `cli/`). Extracted `AgentSession` class as central session management abstraction. Split `main.ts` and `tui-renderer.ts` into focused modules. See `DEVELOPMENT.md` for the new code map. ([#153](https://github.com/badlogic/pi-mono/issues/153))
6873
+ - **Major code refactoring**: Restructured codebase for better maintainability and separation of concerns. Moved files
6874
+ into organized directories (`core/`, `modes/`, `utils/`, `cli/`). Extracted `AgentSession` class as central session
6875
+ management abstraction. Split `main.ts` and `tui-renderer.ts` into focused modules. See `DEVELOPMENT.md` for the new
6876
+ code map. ([#153](https://github.com/badlogic/pi-mono/issues/153))
6755
6877
 
6756
6878
  ## [0.14.2] - 2025-12-08
6757
6879
 
@@ -6777,13 +6899,20 @@ _Dedicated to Peter's shoulder ([@steipete](https://twitter.com/steipete))_
6777
6899
 
6778
6900
  ### Added
6779
6901
 
6780
- - **OpenAI compatibility overrides in models.json**: Custom models using `openai-completions` API can now specify a `compat` object to override provider quirks (`supportsStore`, `supportsDeveloperRole`, `supportsReasoningEffort`, `maxTokensField`). Useful for LiteLLM, custom proxies, and other non-standard endpoints. ([#133](https://github.com/badlogic/pi-mono/issues/133), thanks @fink-andreas for the initial idea and PR)
6902
+ - **OpenAI compatibility overrides in models.json**: Custom models using `openai-completions` API can now specify a
6903
+ `compat` object to override provider quirks (`supportsStore`, `supportsDeveloperRole`, `supportsReasoningEffort`,
6904
+ `maxTokensField`). Useful for LiteLLM, custom proxies, and other non-standard endpoints.
6905
+ ([#133](https://github.com/badlogic/pi-mono/issues/133), thanks @fink-andreas for the initial idea and PR)
6781
6906
 
6782
6907
  - **xhigh thinking level**: Added `xhigh` thinking level for OpenAI codex-max models. Cycle through thinking levels with Shift+Tab; `xhigh` appears only when using a codex-max model. ([#143](https://github.com/badlogic/pi-mono/issues/143))
6783
6908
 
6784
6909
  - **Collapse changelog setting**: Add `"collapseChangelog": true` to `~/.omp/agent/settings.json` to show a condensed "Updated to vX.Y.Z" message instead of the full changelog after updates. Use `/changelog` to view the full changelog. ([#148](https://github.com/badlogic/pi-mono/issues/148))
6785
6910
 
6786
- - **Bash mode**: Execute shell commands directly from the editor by prefixing with `!` (e.g., `!ls -la`). Output streams in real-time, is added to the LLM context, and persists in session history. Supports multiline commands, cancellation (Escape), truncation for large outputs, and preview/expand toggle (Ctrl+O). Also available in RPC mode via `{"type":"bash","command":"..."}`. ([#112](https://github.com/badlogic/pi-mono/pull/112), original implementation by [@markusylisiurunen](https://github.com/markusylisiurunen))
6911
+ - **Bash mode**: Execute shell commands directly from the editor by prefixing with `!` (e.g., `!ls -la`). Output
6912
+ streams in real-time, is added to the LLM context, and persists in session history. Supports multiline commands,
6913
+ cancellation (Escape), truncation for large outputs, and preview/expand toggle (Ctrl+O). Also available in RPC mode
6914
+ via `{"type":"bash","command":"..."}`. ([#112](https://github.com/badlogic/pi-mono/pull/112), original implementation
6915
+ by [@markusylisiurunen](https://github.com/markusylisiurunen))
6787
6916
 
6788
6917
  ## [0.13.2] - 2025-12-07
6789
6918
 
@@ -6839,7 +6968,10 @@ _Dedicated to Peter's shoulder ([@steipete](https://twitter.com/steipete))_
6839
6968
  ### Added
6840
6969
 
6841
6970
  - **Fuzzy search models and sessions**: Implemented a simple fuzzy search for models and sessions (e.g., `codexmax` now finds `gpt-5.1-codex-max`). ([#122](https://github.com/badlogic/pi-mono/pull/122) by [@markusylisiurunen](https://github.com/markusylisiurunen))
6842
- - **Prompt History Navigation**: Browse previously submitted prompts using Up/Down arrow keys when the editor is empty. Press Up to cycle through older prompts, Down to return to newer ones or clear the editor. Similar to shell history and Claude Code's prompt history feature. History is session-scoped and stores up to 100 entries. ([#121](https://github.com/badlogic/pi-mono/pull/121) by [@nicobailon](https://github.com/nicobailon))
6971
+ - **Prompt History Navigation**: Browse previously submitted prompts using Up/Down arrow keys when the editor is empty.
6972
+ Press Up to cycle through older prompts, Down to return to newer ones or clear the editor. Similar to shell history
6973
+ and Claude Code's prompt history feature. History is session-scoped and stores up to 100 entries.
6974
+ ([#121](https://github.com/badlogic/pi-mono/pull/121) by [@nicobailon](https://github.com/nicobailon))
6843
6975
  - **`/resume` Command**: Switch to a different session mid-conversation. Opens an interactive selector showing all available sessions. Equivalent to the `--resume` CLI flag but can be used without restarting the agent. ([#117](https://github.com/badlogic/pi-mono/pull/117) by [@hewliyang](https://github.com/hewliyang))
6844
6976
 
6845
6977
  ## [0.12.11] - 2025-12-05
@@ -6959,7 +7091,7 @@ _Dedicated to Peter's shoulder ([@steipete](https://twitter.com/steipete))_
6959
7091
 
6960
7092
  ### Fixed
6961
7093
 
6962
- - Absolute glob patterns (e.g., `/Users/foo/**/*.ts`) are now handled correctly. Previously the leading `/` was being stripped, causing the pattern to be interpreted relative to the current directory.
7094
+ - Absolute glob patterns (e.g., `/Users/example/**/*.ts`) are now handled correctly. Previously the leading `/` was being stripped, causing the pattern to be interpreted relative to the current directory.
6963
7095
 
6964
7096
  ## [0.11.7] - 2025-12-01
6965
7097
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@f5-sales-demo/xcsh",
4
- "version": "19.105.4",
4
+ "version": "19.105.7",
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.105.4",
61
- "@f5-sales-demo/pi-agent-core": "19.105.4",
62
- "@f5-sales-demo/pi-ai": "19.105.4",
63
- "@f5-sales-demo/pi-natives": "19.105.4",
64
- "@f5-sales-demo/pi-resource-management": "19.105.4",
65
- "@f5-sales-demo/pi-tui": "19.105.4",
66
- "@f5-sales-demo/pi-utils": "19.105.4",
60
+ "@f5-sales-demo/xcsh-stats": "19.105.7",
61
+ "@f5-sales-demo/pi-agent-core": "19.105.7",
62
+ "@f5-sales-demo/pi-ai": "19.105.7",
63
+ "@f5-sales-demo/pi-natives": "19.105.7",
64
+ "@f5-sales-demo/pi-resource-management": "19.105.7",
65
+ "@f5-sales-demo/pi-tui": "19.105.7",
66
+ "@f5-sales-demo/pi-utils": "19.105.7",
67
67
  "@sinclair/typebox": "^0.34",
68
68
  "@xterm/headless": "^6.0",
69
69
  "ajv": "^8.20",
@@ -5,6 +5,7 @@ import * as os from "node:os";
5
5
  import * as path from "node:path";
6
6
  import { $ } from "bun";
7
7
  import { isLocalSpecsCurrent } from "./api-specs-version";
8
+ import { sanitizeAcmePlaceholders, sanitizePublicIpv4Examples } from "./sanitize-generated-content";
8
9
 
9
10
  interface SpecPathOperation {
10
11
  operationId?: string;
@@ -108,30 +109,11 @@ const RESERVED_EMAIL_DOMAINS = new Set(["example.com", "example.net", "example.o
108
109
  */
109
110
  function sanitizeEmails(text: string): string {
110
111
  // The lookbehind skips URL userinfo (`https://token:secret@host`), which is not a contact address.
111
- return text.replace(/(?<![:/])\b[A-Za-z0-9._%+-]+@([A-Za-z0-9.-]+\.[A-Za-z]{2,})\b/g, (whole, domain) =>
112
+ return text.replace(/(?<![:/])\b[A-Za-z0-9._%+-]+@([A-Za-z0-9.-]+\.[A-Za-z]+)\b/g, (whole, domain) =>
112
113
  RESERVED_EMAIL_DOMAINS.has(String(domain).toLowerCase()) ? whole : "dana@example.com",
113
114
  );
114
115
  }
115
116
 
116
- /**
117
- * Upstream specs use ACME as a placeholder tenant, company and hostname. STYLE_GUIDE.md bans it:
118
- * it is not trademark-cleared, and in TLS content the name already belongs to RFC 8555. Rewrite it
119
- * to the `Example` pattern here rather than in the emitted file, so a regeneration cannot bring it
120
- * back (#2650).
121
- *
122
- * `_acme-challenge` is the RFC 8555 DNS-01 record label, not the placeholder, and must survive.
123
- */
124
- function sanitizePlaceholders(text: string): string {
125
- // The sentinel must contain no form of the word being rewritten, or the rewrite eats it.
126
- const CHALLENGE = " RFC8555_DNS01 ";
127
- return text
128
- .replace(/_acme-challenge/gi, CHALLENGE)
129
- .replace(/ACME/g, "Example")
130
- .replace(/Acme/g, "Example")
131
- .replace(/acme/g, "example")
132
- .replaceAll(CHALLENGE, "_acme-challenge");
133
- }
134
-
135
117
  const MAX_RETRIES = 3;
136
118
  const INITIAL_BACKOFF_MS = 2000;
137
119
 
@@ -587,7 +569,7 @@ const output = [
587
569
  .filter(l => l !== undefined)
588
570
  .join("\n");
589
571
 
590
- await Bun.write(outputPath, sanitizeEmails(sanitizePlaceholders(output)));
572
+ await Bun.write(outputPath, sanitizePublicIpv4Examples(sanitizeEmails(sanitizeAcmePlaceholders(output))));
591
573
 
592
574
  const outputSize = (Buffer.byteLength(output) / 1024 / 1024).toFixed(1);
593
575
  console.log(
@@ -631,7 +613,10 @@ if (catalog) {
631
613
  "",
632
614
  ].join("\n");
633
615
 
634
- await Bun.write(catalogOutputPath, sanitizeEmails(sanitizePlaceholders(catalogOutput)));
616
+ await Bun.write(
617
+ catalogOutputPath,
618
+ sanitizePublicIpv4Examples(sanitizeEmails(sanitizeAcmePlaceholders(catalogOutput))),
619
+ );
635
620
  const catalogSize = (Buffer.byteLength(catalogOutput) / 1024 / 1024).toFixed(1);
636
621
  console.log(
637
622
  `Generated ${path.relative(process.cwd(), catalogOutputPath)} (${categories.length} categories, ${catalogSize} MB)`,
@@ -2,6 +2,7 @@
2
2
  // scripts/generate-console-catalog.ts
3
3
  import * as fs from "node:fs";
4
4
  import * as path from "node:path";
5
+ import { sanitizePublicIpv4Examples } from "./sanitize-generated-content";
5
6
 
6
7
  const repoRoot = path.resolve(import.meta.dir, "..");
7
8
  const outputPath = path.join(repoRoot, "src/internal-urls/console-catalog.generated.ts");
@@ -98,7 +99,7 @@ const output = [
98
99
  "",
99
100
  ].join("\n");
100
101
 
101
- await Bun.write(outputPath, sanitizeTenantHosts(output));
102
+ await Bun.write(outputPath, sanitizePublicIpv4Examples(sanitizeTenantHosts(output)));
102
103
  console.log(
103
104
  `Wrote ${outputPath} (workflows=${Object.keys(data.workflows).length}, resources=${Object.keys(data.resources).length})`,
104
105
  );