@f5-sales-demo/xcsh 19.105.4 → 19.105.6
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 +154 -28
- package/package.json +8 -8
- package/scripts/generate-api-spec-index.ts +7 -22
- package/scripts/generate-console-catalog.ts +2 -1
- package/scripts/sanitize-generated-content.ts +141 -0
- package/src/cli.ts +0 -3
- package/src/config/auto-config.ts +12 -1
- package/src/discovery/agents-md.ts +2 -2
- package/src/discovery/agents.ts +7 -7
- package/src/discovery/builtin.ts +14 -14
- package/src/discovery/claude-plugins.ts +6 -6
- package/src/discovery/claude.ts +10 -10
- package/src/discovery/cline.ts +2 -2
- package/src/discovery/codex.ts +10 -10
- package/src/discovery/cursor.ts +4 -4
- package/src/discovery/gemini.ts +7 -7
- package/src/discovery/github.ts +3 -3
- package/src/discovery/mcp-json.ts +2 -2
- package/src/discovery/opencode.ts +7 -7
- package/src/discovery/ssh.ts +2 -2
- package/src/discovery/vscode.ts +2 -2
- package/src/discovery/windsurf.ts +3 -3
- package/src/extensibility/extensions/loader.ts +0 -8
- package/src/extensibility/extensions/types.ts +0 -4
- package/src/internal-urls/build-info-runtime.ts +0 -1
- package/src/internal-urls/build-info.generated.ts +8 -8
- package/src/internal-urls/console-catalog.generated.ts +1 -1
- package/src/internal-urls/index.ts +0 -3
- package/src/internal-urls/terraform-resolve.ts +1 -1
- package/src/internal-urls/xcsh-protocol.ts +0 -73
- package/src/modes/interactive-mode.ts +0 -8
- package/src/prompts/system/system-prompt.md +63 -26
- package/src/prompts/tools/xcsh-api.md +114 -60
- package/src/sandbox/containment.ts +3 -6
- package/src/sdk.ts +0 -47
- package/src/session/compaction/compaction.ts +1 -1
- package/src/system-prompt.ts +0 -21
- package/src/discovery/language.ts +0 -46
- package/src/internal-urls/computer-profile.ts +0 -692
- package/src/internal-urls/profile-collectors.ts +0 -371
- package/src/internal-urls/user-profile.ts +0 -431
package/CHANGELOG.md
CHANGED
|
@@ -2,8 +2,28 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [19.105.6] - 2026-07-31
|
|
6
|
+
|
|
7
|
+
### Breaking Changes
|
|
8
|
+
|
|
9
|
+
- 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))
|
|
10
|
+
|
|
11
|
+
### Removed
|
|
12
|
+
|
|
13
|
+
- 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))
|
|
14
|
+
|
|
5
15
|
### Fixed
|
|
6
16
|
|
|
17
|
+
- 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))
|
|
18
|
+
|
|
19
|
+
## [19.105.5] - 2026-07-31
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
|
|
23
|
+
- Added post-publication Homebrew install verification to the release workflow ([#2719](https://github.com/f5-sales-demo/xcsh/issues/2719))
|
|
24
|
+
- Replaced the deprecated Node 20 Zig setup action with a checksum-pinned official installer ([#61](https://github.com/f5-sales-demo/xcsh/issues/61))
|
|
25
|
+
- 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))
|
|
26
|
+
- 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
27
|
- Regenerated stale same-version release PRs when newer commits have merged into `main` ([#2727](https://github.com/f5-sales-demo/xcsh/issues/2727))
|
|
8
28
|
|
|
9
29
|
## [19.105.3] - 2026-07-31
|
|
@@ -33,16 +53,23 @@
|
|
|
33
53
|
## [19.51.5] - 2026-06-26
|
|
34
54
|
|
|
35
55
|
### Fixed
|
|
36
|
-
|
|
56
|
+
|
|
57
|
+
- Sign + notarize the embedded native addon (`pi_natives.*.node`) in `build-sign-macos` **before** it is embedded into
|
|
58
|
+
the compiled binary. xcsh extracts the embedded `.node` to `~/.xcsh/natives/<ver>/` at runtime; previously that
|
|
59
|
+
extracted copy was ad-hoc-signed, so managed/MDM Macs blocked the `dlopen` ("could not verify it is free of
|
|
60
|
+
malware"). The addon is now Developer-ID-signed with hardened runtime and notarized, so Gatekeeper's online check
|
|
61
|
+
passes it without manual approval.
|
|
37
62
|
|
|
38
63
|
## [19.51.4] - 2026-06-26
|
|
39
64
|
|
|
40
65
|
### Added
|
|
66
|
+
|
|
41
67
|
- 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
68
|
- 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
69
|
- Gated, security-clean relay tracing in `chrome-host` for diagnosing the bridge-connect step.
|
|
44
70
|
|
|
45
71
|
### Fixed
|
|
72
|
+
|
|
46
73
|
- Native host now uses the compiled `xcsh` binary (not `bun + cli.ts`), which survives Chrome's stripped-env launch.
|
|
47
74
|
- 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
75
|
- Pre-existing biome lint/format issues that were blocking CI.
|
|
@@ -67,7 +94,10 @@
|
|
|
67
94
|
|
|
68
95
|
### Changed
|
|
69
96
|
|
|
70
|
-
- Salesforce tools extracted to marketplace plugin: sf_setup, sf_query, sf_org_display, and sf_pipeline_report are now
|
|
97
|
+
- Salesforce tools extracted to marketplace plugin: sf_setup, sf_query, sf_org_display, and sf_pipeline_report are now
|
|
98
|
+
available as an installable plugin (`@f5-sales-demo/xcsh-salesforce`) via the Extension API instead of built-in
|
|
99
|
+
tools. Install with `xcsh plugin install salesforce`. Context discovery, pipeline reporting, and container-adapted
|
|
100
|
+
authentication are preserved with full feature parity. ([#1059](https://github.com/f5-sales-demo/xcsh/issues/1059))
|
|
71
101
|
|
|
72
102
|
## [18.75.0] - 2026-05-23
|
|
73
103
|
|
|
@@ -79,7 +109,11 @@
|
|
|
79
109
|
|
|
80
110
|
### Fixed
|
|
81
111
|
|
|
82
|
-
- Welcome banner cloud provider hints: AWS SSO token expiry now correctly suggests `aws sso login` instead of `aws
|
|
112
|
+
- Welcome banner cloud provider hints: AWS SSO token expiry now correctly suggests `aws sso login` instead of `aws
|
|
113
|
+
configure`; Google Cloud check replaced `gcloud auth list` (false positives on expired tokens) with `gcloud auth
|
|
114
|
+
print-access-token`; F5 XC Context surfaces `errorClass` (network/URL) in hints; GitLab `project_inaccessible` gets
|
|
115
|
+
its own hint; Salesforce differentiates `session_expired` and `not_configured` hints
|
|
116
|
+
([#825](https://github.com/f5-sales-demo/xcsh/issues/825))
|
|
83
117
|
|
|
84
118
|
## [18.64.0] - 2026-05-13
|
|
85
119
|
|
|
@@ -92,7 +126,11 @@
|
|
|
92
126
|
|
|
93
127
|
### Changed
|
|
94
128
|
|
|
95
|
-
- Regenerated API spec index from catalog v2.1.82: http_loadbalancer CRUD verification corrections (6 new server
|
|
129
|
+
- Regenerated API spec index from catalog v2.1.82: http_loadbalancer CRUD verification corrections (6 new server
|
|
130
|
+
defaults, corrected minimum configs, cross-field dependencies, default_pool inline pool discovery, 5 composable
|
|
131
|
+
routing approaches) and tcp_loadbalancer minimum config corrections (listen_port, origin_pools_weights,
|
|
132
|
+
do_not_advertise format, 9 server defaults, forced hash_policy default)
|
|
133
|
+
([#753](https://github.com/f5-sales-demo/xcsh/issues/753), [#757](https://github.com/f5-sales-demo/xcsh/issues/757))
|
|
96
134
|
|
|
97
135
|
## [18.53.0] - 2026-05-09
|
|
98
136
|
|
|
@@ -156,25 +194,40 @@
|
|
|
156
194
|
|
|
157
195
|
### Fixed
|
|
158
196
|
|
|
159
|
-
- Fixed gutter width propagation in the fallback tool renderer: `#formatToolExecution()` now receives the actual
|
|
197
|
+
- Fixed gutter width propagation in the fallback tool renderer: `#formatToolExecution()` now receives the actual
|
|
198
|
+
available width at render-time and uses it for line truncation instead of a hardcoded 80-column limit. On narrow
|
|
199
|
+
terminals (<82 cols) this prevents content wider than the gutter-adjusted viewport; on wide terminals it allows
|
|
200
|
+
longer output lines. ([#117](https://github.com/f5-sales-demo/xcsh/issues/117))
|
|
160
201
|
- 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
202
|
|
|
162
203
|
### Changed
|
|
163
204
|
|
|
164
|
-
- Renamed F5 XC credential system from "profile" to "context" to align with kubectl conventions. The `/profile` command
|
|
205
|
+
- Renamed F5 XC credential system from "profile" to "context" to align with kubectl conventions. The `/profile` command
|
|
206
|
+
is now `/context`, all types/classes use `Context*` naming (`ContextService`, `ContextStatus`, `F5XCContext`, etc.),
|
|
207
|
+
on-disk paths changed from `profiles/` to `contexts/` and `active_profile` to `active_context`, and the status-line
|
|
208
|
+
segment ID is now `context_f5xc`. ([#302](https://github.com/f5-sales-demo/xcsh/issues/302))
|
|
165
209
|
|
|
166
210
|
## [18.12.0] - 2026-04-23
|
|
167
211
|
|
|
168
212
|
### Changed
|
|
169
213
|
|
|
170
|
-
- **System prompt realigned around the SE coworker primary mission.** The `<role>` block now leads with "technical
|
|
214
|
+
- **System prompt realigned around the SE coworker primary mission.** The `<role>` block now leads with "technical
|
|
215
|
+
coworker for F5 Distributed Cloud sales engineers" and names demos, MEDDPICC qualification, customer meeting
|
|
216
|
+
preparation, and F5 XC product subject-matter expertise as primary activities — technical depth is retained as an
|
|
217
|
+
explicit enabling credential, not subordinated. `<behavior>` reframes around the **presentation reflex** (confirming
|
|
218
|
+
a capability before verifying it against current docs) with a conditional clause preserving the **deployment reflex**
|
|
219
|
+
guard when the task is infrastructure. `<stakes>` leads with customer-facing risk (lost deals, damaged credibility,
|
|
220
|
+
post-sale trust erosion) and retains infra stakes (outages, security exposures) as a secondary clause.
|
|
171
221
|
- **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
222
|
- **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
223
|
- **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
224
|
|
|
175
225
|
### Added
|
|
176
226
|
|
|
177
|
-
- **`.xcsh/rules/config-integrity.md`** — new scoped rule carrying the dependency-first IaC guidance that previously
|
|
227
|
+
- **`.xcsh/rules/config-integrity.md`** — new scoped rule carrying the dependency-first IaC guidance that previously
|
|
228
|
+
lived in the always-on `<config-integrity>` block. Fires on `tool:edit` and `tool:write` for `.tf`, `.yaml`, `.yml`,
|
|
229
|
+
`.json`, `.sh`, `Makefile`, `Dockerfile`, `.toml`. Uses `condition: "."` (always-true regex) so the rules engine
|
|
230
|
+
registers it — rules without a `condition` are silently dropped.
|
|
178
231
|
- **`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
232
|
|
|
180
233
|
### Removed
|
|
@@ -187,12 +240,24 @@ Refs: #254, #243.
|
|
|
187
240
|
|
|
188
241
|
### Removed
|
|
189
242
|
|
|
190
|
-
- **All built-in themes except `xcsh-dark` and `xcsh-light` have been removed.** The 99 community themes previously
|
|
243
|
+
- **All built-in themes except `xcsh-dark` and `xcsh-light` have been removed.** The 99 community themes previously
|
|
244
|
+
shipped under `packages/coding-agent/src/modes/theme/defaults/` (`dark-ocean`, `dark-dracula`, `titanium`,
|
|
245
|
+
`anthracite`, etc.), as well as the base `dark` and `light` themes, are no longer included. The hardcoded fallback
|
|
246
|
+
when a user's theme fails to load now targets `xcsh-dark`. Users on a removed theme will fall back to `xcsh-dark` on
|
|
247
|
+
next launch. User-authored themes under `~/.xcsh/agent/themes/` are unaffected.
|
|
191
248
|
|
|
192
249
|
### Changed
|
|
193
250
|
|
|
194
|
-
- **TUI tool-call outcomes now render as a single colored gutter ball (●).** Inline `✓/✗/⚠` status icons were
|
|
195
|
-
|
|
251
|
+
- **TUI tool-call outcomes now render as a single colored gutter ball (●).** Inline `✓/✗/⚠` status icons were
|
|
252
|
+
removed from every tool renderer. A new "warning" outcome (orange ball) signals non-error degraded states such as
|
|
253
|
+
grep with zero matches, exa with zero results, ast-grep with zero matches, or ask falling back to a
|
|
254
|
+
headless/empty-questions path. `xcsh-dark` uses `warmAmber` (#ffb347); `xcsh-light` uses `#b85e00` (WCAG AA on
|
|
255
|
+
white). User-authored themes inherit via the `gutterWarning → warning` fallback chain.
|
|
256
|
+
- **`AgentToolResult` and `tool_execution_end` events gain an optional `isWarning?: boolean`** alongside `isError`.
|
|
257
|
+
Tools that want an orange gutter ball on zero-result or fallback paths set this field (or use the new
|
|
258
|
+
`ToolResultBuilder.isWarning()` fluent method). Extensions subscribing to `tool_execution_end` and `tool_result` hook
|
|
259
|
+
events now receive the flag; existing extensions are unaffected. Backwards-compatible — unset means "not a
|
|
260
|
+
warning."
|
|
196
261
|
- **`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
262
|
|
|
198
263
|
Refs: #173.
|
|
@@ -201,7 +266,10 @@ Refs: #173.
|
|
|
201
266
|
|
|
202
267
|
### Fixed
|
|
203
268
|
|
|
204
|
-
- Widened the `defaultThinkingLevel` schema enum to include `"off"`, which was already a supported runtime value via
|
|
269
|
+
- Widened the `defaultThinkingLevel` schema enum to include `"off"`, which was already a supported runtime value via
|
|
270
|
+
`resolveThinkingLevelForModel` but was not declared as a valid schema value. This closes a type-safety gap where
|
|
271
|
+
programmatic callers (tests, config.yml edits) could set `"off"` without a `SettingValue` type narrowing it. The
|
|
272
|
+
`/settings` UI dropdown is unchanged; the widening is schema-level only.
|
|
205
273
|
|
|
206
274
|
### Changed
|
|
207
275
|
|
|
@@ -3892,7 +3960,10 @@ Refs: #173.
|
|
|
3892
3960
|
|
|
3893
3961
|
### Fixed
|
|
3894
3962
|
|
|
3895
|
-
- External edits to `config.yml` are now preserved when omp reloads or saves unrelated settings. Previously, editing
|
|
3963
|
+
- External edits to `config.yml` are now preserved when omp reloads or saves unrelated settings. Previously, editing
|
|
3964
|
+
config.yml directly (e.g., removing a package from `packages` array) would be silently reverted on next omp startup
|
|
3965
|
+
when automatic setters like `setLastChangelogVersion()` triggered a save.
|
|
3966
|
+
([#1046](https://github.com/badlogic/pi-mono/pull/1046) by [@nicobailonMD](https://github.com/nicobailonMD))
|
|
3896
3967
|
|
|
3897
3968
|
## [8.13.0] - 2026-01-29
|
|
3898
3969
|
|
|
@@ -5042,7 +5113,13 @@ Refs: #173.
|
|
|
5042
5113
|
### Added
|
|
5043
5114
|
|
|
5044
5115
|
- Exported `InteractiveModeOptions` type for programmatic SDK usage
|
|
5045
|
-
- Exported additional UI components for extensions: `ArminComponent`, `AssistantMessageComponent`,
|
|
5116
|
+
- Exported additional UI components for extensions: `ArminComponent`, `AssistantMessageComponent`,
|
|
5117
|
+
`BashExecutionComponent`, `BranchSummaryMessageComponent`, `CompactionSummaryMessageComponent`, `CustomEditor`,
|
|
5118
|
+
`CustomMessageComponent`, `FooterComponent`, `ExtensionEditorComponent`, `ExtensionInputComponent`,
|
|
5119
|
+
`ExtensionSelectorComponent`, `LoginDialogComponent`, `ModelSelectorComponent`, `OAuthSelectorComponent`,
|
|
5120
|
+
`SessionSelectorComponent`, `SettingsSelectorComponent`, `ShowImagesSelectorComponent`, `ThemeSelectorComponent`,
|
|
5121
|
+
`ThinkingSelectorComponent`, `ToolExecutionComponent`, `TreeSelectorComponent`, `UserMessageComponent`,
|
|
5122
|
+
`UserMessageSelectorComponent`
|
|
5046
5123
|
- Exported `renderDiff`, `truncateToVisualLines`, and related types for extension use
|
|
5047
5124
|
- `setFooter()` and `setHeader()` methods on `ExtensionUIContext` for custom footer/header components
|
|
5048
5125
|
- `setEditorComponent()` method on `ExtensionUIContext` for custom editor components
|
|
@@ -5489,7 +5566,12 @@ Refs: #173.
|
|
|
5489
5566
|
|
|
5490
5567
|
### Added
|
|
5491
5568
|
|
|
5492
|
-
- Added 65 new built-in color themes including dark variants (abyss, aurora, cavern, copper, cosmos, eclipse, ember,
|
|
5569
|
+
- Added 65 new built-in color themes including dark variants (abyss, aurora, cavern, copper, cosmos, eclipse, ember,
|
|
5570
|
+
equinox, lavender, lunar, midnight, nebula, rainforest, reef, sakura, slate, solstice, starfall, swamp, taiga,
|
|
5571
|
+
terminal, tundra, twilight, volcanic), light variants (aurora-day, canyon, cirrus, coral, dawn, dunes, eucalyptus,
|
|
5572
|
+
frost, glacier, haze, honeycomb, lagoon, lavender, meadow, mint, opal, orchard, paper, prism, sand, savanna, soleil,
|
|
5573
|
+
wetland, zenith), and material themes (alabaster, amethyst, anthracite, basalt, birch, graphite, limestone, mahogany,
|
|
5574
|
+
marble, obsidian, onyx, pearl, porcelain, quartz, sandstone, titanium)
|
|
5493
5575
|
|
|
5494
5576
|
### Fixed
|
|
5495
5577
|
|
|
@@ -6324,7 +6406,11 @@ Total color count increased from 46 to 50. See [docs/theme.md](docs/theme.md) fo
|
|
|
6324
6406
|
|
|
6325
6407
|
### Breaking
|
|
6326
6408
|
|
|
6327
|
-
- **Session hooks API redesign**: Merged `branch` event into `session` event. `BranchEvent`, `BranchEventResult` types
|
|
6409
|
+
- **Session hooks API redesign**: Merged `branch` event into `session` event. `BranchEvent`, `BranchEventResult` types
|
|
6410
|
+
and `pi.on("branch", ...)` removed. Use `pi.on("session", ...)` with `reason: "before_branch" | "branch"` instead.
|
|
6411
|
+
`AgentSession.branch()` returns `{ cancelled }` instead of `{ skipped }`. `AgentSession.reset()` and
|
|
6412
|
+
`switchSession()` now return `boolean` (false if cancelled by hook). RPC commands `reset`, `switch_session`, and
|
|
6413
|
+
`branch` now include `cancelled` in response data. ([#278](https://github.com/badlogic/pi-mono/issues/278))
|
|
6328
6414
|
|
|
6329
6415
|
### Added
|
|
6330
6416
|
|
|
@@ -6480,7 +6566,11 @@ Total color count increased from 46 to 50. See [docs/theme.md](docs/theme.md) fo
|
|
|
6480
6566
|
|
|
6481
6567
|
- **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
6568
|
|
|
6483
|
-
- **Skills standard compliance**: Skills now adhere to the [Agent Skills
|
|
6569
|
+
- **Skills standard compliance**: Skills now adhere to the [Agent Skills
|
|
6570
|
+
standard](https://agentskills.io/specification). Validates name (must match parent directory, lowercase, max 64
|
|
6571
|
+
chars), description (required, max 1024 chars), and frontmatter fields. Warns on violations but remains lenient.
|
|
6572
|
+
Prompt format changed to XML structure. Removed `{baseDir}` placeholder in favor of relative paths.
|
|
6573
|
+
([#231](https://github.com/badlogic/pi-mono/issues/231))
|
|
6484
6574
|
|
|
6485
6575
|
### Fixed
|
|
6486
6576
|
|
|
@@ -6545,7 +6635,10 @@ Total color count increased from 46 to 50. See [docs/theme.md](docs/theme.md) fo
|
|
|
6545
6635
|
|
|
6546
6636
|
### Fixed
|
|
6547
6637
|
|
|
6548
|
-
- Fixed Claude models via GitHub Copilot re-answering all previous prompts in multi-turn conversations. The issue was
|
|
6638
|
+
- Fixed Claude models via GitHub Copilot re-answering all previous prompts in multi-turn conversations. The issue was
|
|
6639
|
+
that assistant message content was sent as an array instead of a string, which Copilot's Claude adapter
|
|
6640
|
+
misinterpreted. Also added missing `Openai-Intent: conversation-edits` header and fixed `X-Initiator` logic to check
|
|
6641
|
+
for any assistant/tool message in history. ([#209](https://github.com/badlogic/pi-mono/issues/209))
|
|
6549
6642
|
|
|
6550
6643
|
- Detect image MIME type via file magic (read tool and `@file` attachments), not filename extension.
|
|
6551
6644
|
|
|
@@ -6633,7 +6726,11 @@ _Dedicated to Peter's shoulder ([@steipete](https://twitter.com/steipete))_
|
|
|
6633
6726
|
|
|
6634
6727
|
### Added
|
|
6635
6728
|
|
|
6636
|
-
- **Inline image rendering**: Terminals supporting Kitty graphics protocol (Kitty, Ghostty, WezTerm) or iTerm2 inline
|
|
6729
|
+
- **Inline image rendering**: Terminals supporting Kitty graphics protocol (Kitty, Ghostty, WezTerm) or iTerm2 inline
|
|
6730
|
+
images now render images inline in tool output. Aspect ratio is preserved by querying terminal cell dimensions on
|
|
6731
|
+
startup. Toggle with `/show-images` command or `terminal.showImages` setting. Falls back to text placeholder on
|
|
6732
|
+
unsupported terminals or when disabled. ([#177](https://github.com/badlogic/pi-mono/pull/177) by
|
|
6733
|
+
[@nicobailon](https://github.com/nicobailon))
|
|
6637
6734
|
|
|
6638
6735
|
- **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
6736
|
|
|
@@ -6669,7 +6766,11 @@ _Dedicated to Peter's shoulder ([@steipete](https://twitter.com/steipete))_
|
|
|
6669
6766
|
|
|
6670
6767
|
### Added
|
|
6671
6768
|
|
|
6672
|
-
- **Skills system**: Auto-discover and load instruction files on-demand. Supports Claude Code
|
|
6769
|
+
- **Skills system**: Auto-discover and load instruction files on-demand. Supports Claude Code
|
|
6770
|
+
(`~/.claude/skills/*/SKILL.md`), Codex CLI (`~/.codex/skills/`), and OMP-native formats (`~/.omp/agent/skills/`,
|
|
6771
|
+
`.omp/skills/`). Skills are listed in system prompt with descriptions, agent loads them via read tool when needed.
|
|
6772
|
+
Supports `{baseDir}` placeholder. Disable with `--no-skills` or `skills.enabled: false` in settings.
|
|
6773
|
+
([#169](https://github.com/badlogic/pi-mono/issues/169))
|
|
6673
6774
|
|
|
6674
6775
|
- **Version flag**: Added `--version` / `-v` flag to display the current version and exit. ([#170](https://github.com/badlogic/pi-mono/pull/170))
|
|
6675
6776
|
|
|
@@ -6677,7 +6778,11 @@ _Dedicated to Peter's shoulder ([@steipete](https://twitter.com/steipete))_
|
|
|
6677
6778
|
|
|
6678
6779
|
### Added
|
|
6679
6780
|
|
|
6680
|
-
- **Auto-retry on transient errors**: Automatically retries requests when providers return overloaded, rate limit, or
|
|
6781
|
+
- **Auto-retry on transient errors**: Automatically retries requests when providers return overloaded, rate limit, or
|
|
6782
|
+
server errors (429, 500, 502, 503, 504). Uses exponential backoff (2s, 4s, 8s). Shows retry status in TUI with option
|
|
6783
|
+
to cancel via Escape. Configurable in `settings.json` via `retry.enabled`, `retry.maxRetries`, `retry.baseDelayMs`.
|
|
6784
|
+
RPC mode emits `auto_retry_start` and `auto_retry_end` events.
|
|
6785
|
+
([#157](https://github.com/badlogic/pi-mono/issues/157))
|
|
6681
6786
|
|
|
6682
6787
|
- **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
6788
|
|
|
@@ -6703,7 +6808,12 @@ _Dedicated to Peter's shoulder ([@steipete](https://twitter.com/steipete))_
|
|
|
6703
6808
|
|
|
6704
6809
|
### Added
|
|
6705
6810
|
|
|
6706
|
-
- **Hooks system**: TypeScript modules that extend agent behavior by subscribing to lifecycle events. Hooks can
|
|
6811
|
+
- **Hooks system**: TypeScript modules that extend agent behavior by subscribing to lifecycle events. Hooks can
|
|
6812
|
+
intercept tool calls, prompt for confirmation, modify results, and inject messages from external sources.
|
|
6813
|
+
Auto-discovered from `~/.omp/agent/hooks/*.ts` and `.omp/hooks/*.ts`. Thanks to
|
|
6814
|
+
[@nicobailon](https://github.com/nicobailon) for the collaboration on the design and implementation.
|
|
6815
|
+
([#145](https://github.com/badlogic/pi-mono/issues/145), supersedes
|
|
6816
|
+
[#158](https://github.com/badlogic/pi-mono/pull/158))
|
|
6707
6817
|
|
|
6708
6818
|
- **`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
6819
|
|
|
@@ -6741,7 +6851,10 @@ _Dedicated to Peter's shoulder ([@steipete](https://twitter.com/steipete))_
|
|
|
6741
6851
|
|
|
6742
6852
|
### Breaking Changes
|
|
6743
6853
|
|
|
6744
|
-
- **New RPC protocol**: The RPC mode (`--mode rpc`) has been completely redesigned with a new JSON protocol. The old
|
|
6854
|
+
- **New RPC protocol**: The RPC mode (`--mode rpc`) has been completely redesigned with a new JSON protocol. The old
|
|
6855
|
+
protocol is no longer supported. See [`docs/rpc.md`](docs/rpc.md) for the new protocol documentation and
|
|
6856
|
+
[`test/rpc-example.ts`](test/rpc-example.ts) for a working example. Includes `RpcClient` TypeScript class for easy
|
|
6857
|
+
integration. ([#91](https://github.com/badlogic/pi-mono/issues/91))
|
|
6745
6858
|
|
|
6746
6859
|
### Changed
|
|
6747
6860
|
|
|
@@ -6751,7 +6864,10 @@ _Dedicated to Peter's shoulder ([@steipete](https://twitter.com/steipete))_
|
|
|
6751
6864
|
|
|
6752
6865
|
### Changed
|
|
6753
6866
|
|
|
6754
|
-
- **Major code refactoring**: Restructured codebase for better maintainability and separation of concerns. Moved files
|
|
6867
|
+
- **Major code refactoring**: Restructured codebase for better maintainability and separation of concerns. Moved files
|
|
6868
|
+
into organized directories (`core/`, `modes/`, `utils/`, `cli/`). Extracted `AgentSession` class as central session
|
|
6869
|
+
management abstraction. Split `main.ts` and `tui-renderer.ts` into focused modules. See `DEVELOPMENT.md` for the new
|
|
6870
|
+
code map. ([#153](https://github.com/badlogic/pi-mono/issues/153))
|
|
6755
6871
|
|
|
6756
6872
|
## [0.14.2] - 2025-12-08
|
|
6757
6873
|
|
|
@@ -6777,13 +6893,20 @@ _Dedicated to Peter's shoulder ([@steipete](https://twitter.com/steipete))_
|
|
|
6777
6893
|
|
|
6778
6894
|
### Added
|
|
6779
6895
|
|
|
6780
|
-
- **OpenAI compatibility overrides in models.json**: Custom models using `openai-completions` API can now specify a
|
|
6896
|
+
- **OpenAI compatibility overrides in models.json**: Custom models using `openai-completions` API can now specify a
|
|
6897
|
+
`compat` object to override provider quirks (`supportsStore`, `supportsDeveloperRole`, `supportsReasoningEffort`,
|
|
6898
|
+
`maxTokensField`). Useful for LiteLLM, custom proxies, and other non-standard endpoints.
|
|
6899
|
+
([#133](https://github.com/badlogic/pi-mono/issues/133), thanks @fink-andreas for the initial idea and PR)
|
|
6781
6900
|
|
|
6782
6901
|
- **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
6902
|
|
|
6784
6903
|
- **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
6904
|
|
|
6786
|
-
- **Bash mode**: Execute shell commands directly from the editor by prefixing with `!` (e.g., `!ls -la`). Output
|
|
6905
|
+
- **Bash mode**: Execute shell commands directly from the editor by prefixing with `!` (e.g., `!ls -la`). Output
|
|
6906
|
+
streams in real-time, is added to the LLM context, and persists in session history. Supports multiline commands,
|
|
6907
|
+
cancellation (Escape), truncation for large outputs, and preview/expand toggle (Ctrl+O). Also available in RPC mode
|
|
6908
|
+
via `{"type":"bash","command":"..."}`. ([#112](https://github.com/badlogic/pi-mono/pull/112), original implementation
|
|
6909
|
+
by [@markusylisiurunen](https://github.com/markusylisiurunen))
|
|
6787
6910
|
|
|
6788
6911
|
## [0.13.2] - 2025-12-07
|
|
6789
6912
|
|
|
@@ -6839,7 +6962,10 @@ _Dedicated to Peter's shoulder ([@steipete](https://twitter.com/steipete))_
|
|
|
6839
6962
|
### Added
|
|
6840
6963
|
|
|
6841
6964
|
- **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.
|
|
6965
|
+
- **Prompt History Navigation**: Browse previously submitted prompts using Up/Down arrow keys when the editor is empty.
|
|
6966
|
+
Press Up to cycle through older prompts, Down to return to newer ones or clear the editor. Similar to shell history
|
|
6967
|
+
and Claude Code's prompt history feature. History is session-scoped and stores up to 100 entries.
|
|
6968
|
+
([#121](https://github.com/badlogic/pi-mono/pull/121) by [@nicobailon](https://github.com/nicobailon))
|
|
6843
6969
|
- **`/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
6970
|
|
|
6845
6971
|
## [0.12.11] - 2025-12-05
|
|
@@ -6959,7 +7085,7 @@ _Dedicated to Peter's shoulder ([@steipete](https://twitter.com/steipete))_
|
|
|
6959
7085
|
|
|
6960
7086
|
### Fixed
|
|
6961
7087
|
|
|
6962
|
-
- Absolute glob patterns (e.g., `/Users/
|
|
7088
|
+
- 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
7089
|
|
|
6964
7090
|
## [0.11.7] - 2025-12-01
|
|
6965
7091
|
|
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
|
+
"version": "19.105.6",
|
|
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.
|
|
61
|
-
"@f5-sales-demo/pi-agent-core": "19.105.
|
|
62
|
-
"@f5-sales-demo/pi-ai": "19.105.
|
|
63
|
-
"@f5-sales-demo/pi-natives": "19.105.
|
|
64
|
-
"@f5-sales-demo/pi-resource-management": "19.105.
|
|
65
|
-
"@f5-sales-demo/pi-tui": "19.105.
|
|
66
|
-
"@f5-sales-demo/pi-utils": "19.105.
|
|
60
|
+
"@f5-sales-demo/xcsh-stats": "19.105.6",
|
|
61
|
+
"@f5-sales-demo/pi-agent-core": "19.105.6",
|
|
62
|
+
"@f5-sales-demo/pi-ai": "19.105.6",
|
|
63
|
+
"@f5-sales-demo/pi-natives": "19.105.6",
|
|
64
|
+
"@f5-sales-demo/pi-resource-management": "19.105.6",
|
|
65
|
+
"@f5-sales-demo/pi-tui": "19.105.6",
|
|
66
|
+
"@f5-sales-demo/pi-utils": "19.105.6",
|
|
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]
|
|
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(
|
|
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(
|
|
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
|
);
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
const IPV4_RE = /(?<![A-Za-z0-9.])((?:[0-9]{1,3}\.){3}[0-9]{1,3})(?:\/([0-9]{1,2}))?(?![A-Za-z0-9.])/g;
|
|
2
|
+
const DOTTED_VERSION_PREFIX_RE =
|
|
3
|
+
/(?:(?:chrome|headlesschrome|chromium|firefox|safari|edg|edge|opera)\/\s*$|[A-Za-z0-9_.-]*version[A-Za-z0-9_.-]*\s*[:=]\s*['"`]?\s*$|version[A-Za-z0-9_.-]*\)?\.to(?:be|equal)\(\s*['"`]?\s*$)/i;
|
|
4
|
+
const SVG_PATH_ATTRIBUTE_RE = /(?:^|\s)d\s*=\s*(['"])/gi;
|
|
5
|
+
const RFC_8555_TERM_RE =
|
|
6
|
+
/_acme-challenge|\bAutomated Certificate Management Environment\s*\(ACME\)|\bRFC\s*8555\s*\(ACME\)|\bACME\s*\(RFC\s*8555\)|\bACME\s+(?:account|authorization|certificate|challenge|client|directory|nonce|order|protocol|server|service)\b/gi;
|
|
7
|
+
const RFC_8555_TOKEN_RE = /\0RFC8555_([0-9]+)\0/g;
|
|
8
|
+
|
|
9
|
+
type Ipv4Address = readonly [number, number, number, number];
|
|
10
|
+
type Ipv4Range = readonly [Ipv4Address, number];
|
|
11
|
+
|
|
12
|
+
const NON_GLOBAL_RANGES: readonly Ipv4Range[] = [
|
|
13
|
+
[[0, 0, 0, 0], 8],
|
|
14
|
+
[[10, 0, 0, 0], 8],
|
|
15
|
+
[[100, 64, 0, 0], 10],
|
|
16
|
+
[[127, 0, 0, 0], 8],
|
|
17
|
+
[[169, 254, 0, 0], 16],
|
|
18
|
+
[[172, 16, 0, 0], 12],
|
|
19
|
+
[[192, 0, 0, 0], 24],
|
|
20
|
+
[[192, 0, 2, 0], 24],
|
|
21
|
+
[[192, 168, 0, 0], 16],
|
|
22
|
+
[[198, 18, 0, 0], 15],
|
|
23
|
+
[[198, 51, 100, 0], 24],
|
|
24
|
+
[[203, 0, 113, 0], 24],
|
|
25
|
+
[[224, 0, 0, 0], 4],
|
|
26
|
+
[[240, 0, 0, 0], 4],
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
const GLOBAL_PROTOCOL_HOSTS = new Set([9, 10]);
|
|
30
|
+
const DOCUMENTATION_PREFIXES: readonly (readonly [number, number, number])[] = [
|
|
31
|
+
[192, 0, 2],
|
|
32
|
+
[198, 51, 100],
|
|
33
|
+
[203, 0, 113],
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
interface ProtectedRfc8555Terms {
|
|
37
|
+
text: string;
|
|
38
|
+
terms: string[];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function protectRfc8555Terms(text: string): ProtectedRfc8555Terms {
|
|
42
|
+
const terms: string[] = [];
|
|
43
|
+
return {
|
|
44
|
+
text: text.replace(RFC_8555_TERM_RE, term => {
|
|
45
|
+
const token = `\0RFC8555_${terms.length}\0`;
|
|
46
|
+
terms.push(term);
|
|
47
|
+
return token;
|
|
48
|
+
}),
|
|
49
|
+
terms,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Count uses of the name that are not RFC 8555 terminology. */
|
|
54
|
+
export function countAcmePlaceholderOccurrences(text: string): number {
|
|
55
|
+
const protectedText = protectRfc8555Terms(text).text;
|
|
56
|
+
return protectedText.match(/acme/gi)?.length ?? 0;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Replace fictitious ACME tenants, companies, and hosts with the Example pattern while preserving
|
|
61
|
+
* registered RFC 8555 terminology.
|
|
62
|
+
*/
|
|
63
|
+
export function sanitizeAcmePlaceholders(text: string): string {
|
|
64
|
+
const protectedTerms = protectRfc8555Terms(text);
|
|
65
|
+
const sanitized = protectedTerms.text
|
|
66
|
+
.replace(/ACME/g, "Example")
|
|
67
|
+
.replace(/Acme/g, "Example")
|
|
68
|
+
.replace(/acme/g, "example");
|
|
69
|
+
return sanitized.replace(RFC_8555_TOKEN_RE, (token, index: string) => protectedTerms.terms[Number(index)] ?? token);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function parseIpv4(value: string): Ipv4Address | undefined {
|
|
73
|
+
const octets = value.split(".").map(Number);
|
|
74
|
+
if (octets.length !== 4 || octets.some(octet => !Number.isInteger(octet) || octet < 0 || octet > 255)) {
|
|
75
|
+
return undefined;
|
|
76
|
+
}
|
|
77
|
+
return [octets[0], octets[1], octets[2], octets[3]];
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function toInteger(address: Ipv4Address): number {
|
|
81
|
+
return ((address[0] * 256 + address[1]) * 256 + address[2]) * 256 + address[3];
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function inRange(address: Ipv4Address, [base, prefix]: Ipv4Range): boolean {
|
|
85
|
+
const divisor = 2 ** (32 - prefix);
|
|
86
|
+
return Math.floor(toInteger(address) / divisor) === Math.floor(toInteger(base) / divisor);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function isGloballyRoutableUnicast(address: Ipv4Address): boolean {
|
|
90
|
+
if (address[0] === 192 && address[1] === 0 && address[2] === 0 && GLOBAL_PROTOCOL_HOSTS.has(address[3])) {
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
return !NON_GLOBAL_RANGES.some(range => inRange(address, range));
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function isDottedVersion(text: string, offset: number): boolean {
|
|
97
|
+
return DOTTED_VERSION_PREFIX_RE.test(text.slice(Math.max(0, offset - 96), offset));
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function isInsideSvgPathData(text: string, offset: number): boolean {
|
|
101
|
+
const lineStart = text.lastIndexOf("\n", offset - 1) + 1;
|
|
102
|
+
const prefix = text.slice(lineStart, offset);
|
|
103
|
+
for (const match of prefix.matchAll(SVG_PATH_ATTRIBUTE_RE)) {
|
|
104
|
+
const quote = match[1];
|
|
105
|
+
if (!prefix.slice((match.index ?? 0) + match[0].length).includes(quote)) return true;
|
|
106
|
+
}
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function hashAddress(value: string): number {
|
|
111
|
+
let hash = 0x811c9dc5;
|
|
112
|
+
for (const character of value) {
|
|
113
|
+
hash ^= character.charCodeAt(0);
|
|
114
|
+
hash = Math.imul(hash, 0x01000193) >>> 0;
|
|
115
|
+
}
|
|
116
|
+
return hash;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function documentationAddress(value: string, prefixText?: string): string {
|
|
120
|
+
const hash = hashAddress(value);
|
|
121
|
+
const network = DOCUMENTATION_PREFIXES[hash % DOCUMENTATION_PREFIXES.length];
|
|
122
|
+
let host = (Math.floor(hash / DOCUMENTATION_PREFIXES.length) % 254) + 1;
|
|
123
|
+
if (prefixText === undefined) return `${network.join(".")}.${host}`;
|
|
124
|
+
|
|
125
|
+
const originalPrefix = Number(prefixText);
|
|
126
|
+
const prefix = Math.max(24, originalPrefix);
|
|
127
|
+
const hostMask = 0xff << (32 - prefix);
|
|
128
|
+
host &= hostMask;
|
|
129
|
+
return `${network.join(".")}.${host}/${prefix}`;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** Replace unsafe generated IPv4 examples with deterministic RFC 5737 values. */
|
|
133
|
+
export function sanitizePublicIpv4Examples(text: string): string {
|
|
134
|
+
return text.replace(IPV4_RE, (whole: string, value: string, prefix: string | undefined, offset: number) => {
|
|
135
|
+
const address = parseIpv4(value);
|
|
136
|
+
if (!address || (prefix !== undefined && Number(prefix) > 32)) return whole;
|
|
137
|
+
if (!isGloballyRoutableUnicast(address)) return whole;
|
|
138
|
+
if (isDottedVersion(text, offset) || isInsideSvgPathData(text, offset)) return whole;
|
|
139
|
+
return documentationAddress(value, prefix);
|
|
140
|
+
});
|
|
141
|
+
}
|