Skip to content
Open
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
3 changes: 2 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@ one verified pair, both pinned in `vendor/lody/UPSTREAM.md`: bump them together.
vendor edit there first, or do not make it.
- The daemon patches in `packages/box/patches/` (`lody-local-platform.mjs`,
cloud→local platform; `lody-acp-auth-queue.mjs`, the ACP-auth queue chain;
`lody-code-collab-worktree-root.mjs`, Code Collab's worktree root) are
`lody-code-collab-worktree-root.mjs`, Code Collab's worktree root;
`lody-agent-message-split.mjs`, assistant text grouped by `messageId`) are
guarded against the published bundle (sha256; version + anchor count) and must
be re-verified on every daemon bump.
- Upstream merges follow the runbook `docs/LODY-MERGE.md`. Where Lody upstream
Expand Down
41 changes: 38 additions & 3 deletions docs/LODY-MERGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ npm view lody@<candidate> dist.shasum
Then, in ONE change:

1. bump `lody@<version>` in `packages/box/Dockerfile`;
2. re-audit BOTH patches in `packages/box/patches/` — see §5, neither is
2. re-audit ALL FOUR patches in `packages/box/patches/` — see §5, none is
optional and each is guarded twice;
3. record both numbers in `vendor/lody/UPSTREAM.md`.

Expand Down Expand Up @@ -236,10 +236,10 @@ prominently in the pull request body.

## 5. Re-audit the npm-artifact patches

Three scripts in `packages/box/patches/` are applied to the **published npm
Four scripts in `packages/box/patches/` are applied to the **published npm
artifact**, in the Dockerfile's order. The order is load-bearing:
`lody-local-platform.mjs` guards on a sha256 of the file AS PUBLISHED, so nothing
may rewrite it first. All three are idempotent — re-running any of them on an
may rewrite it first. All four are idempotent — re-running any of them on an
already-patched bundle reports it and exits 0, which is what lets the daemon test
harness copy a real box's bundle and re-apply them to the copy.

Expand Down Expand Up @@ -325,6 +325,41 @@ npx vitest run test/lody-worktree-session.test.ts # in packages/webapp, on a b
DELETE this patch rather than updating it.** Their own
`lib/terminal-workdir-resolver.ts:97` already does, so the two may converge.

### 5d. The assistant-message split patch

`packages/box/patches/lody-agent-message-split.mjs` groups streamed assistant
text by the `messageId` the ACP adapter already stamps on every chunk. Without
it, ONE Anthropic message is stored as two text blocks whenever anything — a
tool call, a subagent task — lands between two of its deltas, so the reader gets
a sentence cut in half around a tool card:

```
[21] text "Three"
[22] tool_call toolu_0166kpDv… (grep …)
[23] text " characterization agents are running in parallel, plus …"
```

`claude-acp.js` computes the id (`messageIdForGrouping`, the API message `id`)
and `applyMessageId` puts it on the update; the schema keeps it
(`zContentChunk.messageId`); the history applier drops it and merges only into
`items[items.length - 1]`. The patch carries the id onto the stored item and
makes both `appendOrMergeAdjacentText` copies scan back past trailing non-text
items to the block with the same id. With no id it is byte-for-byte today's
behaviour, so every other adapter is untouched.

Six hunks, guarded by the installed package version plus each anchor at exactly
one occurrence. Re-auditing means:

```sh
grep -n 'appendOrMergeAdjacentText' /tmp/package/dist/index.js # expect 6 lines, 2 definitions
grep -n 'messageId' /tmp/package/dist/index.js | head # the applier must still ignore it
node packages/box/patches/lody-agent-message-split.mjs /tmp/package/dist/index.js
```

**If the new version merges by message id itself, DELETE this patch rather than
updating it.** The daemon already emits the id explicitly for grouping, so this
is the fix upstream is one step away from.

## 6. Dependencies and the patch-file audit

Upstream resolves renderer dependencies through pnpm's catalog; BlitzOS resolves
Expand Down
5 changes: 4 additions & 1 deletion packages/box/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,16 @@ RUN npm install --global --omit=dev \
COPY packages/box/patches/lody-local-platform.mjs /tmp/lody-local-platform.mjs
COPY packages/box/patches/lody-acp-auth-queue.mjs /tmp/lody-acp-auth-queue.mjs
COPY packages/box/patches/lody-code-collab-worktree-root.mjs /tmp/lody-code-collab-worktree-root.mjs
COPY packages/box/patches/lody-agent-message-split.mjs /tmp/lody-agent-message-split.mjs
# Order matters only for the first: its guard is a sha256 of the bundle AS
# PUBLISHED, so nothing may rewrite the file before it runs. The others guard on
# the package version and their own anchor instead, for that reason.
RUN node /tmp/lody-local-platform.mjs /opt/blitz/npm/lib/node_modules/lody/dist/index.js \
&& node /tmp/lody-acp-auth-queue.mjs /opt/blitz/npm/lib/node_modules/lody/dist/index.js \
&& node /tmp/lody-code-collab-worktree-root.mjs /opt/blitz/npm/lib/node_modules/lody/dist/index.js \
&& rm /tmp/lody-local-platform.mjs /tmp/lody-acp-auth-queue.mjs /tmp/lody-code-collab-worktree-root.mjs
&& node /tmp/lody-agent-message-split.mjs /opt/blitz/npm/lib/node_modules/lody/dist/index.js \
&& rm /tmp/lody-local-platform.mjs /tmp/lody-acp-auth-queue.mjs /tmp/lody-code-collab-worktree-root.mjs \
/tmp/lody-agent-message-split.mjs

FROM node:22.20.0-bookworm-slim@sha256:b21fe589dfbe5cc39365d0544b9be3f1f33f55f3c86c87a76ff65a02f8f5848e AS runtime-base

Expand Down
Loading
Loading