Skip to content

Commit e34df67

Browse files
Itay Inbarclaude
andcommitted
v1.4.3: suppress pi changelog block + override deprecated node-domexception
Two cosmetic follow-ups to the v1.4.2 @earendil-works migration. 1. Pre-stamp pi's lastChangelogVersion so the "What's New" block stops rendering inside little-coder's TUI on every pi bump. Pi reads ~/.pi/agent/settings.json#lastChangelogVersion and dumps every newer CHANGELOG entry on startup; jumping pi from 0.68 to 0.75 in v1.4.2 made the entire upstream changelog appear underneath our banner. The launcher now writes the bundled pi version into that key before pi starts, so pi sees "already seen this." Non-destructive merge — quietStartup and any other keys are preserved. /changelog inside the TUI is still the unconditional path for users who want to read it. 2. Override the deprecated node-domexception@1.0.0 transitive via a bundled local stub at vendor/node-domexception/. The upstream package is a 16-line shim that ensures globalThis.DOMException is set; native DOMException exists since Node 18, and we require >= 22.19, so the shim is dead code. The stub exports globalThis.DOMException directly, so fetch-blob's only call site (import DOMException from 'node-domexception') sees the same value it always would have. Wired via package.json#overrides, which npm honors when little-coder is the install root (i.e. `npm install -g little-coder`). vendor/ is now in the `files` array so it ships in the tarball. Result: `npm install -g little-coder` is now warning-free, and the TUI no longer leaks pi's upstream changelog underneath little-coder's own startup banner. All 152 vitest tests + tsc --noEmit clean. Smoke-tested --list-models against the new install. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent c7a073f commit e34df67

6 files changed

Lines changed: 606 additions & 1371 deletions

File tree

CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,21 @@
22

33
All notable changes to little-coder are documented here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and little-coder's public interface (CLI, providers, tools, skills) follows semver starting at `v0.0.1` post-rename.
44

5+
## [v1.4.3] — 2026-05-19
6+
7+
Follow-up to v1.4.2: clean up two cosmetic regressions that the @earendil-works scope migration surfaced.
8+
9+
### Fixed
10+
- **Pi's `What's New` block no longer appears inside little-coder's TUI after a version bump.** Root cause: pi's interactive mode reads its own bundled `CHANGELOG.md` on startup and renders every entry strictly newer than the `lastChangelogVersion` field in `~/.pi/agent/settings.json` (`interactive-mode.js:getChangelogForDisplay`). v1.4.2 jumped the bundled pi from 0.68.1 to 0.75.3, so users who had previously launched any older little-coder saw pi's full 0.68 → 0.75 upstream changelog dumped *underneath* little-coder's own startup banner. That's wrong because little-coder is the surface and pi is the substrate — the chrome above shouldn't suddenly start advertising the substrate's release notes. The launcher (`bin/little-coder.mjs`) now pre-stamps `lastChangelogVersion` to the currently bundled pi version (resolved from `node_modules/@earendil-works/pi-coding-agent/package.json#version`, the same file we already read to find pi's cli.js, so there's no second source of truth) *before* pi starts. Pi then sees "user already saw this changelog" and the block never renders. The merge into `~/.pi/agent/settings.json` is non-destructive — `quietStartup: true` and every other existing key are preserved. Users who genuinely want pi's upstream changelog can still pull it up with `/changelog` inside the TUI.
11+
- **`npm install -g little-coder` no longer prints `node-domexception@1.0.0` deprecation warning.** Root cause: a 5-hop transitive — `@earendil-works/pi-ai` → `@google/genai` → `google-auth-library` → `gaxios` → `node-fetch@3` → `fetch-blob@3` → `node-domexception@1.0.0`. The `node-domexception` package is just a 16-line shim that sets `globalThis.DOMException` when undefined, and native `DOMException` has been built into Node since 18 — so on our `Node >= 22.19` floor, the entire shim is dead code. Replaced it via `package.json#overrides` pointing at a bundled stub at `./vendor/node-domexception/` that exports `module.exports = globalThis.DOMException` directly. The stub ships in the npm tarball (`files` array now includes `vendor/`). Since npm's `overrides` field is honored when little-coder is the install root (which it is for `npm install -g little-coder`), the deprecated upstream package never reaches the user's tree, and npm prints no warning. Functional behavior is identical because the only call site (`fetch-blob/from.js:import DOMException from 'node-domexception'`) sees the same `globalThis.DOMException` it would have gotten from the upstream shim.
12+
13+
### Notes for upgraders
14+
- The bundled stub lives at `vendor/node-domexception/` inside the published package — it's listed under `files` in `package.json`. If you'd added your own `overrides` field that touches `node-domexception` in a hand-rolled fork of little-coder, our entry will take precedence when you publish; in the unlikely case that breaks something for you, override it back in your fork's root `package.json`.
15+
- The `lastChangelogVersion` pre-stamp is one-directional: it writes the *currently bundled* pi version into settings on every launch. If you'd like to see pi's upstream changelog for a future bump, `/changelog` inside the TUI is the unconditional path — it doesn't consult `lastChangelogVersion`.
16+
- No CLI flag, models.json shape, skill-pack, extension API, or per-model profile changes. Little-coder's own startup banner, tagline, and keybind hints (the branding extension at `.pi/extensions/branding/`) are byte-for-byte unchanged from v1.4.2.
17+
18+
---
19+
520
## [v1.4.2] — 2026-05-19
621

722
Bundled-pi maintenance release. Closes [#22](https://github.com/itayinbarr/little-coder/issues/22), [#23](https://github.com/itayinbarr/little-coder/issues/23), [#25](https://github.com/itayinbarr/little-coder/issues/25). The pi runtime moves from `@mariozechner/pi-coding-agent@^0.68.1` to `@earendil-works/pi-coding-agent@^0.75.3` — same author, same project, new npm scope — which makes the deprecation warnings disappear, pulls in pi's recent Windows / undici / cmd-shim fixes, and (because pi 0.75 raised its floor) bumps the supported Node range to ≥ 22.19. No CLI flag, settings, extension API, or skill-pack changes.

bin/little-coder.mjs

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -131,15 +131,30 @@ if (process.env.PI_SKIP_VERSION_CHECK === undefined) {
131131
process.env.PI_SKIP_VERSION_CHECK = "1";
132132
}
133133

134-
// ---- 8. Force pi's global quietStartup so the loaded-resources block stays hidden ----
135-
// Pi's interactive mode dumps an [Extensions] / [Skills] / [Prompts] block on
136-
// every launch unless `quietStartup: true` is set in its global settings
137-
// (~/.pi/agent/settings.json). Our shipped .pi/settings.json doesn't reach pi
138-
// because pi reads from <cwd>/.pi/settings.json (project) or <agentDir>/settings.json
139-
// (global), neither of which is our npm-installed package dir. So the launcher
140-
// non-destructively merges quietStartup: true into the user's actual global
141-
// settings file. Existing keys are preserved. To see the full inventory, run
142-
// `little-coder --verbose` — pi's verbose flag overrides quietStartup.
134+
// ---- 8. Force pi's global quietStartup + pin lastChangelogVersion ----
135+
// Two non-destructive merges into ~/.pi/agent/settings.json (or the dir pointed
136+
// to by PI_CODING_AGENT_DIR):
137+
//
138+
// 1. quietStartup: true
139+
// Pi's interactive mode otherwise dumps an [Extensions] / [Skills] /
140+
// [Prompts] inventory on every launch. Pi reads global settings from
141+
// <agentDir>/settings.json — NOT from our npm-installed package dir —
142+
// so our shipped .pi/settings.json doesn't reach it. To see the
143+
// inventory anyway, run `little-coder --verbose`.
144+
//
145+
// 2. lastChangelogVersion: <currently installed pi version>
146+
// Pi reads its own bundled CHANGELOG.md on startup and renders a
147+
// "What's New" block for every entry strictly newer than this stored
148+
// version (interactive-mode.js:getChangelogForDisplay). That makes pi's
149+
// upstream changelog show up inside little-coder's TUI every time we
150+
// bump the bundled pi dep — which is jarring because little-coder is
151+
// the surface, not pi. We pre-stamp this field to the version we just
152+
// bundled BEFORE pi starts, so pi sees "user already saw this", and
153+
// the block never renders. Users who genuinely want to read pi's
154+
// upstream changelog can still do so with `/changelog` inside the TUI.
155+
//
156+
// Existing keys are preserved. We only write when the desired value differs
157+
// from what's already on disk, so this is a no-op on warm launches.
143158
try {
144159
const agentDirEnv = process.env.PI_CODING_AGENT_DIR;
145160
let agentDir;
@@ -164,8 +179,32 @@ try {
164179
globalSettings = {};
165180
}
166181
}
182+
183+
// Read the bundled pi version. We resolve via the same package.json we used
184+
// to find piEntry, so this stays consistent with whichever pi we actually
185+
// spawn — no second source of truth.
186+
let bundledPiVersion;
187+
try {
188+
const piPkgJson = JSON.parse(
189+
readFileSync(join(piPkgRoot, "package.json"), "utf-8"),
190+
);
191+
if (typeof piPkgJson?.version === "string") bundledPiVersion = piPkgJson.version;
192+
} catch {
193+
// If we can't read pi's version, fall back to leaving lastChangelogVersion
194+
// alone — pi will then show its own changelog on the next launch. Better
195+
// than writing garbage into the user's settings.
196+
}
197+
198+
let mutated = false;
167199
if (globalSettings.quietStartup !== true) {
168200
globalSettings.quietStartup = true;
201+
mutated = true;
202+
}
203+
if (bundledPiVersion && globalSettings.lastChangelogVersion !== bundledPiVersion) {
204+
globalSettings.lastChangelogVersion = bundledPiVersion;
205+
mutated = true;
206+
}
207+
if (mutated) {
169208
writeFileSync(globalSettingsPath, JSON.stringify(globalSettings, null, 2));
170209
}
171210
} catch {

0 commit comments

Comments
 (0)