Commit Graph

218 Commits

Author SHA1 Message Date
can1357 336e1edf7a chore: organized test scripts in CI workspace and package configuration
- Added scripts/fix-dts-extensions.test.ts to the test:scripts npm script.
- Included the .d.ts extension rewrite test in the CI workspace test suite.
- Updated repoScriptTests list in scripts/ci-test-ts.ts to ensure consistent tracking.
2026-07-05 16:01:51 +02:00
can1357 8722985965 Merge PR #4282: fix(install): add network timeouts to install script downloads (@metaphorics) 2026-07-05 13:25:24 +02:00
can1357 541b299375 style: formatted dts extension test with biome 2026-07-05 13:05:02 +02:00
can1357 f4d43c1819 fix dts extension rewrite edge cases 2026-07-05 13:03:09 +02:00
Matt Wilkinson c7961d249b fix(build): emit NodeNext-consumable .d.ts (explicit .js on relative re-exports)
The declaration emit runs under moduleResolution: Bundler, so published .d.ts carried extensionless relative specifiers (export * from "./sdk") that a node16/nodenext consumer can't resolve — the package root failed with TS2834/TS2305. The publish pipeline now rewrites emitted relative specifiers to explicit .js across every package's dist/types.

Co-Authored-By: seal <noreply@sealedsecurity.com>
2026-07-03 11:42:54 -04:00
can1357 5c171b2860 chore: refactored failure reporting and update quiet mode output
- Extracted failure formatting logic into a reusable `formatChunkFailure` function.
- Updated quiet mode to display detailed failure output immediately when a test chunk fails.
- Adjusted final failure summary to improve output readability and conditional flow.
2026-07-03 00:47:56 +02:00
can1357 83176e159f chore: implemented watchdog and stabilize GC for test execution
- Added a per-chunk watchdog that terminates wedged test processes with SIGKILL after a configurable timeout.
- Implemented incremental stream draining to capture test output even when a process is forcibly killed.
- Stabilized test execution by forcing single-threaded GC markers (`BUN_JSC_numberOfGCMarkers=1`) to prevent segmentation faults during heap-heavy operations.
2026-07-03 00:46:46 +02:00
metaphorics 165a33eece fix(install): add network timeouts to install script downloads
The GitHub API and binary download calls in `install_binary()` (`scripts/install.sh`) and `Install-Binary` (`scripts/install.ps1`) could hang indefinitely on stalled connections. Added curl `--connect-timeout`/`--max-time` to the release metadata calls and `--connect-timeout`/`--speed-limit`/`--speed-time` to the binary download, plus `-TimeoutSec` to the PowerShell `Invoke-RestMethod`/`Invoke-WebRequest` calls. Verified `bash -n scripts/install.sh` passes; no TypeScript typecheck is affected.

Closes #4253
2026-07-02 17:30:53 +09:00
can1357 388534802c chore(repo): corrected invalid test script paths in ci configuration
- Replaced the non-existent `ci-test-ts.test.ts` with the active `link-omp.test.ts` in `package.json` and `ci-test-ts.ts`.
- Documented that the invalid test path was previously ignored silently by the bun test runner.
2026-07-02 02:40:07 +02:00
can1357 3ff65ead6b feat(wire): bumped collaborative protocol to version 3
- Bumped the collaborative protocol version (`COLLAB_PROTO`) from 2 to 3.
- Required protocol-3 to coordinate `ui-request`, `ui-request-end`, and `ui-response` frames.
- Rejected older protocol-2 guests at handshake to prevent host-asked requests from hanging.
- Updated verification tests and CI installation check scripts to expect protocol version 3.
2026-07-02 01:51:09 +02:00
can1357 5f1ed0fcde chore: reformat 2026-07-01 23:14:36 +02:00
can1357 8bc597b61f test setup omp link fallback 2026-07-01 21:42:24 +02:00
can1357 58ec27257a Merge PR #3702: fix(setup): harden global omp symlink against bun pm -g bin failure (@roboomp) 2026-07-01 21:42:24 +02:00
can1357 8687899728 ci: disabled concurrent garbage collection in test environment
- Set the `BUN_JSC_useConcurrentGC` environment variable to `"0"` in the child process environment built for test suites.
2026-07-01 00:07:03 +02:00
can1357 cbb471b666 chore: standardized code quality and formatting for tooling scripts
- Added `scripts/**/*.ts` to the linter and formatter inclusion list in `biome.json`.
- Replaced manual array index searches with standard `indexOf` operations.
- Cleaned up unused variables, obsolete helpers, and command-line flags.
- Applied consistent formatting and code style across tooling scripts.
2026-06-30 23:51:16 +02:00
can1357 6d0569788c ci: formatted test runner progress, summary, and failure parsing to match bun style
- Refactored `formatProgressLine` to display passes and failures in the visual style of `bun test` including elapsed time.
- Implemented `extractFailingTests` to parse individual test failures and their raw output details out of captured stdout/stderr.
- Added a `formatSummaryFooter` to output a clean concluding tally of passed/failed chunks and the total wall time.
2026-06-30 21:27:41 +02:00
can1357 bd77bd507c feat: introduced a unified local runner for rust and typescript tests
- Added `local` and `local-ts` modes to `ci-test-ts.ts` to coordinate full local runs of TypeScript and Rust packages in a single progress stream.
- Implemented a quiet output formatter that displays a one-line progress entry and defers verbose output until failure.
- Included previously skipped workspace packages `packages/mnemopi` and `python/robomp/web` in the local testing scope.
- Configured colorized ANSI formatting for progress logs when running in interactive TTY terminals.
- Bound repo-level scripts and rust task orchestration command under the consolidated runner.
2026-06-30 20:39:32 +02:00
can1357 e3b956275f Merge remote-tracking branch 'origin/farm/3d40f8e4/homebrew-darwin-arm64-tiny-runtime' 2026-06-30 17:59:39 +02:00
roboomp 083d1f5a8e fix(release): pinned tiny transformers version
- Added the Transformers.js version define to release-built binaries.
- Covered the release dry-run command so Homebrew assets keep the tiny runtime pin.

Fixes #3904
2026-06-30 14:30:23 +00:00
can1357 467f46b190 perf(scripts/session-stats): added composite index on tool call timestamp and name
- Added a composite index `ss_tc_ts_tool` on the `timestamp` and `tool_name` columns of the `ss_tool_calls` table to optimize query performance.
2026-06-30 07:01:32 +02:00
can1357 b5544b3f19 feat(coding-agent): implemented path recovery for mismatched section tags
- Added `recoverSectionPathFromTag` to reconcile bare or mismatched `[basename#tag]` paths using existing session snapshots.
- Implemented `readSectionForPreview` to fallback to recovered file paths when the authored path is absent.
- Updated `computeHashlineSectionDiff` to use the path recovery logic during preview content acquisition.
- Removed obsolete regression test file `issue-1765-repro.test.ts`.
2026-06-28 17:28:53 +02:00
can1357 469046fbcb chore: implemented parallel execution for test scripts
- Added a worker pool mechanism to run independent test chunks concurrently in local environments.
- Introduced `OMP_TEST_CONCURRENCY` to allow manual control over parallel worker counts.
- Retained sequential, fail-fast execution for CI environments to ensure stability within memory-constrained runner jobs.
- Consolidated environment variable scrubbing into a shared helper function.
2026-06-28 17:23:31 +02:00
can1357 8f6fbafe08 chore: added support for semantic version bumping
- Added logic to automatically calculate versions based on major, minor, or patch keywords.
- Updated the release script input validation to accept semantic bumps in addition to explicit version strings.
- Improved version parsing by adding radix parameters to integer conversion.
2026-06-28 17:17:18 +02:00
roboomp db9d9f3f59 fix(setup): harden global omp symlink against bun pm -g bin failure
The root `setup` script used `ln -sfn ... "$(bun pm -g bin)/omp"`. On
fresh hosts where `$HOME/.bun/install/global/package.json` is missing
`bun pm -g bin` aborts with "No package.json was found", the command
substitution expands to empty, and `ln` tries to write `/omp` —
failing with `Permission denied` (or, on a writable filesystem,
silently linking under `/`).

Move the logic into `scripts/link-omp.sh`:

- Capture `bun pm -g bin` and ignore its failure.
- Fall back to `${BUN_INSTALL:-$HOME/.bun}/bin`, matching Bun's own
  install convention.
- `mkdir -p` the target so the link works even when nothing has yet
  populated the global bin dir.

Fixes #3701
2026-06-28 04:27:03 +00:00
can1357 5a044dc0da feat: consolidated and automate changelog management
- Added `rewrite-changelog.ts` and `fix-changelogs.ts` utilities to automate the consolidation of release notes using LLM-assisted processing.
- Updated multiple internal changelog files by consolidating redundant entries and improving phrasing for readability.
- Implemented `previewLine` utility in `coding-agent` to prevent visual spillover in status rows by managing text truncation and whitespace.
- Updated `package.json` with new workflow scripts for managing package-level change histories and documentation indexes.
2026-06-27 03:08:52 +02:00
can1357 ac904fc70c fix: patched Kimi model edit mode fallback
- Added a fallback from `hashline` to `replace` mode for Kimi-family models to resolve compatibility issues.
- Introduced `PI_STRICT_EDIT_MODE` environment variable to bypass automatic model-specific edit-mode fallbacks.
- Updated `getEditVariantForModel` to perform case-insensitive matching for model variant configurations.
- Added comprehensive unit tests for edit mode resolution and settings configuration.
2026-06-26 13:17:35 +02:00
can1357 305db55cd7 fix(coding-agent/eval): surfaced the exception type and message in the
- Surface the exception type and message in the error display by prepending the formatted error string to the traceback array.
- Prevent the host from hiding the actual error by ensuring the traceback is not empty, consistent with other language runners.
2026-06-26 10:06:48 +02:00
can1357 af01c63e3b test(ai): updated credential access in E2E tests and CI test runner
- Updated the `ai` package E2E tests to retrieve environment variables via `e2eApiKey` to ensure they only execute when E2E testing is enabled.
- Refactored the `scripts/ci-test-ts` runner to conditionally apply the `--only-failures` flag based on provided arguments.
2026-06-25 21:50:55 +02:00
can1357 0cd852053e Merge branch 'farm/6a62fa2b/fix-bunfs-override-validation-fallback'
Serve bundled pi-* and TypeBox through an in-process virtual namespace
on Bun 1.3.14+ where `--compile` extras are unreachable via any
filesystem API (issue #3423).

Merge resolution:
- Reconciled `TYPEBOX_SHIM_PATH` with main's #3414 fall-through:
  `__resolveTypeBoxShimPath(isCompiled, sourcePath, exists)` returns the
  `omp-legacy-pi-bundled:` virtual specifier in compiled mode (no FS
  probe) and the on-disk source path otherwise, dropping to null when
  the shim file is missing so bare typebox imports fall through to native
  resolution.
- Removed the now-dead `--compile` extras path: dropped
  `LEGACY_COMPAT_BUILD_ENTRYPOINTS` usage from both build-binary.ts and
  ci-release-build-binaries.ts and deleted scripts/binary-entrypoints.ts;
  the bundler reaches every surface via legacy-pi-bundled-registry.ts.
- Deleted obsolete tests for the removed bunfs machinery
  (legacy-pi-compat-entrypoints, legacy-pi-typebox-shim-validation) and
  added regression coverage for __resolveTypeBoxShimPath.
- Dropped the binary-compiling smoke driver per maintainer request.

Verified: bun check clean; 77 extensibility tests pass; instrumented
compiled-binary run confirmed onLoad fires for all bundled specifiers.
2026-06-25 05:08:36 +02:00
roboomp 294d41bd3b fix(coding-agent): served bundled pi-* through virtual ns on bun 1.3.14
Bun 1.3.14 stopped exposing `--compile` extras through every filesystem-style API: `fs.existsSync`, `Bun.file().exists()`, `Bun.resolveSync`, and `await import()` on `/$bunfs/...` or `file:///$bunfs/...` all fail; only `/$bunfs/root/<binary-name>` itself answers. The pre-existing legacy-pi rewrite emitted `file:///$bunfs/...` URLs that Bun then could not load, so every legacy extension that imported `@oh-my-pi/pi-*` or `@sinclair/typebox` failed on the `omp-darwin-arm64` release binary.

`legacy-pi-compat.ts` now keeps a JS-heap reference to every bundled pi-* surface in a lazy-loaded sibling `legacy-pi-bundled-registry.ts` and serves them through an `omp-legacy-pi-bundled:` virtual namespace whose `Bun.plugin().onLoad` synthesizes a re-export module — no bunfs path ever leaves the module in compiled mode. Dev / source-link / installed-package modes keep the historical `file://` rewrite (source files exist on disk). The matching `--compile` extras in `scripts/build-binary.ts` are gone; `BUNFS_PACKAGE_ROOT`, `bunfsPath`, `__computeBunfsPackageRoot`, and `__joinBunfsPath` are deleted as dead code. `scripts/smoke-3423.ts` compiles a tiny binary that loads a fixture extension end-to-end through the new path.

Fixes #3423
2026-06-25 02:35:50 +00:00
roboomp 08977b226d fix(release): restored legacy pi-compat --compile entrypoints in release builds
- Extracted the legacy `--compile` entrypoint list to `scripts/binary-entrypoints.ts` and consumed it from both the release CI script and the local dev `build-binary.ts`, so the two cannot drift apart.
- `scripts/ci-release-build-binaries.ts` no longer ships release binaries without the typebox shim, legacy pi shims, and `@oh-my-pi/{agent,natives,tui,utils}` package barrels in bunfs. Commit dc5c93462f removed worker entrypoints and false-comment-claimed the legacy entrypoints were "still" listed, so every published `omp-<platform>-<arch>` since shipped without them and the resolver emitted bunfs URLs to missing files.
- Validated TYPEBOX_SHIM_PATH at module init via __resolveTypeBoxShimPath, mirroring __validateLegacyPiPackageRootOverrides (#2168). When the shim is absent the rewriter leaves bare typebox / @sinclair/typebox imports alone so Bun falls through to native node_modules resolution.
- Pinned both halves of the contract with tests: release+dev scripts must source from the shared constant, every shim path computed in legacy-pi-compat.ts must appear in it, and __resolveTypeBoxShimPath drops missing candidates.

Fixes #3414
2026-06-25 00:14:41 +00:00
roboomp 404471f000 fix(install): expect collab protocol v2 in smoke
The tarball install smoke imports @oh-my-pi/pi-wire and asserts the
exported COLLAB_PROTO value. The chunked welcome protocol bump changed
that contract from 1 to 2, so the smoke must assert the new protocol
value alongside the package constant and tests.

Fixes #3144
2026-06-20 18:59:27 +00:00
can1357 3998d95088 feat: standardized tab expansion to fixed width
- Removed configurable tab width support and the `display.tabWidth` setting across all packages.
- Deleted obsolete utility functions `getIndentation`, `getIndentationNoescape`, and `setDefaultTabWidth`.
- Standardized tab expansion logic to use a fixed `DEFAULT_TAB_WIDTH` globally.
- Cleaned up related configuration schemas, test suites, and internal API signatures to remove path-dependency.
2026-06-19 04:48:41 +02:00
can1357 88aa88f605 fix(coding-agent): bundle mupdf into the compiled binary so PDF reads work
The vendored markit engine kept `mupdf` external, but a single-file
`bun --compile` binary has no node_modules to resolve it from, so the
standalone binary aborted at startup with `Cannot find package 'mupdf'`
— the otherwise-lazy import is resolved eagerly at boot. Bundle mupdf and
embed its WASM blob (scripts/embed-mupdf-wasm.ts, reset after the build);
npm and source installs still load mupdf from node_modules.

Import mupdf lazily inside the PDF converter so the bundled markit chunk's
init stays synchronous: mupdf's top-level await otherwise made the chunk
init async and bun's compiled bundler failed to await it through the
barrel, exposing the converters before their module-level const tables
initialized (undefined EXTENSIONS). Also keeps the ~10MB wasm off non-PDF
document conversions.
2026-06-18 20:44:58 +02:00
can1357 831b664a4c perf(coding-agent): optimized documentation indexing via compressed blob
- Replaced raw TypeScript documentation map with a lazily-inflated gzip blob.
- Reduced bundled binary/npm package size by approximately 0.9MB.
- Encapsulated index logic into `docs-index.ts` to separate header metadata from content.
- Added `postpack` and robust `try/finally` patterns in build scripts to ensure clean artifacts.
- Implemented disk-based fallback during development to maintain existing developer experience.
2026-06-18 18:57:13 +02:00
can1357 8427e69e1e fix(coding-agent): prevented puppeteer startup crashes
- Avoided value-imports of `puppeteer-core` in main startup files to prevent eager loading of the browser-data dependency graph.
- Used `import type` and literal string checks to defer `puppeteer-core` initialization until browser tools are actually invoked.
- Added a test to verify that `puppeteer-core` and `@puppeteer/browsers` remain off the eager startup import graph.
- Externalized additional heavy dependencies to reduce bundle size and improved minification settings in the build script.
2026-06-18 17:22:37 +02:00
can1357 5875b20866 chore(scripts): implemented chunked test execution for coding-agent
- Added `chunkSize` configuration to coding-agent test buckets to prevent OOM errors in CI.
- Updated `codingAgentTestCommands` to generate multiple test processes when a bucket exceeds its chunk limit.
- Refactored `commandsForMode` to support flattened arrays of chunked test commands.
2026-06-18 03:49:20 +02:00
can1357 d4317d3d20 feat(ai): consolidated OpenAI-family streaming and add OpenRouter API support
This change introduces a new `openrouter` API type and extensively refactors OpenAI-family streaming providers, centralizing shared logic and improving robustness.

Key changes include:
- **Unified OpenAI-family Logic:** Consolidated core utilities, compat resolution, request shaping, and stream processing into `openai-shared.ts`, reducing duplication across `openai-completions`, `openai-responses`, and `openai-codex-responses`.
- **OpenRouter API Type:** Introduced a dedicated `openrouter` API type with dual-surface compatibility, allowing it to dispatch requests as either OpenAI Chat Completions or Responses.
- **Enhanced Provider Integration:**
    - Improved Perplexity search to leverage shared OpenAI streaming transports, including API-key fallback to OpenRouter and support for Perplexity's Responses API.
    - Integrated xAI-specific logic directly into the shared `stream.ts` dispatch, removing the dedicated `xai-responses` provider.
    - Refined credential parsing for Google Gemini CLI and handling of Azure deployment names.
- **Robustness & Consistency:** Improved error handling for Codex, standardized output token parameter resolution, and ensured consistent application of reasoning suppression across all Chat Completions dialects.
- **New Documentation:** Added `provider-endpoint-constraints.md` to detail endpoint-specific behaviors and quirks for various providers.
- **Telemetry & Debugging:** Extended telemetry propagation to advisor calls and overflow compaction tasks. Improved debugging for Codex WebSocket failures and stream error messages.
- **Tooling & Security:** Updated browser stealth scripts to prevent detection and added a new `ts-no-inline-cast-access` TTSR rule.
2026-06-17 21:36:48 +02:00
lycaon 9a39b0093f fix(scripts): check current Gemini CLI version source 2026-06-17 00:16:36 -06:00
can1357 508a9f543e feat: removed render_mermaid tool and added width-aware Mermaid clipping
- Removed render_mermaid from tool discovery, task definitions, and registries.
- Removed renderMermaid setting and prompt/docs references tied to the deleted tool.
- Added maxWidth and theme color options to Mermaid ASCII resolution in markdown flow.
- Re-rendered Mermaid ASCII in both directions and clipped output to available width.
2026-06-16 21:32:39 +02:00
can1357 ee6e036073 chore(scripts): raised native test parallelism and removed failure-only test flag
- Removed the `--only-failures` flag from workspace test commands so CI runs complete test passes.
- Raised native test mode parallelism from 1 to 4 for native and integration package execution.
2026-06-15 08:27:59 +02:00
can1357 ba82ed6e59 test: update hashline tests 2026-06-15 07:47:54 +02:00
can1357 907bc9979e feat: renamed opcodes to simplified variants
- Renamed line and block patch op verbs to XCHG, DEL, and INS in parsing and formatting.
- Updated grammar and tokenizer to support XCHG.BLK, DEL.BLK, and INS.PRE/POST/HEAD/TAIL forms.
- Updated diagnostics, docs, prompts, tests, and changelog to use XCHG/DEL/INS-based operators.
- Expanded session-stats parsing to normalize legacy op aliases to compact IDs.
2026-06-15 07:33:24 +02:00
can1357 36991a38e7 fix(scripts): added changelog baseline pinning for recover runs
- Added a `refs/clog` baseline and updated the fixer to prefer it over older `v*` tags when resolving the changelog diff floor.
- Constrained recovery scans to tags containing the baseline and added `--pin` to advance that baseline to `HEAD` after authoritative rewrites.
- Updated release tagging/tag lookup behavior and added a regression test covering recovered released bullets not being re-promoted.
2026-06-15 04:35:12 +02:00
can1357 ecd9f3220f feat(scripts): added changelog recovery mode for historical duplicate cleanup
- Added --recover CLI option to rebuild changelog fixes from tagged history.
- Pruned Unreleased bullets that match historical released items across all tags.
- Normalized output by sorting release sections by version and compacting bullet spacing.
2026-06-15 03:43:24 +02:00
can1357 3f82589ec1 fix: fixed OAuth and profile-boundary regressions across CLI and env handling
- Fixed OAuth credentials to keep unknown fields in schema while preserving existing shape checks.
- Fixed MCP OAuth IDs to be profile-scoped and avoid deleting credentials from non-active profiles.
- Fixed string-flag parsing so PROFILE_BOOTSTRAP_BOUNDARY tokens are not consumed as values.
- Fixed active-profile directory resolution to refresh after env updates so profile .env overrides apply.
2026-06-15 03:20:45 +02:00
can1357 4952b28a8e test(mnemopi): reworked mnemopi test embedding setup and CI bucketing
- Removed the mnemopi Bun preload file and added explicit `./setup` imports in the changed test suites.
- Deleted the `RUN_EMBEDDINGS` flag path and shifted `MNEMOPI_NO_EMBEDDINGS` handling into per-suite before/after hooks.
- Excluded `packages/mnemopi` from the fast parallel CI test bucket with a note about missing fastembed models.
2026-06-15 02:45:03 +02:00
can1357 12950af096 perf(scripts): raised workspace test workers and ARC CPU limits
- Updated workspace-mode CI to run `workspaceTestCommand` with 8 workers instead of 4.
- Raised the documented ARC runner CPU limit from 8 to 16 in caching docs.
2026-06-15 02:44:16 +02:00
roboomp 77a5befd53 fix(ci): authenticate gh release lookup and fail loud on lookup error
Two issues caught in review on #2597:

1. `gh release list` in GitHub Actions requires GH_TOKEN. The release
   notes step in `.github/workflows/ci.yml` had no env block, so gh would
   exit non-zero and the script's silent fallback would re-strand the
   silent-tag entries this change is meant to recover. Pass
   `GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}` to the step.

2. Silently degrading to legacy single-version output on gh failure is
   itself the regression vector — a future token misconfig or gh outage
   would lose data with no signal. `resolvePublishedFloorTag` now throws
   on gh failure with an actionable hint ("pass GH_TOKEN in Actions; set
   OMP_RELEASE_NOTES_FLOOR= locally to opt into legacy mode"). The
   thrown error propagates out of `main` and exits non-zero, failing the
   CI step loudly so the release is rebuilt with the fix.

The legitimate null path is preserved: `OMP_RELEASE_NOTES_FLOOR=`
(empty) still forces single-version mode, and a successful gh call with
no candidate < target still returns null (first-ever publish case).

Verified locally: hiding gh from PATH now exits 1 with the hint;
`OMP_RELEASE_NOTES_FLOOR=` with hidden gh still produces the legacy
84-bullet single-version output.

Refs #2596
2026-06-14 23:43:17 +00:00
roboomp 4d9f9d9edf fix(ci): aggregated release notes across silent intervening tags
scripts/ci-release-notes.ts previously extracted only the single
target-version section, so changelog entries finalized under tags pushed
without a GitHub Release (e.g. v15.12.5 and v15.12.6 — collateral from
the pre-#2564 release-cancellation bug) were stranded out of the next
published release body.

The generator now walks the range (latest-published-release, target],
resolved via 'gh release list', and merges every in-range '## [X.Y.Z]'
section per package — grouped by '### <category>' with bullet-level
dedup so post-release changelog flattening cannot surface the same
entry twice. Versions iterate newest-first so newer phrasing wins on
dup resolution, and categories are sorted into the canonical
Breaking/Added/Changed/Fixed/Removed order regardless of source order.

Falls back to legacy single-version extraction when 'gh' is unavailable
or no prior published release resolves (safe no-op);
'OMP_RELEASE_NOTES_FLOOR=v15.12.4' overrides the lookup for manual
re-runs (empty string forces legacy mode).

Adds scripts/ci-release-notes.test.ts covering: range inclusion above
floor, target-inclusive boundary, dedup of bullets flattened forward
into multiple versions, canonical category ordering, the null-floor
legacy fallback, empty version sections skipped, and no empty-category
emission when dedup drains a bucket. Wired into 'bun run test:scripts'.

Fixes #2596
2026-06-14 23:36:19 +00:00