summaryrefslogtreecommitdiffhomepage
path: root/packages/tool-edit-file/src/extension.ts
AgeCommit message (Collapse)Author
4 daysstyle: switch from tabs to 2-space indentationAdam Malczewski
6 daysMerge 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).
6 daysfix(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.
6 daysfeat(ssh): wave 2 — route filesystem/shell tools behind ExecBackendAdam Malczewski
Wave 2 of transparent SSH support (4 parallel owner-agents on disjoint tool packages). The tools now resolve an ExecBackend per-call from ctx.computerId and call backend.spawn / backend.readFile / etc. instead of node:fs and node:child_process directly — so they are transport-agnostic (local now; remote over SSH later, transparent to the agent). Still LOCAL-ONLY this wave (computerId always undefined -> LocalExecBackend, behavior-identical). - tool-shell: factory takes resolveBackend; execute calls backend.spawn. spawn.ts DELETED (realSpawn was a verbatim duplicate of exec-backend's LocalExecBackend.spawn — logic moved to the sanctioned shared package). manifest dependsOn:[exec-backend]; host.getService at activation. - tool-read-file: readFile/stat/readdir -> backend.* (pure logic untouched; ENOENT .code branches kept). - tool-write-file: exists/stat/writeFile -> backend.* (pure logic untouched). - tool-edit-file: readFile/writeFile -> backend.* + forward-compatible REMOTE diagnostics skip (ctx.computerId set -> skip LSP, return empty — plan §6.1; local path byte-identical to today). LSP lookup stays lazy. - orchestrator: pre-wired @dispatch/exec-backend dep into the 4 tool package.jsons + bun install (build/config, my lane) so isolated verify resolved cleanly; agents added the ../exec-backend tsconfig ref. Verified: tsc -b EXIT 0, biome clean, 1599 vitest pass (was 1592). Refs: notes/ssh-support-plan.md (decisions §0.5/§13). No merge or push.
7 daysfix(tool-edit-file): lazy LSP service lookup — diagnostics now actually workAdam Malczewski
The previous fix (e03a96e) wrapped getService in try/catch to prevent the activation crash, but that wasn't enough: tool-edit-file activates at position 5 in CORE_EXTENSIONS while lsp activates at position 20. So getService ALWAYS threw at activation time, lspService was ALWAYS undefined, and the diagnostics hook was NEVER wired — edits succeeded but never showed LSP feedback. Fix: make the LSP service lookup LAZY — defer it to edit time (when the tool is actually called), not activation time. By then all extensions have activated. The diagnostics function tries getService on each edit call; if LSP isn't loaded, it returns a no-op (graceful degradation).
7 daysfix(tool-edit-file): wrap getService in try/catch to prevent activation crashAdam Malczewski
The per-edit diagnostics change (8f6114b) called host.getService(lspServiceHandle) during activate(). But getService THROWS when a service has no provider — so if the LSP extension activates AFTER tool-edit-file (or isn't loaded at all), the activate() function crashes and the edit_file tool is NEVER REGISTERED. This is why the edit_file tool was missing from the agent toolset. Fix: wrap getService in try/catch — if the LSP service isn't available yet, lspService becomes undefined and edits proceed without diagnostics (the graceful degradation the comment always promised but the code didn't deliver).
7 daysfeat(lsp+tool-edit-file): multi-server diagnostics + per-edit auto-appendAdam Malczewski
LSP extension: - Multi-server aggregation: query ALL connected servers matching the file's extension (not just the first), merge diagnostics tagged by source - Incremental sync: capture each server's textDocumentSync.change during initialize; compute prefix/suffix diff ranges for change:2 servers; full content for change:1 (generic, works for any LSP) - New diff.ts: pure computeChangeRange + offsetToPosition (O(n), tested) - Buffer sync: change(filePath, newText) sends didChange with post-edit in-memory content; openWithText for first open; tracks open doc text - languageId mapping: extended with .rb/.rbs/.c/.cpp/etc. (was 'unknown') - waitForDiagnostics: accepts text override + timeoutMs; returns { formatted, slow, timedOut }; polls for publishDiagnostics push - DiagnosticsStore: hasReceivedPush/clearReceived tracking; formatFiltered with minSeverity (1=Error, 2=Warning) for edit_file integration - LspService.getDiagnostics: service method for cross-extension use tool-edit-file: - After successful edit, calls LSP getDiagnostics with post-edit buffer - Only appends diagnostics with severity ≤ 2 (errors+warnings, no noise) - Appends slow warning (>10s): 'LSP is taking unusually long...' - 60s timeout; graceful degradation when no LSP available - Optional dep on @dispatch/lsp (getService pattern, not manifest depOn) 1468 vitest pass (was 1453, +15 new diff tests).
2026-06-10feat(tools): add run_shell, edit_file, write_file + read_file directory listingAdam Malczewski
Four standard-tier tool extensions (one tool per extension, zero ABI change): - tool-read-file: read_file now lists directory contents (sorted, /-suffixed subdirs) - tool-shell: run_shell (foreground, streamed, cancellable, cwd, timeout + output cap) - tool-edit-file: edit_file (oldString/newString/replaceAll; errors on absent/non-unique) - tool-write-file: write_file (explicit overwrite flag) Registered in host-bin CORE_EXTENSIONS. Live boot clean (shell capability accepted). 686 vitest + 89 bun = 775 tests; tsc -b EXIT 0; biome clean.