summaryrefslogtreecommitdiffhomepage
AgeCommit message (Collapse)Author
2026-06-28fix(workspace-star): clean up starred cache on workspace delete + warn when ↵Adam Malczewski
concurrency service absent Bug 1 (MEDIUM): In-memory starred cache leaks IDs for deleted workspaces. The starredWorkspaces Set in the concurrency manager never cleaned up when a workspace was deleted. FIX: the DELETE /workspaces/:id route now calls concurrencyService.notifyWorkspaceStarred(id, false) after deleting, so the deleted workspace ID is removed from the in-memory cache (preventing stale IDs and preventing a re-created workspace with the same slug from inheriting the old starred state). Bug 2 (MEDIUM): Stale in-memory priority when concurrency extension is absent. If provider-concurrency is not loaded, the star toggle persisted but the in-memory priority cache was never updated (the optional chaining ?. silently skipped the call). Already-queued agents kept their old priority until restart. FIX: the star/unstar routes now check if concurrencyService is defined and log a warning when it is absent, making the degraded behavior visible. The starred state still persists correctly — it just does not affect in-memory scheduling until the extension is loaded. Tests: +5 (star round-trip with concurrency notification, invalid slug 400, delete cleans up cache, absent-service warning log). All 1970 tests pass.
2026-06-28merge: bring dev crash fixes into feature/workspace-starAdam Malczewski
Merge dev to restore production-critical crash fixes that were committed after the branch was cut: SSH pool permanent error listener, uncaughtException/ unhandledRejection guards in host-bin, MemoryMax=24G circuit breaker, memory telemetry logging, LSP disable precaution, and crash investigation notes. The provider-wrapper.test.ts:102 test passes — it was already fixed by the acquire() signature change (adding workspaceId parameter) that realigned the test arguments. No additional test fix needed. Verification: typecheck 0 errors, 1965 tests pass, biome clean.
2026-06-28Merge branch 'dev' into feature/workspace-starAdam Malczewski
2026-06-28feat(workspace-star): starred workspace priority for concurrency limitingAdam Malczewski
2026-06-28docs(crash): definitive findings + Gemini review reportAdam Malczewski
2026-06-28fix(ssh,host-bin): permanent pooled-client error listener + ↵Adam Malczewski
uncaughtException/unhandledRejection guards Root cause of the live production crash (exit-1 'Timed out while waiting for handshake'): the pooled ssh2.Client had no permanent 'error' listener after connect, so a post-connect ssh2 error escaped as an uncaught EventEmitter 'error' with no process-level guard. See notes/crash-investigation-findings.md §1. - packages/ssh/src/pool.ts: attach a permanent 'error' listener to the pooled client in buildConnection that sets state=error, logs (alias, message, level), and does not throw; cleanup() no longer removes it. - packages/host-bin/src/main.ts: add process.on('uncaughtException') (graceful shutdown after logging) and process.on('unhandledRejection') (log + continue), both logging message/stack, memory snapshot, activeConversations count, and timestamp so the failure site is observable.
2026-06-28docs(memory-leak): comprehensive handoff for OpenCode investigationAdam Malczewski
2026-06-28fix: disable LSP + change memory telemetry interval to 15sAdam Malczewski
- Disable LSP extension (import + CORE_EXTENSIONS) due to crashes - Make transport-http tolerate LSP being absent (optional getService) - Remove lsp from transport-http dependsOn manifest - Change memory telemetry sample interval from 60s to 15s
2026-06-28feat(observability): periodic memory-usage logging to localize leak sourceAdam Malczewski
2026-06-28feat(bin): apply-memory-limits.sh — apply MemoryMax cgroup limits to live ↵Adam Malczewski
service Hands the user a one-command script to apply the systemd MemoryMax/MemoryHigh cgroup limits to the live dispatch.service without a full reinstall. Patches in the real user (same as bin/install), daemon-reloads, and restarts.
2026-06-28fix(systemd): add MemoryMax=24G circuit breaker to prevent segfault crashesAdam Malczewski
The server has a memory leak (~2.5 GB/h) that eventually triggers a Bun runtime segfault. These cgroup limits turn the uncontrolled crash into a controlled OOM-kill → clean restart via Restart=on-failure. MemoryHigh=20G (soft throttle) + MemoryMax=24G (hard cap). Machine has 33.24 GB total; 24G leaves OS headroom.
2026-06-28docs(server-crash): investigate LSP-related server crashAdam Malczewski
2026-06-27fix(lsp): bound pushDiagnostics cache — evict oldest entries for unopened ↵Adam Malczewski
background files
2026-06-27fix(lsp): fix crashes (optional chaining, fs.watch error) + memory leak ↵Adam Malczewski
(document lifecycle) + leaked init promises
2026-06-27Merge branch 'feature/vision-handoff' into devAdam Malczewski
# Conflicts: # packages/session-orchestrator/src/extension.ts # packages/session-orchestrator/src/orchestrator.ts
2026-06-27feat(vision): prefix consultation tab titles with 'IMAGE - 'Adam Malczewski
When a non-vision model (e.g. GLM) calls consult_vision, the new Kimi consultation tab now shows 'IMAGE - <question>' instead of the bare question-derived title, making image-consultation tabs visually distinguishable from normal conversation tabs. - Add formatConsultationTitle(question) pure helper (pure.ts): prefixes 'IMAGE - ' and truncates the question to 80 chars (matching the conversation store's TITLE_MAX) with an ellipsis. - Add setConversationTitle dep to VisionHandoffDeps, wired in the extension to the conversation store's setConversationTitle. - Call it in consultVision BEFORE the turn starts so the title is correct from the first moment (the store keeps a non-'Untitled' title on first message append). Best-effort: a title-write failure logs a warning but does not break the consultation. - Tests: 4 pure + 2 service (title set + optional-dep graceful).
2026-06-27feat(vision): store images in tmp dir instead of SQLite — compact URLs + ↵Adam Malczewski
purge on compaction/close
2026-06-27feat(provider-concurrency): persist concurrency limits across reboots via ↵Adam Malczewski
host storage
2026-06-27feat(concurrency): add "queued" ConversationStatus — emit when request ↵Adam Malczewski
blocks on acquire, re-emit "active" when slot granted
2026-06-27feat(vision): image compaction for vision-capable models + global vision ↵Adam Malczewski
settings
2026-06-27fix(vision): detect umans kimi + qwen models as vision-capable (not just kimi)Adam Malczewski
2026-06-27feat(vision-handoff): model-directed consult_vision tool replacing ↵Adam Malczewski
auto-transcription
2026-06-27fix(vision-handoff): omit temperature on vision transcription call (Kimi ↵Adam Malczewski
rejects temperature: 0) The vision handoff hardcoded temperature: 0 for the transcription sub-call, but the Moonshot/Kimi vision model only allows temperature: 1 (or omitted), causing an HTTP 400 "invalid temperature: only 1 is allowed for this model" that blocked the entire image analysis for non-vision models like GLM 5.2. Fix: omit temperature entirely so each vision provider uses its own default — the truly universal, provider-agnostic approach (different providers have different temperature constraints).
2026-06-27feat(provider-concurrency): add release cooldown (200ms) to prevent N+1 ↵Adam Malczewski
overshoot from provider accounting lag
2026-06-27Merge branch 'dev' into feature/vision-handoffAdam Malczewski
2026-06-27Merge branch 'dev' into feature/provider-concurrencyAdam Malczewski
2026-06-27fix(bin): rename dispatch-web → frontend in up/build scriptsAdam Malczewski
2026-06-27feat(vision-handoff): implement vision for capable models and universal ↵Adam Malczewski
vision handoff
2026-06-27feat(provider-concurrency): implement per-provider in-memory concurrency ↵Adam Malczewski
limits with oldest-agent-first scheduling
2026-06-27style: reformat heartbeat merge to 2-space indentationAdam Malczewski
2026-06-27Merge branch 'dev' into feature/heartbeatAdam Malczewski
# Conflicts: # packages/host-bin/package.json # packages/host-bin/src/main.ts # packages/session-orchestrator/src/orchestrator.ts # packages/system-prompt/src/service.test.ts # packages/system-prompt/src/service.ts # packages/system-prompt/src/types.ts # packages/transport-contract/package.json # packages/transport-http/package.json # packages/transport-http/src/app.test.ts # packages/transport-http/src/app.ts # packages/transport-http/src/extension.ts # packages/transport-http/tsconfig.json # tsconfig.json
2026-06-27Merge branch 'feature/indent-change' into devAdam Malczewski
2026-06-27chore: update path references for directory rename (dispatch-backend → ↵Adam Malczewski
backend, dispatch-web → frontend)
2026-06-27feat(heartbeat): GET /workspaces/:id/heartbeat/next-run endpoint (CR-HB-3)Adam Malczewski
2026-06-27feat(heartbeat): send heartbeat conversations to a dedicated heartbeat workspaceAdam Malczewski
2026-06-26style: switch from tabs to 2-space indentationAdam Malczewski
2026-06-26feat(heartbeat): resolve empty systemPrompt to global default (CR-HB-2)Adam Malczewski
2026-06-26fix(install): restart service instead of start (no-op when already running)Adam Malczewski
2026-06-26fix(install): run build as user, sudo only on privileged linesAdam Malczewski
The script previously required sudo for the entire script (id -u check), which meant bin/build ran as root and created root-owned dist/ files. On the next build, the normal user couldn't overwrite them (EACCES). Now the script runs without a sudo prefix: the build step runs as the normal user (dist/ files are user-owned), and sudo is used only on the specific lines that write to system directories (/usr/bin, /etc, /usr/share) or call systemctl.
2026-06-26fix(build): run tsc --build before bun build --compileAdam Malczewski
bin/build was compiling the binary directly from stale dist/*.js files without first recompiling the TypeScript packages. Since package.json main fields point to dist/index.js, source edits to .ts files were silently lost in the compiled binary. Now tsc --build runs first (composite project references rebuild all packages in dependency order), then bun build --compile bundles the fresh dist/ output.
2026-06-26feat(heartbeat): resolve [type:name] variables in heartbeat prompts (CR-HB-1)Adam Malczewski
2026-06-26fix(kernel): disable MAX_STEPS limit (0 = unlimited)Adam Malczewski
Agents were being cut off mid-task at 50 steps. The MAX_STEPS=50 hardcoded limit was silently terminating turns while the model was actively making tool calls, leaving conversations idle with a dangling tool-result as the last chunk. Setting MAX_STEPS to 0 disables the limit — the loop runs until the model stops making tool calls naturally or the abort signal fires. The max-steps code path is preserved for when MAX_STEPS > 0.
2026-06-26feat(heartbeat): workspace heartbeat loop with configurable AI monitoringAdam Malczewski
2026-06-25fix(ssh): POST /computers/:alias/test hangs after successful SSH connectAdam Malczewski
The test endpoint's runProbe() waited for the ssh2 stream's 'close' event, which some SSH servers never emit for short-lived exec channels (the command 'true' exits instantly). This caused the promise to hang forever — the HTTP response never returned, and the FE's Test spinner spun indefinitely. Three fixes: 1. runProbe now resolves on the 'exit' event (not 'close') — the command has finished and the exit code is available. 'close' is kept as a fallback. Stream data/stderr are drained to prevent buffer deadlocks. 2. runProbe has a 15s timeout safety net — if the exec callback or 'exit' event never fires (e.g. server requires a pty for exec), the probe resolves false instead of hanging forever. 3. The entire test() method is wrapped in a 30s Promise.race timeout — even if pool.acquire() or pool.drop() hangs, the endpoint ALWAYS responds with { ok, error? }. The probe is fully non-interactive (no blocking prompts). tsc EXIT 0, biome clean, 1756 tests pass.
2026-06-25feat(ssh): discover computers from ~/.ssh/known_hosts + remote system-promptAdam Malczewski
Two improvements to the SSH support feature: 1. KNOWN_HOSTS DISCOVERY (packages/ssh): Computers are now auto-discovered from ~/.ssh/known_hosts (every hostname you've ever connected to) in ADDITION to ~/.ssh/config (explicit Host aliases). Config entries take precedence (full params); known_hosts entries get defaulted params (User=defaultUser, IdentityFile=null→pool probes default keys, Port from [host]:port or 22, knownHost=true). Zero-config — no ~/.ssh/config file needed; hosts just appear. Reject list: dispatch.toml [ssh].reject = [...] (glob patterns like github.com, *.ts.net) filters noise from the catalog. Read from both the global ~/.config/dispatch/dispatch.toml and the project dispatch.toml. Parsed with Bun.TOML.parse (zero deps). Only filters discovery (catalog); specific lookups (getComputer/getStatus/test/connect) ignore the reject list (it's a visibility filter, not access control). New pure functions: parseKnownHosts(), isRejected(), globMatch(). +26 tests. tsc EXIT 0, biome clean, 1756 tests pass. 2. REMOTE SYSTEM-PROMPT AWARENESS (packages/system-prompt): When a conversation has a computerId set (remote turn), the system prompt now resolves system:os, system:hostname, git:branch/git:status, and file: reads against the REMOTE machine — not the local host. Previously the prompt always said 'Arch Linux (WSL)' + local hostname even when the agent was connected to a remote Artix Linux machine. The ResolverAdapters' hostname()/platform() are now async (so a remote adapter can run 'hostname'/'uname -s' over SSH). The system-prompt extension builds remote adapters from the ExecBackend (readFile→SFTP, spawn→SSH exec). Cache invalidation now checks computerId (switching computers rebuilds the prompt). The compaction path also threads computerId. @dispatch/system-prompt now depends on @dispatch/exec-backend.
2026-06-25docs(tasks): mark FE final sync check GREEN — all 3 handoffs + ↵Adam Malczewski
cross-cutting verified FE confirmed whole-tree green (typecheck 0/0, 795/795 tests, biome clean, build OK, git clean). All three handoffs GREEN with no integration gaps: - provider-retry: yellow alert-warning bubble renders w/ countdown. - SSH #1 wire types: defaultComputerId + Computer/ComputerEntry resolve. - SSH #2 computer API: full src/features/computer/ feature wired + typecheck-clean. Cross-cutting verified: provider-retry is WS-stream (TranscriptState.providerRetry → ChatView), computer is HTTP-only (AppStore.computerId → ComputerField sidebar) — disjoint state/channels/regions/mount-keys; no collision. SSH support + provider- retry integration is complete and validated end-to-end on both repos.
2026-06-25Merge branch 'dev' into feature/ssh-supportAdam Malczewski
Brings dev's retry-with-backoff (the transient `provider-retry` AgentEvent the web frontend consumes) + the LSP-dead-server per-edit-hang fix into the SSH feature branch, alongside the SSH waves 0-5c. All code files auto-merged cleanly (run-turn.ts, orchestrator.ts, runtime.ts, wire/index.ts, tool-edit-file/extension.ts, run-turn.test.ts — both computerId threading and retry-with-backoff coexist). Only tasks.md conflicted (status section — orchestrator-resolved; both feature sections kept). Verified post-merge: tsc -b EXIT 0, biome clean (391 files), 1730 vitest pass +6 sshd-integration skipped (was 1690; +40 from dev's retry/LSP tests). Wire dist rebuilt so the FE can re-sync the pinned @dispatch/wire dep and pick up BOTH provider-retry AND the SSH Computer/defaultComputerId types. No merge or push (into dev or otherwise).
2026-06-25Merge branch 'feature/lsp-bugfix' into devAdam Malczewski
2026-06-25fix(lsp): stop per-edit hangs on dead/slow servers (10s cap + skip + self-heal)Adam Malczewski
The LSP diagnostics path hung up to 60s per edit whenever a configured Ruby language server was dead or slow (the reported Steep langserver case): a killed/crashed server was never detected (stayed "connected" forever), servers were queried sequentially with a 60s budget each, and a corrupted-but-alive server (Steep's ~3h phantom-SyntaxError drift) had no recovery. Four fixes, all in packages/lsp/ (the tool-edit-file call site lowered to 10s): 1. Dead-process detection: SpawnedProcess.onExit (Bun proc.exited) + stdout-end defence flip the client to error, dispose the rpc, kill the proc. The manager re-spawns a fresh server after the 30s backoff. Dead servers are now skipped (0s) instead of polled for 60s. 2. Concurrent fan-out + 10s hard cap: new aggregateDiagnostics queries all matching servers at once, each capped at 10s. A non-responder is skipped with "LSP took too long (>10s), skipped — raise this to the user" instead of blocking the fast server's results. Replaces the vague "unusually long" warning (now structurally impossible: slow is always false). 3. Corruption self-heal: a detector flags a server re-emitting identical non-empty diagnostics despite the file changing; after 5 repeats the client is marked broken and re-spawned. Clean files never trip it. (Acknowledged false-positive risk on persistent unfixed errors; CLI type-check gate stays authoritative.) 4. sendRequest timeout: hover/definition/references cap at 10s so they can't hang the turn against a dead server; the initialize handshake keeps its 45s race. Verification: typecheck clean; 1573 tests pass (96 files), +15 new LSP tests (86 in packages/lsp); biome clean. No kernel/contract changes; onExit is internal to packages/lsp.
2026-06-25chore: remove stale .skills/ORCHESTRATOR.md duplicateAdam Malczewski
This was the OLD orchestrator manual (references the retired `opencode run` CLI + `opencode-go/mimo-v2.5-pro`, MVP-era content). The current manual lives at root ORCHESTRATOR.md (references the `dispatch` CLI + umans/umans-glm-5.2). Unrelated housekeeping; split from the retry feature commit.