Skip to content

chore(release): Pi-Bolt 1.2.0 - #315

Merged
Kushalkhemka merged 15 commits into
pi-boltfrom
release/1.2.0
Nov 10, 2026
Merged

Kushalkhemka merged 15 commits into
pi-boltfrom
release/1.2.0

Conversation

@Kushalkhemka

Copy link
Copy Markdown
Member

Pi-Bolt 1.2.0: the performance round, remote control off by default, version bump and release notes (docs/releases/1.2.0.md).

  • Starts: prompt templates after the first frame, the model list built once, the git watcher after the first frame, generated checks for settings, models.json and tool schemas, modules loaded when first used. Ready to type, 1.1.7 / 1.2.0: blank home 161.6 / 143.1 M instructions, typical home 270.5 / 163.4 M, typical home with two extensions 501.3 / 390.0 M.
  • Turns and streaming: the end of a reply is drawn at once; a streaming reply lays out only its last block; a growing code block is highlighted only where it grew (15 languages, blocks of 256 characters or more).
  • Resume: a resumed fullscreen transcript draws its end first.
  • Codex: a request serializes the conversation once.
  • Remote control is behind remoteControl.enabled, off by default, set with pi-bolt remote-control enable; the pibolt-mobile-ui skill moves to skills/ and is in no build.
  • Bench: --home realistic, --home-extensions, long-block answers.

The engine is unchanged since 1.1.7, so release.yml reuses the 1.1.7 runtimes. Measured and gated on macOS on Apple silicon only: this pull request's CI is the first run on Linux and Windows.

…a launcher without uname

- bench/benchmark.py --home realistic starts every run with a home and project as they are after daily use (prompt
  templates, skills, a model store, AGENTS.md files, a git project); --home-extensions DIR[,DIR] adds Pi packages to it.
- bench/answers/: long code blocks, a long list, a table and long paragraphs for long_answer.py --file.
- The npm launcher tells macOS from Linux with a folder test instead of running uname. Its file, npm/bin/pi-bolt, is
  committed whole with the release's version change.
…resolve each resource path once

Autocomplete and the resource listing are built from the template files' names at start and rebuilt once the
templates are read; frontmatter takes a fast path for simple YAML. The files this shares with later workstreams
(package-manager.ts, resource-loader.ts, skills.ts, interactive-mode.ts and its status test) are in those commits.
The models store is read once and the registry is composed once, unless what it is built from changed.
…and draw the end of a reply at once

The footer reads the branch at start and attaches its watchers after the first frame (no git process in an unchanged
reftable repository). The TUI draws a finished reply at once instead of on its next frame. interactive-mode.ts, which
this shares with other workstreams, is in the remote control commit.
…message

Blocks before the last are kept from the previous frame while the inline state allows it (not across display math or
an open inline link); the main screen writes a frame in one call. markdown.ts and its streaming test, shared with the
lazy modules and the code highlighter, are in the code highlighting commit.
… generated code at start

scripts/generate-start-schemas.ts writes the checks and tool schemas (renumbered so the output does not depend on what
TypeBox built before in the process); build:unbundled and npm run check fail on a stale file. TypeBox loads when an
extension needs it. bash.ts and startup-lazy-init.test.ts are in the lazy modules commit, package.json in the remote
control commit.
…n first used

Through utils/lazy-packages.ts and pi-tui's marked-module.ts (a Marked proxy that forwards construction, statics and
their writes). This commit holds the files it shares with earlier workstreams whole: package-manager.ts and
resource-loader.ts (resources), bash.ts and startup-lazy-init.test.ts (tool schemas). Its parts of theme.ts and
markdown.ts are in the code highlighting commit; of main.ts, args.ts, settings-manager.ts, pi-bolt-compile.ts and
pi-bolt-update-windows.ts in the remote control commit.
… first

pi -c renders the entries the first frame shows, writes the frame, then renders the rest; scrolling, a resize or the
scrollbar completes the transcript first. interactive-mode.ts is in the remote control commit.
The request body is built once per request and its bytes are reused for the WebSocket delta check and the request
cache; the same for Azure OpenAI responses.
…grew

A streaming code block of 256 characters or more in TypeScript, JavaScript, Python, Bash, JSON, Rust, Go, C, C++, Java,
HTML, CSS, YAML, diff or SQL is highlighted again from its last settled line, with the same result as a full highlight;
other languages and shorter blocks are highlighted in full. The expressions derived from the grammars pass a
static check against super-linear backtracking, and a work bound falls back to full highlights. This commit also holds
whole the shared theme.ts (lazy modules), markdown.ts (Markdown streaming, lazy modules) and
markdown-streaming-blocks.test.ts (Markdown streaming).
…l leaves the builds

- remoteControl.enabled (global settings only, default false), set by pi-bolt remote-control enable|disable|status and
  the /settings toggle. While it is off /remote-control is not listed and prints how to turn it on, service install and
  pair refuse, and the background service does not listen or start a tunnel in any state, and exits.
- A session that sees it turned off (the toggle, or /reload after the shell command) stops its /remote-control.
- pi-bolt service restart restarts a running service; the installers and the Windows update run it after an update.
- The pibolt-mobile-ui skill moves to skills/ at the repository's root with a README; no build, compile or in-place
  update keeps it.

This commit holds whole the files it shares with earlier workstreams: interactive-mode.ts (resources, interactive
start, lazy modules, resume), main.ts, cli/args.ts, settings-manager.ts, pi-bolt-compile.ts and pi-bolt-update-windows.ts
(lazy modules), core/skills.ts and interactive-mode-status.test.ts (resources), and package.json (tool schemas).
The release notes, the 1.2.0 against 1.1.7 benchmarks and the version. npm/bin/pi-bolt also holds the launcher change
of the bench and launcher commit.
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 10, 2026 •

Copy link
Copy Markdown
Codex Review Summary: ✅ Completed

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-10T12:56:19.265520Z dd0bc36 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dd0bc36cac

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

…e, and read install.ps1 with either line ending

The generator started node_modules/.bin/biome, a shell script that Windows cannot start, so the build stopped there.
The installer test expected LF in install.ps1, which a fresh checkout has with CRLF.
The frontmatter fast path's printable-character check is one character class with the u flag: the same strings pass.
…ce remote control is turned off

RemoteControlController.start() checks the setting, and whether stop() ran, after waiting for the claim, after the
listener opened (closing it again), and before and after starting a tunnel. A session stops a start that is under way,
not only a running server, when the /settings toggle or /reload turns remote control off.
… every platform

On Windows it wrote ..\typebox-shaped.ts into tool-schemas.generated.ts, so its check called the committed file stale
and the build stopped.

@opensec-code-review opensec-code-review Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OpenSec security review

✅ No security findings in this change.

The change is a large performance and startup package: lazy loading of chalk/semver/hosted-git-info/TypeBox/yaml, generated tool and config validators, deferred prompt templates with a file-only first listing, a transcript backfill/renderer rework, a streaming code highlighter, request-body/request-conversion caches, remote control gated behind a settings switch, and installer/build changes. I reviewed the trust boundaries the change touches (project-resource collection and path dedupe, frontmatter parsing, provider request paths, remote-control gating, the highlighters and the new event dispatch) and had the three surviving leads independently verified; all were rejected, so the findings list is empty.

Notes (uncertain or pre-existing, not counted)
  • Pre-existing, not introduced: /settings turning remote control off can race a simultaneous /remote-control start between interactive-mode.ts:7191 and :2383; the controller's own check is the only guard.
  • Informational: service-host.ts:359 keeps listening if onTurnedOff is absent, unreachable through the shipped wiring.
  • Hardening only (not vulnerabilities): models.ts:566 could Object.freeze the store entry; firstHitEnd could charge 1 + scanned; request-cache/request-body could drop state in clearRequestCache() on session end.
  • Static review: /work has no node_modules, so no differential or execution tests were run; the bundled-binary require() paths were checked against build script assertions only.
8 candidates rejected by verification
  • Models-store entry handed to providers without structuredClone; FileModelsStore.read returns live shared state, so a provider mutation would contaminate the process-wide catalog: Verified reject: the no-copy is new (models.ts:566, withComment on the store contract at models-store.ts:127-129), but stored is inert JSON parsed from disk and only in-repo provider code (radius.ts:50, remote-catalog-provider.ts:156/251, llama/provider.ts:233) holds it, all filtering/copying; no untrusted actor reaches the mutation.
  • New request-body/request-conversion cache retains whole-transcript bytes in module-level state, never evicted at session end: Verified reject: retention is bounded (MAX_TABLES 4 / MAX_CONVERSATIONS 4 with idle eviction), keyed by session id, and reuse is gated on structural equality of the actual content (matches/snapshot, sameSources), so no cross-session substitution and no new disclosure channel; only a local account already reading process memory is affected.
  • GrowingHighlighter's 'hit end' attempts are charged O(1) while firstHitEnd may scan to end of line, so attacker code blocks with long lines can cost work superlinearly more than the budget intends (client-side CPU DoS): Verified reject: a newline-free line hits at the first attempt rather than failing, each position is attempted at most once per pass, and the total stays a small fraction of the full highlight (~17-20K instr/char) that the same input already costs; the fall-back stops extra work at ~2x full-highlight work, so at most a modest constant over the baseline.
  • frontmatter.ts:38-52 bare require("yaml") when isBunBinary||isBundledNode could resolve an untrusted repo's node_modules/yaml: Rejected: same lazy-loading pattern as the pre-existing lazy-packages.ts, not introduced here; bun build --compile and the esbuild bundle inline the literal require, and build-coding-agent-bundle.mjs:108-120 fails the build on any unexpected external import.
  • ResourcePathKeys fast path (resource-path-keys.ts:41 prepare, :76 plainEntryKey) skips realpath, so two distinct folders could collide on a dedupe key: Rejected: a key is only taken for paths no symlink reached and is the root's realpath plus the stored relative path, so keys equals realpath; a wrong key could only drop an identical file, and project-local ranks first anyway.
  • Generated config/schema checks (config-checks.generated.ts) differ from the removed TypeBox Value.Check, e.g. patternProperties '^.*$' admitting newline-keyed unvalidated values, or header/baseUrl only minLength:1: Rejected: the file is literally typebox/schema Build(schema).Functions()/Entry() output (what Compile() runs) and a differential test covers it (test/start-schemas.test.ts:150-185); the patternProperties and minLength behaviours are identical to the code removed, and the inputs are the user's own trusted models.json.
  • Remote-control start paths could bypass the remoteControl.enabled gate: Rejected: every start path is gated (service-host.ts:256/375/397/416/470/605 plus the :359 poll, interactive-mode.ts:2383/7191, service-cli.ts:94), the setting is read global-only, and service restart requires an existing file and a running query, which still hits the gate.
  • subscribeToAgent no longer awaits handleEvent, so a burst of events could start init() twice: Rejected: subscribeToAgent runs after isInitialized = true (interactive-mode.ts:1114 vs 1136/2399/2409) and handleEvent stays synchronous until its one awaited return, so emission order is preserved and no second init() can overlap.

Range 1f25c45471df..dd0bc36cacff, 13350 changed lines. Review by OpenSec Code Review.

@opensec-code-review opensec-code-review Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OpenSec security review

✅ No security findings in this change.

The change is a startup-performance refactor for the 1.2.0 release: npm packages are lazily loaded, frontmatter parsing gets a hand-written fast path, TypeBox schema construction is replaced by generated code, model catalog refresh/publish and TUI transcript rendering are made incremental, remote control becomes an explicit global opt-in, and the bundled mobile-ui skill is dropped. I read the full diff per file with the whole functions at head and their callers (installers and update/signing path, generated config and tool schemas, package/skill/prompt resource loading and path dedupe, model store and auth resolution, remote control service and CLI, MCP/tool extensions, and the TUI markdown/alt-screen write paths), and compared base versus head for every place a check, gate or sanitizer could have moved. No attacker-reachable weakening survived verification: the release-signature and checksum paths are byte-identical and fail-closed, the generated schemas are behavioural clones (differentially fuzzed), terminal sanitization entry points are untouched, and the new remote-control gating reads global settings only.

Notes (uncertain or pre-existing, not counted)
  • Pre-existing, unchanged by this change: model tool-call arguments are validated with coerce:true, so a string like "42" is accepted for a numeric field (packages/ai/src/utils/validation.ts).
  • Pre-existing: settings.json itself is not schema-validated at all; only keybindings.json and models.json go through the generated checkers.
  • Pre-existing: hyperlink() in packages/tui/src/components/text.ts never validates its target; it is only reached from an already-sanitized href lexed from ESC/BEL/C1-free text, identical at base.
  • Could not run the Bun/esbuild resolution experiment (no bun or node_modules in the checkout); that conclusion rests on the bundle banner (scripts/build-coding-agent-bundle.mjs) and validateExternalImports.
  • install.ps1 uses PowerShell Remove-Item -Recurse on a fixed path, which would follow a junction out of the install dir; planting one requires write access to an install dir the installer itself ACL-protects, so no privilege is gained.
11 candidates rejected by verification
  • Generated config checks (config-checks.generated.ts) accept what the TypeBox schema rejects: Differential fuzz against TypeBox Value.Check found zero divergences (108k models.json inputs, 211k keybinding values); both checkers only read the user's own global config, not repo-supplied files.
  • tool-schemas.generated.ts drifts from the real tool argument schemas, widening what a model-supplied argument may be: The schemas were moved verbatim; rebuilding all 11 from TypeBox yields identical keywords and the same validator (packages/ai/src/utils/validation.ts) consumes them unchanged.
  • Lazy literal require() in utils/lazy-packages.ts / tui/src/marked-module.ts can be made to resolve an attacker-planted module: Each branch resolves in the bundle (inlined) or the package's own node_modules via createRequire(import.meta.url); cwd/NODE_PATH precedence is unchanged from base.
  • parseSimpleFrontmatter fast path diverges from yaml().parse on an untrusted skill/prompt/agent file: The fast path is all-or-nothing per block and delegates every value whose YAML type could differ; accepted subset matches YAML 1.2 core, and no parsed key feeds a trust decision.
  • Markdown/TUI refactor lets model output emit its own terminal escape sequences (OSC-8, clipboard, cursor): sanitizeTerminalText entry points are byte-identical at base, all blocks derive from the sanitized source, and OSC-8 links are still gated on isWebLink.
  • Installer/update now deletes /skills/pibolt-mobile-ui and runs 'pi service restart': Fixed literal path inside the install dir, and restart refuses unless the service file exists and the service is already running; planting a junction needs install-dir write access.
  • models-store read() no longer clones, so a stored catalog can be mutated by a provider: The only consumer (packages/ai/src/models.ts withKnownModelTypes) copies; corrupting the cache requires provider code, i.e. trusted config.
  • checkProviderAuth bypasses resolveProviderAuth and its abort plumbing in packages/ai/src/models.ts: Only affects provider availability reporting (can hide a provider, not expose data); no credential or boundary is crossed.
  • resource-path-keys.ts symlink-aware dedupe could drop or duplicate a resource and change which file wins: Keys only dedupe resources within one load pass and fall back to full realpath for anything that may be a symlink; no path check consumes the key.
  • Lazy process.getBuiltinModule('node:crypto') weakens release-signature verification in pi-bolt-compile.ts: verify(null, sums, key, signature) is unchanged and still inside a try/catch that sets signed=false, which throws a CompileError; failure stays fail-closed.
  • A project settings.json can turn remote control on: getRemoteControlEnabled() reads globalSettings only and SettingsManager skips the project file when the project is not trusted; the change tightens this rather than loosening it.

Range 1f25c45471df..0b5ff09cd319, 13353 changed lines. Review by OpenSec Code Review.

@Kushalkhemka
Kushalkhemka merged commit 55d0c5c into pi-bolt Nov 10, 2026
25 of 26 checks passed
@Kushalkhemka
Kushalkhemka deleted the release/1.2.0 branch November 10, 2026 13:44

@opensec-code-review opensec-code-review Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OpenSec security review

✅ No security findings in this change.

No security findings. The change is predominantly startup-cost and rendering work; its one security-relevant addition is a remote-control opt-in gate that is enforced from the global settings only, refuses install/pair before I/O, and is re-checked across the service host's poll, listen and tunnel steps, with start generations guarding the controller. The release chain keeps signature and checksum verification on every path (fail-closed through process.getBuiltinModule), the new ignore-rule and resource-path-key fast paths are equivalence-preserving, and the new frontmatter fast path rejects special keys and indicators before falling back to the yaml package. The one behavioural gap found - a running /remote-control survives a failed /reload that had already re-read the gate - was verified and rejected as a vulnerability because the only party retaining access is a device the user paired (revocation is /remote-control devices), it gains no capability it did not have before the disable, and the off switch is itself new in this change; it is recorded as a hardening note with a one-line fix.

Notes (uncertain or pre-existing, not counted)
  • Scope: 179 reviewable files, ~13.6k changed lines, base 1f25c45 -> head 8a70a2e. There is no ./security-context directory in the repo, so the trust model came from SECURITY.md, packages/coding-agent/docs/remote-control.md, the project-trust docs and the package/extension loading docs.
  • The change is mostly startup-cost work (lazy builtins and packages, generated TypeBox checkers, incremental markdown lexing and highlighting, deferred prompt loading, resource path-key dedupe), plus one security feature: remoteControl.enabled (global settings only, default off) gating /remote-control, the background service, install and pair.
  • The new gate held up under adversarial reading: a project's .pi/settings.json, package settings and CLI overrides cannot enable it (getRemoteControlEnabled reads globalSettings only), service install/pair are refused before any I/O, runServiceHost exits before the host key or listener when off, serve() re-checks before every listen and before the tunnel, retry timers and late tunnels are dropped, and controller start generations are checked after the claim, after the listener, before the tunnel and on a late tunnel. service restart (run by both installers and by pi-bolt update) only acts on a service that is installed and already running, so an update cannot start one.
  • G1 (hardening, not a finding): the remote-control stop on disable only runs from applyRuntimeSettings(), inside the try of handleReloadCommand (interactive-mode.ts:7071). A throw later in the reload (settings are re-read at agent-session.ts:3991, before resource loading at 3994) reaches the catch at 7092-7097 and leaves an already running controller listening with its tunnel up, while remote-control status reports off. Suggested fix: call stopRemoteControlWhenOff() from a finally in handleReloadCommand (or re-read the setting in the catch), and give controller.ts:256 the same teardown as the post-listener guard at 243-249 so a start that resumes with the gate off closes its listener too.
  • G2 (hardening, not a finding): the /settings remote-control toggle is a silent no-op when the global settings file failed to load (save() returns early, interactive-mode.ts:5573-5576 shows nothing), so the session serves while the persisted gate stays off. Surface the error like the CLI enable path does.
  • G3 (informational): install.ps1:566-567 removes skills/pibolt-mobile-ui unconditionally, including when installing an older release that still ships it; that only deletes the user's own copy of a removed bundled skill.
  • Files read in full at head include: core/package-manager.ts (helpers and collectors), core/skills.ts, core/resource-path-keys.ts, core/prompt-templates.ts, utils/frontmatter.ts, remote-control/controller.ts, remote-control/service-cli.ts, remote-control/service-host.ts, core/settings-manager.ts (remoteControl and save paths), modes/interactive/interactive-mode.ts (reload, runtime settings, /settings, /remote-control), pi-bolt-compile.ts and pi-bolt-update-windows.ts signature paths, npm/bin/pi-bolt, install.sh, install.ps1, core/tools/{bash,edit,find}.ts hunks and the generated tool/config schema checkers.
12 candidates rejected by verification
  • Turning remote control off does not stop a running /remote-control when /reload fails: Ordering is real: agent-session.ts:3991 re-reads settings (making the in-memory gate false), agent-session.ts:3994 and later steps can throw, and the catch at interactive-mode.ts:7092-7097 skips applyRuntimeSettings() (7071), the only caller of stopRemoteControlWhenOff() on that path; nothing polls the setting in an interactive session, so a running controller keeps its listener and tunnel until a later successful reload. Rejected because the only party that keeps access is a device in ~/.pi/agent/remote-control/devices.json (noise handshake in server.ts), i.e. a device the user paired and that can already type into the session; remote-control disable is documented as an enable toggle, not a revocation (/remote-control devices revokes, and service uninstall says paired phones stay paired). Nothing was removed either: the off switch is new in this change, so the failure state is the pre-change status quo. Trigger is also narrower than first claimed: extension and package load failures are collected, not thrown. Kept as a hardening note (G1).
  • Signature/checksum verification now resolves node:crypto through process.getBuiltinModule: Replacing import { createPublicKey, verify } from "node:crypto" with process.getBuiltinModule("node:crypto") narrows tamper resistance against code already executing in the Pi process (an installed extension), which can write the install directory anyway, so no new capability. Fail-closed: a missing builtin or throwing verify lands in the catch and returns false, and both callers abort (CompileError("the release's signature does not verify...")). sha256 paths compare against the signed SHA256SUMS, so a wrong hash also aborts.
  • Ignore-rule shortcut could include paths a matcher ignores (WeakSet of matchers with rules): isIgnored returns false only for matchers that cannot ignore anything. The single ig.add call in package-manager.ts (339) is immediately followed by matchersWithRules.add, listWithIgnoreRules (350-361) adds a folder's rules from its own listing before any child is tested, and skills.ts builds its own matcher and calls ig.ignores directly (skills.ts:212,252) rather than this helper. Root-relative path semantics are unchanged (toPosixPath(relative(root, ...)), directory form with a trailing slash).
  • ResourcePathKeys realpath folding could drop a resource or let a project path displace a user path: Keys stay equivalent to getResourcePathKey: notePlainEntry is only set for entries reached through no symlink (plainPath && !entry.isSymbolicLink()), symlinked roots go through canonicalizePath, and prepare matches names exactly against a listing that skips symlinks. Dedupe order still keeps the earlier (project-over-global) entry, so no path gains precedence it did not have. Any mismatch would duplicate or drop a resource, not introduce new code loading.
  • New hand-written YAML frontmatter parser on repo-controlled skill/command metadata: The fast path only accepts top-level key: value lines with plain or simply-quoted values and otherwise returns undefined, falling back to yaml().parse. It rejects __proto__/null/true/false keys, duplicate keys, key length >128, indicators, numbers, : , #, trailing :, tabs and non-printable characters, and avoids ''/escape handling it does not implement, so no prototype pollution and no value divergence found; a thrown yaml error is caught by the callers that load resources. Repo resources behind this parser also load only after project trust.
  • Runtime TypeBox schema checks replaced by build-generated checkers: Validation still runs (Value.Check semantics generated at build time from the same schemas), with equivalence tests over hundreds of documents plus a staleness test and a check:start-schemas script; the models/keybindings/theme/tool inputs are user-owned config and model-facing tool arguments, not an untrusted actor's path to a new sink.
  • Deferred prompt-template loading and removed existsSync before statSync: Listing and reading are split, but reads reuse the same trust-filtered, resolved path list (lastPromptPaths) and loadPromptTemplateFiles still reads through readFileSync with per-file diagnostics. The existsSync before statSync in the explicit-paths loop only changes whether a missing path produces a warning; the throwing path is unchanged.
  • Bundled mobile-ui skill removal and updater deleting skills/pibolt-mobile-ui: The delete targets a fixed literal path inside the versioned build folder under the user's own ~/.pi-bolt (ACL-protected by Protect-PiBoltFolder), rmSync unlinks rather than following symlinks, and no reader of /skills remains (bundled-skills.ts deleted, main.ts no longer adds bundled skill paths), so this removes a load path rather than adding one.
  • zstd request-body compression in the Codex/OpenAI adapters: Compress-only path (no untrusted decompression, so no decompression bomb), encoding set on a real Headers object rather than by string concatenation, and the request-cache reuse still refuses callers with an onPayload hook, mutable messages or no session id.
  • Stored model catalogs are no longer structuredClone'd before being published: A contract change (the store snapshot and the live registry now alias the same Model objects) with no sink found: the write path still clones, and no consumer mutates a published model in place. The persisted store is written from the TLS-authenticated catalog, so controlling it already requires the user's own machine.
  • npm launcher detects macOS by testing /System/Library/CoreServices: Only a root-owned path can make Linux report darwin, and the consequence is choosing ~/.pi-bolt/npm//pi-bolt-darwin-* and installing a Darwin build whose archive is still fetched through install.sh against the signed SHA256SUMS. Availability only.
  • New regex-reach analyser decides when an incremental highlight may be reused: The failure direction is safe for correctness (unknown syntax, lookbehind, backreferences to unseen groups yield undefined/UNBOUNDED, which disables reuse or over-approximates), grammars are whitelisted, and the work is guarded by a hang case corpus, a fuzz harness in a child process and a work test in a worker with a kill switch. A residual timing risk on adversarial code blocks is a CPU DoS already bounded by that harness, not a new capability for an attacker.

Range 1f25c45471df..8a70a2ed2c9c, 13568 changed lines. Review by OpenSec Code Review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants