New pkg/chat/tool_handler.go: ToolCallHandler interface + ToolCall
type + BuildToolManifest helper + Core-action dispatch adapter +
inline {"tool_call": ...} JSON parser. Service.Send now detects
inline tool calls during stream, invokes OnToolCall, persists a
'tool' result message, and continues the completion loop. Manifest
is prepended to system prompt when a handler is registered
(no-op when unregistered — back-compat).
Good/Bad/Ugly coverage in tool_handler_test.go: valid tool_call
dispatches through mock executor and lands in history; unknown
tool name surfaces error into conversation (not a silent drop);
malformed inline JSON does NOT dispatch — stream continues, no
executor call, assistant message preserves the raw tool_call
fragment for audit.
go vet + go test ./pkg/chat/... clean (codex 0.124.0, gpt-5.5,
LEK AGENTS.md loaded).
Closes tasks.lthn.sh/view.php?id=22
Co-authored-by: Codex <noreply@openai.com>
Co-Authored-By: Virgil <virgil@lethean.io>
Added layout primitives to pkg/window/tiling.go:
- BesideEditor — position a window beside an editor, same height,
on the side with more empty space
- SuggestLayout — layout N windows on screen (golden-ratio split
for 2, grid for 3+)
- FindEmptySpace — find the largest rectangular empty region that
fits a minimum size; return (rect, ok)
- ArrangePair — 60/40 or 50/50 split based on aspect ratios
Plus Rect/Size aliases and a WindowPlacement type. Good/Bad/Ugly
test coverage + godoc examples.
pkg/mcp/tools_layout.go left unchanged — this branch already
registers layout_beside_editor / layout_suggest / screen_find_space
/ window_arrange_pair on top of the new helpers.
go vet clean. go test pkg/window/... passes under HOME override
(legacy layout-save tests need writeable ~/Library on non-sandbox).
Closes tasks.lthn.sh/view.php?id=30
Co-authored-by: Codex <noreply@openai.com>
Co-Authored-By: Virgil <virgil@lethean.io>
pkg/chat/service.go + messages.go implement the RFC §15.1–§15.8
chat service with the full IPC surface:
- gui.chat.send — streams assistant reply, returns message id
- gui.chat.history — []Message for a conversation
- gui.chat.models — []Model (name, size, status)
- gui.chat.selectModel — sets active model
- gui.chat.conversations.list/load/delete
- gui.chat.thinking.start/stop — explicit thinking-state tracking
MCP tool registrations in pkg/mcp/tools_chat.go mirror the IPC
surface (chat_send, chat_history, chat_models, etc). WS bridge in
pkg/display/display.go wires chat:conversations:load and
chat🤔stop, keeping legacy chat:conversations:get and
chat🤔end paths pointed at the new handlers for compat.
Good/Bad/Ugly tests per action in service_test.go + godoc example
in service_example_test.go. go vet + go test ./pkg/chat/... +
./pkg/... all clean.
Closes tasks.lthn.sh/view.php?id=14
Co-authored-by: Codex <noreply@openai.com>
Co-Authored-By: Virgil <virgil@lethean.io>
display.go: menu builder now consults menu.Service.ShowDevTools()
and, when enabled, adds Developer > Open DevTools + Close DevTools
menu items. Handlers route to the focused window (or the only open
window) via the existing webview.devtoolsOpen /
webview.devtoolsClose actions — which already land on Wails
WebviewWindow.OpenDevTools / CloseDevTools.
Tests: Good/Bad/Ugly coverage for both MCP tool handlers in
tools_webview_test.go plus a menu-level test in display_test.go
that clicks the built items and verifies mock devtools state flips
open/closed, with a disabled-config case.
tools_webview.go already had the handlers + registration on this
branch; locked down with tests instead of re-implementing.
Closes tasks.lthn.sh/view.php?id=31
Co-authored-by: Codex <noreply@openai.com>
Co-Authored-By: Virgil <virgil@lethean.io>
New pkg/preload package:
- preload.go — InjectPreload(webview, origin) entry point; builds
three-step preload: storage polyfills, Electron shim (origin-
filtered), app preloads from .core/view.yaml manifest.preloads.
- assets/storage_polyfills.js — localStorage/sessionStorage/
IndexedDB bridges.
- assets/electron_shim.js — minimal ipcRenderer.send/invoke
mapping to core.QUERY/ACTION.
- Adds a minimal window.core.ml.generate shim — gates the
AI-native browser path (RFC §11a).
pkg/window/wails.go wires into Wails OnPageLoad via reflection when
the runtime exposes the hook, with a clean fallback for the
stubbed/test runtime. Legacy display-preload code detected and
skipped when the new package is in play.
Good/Bad/Ugly tests in pkg/preload/preload_test.go. go vet + go
test clean.
Closes tasks.lthn.sh/view.php?id=16
Co-authored-by: Codex <noreply@openai.com>
Co-Authored-By: Virgil <virgil@lethean.io>
Guard eventBuffer access under RLock inside broadcaster() so a
concurrent buffer swap can't trip a nil-ref crash.
Co-Authored-By: Virgil <virgil@lethean.io>
New pkg/lifecycle/mode.go introduces AppMode (Manager | Worker) and
DetectMode() that returns:
- Manager by default (explicit or empty env)
- Worker when CORE_APP_MODE=worker, or when empty env + CI=true signals
a headless/compute context
Prerequisite for the BugSETI compute worker pattern (core/gui RFC.md §9.1) —
manager GUI runs the full app UI, workers run headless compute with only an
RPC surface.
Tests follow the core/go {Good,Bad,Ugly} naming convention; go test
./pkg/lifecycle/... passes.
Co-authored-by: Codex <noreply@openai.com>
Closes tasks.lthn.sh/view.php?id=32