summaryrefslogtreecommitdiff
AgeCommit message (Collapse)Author
2026-07-08Bump version to 0.42.10.42.1Paul Buetow
2026-07-08fixPaul Buetow
2026-07-03remove thisPaul Buetow
2026-07-02Remove hexai-tmux-edit popup editor featurev0.42.0Paul Buetow
The tmux popup editor and its per-agent detection (Cursor/Amp/Aider) added maintenance surface without enough use to justify it; Codex and Claude Code already support external-editor mode natively via Ctrl+G. Drops internal/tmuxedit, cmd/hexai-tmux-edit, the [tmux_edit] config schema, the Mage build target, and all related docs/README mentions. Bump version to 0.42.0. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-06-19Bump version to 0.41.2v0.41.2Paul Buetow
2026-06-19Fix MCP protocol test cleanup for 7k0Paul Buetow
2026-06-19fix mcp protocol test cleanup (7k0)Paul Buetow
2026-06-19Fix MCP invalid JSON test race (4k0)Paul Buetow
2026-06-19Harden action handler registration for nk0Paul Buetow
2026-06-19Refactor hexaiaction handlers for nk0Paul Buetow
2026-06-19mk0 remove MCP server from default mage buildsPaul Buetow
2026-06-19ok0 document LSP and LLM exportsPaul Buetow
2026-06-19ik0 remove mutable clock holdersPaul Buetow
2026-06-18ik0 replace remaining test seams with DIPaul Buetow
2026-06-18ik0 replace test seams with dependency injectionPaul Buetow
2026-06-11Fix error wrapping: use %w for primary child error in tmux actionPaul Buetow
In runInTmuxChild, the primary failure is the child runFn error; the echo-through failure is secondary context. Wrap the primary error with %w (keeping copyErr as %v, since fmt.Errorf allows only one %w) so errors.Is/As work across the chain. Audited all other fmt.Errorf %v/%s sites in internal/ and cmd/: they format strings, ints, status codes, or an []error aggregate (syncer), none of which is a single primary error to unwrap, so they stay as-is. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11appconfig: split FeatureConfig into cohesive per-subsystem structsPaul Buetow
The FeatureConfig section was a grab-bag mixing five unrelated non-LLM subsystems (ignore filtering, stats, tmux popup editor, tmux action menu, MCP server). Decompose it into named per-subsystem structs (IgnoreConfig, StatsConfig, TmuxEditConfig, TmuxActionConfig, MCPConfig) embedded into FeatureConfig so the subsystem boundaries are explicit. Embedding keeps Go field promotion intact, so existing flat read access (e.g. cfg.MCPPromptsDir) and the JSON/TOML on-disk shape are unchanged; only composite literals that set these leaf fields directly were updated to the nested form. Add fine-grained, defensive-copy section accessors on App (IgnoreSection, StatsSection, TmuxEditSection, TmuxActionSection, MCPSection) so consumers can depend on a single subsystem's config instead of the whole App God-struct. Decouple slashcommands.NewSyncer to accept appconfig.MCPConfig rather than appconfig.App. All tests pass with -race; appconfig coverage 91.5%, total 86.2%. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11Fix unsafe time.Timer.Reset on active timers in runlock and filelockPaul Buetow
Both filelock.AcquireExclusive and askcli.waitOrAcquireAskLockFD created a single time.Timer and called Reset() on it each retry iteration before it had necessarily fired. Per the Go timer API, Reset()-ing a timer that may still be pending is unsafe: a stale value can already be queued on the channel, causing a spurious early wake-up. Replace the reused-timer + Reset() pattern with a fresh time.After(...) per loop iteration, which guarantees a clean full retry interval (or context cancellation) every time and removes the reuse-while-active hazard. Dropped the now-unused *time.Timer parameter from waitOrAcquireAskLockFD and introduced named retry-interval constants. Add a context-cancel-while-blocked test for the runlock retry loop. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11Fix LSP panic: bounds-check stale line index in async chat applyPaul Buetow
When handleChatPrompt detects an in-editor chat prompt it captures the line index, then spawns a goroutine (requestChatResponse) that later calls applyChatEdits/buildChatHistory. If a concurrent didChange shrinks the document in the meantime, the captured lineIdx can exceed len(d.lines), causing an index-out-of-range panic in the chat goroutine. - applyChatEdits: skip the stale edit (and log) when lineIdx is < 0 or >= len(d.lines), rather than indexing d.lines[lineIdx] and panicking (or corrupting the already-changed document at the wrong position). - buildChatHistory: clamp the starting index to len(d.lines)-1 so the upward walk over d.lines[i] cannot read past the end. Adds regression test TestChatEdits_StaleLineIndexAfterShrink covering the shrink-then-apply race for both functions, including the one-past-the-end boundary and a negative index. Confirmed the test panics without the fix and passes with it; full `mage test` (-race) green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11Thread context.Context through blocking I/O entry pointsPaul Buetow
Accept ctx as the first parameter on the blocking I/O entry points and propagate it to downstream blocking calls so the work is cancellable from the process entry point: - appconfig.Load / LoadWithOptions: honor ctx before the blocking file reads, returning defaults on a cancelled context. - LSP: lsp.Server.Run(ctx) ties the serve loop to the caller context via a new watchParentContext bridge (cancels the server context, aborting in-flight LLM work). Threaded through hexailsp.Run/RunWithConfig/ RunWithFactory and runtimeconfig.Store.Reload. - MCP: mcp.Server.Run(ctx) stops accepting requests once ctx is cancelled; threaded through hexaimcp.Run/RunWithFactory/RunBackfill. - editor: RunEditor/OpenTempAndEdit/OpenFile take ctx and use exec.CommandContext so a cancelled context kills the editor subprocess; threaded through hexaicli, hexaiaction and askcli call sites. Top-level callers (cmd/hexai-lsp-server, cmd/hexai-mcp-server) now build a signal-cancelled context (SIGINT/SIGTERM) so shutdown tears the run down cleanly. Updated comments to explain the cancellation flow and added cancellation tests for the LSP/MCP loops, editor, and config load. All tests pass with -race; cross-package coverage 86.2%. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11llm: add compile-time interface checks for all providersPaul Buetow
Add the missing var _ Client / var _ Streamer compile-time satisfaction check to anthropicClient, and clarify the existing assertion comments for openAIClient, openRouterClient, ollamaClient (all Client+Streamer) and youSearchClient (Client only; the You.com research API is non-streaming). All providers use value receivers, so assertions use zero-value structs. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11Consolidate LLM timeout/retry/breaker values into policy packagePaul Buetow
The per-request HTTP timeouts (30s chat, 120s research), retry policy (attempts, backoff, jitter), and circuit-breaker tuning (threshold, cooldown) were previously scattered as bare literals across each provider constructor and resilience.go/circuitbreaker.go, making the operational policy hard to discover and prone to drift. Introduce internal/llm/policy with documented named constants as the single source of truth, and reference them from all provider constructors, the default retry policy, and the shared circuit breaker. Update comments to explain the policy and reasoning. Add tests validating the values and their internal consistency. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11Extract shared chatrun package to eliminate chat-runner DRY violationsPaul Buetow
The CLI, LSP server and tmux code-action tool each carried near-identical chat-running logic: invoking the LLM (streaming-aware), collecting the response, and accounting sent/received bytes into the stats package. Introduce internal/chatrun with: - Invoke: streaming-aware LLM call that collects the full response and optionally mirrors chunks to a writer (nil writer = collect only). - SentBytes / Account: shared byte counting and stats.Update. Wire all three surfaces to it: - hexaicli: runChatRequest delegates to chatrun.Invoke; summarizeChatRun uses chatrun.Account. Removed the duplicated streaming/simple helpers. - hexaiaction: runOnce uses chatrun.Invoke + chatrun.Account, keeping the tmux status update local. - lsp: chatWithStats and the completion path use chatrun.SentBytes/Invoke; extracted unavailableClientError to keep chatWithStats small. chatrun has 100% test coverage; full suite passes with -race. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11llm: return concrete client types from provider constructorsPaul Buetow
Follow the Go idiom "return concrete types, accept interfaces": the provider constructors newOpenAI, newAnthropic, newOpenRouter, newOllama and their *WithTimeout variants now return their concrete *Client value types instead of the Client interface. The provider factories registered in the registry still return Client, so NewFromConfig and the registry keep working unchanged. Updated comments to explain the reasoning, dropped the now-redundant type assertions in tests, and switched the anthropic Streamer-capability tests to assert via an explicit Client interface value. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11Magefile: convert Default to a function and add binaryName constantPaul Buetow
Convert the Default target from a `Default = Build` variable to a documented `Default()` function (Mage supports both forms), and introduce a binaryName constant for the primary hexai binary so the output name is defined once instead of being repeated across the Build, Dev, and Install targets. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11Refactor lsp.Server God Object: extract chat and completion subsystemsPaul Buetow
The Server type accumulated two large, tangled feature subsystems (in-editor chat and code completion) alongside its core LSP dispatch role. Pull them into cohesive types that own their state and logic while delegating shared infrastructure back to Server via a back-reference. - Add completionService (completion_service.go): owns the completion cache/throttle state (completionState) and all completion request-handling logic (handleCompletion, plan/jobs/execute, provider-native path, post-processing, message building, prefix heuristics). Methods moved off Server in handlers_completion.go to completionService. - Add chatService (chat_service.go + chat_handlers.go): owns the input-activity clock (lastInput, with its own mutex instead of Server.mu) and all in-editor chat logic (detection, transcript history, message building, edit application, inline prompts) plus the slash-command handlers (chat_commands.go). - Server now holds chat/completion fields, wires them in NewServer, and delegates (dispatch table, didChange, debounce gate) to them. Thin Server shims preserve the existing completion-state API for callers/tests. Pure refactor: no behavior or LSP protocol changes. Tests adjusted only to reach the relocated methods/state via the services. All tests pass with -race; coverage 86.1%. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11Add retry and circuit-breaker resilience around LLM HTTP calls (ak0)Paul Buetow
Wrap the shared provider HTTP choke point (doJSONRequest in llm/util.go, used by openai, openrouter, anthropic and ollama) with two resilience patterns implemented with the standard library only: - Retry with exponential backoff + jitter (resilience.go): 3 attempts by default, retrying transient network errors and retryable HTTP statuses (429 and 5xx). Client errors (4xx) and successes are returned immediately and never retried. Backoff waits are context-aware so cancellation and deadlines are respected; retried response bodies are drained and closed for connection reuse. - Circuit breaker (circuitbreaker.go, own file as it has >3 methods): classic closed/open/half-open breaker that trips after 5 consecutive transient failures and stays open for a 30s cooldown, then allows a single trial probe. Only transient failures count; 4xx never trips it. A nil breaker is a valid no-op. doJSONRequest now delegates to doJSONRequestResilient; the single-attempt primitive is preserved as doJSONRequestOnce. Adds httptest-based unit tests for retry/backoff/breaker logic with no real network calls; new code coverage is >80%. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10Replace panics with returned errors in llm.RegisterProviderPaul Buetow
RegisterProvider now returns an error for an empty name, a nil factory, or a duplicate registration instead of panicking, making registration composable and testable without recover(). RegisterAllProviders caches the one-time registration error (sync.Once cannot return a value) and returns it to every caller. Updated all call sites: hexailsp, hexaicli and hexaiaction propagate the error with context; test TestMains fail fast via panic. Added unit tests covering empty name, nil factory, duplicate, success and idempotent re-registration. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10Fix mixed receivers on commandTable typePaul Buetow
The commandTable type had mixed receiver kinds: get, rootCompletionEntries and singleSelectorNames used value receivers while add used a pointer receiver because it mutates the table. Standardize on pointer receivers for all methods (the mutating add forces this choice) and return *commandTable from newCommandTable. Call sites are unaffected since commandRegistry is an addressable package-level variable. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10lsp: rename 'close' return to 'closeStr' in inlineMarkers to avoid shadowing ↵Paul Buetow
builtin The named return value 'close' in Server.inlineMarkers() shadowed the Go builtin 'close'. Renamed it to 'closeStr' (matching the 'openStr' naming used by callers) and added a comment explaining the reasoning. Callers use positional returns, so no call sites changed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10Enable -race flag in mage Test targetPaul Buetow
The Test target now runs `go test -race -v ./...` so the race detector catches data races during the normal test workflow. The full suite (1017 tests) passes cleanly under the race detector. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09v0.41.1v0.41.1Paul Buetow
2026-06-06Add 'ask edit ID' to edit task description in $EDITOR; bump to 0.41.0v0.41.0Paul Buetow
Amp-Thread-ID: https://ampcode.com/threads/T-019e9b82-6ba0-77a4-b4a0-5c2cbf9bf39f Co-authored-by: Amp <amp@ampcode.com>
2026-06-05Add 'ask edit' subcommand and collapse multi-line task descriptionsv0.40.0Paul Buetow
- ask edit opens $EDITOR and creates a task from the (multi-line) content, reusing the shared internal/editor package - collapse newlines in list output and fish completion so multi-line descriptions render on one line and don't break completion Bump version to 0.40.0 Amp-Thread-ID: https://ampcode.com/threads/T-019e96a1-9c8e-73d6-95b4-b55cb12cc762 Co-authored-by: Amp <amp@ampcode.com>
2026-05-31Bump version to 0.39.5v0.39.5Paul Buetow
2026-05-31ask: fix watch output to match regular commands by preserving terminal width ↵Paul Buetow
detection
2026-05-31ask: add completed sub-command to list completed tasksPaul Buetow
2026-05-29chore: bump version to 0.39.4v0.39.4Paul Buetow
2026-05-29fix(askcli): use real TAB split in fish dependency completionPaul Buetow
2026-05-29askcli: prevent stale-lock inode split during contentionPaul Buetow
2026-05-29askcli: keep ask add successful when alias assignment failsPaul Buetow
2026-05-27Fix mage coverage refreshv0.39.30.39.3Paul Buetow
2026-05-26chore: bump version to 0.39.2v0.39.2Paul Buetow
2026-05-26chore: bump go.mod to Go 1.26.0Paul Buetow
2026-05-26feat(askcli): add projects subcommandPaul Buetow
2026-05-26fix(lsp): stop timer leak in deferShowDocumentPaul Buetow
Replace time.After with time.NewTimer + defer timer.Stop() to prevent a leaked goroutine when the context is cancelled before the timer fires.
2026-05-26build: bump minimum Go version to 1.24.0Paul Buetow
Updates go.mod from 1.21.0 to 1.24.0 because tests use testing.T.Chdir, which requires Go 1.24. Also fixes pre-existing fmt.Errorf non-constant format strings in task_selector.go that the printf vet analyzer flags when running go test with the newer minimum version.
2026-05-26feat(askcli): add watch subcommandPaul Buetow
Implements `ask watch [subcommand...]` which re-runs a read-only subcommand every 2 seconds and redraws output when it changes, similar to gnu-watch. Safety features: - Restricted to read-only subcommands (list, all, ready, info, urgency, help, dep list) - Recursive watch is blocked - Captures stderr so error messages are visible in the watched display Also adds readOnly field to commandEntry registry for maintainability.
2026-05-20Bump version to 0.39.1v0.39.1Paul Buetow
Amp-Thread-ID: https://ampcode.com/threads/T-019e45ff-4976-750c-b2e6-121d0e5991ef Co-authored-by: Amp <amp@ampcode.com>
2026-05-20test(yousearch): add unit tests; allow base URL override for testsPaul Buetow
Amp-Thread-ID: https://ampcode.com/threads/T-019e45ff-4976-750c-b2e6-121d0e5991ef Co-authored-by: Amp <amp@ampcode.com>