Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .devcontainer/host/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Multi-arch Node 24.15.0 bookworm-slim index (amd64 on CI/dogfood, arm64 locally).
# Multi-arch Node 24.21.0 bookworm-slim index (amd64 on CI/dogfood, arm64 locally).
# Update the tag AND digest with .nvmrc; the build refuses version drift.
FROM node:24.15.0-bookworm-slim@sha256:4e6b70dd6cbfc88c8157ba19aa3d9f9cce6ba4703576d55459e45efcbc9c5f5d
FROM node:24.21.0-bookworm-slim@sha256:0e0ff40c39bc087845bfb27465a0df4ea419520094bc35842ff83dd8cbe6f9b6

# Development tools for git/worktrees and future Node-ABI native builds, plus
# standalone Chromium's runtime libraries (not Electron or a browser binary).
Expand Down
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
24.15.0
24.21.0
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Volli is a local-first macOS workspace for Tickets, Sessions, worktrees, and rev

## Prerequisites

Use macOS, Node.js `^24.15.0`, and pnpm `11.10.0`. A `.nvmrc` carries the pin (`nvm use`), and the range is enforced rather than advisory: `pnpm install` hard-fails outside it (`engineStrict` in `pnpm-workspace.yaml`), and the desktop dev/start scripts preflight the running Node before anything spawns — an unsupported Node builds native modules (better-sqlite3, node-pty) against the wrong ABI, which surfaces later as a dead database and a greyed-out sign-in. Install dependencies from the repository root:
Use macOS, Node.js `^24.16.0`, and pnpm `11.10.0`. A `.nvmrc` carries the pin (`nvm use`), and the range is enforced rather than advisory: `pnpm install` hard-fails outside it (`engineStrict` in `pnpm-workspace.yaml`), and the desktop dev/start scripts preflight the running Node before anything spawns — an unsupported Node builds native modules (better-sqlite3, node-pty) against the wrong ABI, which surfaces later as a dead database and a greyed-out sign-in. Install dependencies from the repository root:

```bash
pnpm install
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ Projects, tickets, and chat history stay on your machine. Model requests go to t

## Build from source

Requirements: macOS, Node.js `^24.15.0` (a `.nvmrc` is provided — `nvm use`), and pnpm `11.10.0`. The Node range is enforced: `pnpm install` and the dev scripts refuse to run under an unsupported Node, because native modules built against the wrong ABI leave the app unable to open its database (and sign-in disabled).
Requirements: macOS, Node.js `^24.16.0` (a `.nvmrc` is provided — `nvm use`), and pnpm `11.10.0`. The Node range is enforced: `pnpm install` and the dev scripts refuse to run under an unsupported Node, because native modules built against the wrong ABI leave the app unable to open its database (and sign-in disabled).

```bash
git clone https://github.com/hussainph/volli-code.git
Expand Down
2 changes: 1 addition & 1 deletion apps/docs/src/content/docs/reference/build-from-source.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ description: Install Volli's development dependencies, start the desktop develop
---

Use these commands to run the desktop app from the repository. You need macOS,
Git, Node `^24.15.0`, and pnpm `11.10.0`, as pinned in the root `package.json`.
Git, Node `^24.16.0`, and pnpm `11.10.0`, as pinned in the root `package.json`.

## Start the development app

Expand Down
14 changes: 8 additions & 6 deletions docs/development/host-linux.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ The VC-552 inventory comment records the module lists and test caveats.

The image in `.devcontainer/host/Dockerfile` is a **development toolchain**, not
a production hostd deployment. Its multi-architecture base is pinned by digest;
its Node version must equal `.nvmrc` (currently 24.15.0), and Corepack installs
its Node version must equal `.nvmrc` (currently 24.21.0), and Corepack installs
the root manifest's exact pnpm version. It includes git/SSH, Python/make/g++ for
native compilation, fonts and Chromium runtime libraries. It contains neither
Electron, Chromium itself, source code, installed workspace dependencies nor
Expand Down Expand Up @@ -103,11 +103,13 @@ for your own checkout if needed. No production secrets are baked or mounted.
Standalone Chromium provisioning belongs to the browser/worker ticket; these
libraries support it without installing another browser in every dev image.

The previous 24.13.0 `.nvmrc` pin could not install the current dependency graph:
jsdom 30.0.1 requires Node ^24.15.0 in the 24.x line, and `engineStrict` rejects
older versions. The host lane/image therefore use 24.15.0, and the root
`engines.node` floor is ^24.15.0 too. The host lane's exact-version install
checks the full graph rather than inferring compatibility from the caret range.
The host lane/image use Node 24.21.0, and the root `engines.node` floor is
^24.16.0. Node 24.16.0 added libuv 1.52.1, including the Linux PTY premature-EOF
fix (libuv#4992/#4997); the older 24.15.0 pin could lose a shell's final output
before node-pty delivered exit (VC-639). Electron 44 already includes this fix.
The host lane's exact-version install checks the full graph rather than inferring
compatibility from the caret range. The residual libuv#5165 case needs libuv
1.53.0; revisit once Node ships that version (nodejs/node#66282).

When bumping Node, update `.nvmrc`, the Dockerfile's tag and multi-arch digest
together; the image build catches drift. A root `packageManager` bump also
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
"yaml": "2.9.0"
},
"engines": {
"node": "^24.15.0"
"node": "^24.16.0"
},
"packageManager": "pnpm@11.10.0"
}
2 changes: 1 addition & 1 deletion packages/host-core/src/db-open-failure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ import { DatabaseFromNewerVersionError } from "./db/schema-compatibility";
* — main cannot read the root manifest at runtime (it is not packaged), so
* the test is what keeps this string from drifting into a lie.
*/
export const REQUIRED_NODE_RANGE = "^24.15.0";
export const REQUIRED_NODE_RANGE = "^24.16.0";

/**
* The signatures a wrong-ABI or missing native build leaves in its error.
Expand Down
35 changes: 35 additions & 0 deletions packages/host-core/src/pty/manager.pty.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,41 @@ describe("terminal supervisor on node-pty under plain Node (VC-560)", () => {
await until(() => ledger.exited.has(0), "the shell to exit after its window closed");
});

it("delivers a large final output and UTF-8 tail before exit", async () => {
const owner = makeClient("owner");
const sessionId = await start(owner);
const publish = owner.sink.publish.bind(owner.sink);
owner.sink.publish = (topic, payload) => {
publish(topic, payload);
if (topic === "terminal-data") {
const data = payload as TerminalDataEvent;
// Model a consuming client, after the pipeline has accounted its send.
queueMicrotask(() => manager.ack(owner.sink, sessionId, data.data.length));
}
};
manager.write(
owner.sink,
sessionId,
"printf '%0200000d' 0; printf '\\342\\230\\203-%s\\n' $((4+4)); exit 3\r",
);
await until(
() => owner.events.some((event) => event.topic === "terminal-exit"),
"the exit event",
);
const exitIndex = owner.events.findIndex((event) => event.topic === "terminal-exit");
const output = owner.events
.slice(0, exitIndex)
.filter((event) => event.topic === "terminal-data")
.map((event) => (event.payload as TerminalDataEvent).data)
.join("");
expect(output).toContain("0".repeat(200_000));
expect(output).toContain("☃-8");
expect(owner.events[exitIndex]?.payload).toEqual({ sessionId, exitCode: 3 });
expect(owner.events.slice(exitIndex + 1).some((event) => event.topic === "terminal-data")).toBe(
false,
);
});

it("delivers the shell's exit to the attached client after its final output", async () => {
const owner = makeClient("owner");
const sessionId = await start(owner);
Expand Down
2 changes: 1 addition & 1 deletion pnpm-workspace.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ packages:
- packages/*

# Hard-fail `pnpm install` when the running Node is outside the root
# `engines.node` pin (^24.15.0). Without this, an install under a stray older
# `engines.node` pin (^24.16.0). Without this, an install under a stray older
# Node (a machine's /usr/local/bin/node beside Homebrew's current, say)
# succeeds and quietly builds native modules against the wrong ABI — the
# desktop app then boots into a dead database with sign-in greyed out (VC-76).
Expand Down
Loading