| Age | Commit message (Collapse) | Author |
|
|
|
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.
|
|
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.
|
|
bin/up ran `bun --watch main.ts` without setting BACKEND_PORT, so a
shell-exported BACKEND_PORT (e.g. 24991 in ~/.bashrc, set so the Dispatch
CLI hits the prod server) overrode .env's dev value 24203 — Bun lets shell
env win over .env — binding the dev server onto the production port and
colliding with the active dispatch-server systemd service. transport-http
then failed to activate (Bun.serve "port in use"), so the HTTP server
never came up and the frontend got "Failed to fetch".
Force BACKEND_PORT=24203 + SURFACE_WS_PORT=24205 in the setsid invocation
so the dev stack is deterministic regardless of the shell environment.
|
|
conversation
kernel: executeToolCall now races tool.execute against the abort signal
via Promise.race; on abort resolves (not rejects) with an "Aborted" result
so the step completes normally → finishReason "aborted" → turn seals
cleanly (done event) → finally clears activeTurns → conversation freed,
next message accepted. run-turn strips tool-call chunks from the assistant
message on abort (keeps text/thinking) and omits tool-result messages to
avoid persisting dangling tool calls that would 400 the provider next turn.
tool-shell: realSpawn spawns detached (own process group); on abort AND
timeout kills the entire group (process.kill(-pgid, SIGKILL)) and resolves
immediately — no child.on("close") dependency, so a grandchild holding the
pipes can't stall the spawn promise or leak.
Also: ORCHESTRATOR.md migrated to dispatch CLI summon mechanism; .skills
summary; bin/sync-env PATH injection; frontend handoff docs.
1453 vitest pass · tsc -b EXIT 0 · biome clean.
|
|
Also adds bin/sync-env script for updating system env keys.
|
|
The sed substitution failed because the comment line contained '/' chars.
Now writes the service file via heredoc with User=/Group= patched in.
Also removes any previous masked service file first.
|
|
systemd service: User= and Group= patched by bin/install from SUDO_USER.
bin/setup-env: chowns data dirs to the real user. Since the service runs
as the user, os.homedir() resolves correctly for skills discovery —
no separate HOME env var needed.
|
|
The skills extension scans ~/.skills/ via os.homedir(). Under systemd as
root, this resolves to /root — no skills there. setup-env now resolves
the real user's home via SUDO_USER and writes HOME=<user home> to
/etc/dispatch/env.
|
|
bin/build: compiles standalone binaries (dispatch-server + dispatch CLI)
via bun build --compile, builds the frontend static bundle with
VITE_HTTP_PORT=24991 + VITE_WS_PORT=24990, copies to dist/web/.
bin/install: installs binaries to /usr/bin/, frontend to
/usr/share/dispatch/web/, systemd service to /etc/systemd/system/,
config to /etc/dispatch/env, data dirs to /var/lib/dispatch/ +
/var/log/dispatch/. Enables + starts the dispatch systemd service.
Supports --uninstall and --no-build flags.
systemd/dispatch.service: Type=simple, reads /etc/dispatch/env,
restarts on failure, logs to journald.
systemd/dispatch.env: template config (ports 24991 HTTP + 24990 WS,
DISPATCH_WEB_DIR, API key, data paths).
transport-http: optional webDir static file serving — unmatched GET
requests fall through to Bun.file() serving with SPA index.html
fallback. Gated on DISPATCH_WEB_DIR env var (backward compatible).
|
|
split (B2)
FE slice 1 — backend-declared, frontend-agnostic surface system (verified live): new types-only @dispatch/ui-contract (SurfaceSpec / field kinds / region / ActionRef / catalog), surface-registry (typed service handle), transport-ws (Bun WS :24205, path-agnostic upgrade), surface-loaded-extensions (first real surface); kernel HostAPI.getExtensions; host-bin wiring; bin/up. Harness: retire AGENTS 'backend only', ORCHESTRATOR §3/§7/§8, frontend-design.md locked.
B2 — wire-types split (chat-slice prerequisite): new types-only @dispatch/wire single-sources the wire ABI (AgentEvent + 11 variants; conversation model Chunk/ChatMessage/Role/TurnId/StepId + 6 chunk variants; Usage) with zero @dispatch/* deps. @dispatch/kernel re-exports via shims so its public surface is byte-identical (zero consumer blast radius). transport-contract re-exports AgentEvent from @dispatch/wire and drops its @dispatch/kernel dependency, so HTTP clients (the web frontend) consume the wire without the kernel runtime.
tsc -b + biome clean; 460 vitest + 77 bun pass.
|
|
|
|
Add a DEBUG=1 convenience flag to bin/up that turns on full LLM debug logging
(DISPATCH_DEBUG_LLM) plus the per-step usage/cache split (DISPATCH_DEBUG_USAGE)
and routes the JSON request/response files into the container's /app/logging,
which maps to the project-root logging/ dir on the host via the existing .:/app
bind mount. This makes it easy to verify cache hits (including the prompt-cache
warming replay) without docker exec.
- bin/up: DEBUG=1 sets DISPATCH_DEBUG_LLM/_USAGE=1 and DISPATCH_DEBUG_LLM_DIR=
/app/logging as DEFAULTS (explicit DISPATCH_DEBUG_* still win). Pre-creates
the host log dir; /app/* targets are already host-owned so no sudo chown,
while the /tmp fallback keeps its ownership fix.
- docker-compose.yml: forward DISPATCH_DEBUG_LLM_DIR into the api container.
- .gitignore: ignore logging/.
|
|
|
|
The Docker path (bin/up) already builds and bundles cs, but the native
package path (bin/service install -> bin/build-pkg -> makepkg) did not, so
search_code would have no cs binary under a systemd/s6 install and fall back
to its 'cs not found' error.
- packaging/PKGBUILD: add 'code-search' to the split pkgname array; add go+git
to makedepends; build the patched, statically-linked cs (pinned v3.1.0
commit + docker/cs/luau-declarations.patch) in build(); install it to
/usr/bin/cs via a dedicated package_code-search() (with the upstream MIT
LICENSE). Pin kept in lockstep with the Dockerfiles.
- bin/install-pkg: install code-search alongside dispatch + dispatch-systemd
by default (and under --all).
Verified: full run produces code-search-0.0.1-1-x86_64.pkg.tar.zst
containing a working /usr/bin/cs (v3.1.0, static) with Luau declaration
detection; the dispatch package no longer contains cs. Tests (598) + biome
still pass.
|
|
The debug-logger.ts module existed but was completely orphaned — none of
its functions had any callsites, so DISPATCH_DEBUG_LLM=1 did nothing.
Wires it in across the stack:
- llm/debug-logger.ts: add wrapFetchWithLogging() that tees SSE bodies via
TransformStream + response.clone() so we capture every chunk without
draining the body the AI SDK consumes. Redacts authorization / x-api-key
/ cookie headers in logs. Also exports nextDebugSeq() so requests and
log files share an id.
- llm/provider.ts: all 3 factories (Claude OAuth, plain-API-key Anthropic,
OpenAI-compatible) now pass fetch: wrapFetchWithLogging(globalThis.fetch).
For Claude OAuth the wrap goes on the inner base fetch so logged bodies
reflect the post-transform shape + Claude-Code session headers. Added
tabId to ProviderConfig for log labelling.
- agent/agent.ts: threads tabId through createProvider and emits
logAgentLoop / logStepLifecycle / logStreamEvent at every meaningful
point in the run loop — step start/end, tool count, every fullStream
event. All are no-ops when DISPATCH_DEBUG_LLM is unset.
- core/index.ts: re-exports the debug helpers.
- tests/llm/provider.test.ts: switch one full-object equality assertion
to property assertions so the test survives the new fetch: wrapper.
Plumbing the env var into the container required three more fixes:
- bin/up: re-export DISPATCH_DEBUG_LLM* so docker compose forwards them
(compose only forwards vars referenced in the environment: block).
Also pre-creates /tmp/dispatch/llm-debug and chowns it on first run so
the container's UID-1000 bun process can write into it without EACCES.
- docker-compose.yml: declare the debug vars on api.environment and
bind-mount /tmp/dispatch/llm-debug:/tmp/dispatch/llm-debug so logs are
inspectable from the host without docker exec.
- docker/entrypoint.dev.sh: explicitly forward DISPATCH_DEBUG_* through
the 'su -' login-shell barrier — su - resets the environment to TERM/
PATH/HOME/SHELL/USER/LOGNAME only, silently stripping everything else.
This is why the vars appeared via 'docker exec env' (which spawns a
new process inheriting the container env) but were absent from the
actual bun process's /proc/<pid>/environ.
bin/build: drop stray sudo for consistency with bin/up and bin/down.
|
|
units (User=%i)
The per-user systemd manager ([email protected]) fails to start on WSL
(kernel 6.6.87.2, microsoft/WSL#13186 — 'Failed to spawn executor:
Device or resource busy'), which breaks pacman's
30-systemd-daemon-reload-user.hook on install.
Changes:
- New [email protected] + [email protected] system
template units with User=%i (run as the named instance user)
- Remove old user-scope dispatch-api.service / dispatch-frontend.service
- Install to /usr/lib/systemd/system/ instead of .../systemd/user/
- Update PKGBUILD, .install hints, and bin/service to use
sudo systemctl dispatch-api@<user>
|
|
management script
|
|
separate dispatch-electron, add bun-based frontend serve
PKGBUILD is now a split package producing three .pkg.tar.zst files in one
makepkg run:
- dispatch base application files (/opt/dispatch), CLI wrappers
(dispatch-api, dispatch-frontend), env configs
(/etc/dispatch/dispatch-api.conf,
/etc/dispatch/dispatch-frontend.conf)
- dispatch-systemd systemd user units for dispatch-api + dispatch-frontend
(conflicts with dispatch-s6)
- dispatch-s6 s6-rc service pipelines (-srv + -log) for both services
(conflicts with dispatch-systemd)
The Electron desktop wrapper moved to its own self-contained PKGBUILD at
packaging/electron/, producing dispatch-electron. It bundles its own copy of
the frontend dist + electron entry points under /opt/dispatch-electron and
does not depend on the base dispatch package, so users can install it
standalone and point VITE_API_URL at any backend at build time.
Files under packaging/ are now read directly from ${_projectdir}/packaging/
rather than via source=(); the two s6 service dirs share basenames (run,
type) which would collide inside ${srcdir}.
New frontend static server: packages/frontend/serve.ts uses Bun's built-in
HTTP server (no extra runtime deps) with SPA fallback to index.html and
path-traversal protection. PORT/HOST/DIST_DIR overridable via env. Exposed
as 'bun run --cwd packages/frontend serve' and via /usr/bin/dispatch-frontend.
Build scripts:
- bin/build-pkg now prints the freshest built packages
- bin/install-pkg installs dispatch + dispatch-systemd by default;
accepts package names or --all; searches both
packaging/ and packaging/electron/
- bin/build-pkg-electron new, builds the electron split
- bin/build-pkg-windows replaces bin/windows-pkg; drops the hard-coded
WSL copy step, just prints the win-unpacked path
.gitignore extended to cover packaging/*.tar.zst and packaging/electron/{src,pkg,*.pkg.tar.zst,*.tar.zst}.
|
|
- Add is_subagent checkbox to agent editor; subagents are hidden from Chat Settings
- Add is_subagent field to AgentDefinition type, TOML serialization, and API route
- Filter subagents from ModelSelector agent list
- Fix all biome lint/format errors across codebase (useLiteralKeys, noNonNullAssertion, noExplicitAny, formatting, import sorting)
- Fix svelte-check errors (type narrowing in SkillsBrowser, ToolPermissions, SidebarPanel)
- Fix a11y warnings in App.svelte (label-control associations)
- Fix test mocks missing BackgroundShellStore, BackgroundTranscriptStore, createWebSearchTool, createYoutubeTranscribeTool
- Update stale 409 test to match current message-queuing behavior
- Exclude packaging/ and release/ dirs from biome to avoid linting stale build artifacts
|
|
and Windows exe build
- Add Electron wrapper (main.cjs, preload.cjs) for desktop frontend
- Add systemd service unit, env config, and sysusers for backend API
- Add PKGBUILD and .install for Arch package (makepkg -si)
- Add desktop entry, SVG/PNG icon, and wrapper scripts
- Add bin/build-pkg, bin/install-pkg, bin/windows-pkg scripts
- Make API port configurable via PORT env var (default 3000, prod 18390)
- Add electron-builder config for Windows exe cross-compilation
- Set vite base to './' for Electron file:// loading
|
|
handling
- Agent Builder: full CRUD with card grid, drag-and-drop model reorder, edit/delete
- Auto-save on edit with 600ms debounce, AbortController for concurrency, fieldset disabled until name entered
- Agent definitions stored as TOML with cwd field, loaded from global/project dirs
- Working directory: per-tab CWD override in Chat Settings, agent default CWD, auto-create on first message
- CWD validation: check-dir endpoint with ~ expansion, real-time validity indicator
- Subagent CWD validated against parent's effective CWD using path.relative
- Unavailable tool calls: caught gracefully, shown as tool call with error badge, model retries
- UI: tab bar border radius, sidebar border removed, chat input ghost style, scroll-to-bottom rectangle
- Skills dir collapse uses CSS rotation, Model Choice renamed to Chat Settings, System Prompt view removed
- Reusable SkillsBrowser/ToolPermissions with external mode for Agent Builder
- ModelSelector: Agent/Manual toggle, agent list, Agent Settings link
- Page router, skills recursive scanning, bin/up gopass removed, docker volume mounts
|
|
- Remove ModelResolver, model definitions, model tags, fallback order, agent templates
- Remove all [[models]], [agents], and fallback from dispatch.toml and config schema
- ModelRegistry is now a pure key-state manager
- dispatch.toml reduced to keys + permissions only
- Docker: fix entrypoint for existing UID, skip bun install in frontend container
- Docker: scoped build cache prune in bin/clean
|
|
- Add SQLite database at ~/.local/share/dispatch/dispatch.db with tables: credentials, api_keys, wake_schedule, usage_cache
- Store Claude OAuth credentials in DB with import button in Model Status UI
- Store OpenCode/Copilot API keys in DB with paste-to-import modal
- Store OpenCode cookie and workspace IDs in DB
- Migrate wake schedule from .wake-schedule.json to DB
- Migrate usage cache from in-memory Map + localStorage to DB
- Remove all env var and file fallbacks — DB is the single source of truth
- Add seed scripts: bin/import-credentials.ts, bin/seed-opencode-keys.ts
- Docker: container runs as host UID/GID with matching home directory
- Clean up dispatch.toml: remove env fields, update comments
- Progress bar time markers for usage cycle tracking
|
|
effort, and dynamic model listing
|
|
- Sidebar uses absolute inset-0 with overflow-y-auto for proper scrolling
- Border moved to inner div so it hides with sidebar
- Copilot auth script uses portable sed instead of grep -P (macOS compat)
- dispatch.toml with 3 keys, 4 models, fallback order
- .env.dispatch with key placeholders and script reference
- docker-compose loads .env.dispatch via env_file
|
|
- Base URL corrected: zen/v1 -> zen/go/v1 (opencode-go provider)
- Model changed: deepseek-v4-flash-free -> deepseek-v4-flash
- Added wrapLanguageModel middleware to inject reasoning_content via
providerMetadata.openaiCompatible before each stream call
- Fixed test mocks: removed vi.importActual (unsupported in Bun), added
tool factory mocks, preserved real tool export in ai mock
- Added 11 tests for the normalizeMessages middleware
|
|
- Bun monorepo with @dispatch/core, @dispatch/api, @dispatch/frontend
- Agent runtime with Vercel AI SDK, streaming via WebSocket
- Tools: read_file, write_file, list_files (scoped to working directory)
- Hono API server with POST /chat, GET /status, GET /health, WS /ws
- Svelte 5 + DaisyUI frontend with chat UI, theme switcher, copy button
- OpenCode Go (Zen) as LLM provider, deepseek-v4-flash-free model
- Docker setup (dev + prod) with bin/ scripts and gopass secrets
- Biome v2 linting/formatting, Vitest tests (44 passing)
- Debug info attached to error messages for diagnostics
|