f8fc5db929b44e9dd8d240d1a7f9fee5ef767e42
- New services/truncate.ts. Tmpfs storage at /tmp/boocode-truncations/ (BOOCODE_TRUNCATION_DIR env var overrides for tests). 12-char base32 opaque ids (~60 bits entropy, "tr_<id>"). Three exports: storeTruncation, readTruncation, truncateIfNeeded (wrap-or-passthrough helper). cleanupTruncations does TTL-pass (7 days) + orphan-reap (parts query on payload->'output'->>'outputPath') in one shot. - Wired four tools through truncateIfNeeded: view_file (raw full file), list_dir (full filtered+secret-filtered entries serialized one-per-line), web_fetch (textRaw pre-slice), codecontext_client (body.result pre-slice). Each returns the existing sliced view plus an optional outputPath field when truncation fires. - New view_truncated_output ToolDef. Resolves opaque id → on-disk content internally; model never sees the truncation dir. Same start_line / end_line slicing semantics as view_file. Registered in ALL_TOOLS (alpha sort places it after view_file automatically) and READ_ONLY_TOOL_NAMES. - cleanupTruncations piggybacks on the v1.13.3 stuck-row sweeper's 60s setInterval. No-op when truncation dir is empty. Not wired (TODO follow-up): grep and find_files. file_ops returns post-cap results to the tool execute path, so the "full content" isn't recoverable without a refactor of fileOps.grep / fileOps.findFiles to expose the uncapped result. web_search is silent-slice (no truncated flag); outside scope. Five sites of seven covered; the remaining two are the only ones needing a file_ops change. Tests: 7 new in truncate.test.ts (roundtrip, unknown id, malformed id, truncateIfNeeded false/true/over-cap/storage-failure paths). 186 total (was 179). cleanupTruncations file-system half implicitly via TTL pass; orphan-reap branch covered by the live container smoke. Smoke verified end-to-end against the live container: - view_file with start_line=1, end_line=3 on CLAUDE.md → tool_result part carried outputPath "tr_cdpn1o04k6ma" + truncated=true. - /tmp/boocode-truncations/tr_cdpn1o04k6ma exists, 15876 bytes, mode 0o600, parent dir mode 0o700. - Follow-up view_truncated_output(id, start_line=50, end_line=55) returned the actual lines 50-55 of CLAUDE.md (the 808notes/BooCode bullets). - ALL_TOOLS count=20 (was 19); alpha sort places view_truncated_output between view_file and watch_changes. Closes a v1.12 catalog row that was scoped but deferred. The v1.13 parts table made outputPath ride on the existing tool_result payload with no schema change beyond the storage helper itself. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
boocode
Self-hosted single-user developer chat app. v1: chat only.
Stack
- Node 20, Fastify, postgres (porsager/postgres), ws, zod
- React 18, Vite, TypeScript, Tailwind v4, shadcn/ui
- Postgres 16
- pnpm workspaces
Layout
apps/server— Fastify API + WebSocket + inference loop + file-read toolsapps/web— React frontend; served by Fastify in production, Vite in dev
Local dev
Requires Node 20, pnpm, Docker (for Postgres), and ripgrep.
# install
pnpm install
# bring up postgres only
cp .env.example .env
# edit POSTGRES_PASSWORD if you like; default DATABASE_URL points at the container
docker compose up -d boocode_db
# run server (port 3000) and web (port 5173) in two shells
DATABASE_URL=postgres://boocode:devpass@127.0.0.1:5500/boocode \
LLAMA_SWAP_URL=http://100.101.41.16:8401 \
pnpm dev:server
pnpm dev:web
The Vite dev server proxies /api and /api/ws/* to the Fastify backend with a
synthetic Remote-User: sam header so the Authelia auth layer can be skipped
during development.
Production
cd /opt/boocode
docker compose up --build -d
Binds to 100.114.205.53:9500 (Tailscale). Authelia is expected to gate the
upstream and inject Remote-User. Postgres binds loopback only.
What v1 has
Project sidebar, sessions per project, chat with streaming responses over
WebSocket, four file-read tools scoped to the project root (view_file,
list_dir, grep, find_files), and a model picker driven by llama-swap's
/v1/models.
What v1 does not have lives in v2 (terminal pane) and v3 (Coder pane).
Languages
TypeScript
94.3%
CSS
1.9%
JavaScript
1.2%
Shell
0.8%
Go
0.6%
Other
1.2%