little-coder 1.4.2 → 1.4.3

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 CHANGED
@@ -2,6 +2,21 @@
2
2
 
3
3
  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.
4
4
 
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
+
5
20
  ## [v1.4.2] — 2026-05-19
6
21
 
7
22
  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.
@@ -131,15 +131,30 @@ if (process.env.PI_SKIP_VERSION_CHECK === undefined) {
131
131
  process.env.PI_SKIP_VERSION_CHECK = "1";
132
132
  }
133
133
 
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.
143
158
  try {
144
159
  const agentDirEnv = process.env.PI_CODING_AGENT_DIR;
145
160
  let agentDir;
@@ -164,8 +179,32 @@ try {
164
179
  globalSettings = {};
165
180
  }
166
181
  }
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;
167
199
  if (globalSettings.quietStartup !== true) {
168
200
  globalSettings.quietStartup = true;
201
+ mutated = true;
202
+ }
203
+ if (bundledPiVersion && globalSettings.lastChangelogVersion !== bundledPiVersion) {
204
+ globalSettings.lastChangelogVersion = bundledPiVersion;
205
+ mutated = true;
206
+ }
207
+ if (mutated) {
169
208
  writeFileSync(globalSettingsPath, JSON.stringify(globalSettings, null, 2));
170
209
  }
171
210
  } catch {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "little-coder",
3
- "version": "1.4.2",
3
+ "version": "1.4.3",
4
4
  "description": "A pi-based coding agent optimized for small local language models. Reproduces the whitepaper's scaffold-model-fit adaptations as pi extensions.",
5
5
  "homepage": "https://github.com/itayinbarr/little-coder",
6
6
  "repository": {
@@ -23,6 +23,7 @@
23
23
  ".pi/extensions/",
24
24
  ".pi/settings.json",
25
25
  "models.json",
26
+ "vendor/",
26
27
  "LICENSE",
27
28
  "NOTICE",
28
29
  "README.md",
@@ -39,6 +40,9 @@
39
40
  "@sinclair/typebox": "^0.34.49",
40
41
  "playwright": "^1.59.1"
41
42
  },
43
+ "overrides": {
44
+ "node-domexception": "file:./vendor/node-domexception"
45
+ },
42
46
  "devDependencies": {
43
47
  "typescript": "^5.6.0",
44
48
  "vitest": "^2.1.0"
@@ -0,0 +1,9 @@
1
+ // Drop-in replacement for the deprecated `node-domexception@1.0.0` shim.
2
+ // Bundled with little-coder; wired in via `package.json#overrides` so the
3
+ // transitive `fetch-blob -> node-domexception` chain (pulled in via
4
+ // @earendil-works/pi-ai -> @google/genai -> google-auth-library -> gaxios ->
5
+ // node-fetch -> fetch-blob) doesn't emit a deprecation warning during
6
+ // `npm install -g little-coder`. Native `globalThis.DOMException` has been
7
+ // available since Node 18, and little-coder requires Node >= 22.19, so this
8
+ // is always defined at import time.
9
+ module.exports = globalThis.DOMException;
@@ -0,0 +1,10 @@
1
+ {
2
+ "name": "node-domexception",
3
+ "version": "1.0.1",
4
+ "description": "Bundled with little-coder. Returns Node's native globalThis.DOMException (built-in since Node 18). Replaces the deprecated upstream node-domexception@1.0.0 via npm overrides so `npm install -g little-coder` no longer prints its deprecation warning. We pin engines.node to >= 18 because that's where native DOMException landed; the launcher's own preflight enforces >= 22.19, so this is satisfied transitively.",
5
+ "main": "index.js",
6
+ "engines": {
7
+ "node": ">=18.0.0"
8
+ },
9
+ "license": "MIT"
10
+ }