From 421c38cd8c83e9999bf2a8ec160d04c6ab1dbf6a Mon Sep 17 00:00:00 2001 From: Hibryda Date: Tue, 17 Mar 2026 01:12:25 +0100 Subject: [PATCH] docs: update all documentation for agor rebrand and dual-repo structure --- .claude/CLAUDE.md | 28 +++++------ CHANGELOG.md | 75 +++++++++++++++++------------- CLAUDE.md | 46 +++++++++--------- README.md | 14 +++--- TODO.md | 29 +++++++----- docs/README.md | 10 ++-- docs/architecture.md | 34 +++++++------- docs/decisions.md | 2 +- docs/e2e-testing.md | 32 ++++++------- docs/findings.md | 4 +- docs/multi-machine.md | 32 ++++++------- docs/orchestration.md | 4 +- docs/phases.md | 24 +++++----- docs/production.md | 14 +++--- docs/progress/v2-archive.md | 32 ++++++------- docs/progress/v2.md | 8 ++-- docs/progress/v3.md | 22 ++++----- docs/provider-adapter/findings.md | 4 +- docs/provider-adapter/task_plan.md | 10 ++-- docs/release-notes.md | 6 +-- docs/sidecar.md | 2 +- 21 files changed, 225 insertions(+), 207 deletions(-) diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md index 4f8af11..908da84 100644 --- a/.claude/CLAUDE.md +++ b/.claude/CLAUDE.md @@ -5,7 +5,7 @@ - Docs are in `docs/`. Architecture in `docs/architecture.md`. - v2 Phases 1-7 + multi-machine (A-D) + profiles/skills complete. Extras: SSH, ctx, themes, detached mode, auto-updater, shiki, copy/paste, session resume, drag-resize, session groups, Deno sidecar, Claude profiles, skill discovery. - v3 Mission Control (All Phases 1-10 + Production Readiness Complete): project groups, workspace store, 15+ Workspace components, session continuity, multi-provider adapter pattern, worktree isolation, session anchors, Memora adapter, SOLID refactoring, multi-agent orchestration (btmsg/bttask, 4 Tier 1 roles, role-specific tabs), dashboard metrics, auto-wake scheduler, reviewer agent. Production: sidecar supervisor (auto-restart, exponential backoff), FTS5 search (3 virtual tables, Spotlight overlay), plugin system (Web Worker sandbox, permission-gated), Landlock sandbox (kernel 6.2+), secrets management (system keyring), OS+in-app notifications, keyboard-first UX (18+ palette commands, vi-nav), agent health monitoring (heartbeats, dead letter queue), audit logging, error classification (6 types), optimistic locking (bttask). Hardening: TLS relay, SPKI pinning (TOFU), WAL checkpoint (5min), subagent delegation fix, plugin sandbox tests (26), SidecarManager actor pattern, per-message btmsg acknowledgment, Aider autonomous mode. 507 vitest + 110 cargo + 109 E2E. -- Consult Memora (tag: `bterminal`) before making architectural changes. +- Consult Memora (tag: `agor`) before making architectural changes. ## Documentation References @@ -34,7 +34,7 @@ - Agent dispatcher (`src/lib/agent-dispatcher.ts`) is a thin coordinator (260 lines) routing sidecar events to the agent store. Delegates to extracted modules: `utils/session-persistence.ts` (session-project maps, persistSessionForProject), `utils/subagent-router.ts` (spawn + route subagent panes), `utils/auto-anchoring.ts` (triggerAutoAnchor on compaction), `utils/worktree-detection.ts` (detectWorktreeFromCwd pure function). Provider-aware via message-adapters.ts. - AgentQueryOptions supports `provider` field (defaults to 'claude', flows Rust -> sidecar), `provider_config` blob (Rust passes through as serde_json::Value), `permission_mode` (defaults to 'bypassPermissions'), `setting_sources` (defaults to ['user', 'project']), `system_prompt`, `model`, `claude_config_dir` (for multi-account), `additional_directories`, `worktree_name` (when set, passed as `extraArgs: { worktree: name }` to SDK → `--worktree ` CLI flag), `extra_env` (HashMap, injected into sidecar process env; used for BTMSG_AGENT_ID). - Multi-agent orchestration: Tier 1 (management agents: Manager, Architect, Tester, Reviewer) defined in groups.json `agents[]`, converted to ProjectConfig via `agentToProject()`, rendered as full ProjectBoxes. Tier 2 (project agents) are regular ProjectConfig entries. Both tiers get system prompts. Tier 1 prompt built by `generateAgentPrompt()` (utils/agent-prompts.ts): 7 sections (Identity, Environment, Team, btmsg docs, bttask docs, Custom context, Workflow). Tier 2 gets optional `project.systemPrompt` as custom context. BTMSG_AGENT_ID env var injected for Tier 1 agents only (enables btmsg/bttask CLI usage). Periodic re-injection: AgentSession runs 1-hour timer, sends context refresh prompt when agent is idle (autoPrompt → AgentPane → startQuery with resume=true). -- bttask kanban: Rust bttask.rs module reads/writes tasks table in shared btmsg.db (~/.local/share/bterminal/btmsg.db). 7 operations: list_tasks, create_task, update_task_status, delete_task, add_comment, task_comments, review_queue_count. Frontend: TaskBoardTab.svelte (kanban 5 columns, 5s poll). CLI `bttask` tool gives agents direct access; Manager has full CRUD, Reviewer has read + status + comments, other roles have read-only + comments. On task→review transition, auto-posts to #review-queue btmsg channel (ensure_review_channels creates #review-queue + #review-log idempotently). Reviewer agent gets Tasks tab in ProjectBox (reuses TaskBoardTab). reviewQueueDepth in AttentionInput: 10pts per review task, capped at 50 (priority between file_conflict 70 and context_high 40). ProjectBox polls review_queue_count every 10s for reviewer agents → setReviewQueueDepth() in health store. +- bttask kanban: Rust bttask.rs module reads/writes tasks table in shared btmsg.db (~/.local/share/agor/btmsg.db). 7 operations: list_tasks, create_task, update_task_status, delete_task, add_comment, task_comments, review_queue_count. Frontend: TaskBoardTab.svelte (kanban 5 columns, 5s poll). CLI `bttask` tool gives agents direct access; Manager has full CRUD, Reviewer has read + status + comments, other roles have read-only + comments. On task→review transition, auto-posts to #review-queue btmsg channel (ensure_review_channels creates #review-queue + #review-log idempotently). Reviewer agent gets Tasks tab in ProjectBox (reuses TaskBoardTab). reviewQueueDepth in AttentionInput: 10pts per review task, capped at 50 (priority between file_conflict 70 and context_high 40). ProjectBox polls review_queue_count every 10s for reviewer agents → setReviewQueueDepth() in health store. - btmsg/bttask SQLite conventions: Both btmsg.rs and bttask.rs open shared btmsg.db with WAL mode + 5s busy_timeout (concurrent access from Python CLIs + Rust backend). All queries use named column access (`row.get("column_name")`) — never positional indices. Rust structs use `#[serde(rename_all = "camelCase")]`; TypeScript interfaces MUST match camelCase wire format. TestingTab uses `convertFileSrc()` for Tauri 2.x asset URLs (not `asset://localhost/`). - ArchitectureTab: PlantUML diagram viewer/editor. Stores .puml files in `.architecture/` project dir. Renders via plantuml.com server using ~h hex encoding (no Java dependency). 4 templates: Class, Sequence, State, Component. Editor + SVG preview toggle. - TestingTab: Dual-mode component (mode='selenium'|'tests'). Selenium: watches `.selenium/screenshots/` for PNG/JPG, displays in gallery with session log, 3s poll. Tests: discovers files in standard dirs (tests/, test/, spec/, __tests__/, e2e/), shows content. @@ -49,7 +49,7 @@ - Agent preview terminal: `AgentPreviewPane.svelte` is a read-only xterm.js terminal (disableStdin:true) that subscribes to an agent session's messages via `$derived(getAgentSession(sessionId))` and renders tool calls/results in real-time. Bash commands shown as cyan `❯ cmd`, file ops as yellow `[Read] path`, results as plain text (80-line truncation), errors in red. Spawned via 👁 button in TerminalTabs (appears when agentSessionId prop is set). TerminalTab type: `'agent-preview'` with `agentSessionId` field. Deduplicates — won't create two previews for the same session. ProjectBox passes mainSessionId to TerminalTabs. - Maximum 4 active xterm.js instances to avoid WebKit2GTK memory issues. Agent preview uses disableStdin and no PTY so is lighter, but still counts. - Store files using Svelte 5 runes (`$state`, `$derived`) MUST have `.svelte.ts` extension (not `.ts`). Import with `.svelte` suffix. Plain `.ts` compiles but fails at runtime with "rune_outside_svelte". -- Session persistence uses rusqlite (bundled) with WAL mode. Data dir: `dirs::data_dir()/bterminal/sessions.db`. +- Session persistence uses rusqlite (bundled) with WAL mode. Data dir: `dirs::data_dir()/agor/sessions.db`. - Layout store persists to SQLite on every addPane/removePane/setPreset/setPaneGroup change (fire-and-forget). Restores on app startup via `restoreFromDb()`. - Session groups: Pane.group? field in layout store, group_name column in sessions table, collapsible group headers in sidebar. Right-click pane to set group. - File watcher uses notify crate v6, watches parent directory (NonRecursive), emits `file-changed` Tauri events. @@ -69,29 +69,29 @@ - Theme system: 17 themes in 3 groups — 4 Catppuccin + 7 Editor (VSCode Dark+, Atom One Dark, Monokai, Dracula, Nord, Solarized Dark, GitHub Dark) + 6 Deep Dark (Tokyo Night, Gruvbox Dark, Ayu Dark, Poimandres, Vesper, Midnight). All map to same 26 --ctp-* CSS custom properties — zero component changes needed. ThemeId replaces CatppuccinFlavor. getCurrentTheme()/setTheme() are primary API (deprecated wrappers exist). THEME_LIST has ThemeMeta with group metadata for custom dropdown UI. Open terminals hot-swap via onThemeChange() callback registry in theme.svelte.ts. Typography uses --ui-font-family/--ui-font-size (UI elements, sans-serif fallback) and --term-font-family/--term-font-size (terminal, monospace fallback) CSS custom properties (defined in catppuccin.css). initTheme() restores all 4 font settings (ui_font_family, ui_font_size, term_font_family, term_font_size) from SQLite on startup. - Detached pane mode: App.svelte checks URL param `?detached=1` and renders a single pane without sidebar/grid chrome. Used for pop-out windows. - Shiki syntax highlighting uses lazy singleton pattern (avoid repeated WASM init). 13 languages preloaded. Used in MarkdownPane and AgentPane text messages. -- Cargo workspace at repo root: members = [src-tauri, bterminal-core, bterminal-relay]. Cargo.lock is at workspace root, not in src-tauri/. -- EventSink trait (bterminal-core/src/event.rs) abstracts event emission. PtyManager and SidecarManager are in bterminal-core, not src-tauri. src-tauri has thin re-exports. -- RemoteManager (src-tauri/src/remote.rs) manages WebSocket client connections to bterminal-relay instances. 12 Tauri commands prefixed with `remote_`. +- Cargo workspace at repo root: members = [src-tauri, agor-core, agor-relay]. Cargo.lock is at workspace root, not in src-tauri/. +- EventSink trait (agor-core/src/event.rs) abstracts event emission. PtyManager and SidecarManager are in agor-core, not src-tauri. src-tauri has thin re-exports. +- RemoteManager (src-tauri/src/remote.rs) manages WebSocket client connections to agor-relay instances. 12 Tauri commands prefixed with `remote_`. - remote-bridge.ts adapter wraps remote machine management IPC. machines.svelte.ts store tracks remote machine state. - Pane.remoteMachineId?: string routes operations through RemoteManager instead of local managers. Bridge adapters (pty-bridge, agent-bridge) check this field. -- bterminal-relay binary (bterminal-relay/) is a standalone WebSocket server with token auth, rate limiting, and per-connection isolated managers. Commands return structured responses (pty_created, pong, error) with commandId for correlation via send_error() helper. +- agor-relay binary (agor-relay/) is a standalone WebSocket server with token auth, rate limiting, and per-connection isolated managers. Commands return structured responses (pty_created, pong, error) with commandId for correlation via send_error() helper. - RemoteManager reconnection: exponential backoff (1s-30s cap) on disconnect, attempt_tcp_probe() (TCP-only, no WS upgrade), emits remote-machine-reconnecting and remote-machine-reconnect-ready events. Frontend listeners in remote-bridge.ts; machines store auto-reconnects on ready. -- v3 workspace store (`workspace.svelte.ts`) replaces layout store for v3. Groups loaded from `~/.config/bterminal/groups.json` via `groups-bridge.ts`. State: groups, activeGroupId, activeTab, focusedProjectId. Derived: activeGroup, activeProjects. +- v3 workspace store (`workspace.svelte.ts`) replaces layout store for v3. Groups loaded from `~/.config/agor/groups.json` via `groups-bridge.ts`. State: groups, activeGroupId, activeTab, focusedProjectId. Derived: activeGroup, activeProjects. - v3 groups backend (`groups.rs`): load_groups(), save_groups(), default_groups(). Tauri commands: groups_load, groups_save. -- Telemetry (`telemetry.rs`): tracing + optional OTLP export to Tempo. `BTERMINAL_OTLP_ENDPOINT` env var controls (absent = console-only). TelemetryGuard in AppState with Drop-based shutdown. Frontend events route through `frontend_log` Tauri command → Rust tracing (no browser OTEL SDK — WebKit2GTK incompatible). `telemetry-bridge.ts` provides `tel.info/warn/error()` convenience API. Docker stack at `docker/tempo/` (Grafana port 9715). -- E2E test mode (`BTERMINAL_TEST=1`): watcher.rs and fs_watcher.rs skip file watchers, wake-scheduler disabled via `disableWakeScheduler()`, `is_test_mode` Tauri command bridges to frontend. Data/config dirs overridable via `BTERMINAL_TEST_DATA_DIR`/`BTERMINAL_TEST_CONFIG_DIR`. E2E uses WebDriverIO + tauri-driver, single session, TCP readiness probe. Phase A: 7 data-testid-based scenarios in `agent-scenarios.test.ts` (deterministic assertions). Phase B: 6 scenarios in `phase-b.test.ts` (multi-project grid, independent tab switching, status bar fleet state, LLM-judged agent responses/code generation, context tab verification). LLM judge (`llm-judge.ts`): raw fetch to Anthropic API using claude-haiku-4-5, structured verdict (pass/fail + reasoning + confidence), `assertWithJudge()` with configurable threshold, skips when `ANTHROPIC_API_KEY` absent. CI workflow (`.github/workflows/e2e.yml`): unit + cargo + e2e jobs, xvfb-run, path-filtered triggers, LLM tests gated on secret. Test fixtures in `fixtures.ts` create isolated temp environments. Results tracked via JSON store in `results-db.ts`. +- Telemetry (`telemetry.rs`): tracing + optional OTLP export to Tempo. `AGOR_OTLP_ENDPOINT` env var controls (absent = console-only). TelemetryGuard in AppState with Drop-based shutdown. Frontend events route through `frontend_log` Tauri command → Rust tracing (no browser OTEL SDK — WebKit2GTK incompatible). `telemetry-bridge.ts` provides `tel.info/warn/error()` convenience API. Docker stack at `docker/tempo/` (Grafana port 9715). +- E2E test mode (`AGOR_TEST=1`): watcher.rs and fs_watcher.rs skip file watchers, wake-scheduler disabled via `disableWakeScheduler()`, `is_test_mode` Tauri command bridges to frontend. Data/config dirs overridable via `AGOR_TEST_DATA_DIR`/`AGOR_TEST_CONFIG_DIR`. E2E uses WebDriverIO + tauri-driver, single session, TCP readiness probe. Phase A: 7 data-testid-based scenarios in `agent-scenarios.test.ts` (deterministic assertions). Phase B: 6 scenarios in `phase-b.test.ts` (multi-project grid, independent tab switching, status bar fleet state, LLM-judged agent responses/code generation, context tab verification). LLM judge (`llm-judge.ts`): raw fetch to Anthropic API using claude-haiku-4-5, structured verdict (pass/fail + reasoning + confidence), `assertWithJudge()` with configurable threshold, skips when `ANTHROPIC_API_KEY` absent. CI workflow (`.github/workflows/e2e.yml`): unit + cargo + e2e jobs, xvfb-run, path-filtered triggers, LLM tests gated on secret. Test fixtures in `fixtures.ts` create isolated temp environments. Results tracked via JSON store in `results-db.ts`. - v3 SQLite additions: agent_messages table (per-project message persistence), project_agent_state table (sdkSessionId, cost, status per project), sessions.project_id column. - v3 App.svelte: VSCode-style sidebar layout. Horizontal: left icon rail (GlobalTabBar, 2.75rem, single Settings gear icon) + expandable drawer panel (Settings only, content-driven width, max 50%) + main workspace (ProjectGrid always visible) + StatusBar. Sidebar has Settings only — Sessions/Docs/Context are project-specific (in ProjectBox tabs). Keyboard: Ctrl+B (toggle sidebar), Ctrl+, (settings), Escape (close). - v3 component tree: App -> GlobalTabBar (settings icon) + sidebar-panel? (SettingsTab) + workspace (ProjectGrid) + StatusBar. See `docs/architecture.md` for full tree. -- MarkdownPane reactively watches filePath changes via $effect (not onMount-only). Uses sans-serif font (Inter, system-ui), all --ctp-* theme vars. Styled blockquotes with translucent backgrounds, table row hover, link hover underlines. Inner `.markdown-pane-scroll` wrapper with `container-type: inline-size` for responsive padding via `--bterminal-pane-padding-inline`. -- AgentPane UI (redesigned 2026-03-09): sans-serif root font (`system-ui, -apple-system, sans-serif`), monospace only on code/tool names. Tool calls paired with results in collapsible `
` groups via `$derived.by` toolResultMap (cache-guarded by tool_result count). Hook messages collapsed into compact `
` with gear icon. Context window meter inline in status strip. Cost bar minimal (no background, subtle border-top). Session summary with translucent surface background. Two-phase scroll anchoring (`$effect.pre` + `$effect`). Tool-aware output truncation (Bash 500 lines, Read/Write 50, Glob/Grep 20, default 30). Colors softened via `color-mix()`. Inner `.agent-pane-scroll` wrapper with `container-type: inline-size` for responsive padding via shared `--bterminal-pane-padding-inline` variable. +- MarkdownPane reactively watches filePath changes via $effect (not onMount-only). Uses sans-serif font (Inter, system-ui), all --ctp-* theme vars. Styled blockquotes with translucent backgrounds, table row hover, link hover underlines. Inner `.markdown-pane-scroll` wrapper with `container-type: inline-size` for responsive padding via `--agor-pane-padding-inline`. +- AgentPane UI (redesigned 2026-03-09): sans-serif root font (`system-ui, -apple-system, sans-serif`), monospace only on code/tool names. Tool calls paired with results in collapsible `
` groups via `$derived.by` toolResultMap (cache-guarded by tool_result count). Hook messages collapsed into compact `
` with gear icon. Context window meter inline in status strip. Cost bar minimal (no background, subtle border-top). Session summary with translucent surface background. Two-phase scroll anchoring (`$effect.pre` + `$effect`). Tool-aware output truncation (Bash 500 lines, Read/Write 50, Glob/Grep 20, default 30). Colors softened via `color-mix()`. Inner `.agent-pane-scroll` wrapper with `container-type: inline-size` for responsive padding via shared `--agor-pane-padding-inline` variable. - ProjectBox uses CSS `style:display` (flex/none) instead of `{#if}` for tab content panes — keeps AgentSession mounted across tab switches (prevents session ID reset and message loss). Terminal section also uses `style:display`. Grid rows: auto auto 1fr auto. - Svelte 5 event syntax: use `onclick` not `on:click`. Svelte 5 requires lowercase event handler attributes (no colon syntax). ## Memora Tags -Project tag: `bterminal` -Common tag combinations: `bterminal,architecture`, `bterminal,research`, `bterminal,tech-stack` +Project tag: `agor` +Common tag combinations: `agor,architecture`, `agor,research`, `agor,tech-stack` ## Operational Rules diff --git a/CHANGELOG.md b/CHANGELOG.md index 5faed8a..c04bf1f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,8 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added +- **Dual-repo commercial structure** — agents-orchestrator/agents-orchestrator private repo as commercial source of truth, DexterFromLab/agent-orchestrator as community mirror. Two git remotes (origin + orchestrator) configured locally +- **agor-pro plugin crate** — Tauri 2.x plugin for commercial features. Feature-gated via `--features pro`. Registered via `app.handle().plugin(agor_pro::init())` in setup(). Scaffold with `pro_status` command +- **Commercial Tauri config overlay** — `tauri.conf.commercial.json` with separate bundle ID (`com.agentsorchestrator.pro`) and updater endpoints +- **Asymmetric test configuration** — `AGOR_EDITION=pro` env var enables `tests/commercial/` in vitest. Pro: 509 tests, Community: 507 tests. Same framework, different coverage +- **CI leak prevention** — `leak-check.yml` blocks commercial code on community pushes. `commercial-build.yml` validates pro edition. `pat-health.yml` weekly PAT monitoring +- **Pre-push hook** — `.githooks/pre-push` detects and blocks commercial paths when pushing to origin +- **Makefile** — setup, build, build-pro, test, test-pro, sync, clean targets +- **Commercial docs** — CONTRIBUTING.md (dual-repo model, CLA, SPDX), MAINTENANCE.md (PAT rotation, sync workflow, release checklists), LICENSE-COMMERCIAL + ### Changed -- **Repo flattened** — all source code moved from `v2/` subdirectory to repo root. 351-commit history squashed by upstream rebuild. Branch `hib_changes_v2` created from new flat `main` with reconciled docs, CLI tools, and scaffolding. All path references in CLAUDE.md and docs/ updated +- **bterminal→agor rebrand** — Cargo crates: bterminal-core→agor-core, bterminal-relay→agor-relay. Env vars: BTERMINAL_*→AGOR_*. Config paths: ~/.config/agor, ~/.local/share/agor. CSS: --agor-pane-padding-inline. Plugin API: `agor` object. Package names: agents-orchestrator, agor-sidecar +- **Repo flattened** — all source code moved from `v2/` subdirectory to repo root. 351-commit history squashed by upstream rebuild. Branch `hib_changes_v2` created from new flat `main` with reconciled docs, CLI tools, and scaffolding ### Added - **Plugin sandbox Web Worker migration** — replaced `new Function()` sandbox with dedicated Web Worker per plugin. True process-level isolation — no DOM, no Tauri IPC, no main-thread access. Permission-gated API proxied via postMessage with RPC pattern. 26 tests (MockWorker class in vitest) @@ -32,14 +43,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - **Comprehensive documentation suite** — 4 new docs: `architecture.md` (end-to-end system architecture with component hierarchy, data flow, IPC patterns), `sidecar.md` (multi-provider runner lifecycle, env stripping, NDJSON protocol, build pipeline), `orchestration.md` (btmsg messaging, bttask kanban, agent roles, wake scheduler, session anchors, health monitoring), `production.md` (sidecar supervisor, Landlock sandbox, FTS5 search, plugin system, secrets management, notifications, audit logging, error classification, telemetry) -- **Sidecar crash recovery/supervision** — `bterminal-core/src/supervisor.rs`: SidecarSupervisor wraps SidecarManager with auto-restart, exponential backoff (1s base, 30s cap, 5 retries), SidecarHealth enum (Healthy/Degraded/Failed), 5min stability window. 17 tests +- **Sidecar crash recovery/supervision** — `agor-core/src/supervisor.rs`: SidecarSupervisor wraps SidecarManager with auto-restart, exponential backoff (1s base, 30s cap, 5 retries), SidecarHealth enum (Healthy/Degraded/Failed), 5min stability window. 17 tests - **Notification system** — OS desktop notifications via `notify-rust` + in-app NotificationCenter.svelte (bell icon, unread badge, history max 100, 6 notification types). Agent dispatcher emits on complete/error/crash. notifications-bridge.ts adapter -- **Secrets management** — `keyring` crate with linux-native (libsecret). SecretsManager in secrets.rs: store/get/delete/list with `__bterminal_keys__` metadata tracking. SettingsTab Secrets section. secrets-bridge.ts adapter. No plaintext fallback +- **Secrets management** — `keyring` crate with linux-native (libsecret). SecretsManager in secrets.rs: store/get/delete/list with `__agor_keys__` metadata tracking. SettingsTab Secrets section. secrets-bridge.ts adapter. No plaintext fallback - **Keyboard-first UX** — Alt+1-5 project jump, Ctrl+H/L vi-nav, Ctrl+Shift+1-9 tab switch, Ctrl+J terminal toggle, Ctrl+Shift+K focus agent, Ctrl+Shift+F search overlay. `isEditing()` guard prevents conflicts. CommandPalette rewritten: 18+ commands, 6 categories, fuzzy filter, arrow nav, keyboard shortcuts overlay - **Agent health monitoring** — heartbeats table + dead_letter_queue table in btmsg.db. 15s heartbeat polling in ProjectBox. Stale detection (5min threshold). ProjectHeader heart indicator (green/yellow/red). StatusBar health badge - **FTS5 full-text search** — rusqlite upgraded to `bundled-full`. SearchDb with 3 FTS5 virtual tables (search_messages, search_tasks, search_btmsg). SearchOverlay.svelte: Spotlight-style Ctrl+Shift+F overlay, 300ms debounce, grouped results with FTS5 highlight snippets -- **Plugin system** — `~/.config/bterminal/plugins/` with plugin.json manifest. plugins.rs: discovery, path-traversal-safe file reading, permission validation. plugin-host.ts: sandboxed `new Function()` execution, permission-gated API (palette, btmsg:read, bttask:read, events). plugins.svelte.ts store. SettingsTab plugins section. Example hello plugin -- **Landlock sandbox** — `bterminal-core/src/sandbox.rs`: SandboxConfig with RW/RO paths, applied via `pre_exec()` in sidecar child process. Requires kernel 6.2+ (graceful fallback). Per-project toggle in SettingsTab +- **Plugin system** — `~/.config/agor/plugins/` with plugin.json manifest. plugins.rs: discovery, path-traversal-safe file reading, permission validation. plugin-host.ts: sandboxed `new Function()` execution, permission-gated API (palette, btmsg:read, bttask:read, events). plugins.svelte.ts store. SettingsTab plugins section. Example hello plugin +- **Landlock sandbox** — `agor-core/src/sandbox.rs`: SandboxConfig with RW/RO paths, applied via `pre_exec()` in sidecar child process. Requires kernel 6.2+ (graceful fallback). Per-project toggle in SettingsTab - **Error classification** — `error-classifier.ts`: classifyApiError() with 6 types (rate_limit, auth, quota, overloaded, network, unknown), actionable messages, retry delays. 20 tests - **Audit log** — audit_log table in btmsg.db. AuditLogTab.svelte: Manager-only tab, filter by type+agent, 5s auto-refresh. audit-bridge.ts adapter. Events: agent_start/stop/error, task changes, wake events, prompt injection - **Usage meter** — UsageMeter.svelte: compact inline cost/token meter with color thresholds (50/75/90%), hover tooltip. Integrated in AgentPane cost bar @@ -47,7 +58,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - **Optimistic locking for bttask** — `version` column in tasks table. `WHERE id=? AND version=?` in update_task_status(). Conflict detection in TaskBoardTab. Both Rust + Python CLI updated - **Unified test runner** — `v2/scripts/test-all.sh` runs vitest + cargo tests with optional E2E (`--e2e` flag). npm scripts: `test:all`, `test:all:e2e`, `test:cargo`. Summary output with color-coded pass/fail - **Testing gate rule** — `.claude/rules/20-testing-gate.md` requires running full test suite after every major change (new features, refactors touching 3+ files, store/adapter/bridge/backend changes) -- **E2E test mode infrastructure** — `BTERMINAL_TEST=1` env var disables file watchers (watcher.rs, fs_watcher.rs), wake scheduler, and allows data/config dir overrides via `BTERMINAL_TEST_DATA_DIR`/`BTERMINAL_TEST_CONFIG_DIR`. New `is_test_mode` Tauri command bridges test state to frontend +- **E2E test mode infrastructure** — `AGOR_TEST=1` env var disables file watchers (watcher.rs, fs_watcher.rs), wake scheduler, and allows data/config dir overrides via `AGOR_TEST_DATA_DIR`/`AGOR_TEST_CONFIG_DIR`. New `is_test_mode` Tauri command bridges test state to frontend - **E2E data-testid attributes** — Stable test selectors on 7 key Svelte components: AgentPane (agent-pane, data-agent-status, agent-messages, agent-stop, agent-prompt, agent-submit), ProjectBox (project-box, data-project-id, project-tabs, terminal-toggle), StatusBar, AgentSession, GlobalTabBar, CommandPalette, TerminalTabs - **E2E Phase A scenarios** — 7 human-authored test scenarios (22 tests) in `agent-scenarios.test.ts`: app structural integrity, settings panel, agent pane initial state, terminal tab management, command palette, project focus/tab switching, agent prompt submission (graceful Claude CLI skip) - **E2E test fixtures** — `tests/e2e/fixtures.ts`: creates isolated temp environments with data/config dirs, git repos, and groups.json. `createTestFixture()`, `createMultiProjectFixture()`, `destroyTestFixture()` @@ -61,18 +72,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - **E2E fixture env propagation** — `tauri:options.env` does not reliably set process-level env vars for Rust `std::env::var()`. Added `process.env` injection at module scope in wdio.conf.js so fixture groups.json is loaded instead of real user config - **LLM judge CLI context pollution** — Claude CLI loaded project CLAUDE.md files causing model to refuse JSON output. Fixed by running judge from `cwd: /tmp` with `--setting-sources user` and `--system-prompt` flags - **E2E mocha timeout** — Increased global mocha timeout from 60s to 180s. Agent-running tests (B4/B5) need 120s+ for Claude CLI round-trip -- **E2E test suite — 27 failures fixed** across 3 spec files: bterminal.test.ts (22 — stale v2 CSS selectors, v3 tab order/count, JS-dispatched KeyboardEvent for Ctrl+K, idempotent palette open/close, backdrop click close, scrollIntoView for below-fold settings, scoped theme dropdown selectors), agent-scenarios.test.ts (3 — JS click for settings button, programmatic focus check, graceful 40s agent timeout with skip), phase-b.test.ts (2 — waitUntil for project box render, conditional null handling for burn-rate/cost elements). 82 E2E passing, 0 failing, 4 skipped +- **E2E test suite — 27 failures fixed** across 3 spec files: agor.test.ts (22 — stale v2 CSS selectors, v3 tab order/count, JS-dispatched KeyboardEvent for Ctrl+K, idempotent palette open/close, backdrop click close, scrollIntoView for below-fold settings, scoped theme dropdown selectors), agent-scenarios.test.ts (3 — JS click for settings button, programmatic focus check, graceful 40s agent timeout with skip), phase-b.test.ts (2 — waitUntil for project box render, conditional null handling for burn-rate/cost elements). 82 E2E passing, 0 failing, 4 skipped - **AgentPane.svelte missing closing `>`** — div tag with data-testid attributes was missing closing angle bracket, causing template parse issues ### Changed -- **WebDriverIO config** — TCP readiness probe replaces blind 2s sleep for tauri-driver startup (200ms interval, 10s deadline). Added BTERMINAL_TEST=1 passthrough in capabilities +- **WebDriverIO config** — TCP readiness probe replaces blind 2s sleep for tauri-driver startup (200ms interval, 10s deadline). Added AGOR_TEST=1 passthrough in capabilities ### Security - `claude_read_skill` path traversal: added `canonicalize()` + `starts_with()` validation to prevent reading arbitrary files via crafted skill paths (commands/claude.rs) - **Sidecar env allowlist hardening** — added `ANTHROPIC_*` to Rust-level `strip_provider_env_var()` as defense-in-depth (Claude CLI uses credentials file, not env for auth). Dual-layer stripping documented: Rust layer (first checkpoint) + JS runner layer (per-provider) - **Plugin sandbox hardening** — 13 shadowed globals in `new Function()` sandbox (window, document, fetch, globalThis, self, XMLHttpRequest, WebSocket, Function, importScripts, require, process, Deno, __TAURI__, __TAURI_INTERNALS__). `this` bound to undefined via `.call()`. 35 tests covering all shadows, permissions, and lifecycle. Known escape vectors documented in JSDoc - **WAL checkpoint** — periodic `PRAGMA wal_checkpoint(TRUNCATE)` every 5 minutes on sessions.db + btmsg.db to prevent unbounded WAL growth under sustained multi-agent load. 2 tests -- **TLS support for bterminal-relay** — optional `--tls-cert` and `--tls-key` CLI args. Server wraps TCP streams with native-tls. Client already supports `wss://` URLs. Generic handler refactor avoids code duplication +- **TLS support for agor-relay** — optional `--tls-cert` and `--tls-key` CLI args. Server wraps TCP streams with native-tls. Client already supports `wss://` URLs. Generic handler refactor avoids code duplication - **Landlock fallback logging** — improved warning message with kernel version requirement (6.2+) and documented 3 enforcement states ### Fixed @@ -104,7 +115,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - **Regression tests for btmsg/bttask bug fixes** — 49 new tests: btmsg.rs (8, in-memory SQLite with named column access regression for status vs system_prompt), bttask.rs (7, named column access + serde camelCase), sidecar strip_provider_env_var (8, all prefix combinations), btmsg-bridge.test.ts (17, camelCase fields + IPC commands), bttask-bridge.test.ts (10, camelCase + IPC), plantuml-encode.test.ts (7, hex encoding algorithm). Total: 327 vitest + 72 cargo - **Configurable stall threshold** — per-project range slider (5–60 min, step 5) in SettingsTab. `stallThresholdMin` in `ProjectConfig` (groups.json), `setStallThreshold()` API in health store with `stallThresholds` Map and `DEFAULT_STALL_THRESHOLD_MS` fallback. ProjectBox `$effect` syncs config → store on mount/change - **Memora adapter** — `MemoraAdapter` (memora-bridge.ts) implements `MemoryAdapter` interface, bridging to Memora's SQLite database (`~/.local/share/memora/memories.db`) via read-only Rust backend (`memora.rs`). FTS5 text search, tag filtering via `json_each()`. 4 Tauri commands (memora_available, memora_list, memora_search, memora_get). Registered in App.svelte onMount. 16 vitest + 7 cargo tests. MemoriesTab now shows Memora memories on startup -- **Codex provider runner** — `sidecar/codex-runner.ts` wraps `@openai/codex-sdk` (dynamic import, graceful failure if not installed). Maps Codex ThreadEvents (agent_message, reasoning, command_execution, file_change, mcp_tool_call, web_search) to common AgentMessage format via `codex-messages.ts` adapter. Sandbox/approval mode mapping from BTerminal permission modes. Session resume via thread ID. `providers/codex.ts` ProviderMeta (gpt-5.4 default, hasSandbox, supportsResume). 19 adapter tests +- **Codex provider runner** — `sidecar/codex-runner.ts` wraps `@openai/codex-sdk` (dynamic import, graceful failure if not installed). Maps Codex ThreadEvents (agent_message, reasoning, command_execution, file_change, mcp_tool_call, web_search) to common AgentMessage format via `codex-messages.ts` adapter. Sandbox/approval mode mapping from Agents Orchestrator permission modes. Session resume via thread ID. `providers/codex.ts` ProviderMeta (gpt-5.4 default, hasSandbox, supportsResume). 19 adapter tests - **Ollama provider runner** — `sidecar/ollama-runner.ts` uses direct HTTP to `localhost:11434/api/chat` with NDJSON streaming (zero external dependencies). Health check before session start. Configurable host/model/num_ctx/think via providerConfig. Supports Qwen3 extended thinking. `ollama-messages.ts` adapter maps streaming chunks to AgentMessage (text, thinking, cost with token counts). `providers/ollama.ts` ProviderMeta (qwen3:8b default, modelSelection only). 11 adapter tests - All 3 providers registered in App.svelte onMount + message-adapters.ts. `build:sidecar` builds all 3 runners - **S-1 Phase 3: Worktree isolation per project** — per-project `useWorktrees` toggle in SettingsTab. When enabled, agents run in git worktrees at `/.claude/worktrees//` via SDK `extraArgs: { worktree: sessionId }`. CWD-based worktree detection in agent-dispatcher (`detectWorktreeFromCwd()`) matches `.claude/`, `.codex/`, `.cursor/` worktree patterns on init events. Dual detection: CWD-based (primary) + tool_call-based (subagent fallback). 8 files, +125 lines, 7 new tests. 226 vitest + 42 cargo tests @@ -127,7 +138,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Collapsible cost summary in AgentPane: `cost.result` wrapped in `
` (collapsed by default, expandable with 80-char preview) (AgentPane.svelte) - Project max aspect ratio setting: `project_max_aspect` (float 0.3–3.0, default 1.0) limits project box width via CSS `max-width: calc(100vh * var(--project-max-aspect))` (SettingsTab.svelte, ProjectGrid.svelte, App.svelte) - No-implicit-push rule: `.claude/rules/52-no-implicit-push.md` — never push unless user explicitly asks -- `StartupWMClass=bterminal` in install-v2.sh .desktop template for GNOME auto-move extension compatibility +- `StartupWMClass=agor` in install-v2.sh .desktop template for GNOME auto-move extension compatibility - MarkdownPane link navigation: relative file links open in Files tab, external URLs open in system browser via `xdg-open`, anchor links scroll in-page (MarkdownPane.svelte, ProjectFiles.svelte, lib.rs) - `open_url` Tauri command for opening http/https URLs in system browser (lib.rs) - Tab system overhaul: renamed Claude→Model, Files→Docs, added 3 new tabs (Files, SSH, Memory) with PERSISTED-EAGER/LAZY mount strategies (ProjectBox.svelte) @@ -172,8 +183,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - SettingsTab: added Providers section with collapsible per-provider config panels (enabled toggle, default model, capabilities display) and per-project provider dropdown - AgentPane: capability-driven rendering via ProviderCapabilities props (hasProfiles, hasSkills, supportsResume gates) - AgentPane UI redesign: sans-serif root font (system-ui), tool calls paired with results in collapsible `
` groups, hook messages collapsed into compact labels, context window usage meter in status strip, cost bar made minimal (no background), session summary with translucent background, two-phase scroll anchoring, tool-aware output truncation (Bash 500/Read 50/Glob 20 lines), colors softened via `color-mix()`, responsive margins via container queries (AgentPane.svelte) -- MarkdownPane: added inner scroll wrapper with `container-type: inline-size`, responsive padding via shared `--bterminal-pane-padding-inline` variable (MarkdownPane.svelte) -- Added `--bterminal-pane-padding-inline: clamp(0.75rem, 3.5cqi, 2rem)` shared CSS variable for responsive pane padding (catppuccin.css) +- MarkdownPane: added inner scroll wrapper with `container-type: inline-size`, responsive padding via shared `--agor-pane-padding-inline` variable (MarkdownPane.svelte) +- Added `--agor-pane-padding-inline: clamp(0.75rem, 3.5cqi, 2rem)` shared CSS variable for responsive pane padding (catppuccin.css) ### Fixed - FilesTab invalid HTML nesting: file tab bar used `