tsx 4.23.13 pulls its own esbuild 0.28.1; allowScripts only listed
0.27.2 (tsup/vite), so npm warned about the blocked postinstall. Also
records the marked<16 / typescript-7 / wrap-ansi-10 constraints in the
memo so a future upgrade pass doesn't have to rediscover them.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
tsc --noEmit passes with zero errors and runs noticeably faster. The
project only uses the tsc CLI for typechecking (no programmatic
typescript API imports); tsup/esbuild drives the build and is
unaffected. The native port pulls per-platform @typescript/typescript-*
binaries as optional deps, like esbuild already does.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Dev-only. Config (globals/environment/include) and the vi.* API surface
used by the suite are unchanged; all 45 files / 366 tests pass. Node 24
satisfies vitest 5's engine range.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Lines wider than the terminal (wide markdown tables, long code lines) were
soft-wrapped by the terminal but counted as one row by Ink's <Static> redraw,
desyncing its cursor math and stranding duplicate copies of the status bar and
input box in scrollback on every re-render.
renderMarkdown now wraps its output to the caller's width via wrap-ansi, and
every <Static> item (plus the live streaming line) is held within a
width-bounded Box so nothing the terminal would soft-wrap reaches Ink.
Also sets cli-table3 header color to yellow (red-on-blue themes made table
headers unreadable).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Major changes:
- Replace alternate screen buffer + app-side mouse tracking/virtual scroll
with normal screen buffer + Ink <Static> for permanent scrollback.
Terminal's native scroll/selection/copy just works — no mouseInput.ts needed.
- Fix burn rate (🔥) to use model response time (modelTimeMs) instead of
session elapsed time, so it reflects actual generation throughput.
- Upgrade dependencies: openai 6→7, commander 13→15, execa 9→10, vitest 3→4,
node types 22→26, tsup target node20→node22.
- Update upgrade memo with current architecture, all completed upgrades,
and working tree status.
- Switch to the terminal's alternate screen buffer once a session starts,
clearing and homing the cursor so content starts flush at (0,0)
- Replace <Static> scrollback with a fixed-height viewport (overflowY hidden)
that top-aligns short conversations and auto-scrolls to the latest message
once content exceeds the screen, keeping the input pinned to the bottom
- Rewrite ChatInput's cursor handling: track cursor offset directly instead of
relying on ink-text-input, and report the real terminal cursor position via
useCursor + a Yoga-tree walk (absolutePosition.ts) so CJK IME composition
windows anchor at the actual caret instead of the terminal's fallback corner
- Print a "resume this conversation" hint after leaving the alt screen on exit
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Every exit path (Ctrl+C, /exit, SIGTERM/SIGHUP) now prints "Resume this
conversation later with: locode --resume <id>" once Ink has released the
terminal, so the session id isn't lost the moment the process ends.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Add todo_write tool with live checklist rendering in the UI
- Add permission modes (default/plan/auto-edit/auto-accept) cycled via Shift+Tab or /perm
- Load CLAUDE.md/AGENTS.md as project instructions into the system prompt
- Forward sub-agent tool calls/results to parent UI panel
- Auto-compact context mid-turn and keep model moving with a synthetic user turn
- Prune older image_url parts to cap vision token cost
- Idle-abort guard for stalled streaming backends
- Improve background bash jobs, kill whole process trees on timeout/exit
- Expand hooks: command/http hooks, blocking, JSON outputSchema
- MCP: JSON schema → Zod conversion, parallel connection, duplicate server detection
- Add tests for loop, confirmFn, projectInstructions, readFile, bash, todoWrite, contextWindowCache
A day of dogfooding locode on itself surfaced several real bugs, most centered on
the backend request lifecycle silently hanging with no error surfaced to the user:
- bash/hooks: execa's shell:true defaulted to cmd.exe on Windows, which lacks
Unix tools (cat, sed, grep, ...) and fails a whole pipe with an unhelpful exit
255 if any stage isn't found. Added src/utils/shell.ts to resolve real Git Bash
when available.
- agent/loop: the backend client's own `timeout` only bounds time-to-first-byte —
once a streaming response starts, a backend that goes silent mid-stream (or one
that sends periodic content-less "heartbeat" chunks to keep the connection alive
through a proxy) hung the request forever with zero output. Added an idle-abort
guard that pokes only on chunks carrying real progress (usage/text/tool-calls/
finish_reason), covering the main stream, the non-streaming malformed-JSON
retry, and compactSession.
- agent/loop: a single tool-call-heavy turn (e.g. reading dozens of files) had no
auto-compaction safety net at all — shouldAutoCompact was only ever checked
between turns, never during one, so a long turn could blow past the context
window with no mid-turn correction. Now checked every iteration; re-anchors
mutationCommitLength afterward since compaction replaces session.messages
wholesale.
- agent/loop: hitting the iteration cap surfaced as an opaque "Request failed"
even when every prior tool call (including file edits) had actually succeeded.
Added MaxIterationsError, rendered as a calm "paused, send another message to
continue" notice instead, and raised the default cap 25 -> 50.
- agent/loop: removed a dead-code branch (fallback-malformed retry handling
placed inside a native-mode-only code path, so session.mode === "fallback"
could never be true there) that TypeScript correctly flagged as a type error.
- ui/App: text_done fires with an empty fullText for pure tool-call turns (no
preceding prose); the assistant-message push had no guard, rendering a blank
line every time. Now skipped when fullText is empty.
- ui/App+index: alternate-screen-buffer mode and StatusBar-above-ChatInput
layout, fixing the reported "prompt starts below the dashboard, jumps up on
space" glitch. Added input history (up/down recall).
- utils/writeFileAtomic: random temp-file suffix instead of a fixed `<file>.tmp`,
so concurrent writes to the same directory can't collide.
Also fixes two hardcoded version strings (cli.ts --version, mcp/client.ts's
self-reported MCP identity) that were left stale at 0.2.0 through the 0.3.0
bump, and a stale maxIterations default noted in the README.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Bump to 0.3.0.
- bash_kill tool lets the model terminate a still-running backgrounded
job (Ctrl+B); all running jobs are killed on process exit so they
don't outlive locode as orphans.
- Finished background jobs are now evicted from the registry after a
10-minute TTL instead of accumulating for the life of the session.
- The chat completion request timeout is now configurable
(requestTimeoutMs / LOCODE_REQUEST_TIMEOUT_MS, default 180000) so
backends that queue requests behind a concurrency limit (e.g.
Ollama's OLLAMA_NUM_PARALLEL) under multi-session load aren't forced
into a hard failure at a fixed 3 minutes.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The 8-iteration-per-turn cap was hardcoded from before this session's feature work and
too tight for genuine multi-file tasks, causing "Max tool-call iterations reached" on
legitimately multi-step work. Raised the default to 25 and made it configurable via
`locode config set maxIterations <n>` / $LOCODE_MAX_ITERATIONS, mirroring the existing
contextWindow config pattern.
Also bumps the version to 0.2.0 (package.json, --version, and the MCP client's
self-reported identity) to reflect the substantial feature additions since 0.1.0.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Substantially expands locode's tool loop toward feature parity with Claude Code:
- web_search / web_fetch: DuckDuckGo-backed search and URL fetching (HTML stripped to text)
- git_status / git_commit: structured git tools with real diff/status/commit-list previews
before any mutating operation is confirmed
- agent tool: sub-agents run an isolated, headless tool loop sharing the parent's permissions;
bounded by an explicit depth guard (no nested sub-agents) and a 120s hard timeout, independent
of the toolset already excluding `agent` for sub-agent sessions
- MCP client support (stdio + streamable HTTP transports) via the official SDK: locode connects
to servers configured in `.mcp.json` or via `locode mcp add`, and exposes their tools alongside
the built-in ones, namespaced as `mcp__<server>__<tool>`
- Session persistence: conversations auto-save after every turn; `--continue`/`--resume`,
`locode sessions list/rm`, and an interactive resume picker
- Context compaction: tracks real token usage via `stream_options.include_usage` (falling back to
a char-based estimate), auto-detects the model's context window (Ollama/LM Studio native APIs,
cached, else a configurable default), and auto-summarizes the conversation at 85% usage or on
demand via /compact
- Status bar and welcome banner: added a context-usage indicator and fixed several dim-by-default
colors that were hard to read
Session/loop architecture changed to support all of this: Session now carries its own toolset
(tools + registry + OpenAI schemas) built from local + MCP tools, so runTurn no longer depends on
a fixed global tool list — the same mechanism that lets sub-agents inherit MCP tools while
excluding `agent` itself.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>