docs: update meta files for S-1 Phase 2 filesystem write detection
This commit is contained in:
parent
e5d9f51df7
commit
d1ce031624
5 changed files with 48 additions and 8 deletions
|
|
@ -5,7 +5,7 @@
|
|||
- v1 is a single-file Python app (`bterminal.py`). Changes are localized.
|
||||
- v2 docs are in `docs/`. Architecture decisions are in `docs/task_plan.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 Complete + S-1 Conflict Detection): project groups, workspace store, 12 Workspace components, session continuity, workspace teardown, file overlap conflict detection (Bash writes, dismiss/acknowledge, worktree suppression), dead v2 component cleanup. 194 vitest + 34 cargo tests.
|
||||
- v3 Mission Control (All Phases 1-10 Complete + S-1 Phase 1/1.5/2 Conflict Detection): project groups, workspace store, 12 Workspace components, session continuity, workspace teardown, file overlap conflict detection (Bash writes, dismiss/acknowledge, worktree suppression), inotify-based external write detection (S-1 Phase 2), dead v2 component cleanup. 202 vitest + 39 cargo tests.
|
||||
- v3 docs: `docs/v3-task_plan.md`, `docs/v3-findings.md`, `docs/v3-progress.md`.
|
||||
- Consult Memora (tag: `bterminal`) before making architectural changes.
|
||||
|
||||
|
|
@ -53,9 +53,9 @@
|
|||
- Notifications use ephemeral toast system: `notifications.svelte.ts` store (max 5, 4s auto-dismiss), `ToastContainer.svelte` display. Agent dispatcher emits toasts on agent complete/error/crash.
|
||||
- StatusBar → Mission Control bar: running/idle/stalled agent counts (color-coded), total $/hr burn rate, "needs attention" dropdown priority queue (up to 5 cards sorted by urgency score, click-to-focus), total tokens + cost. Uses health.svelte.ts store (not workspace store for health signals).
|
||||
- health.svelte.ts store: per-project health tracking via ProjectTracker map. ActivityState = inactive|running|idle|stalled (15-min stall threshold). Burn rate from 5-min EMA costSnapshots. Context pressure = tokens/model limit. File conflict count from conflicts.svelte.ts. Attention scoring: stalled=100, error=90, ctx>90%=80, file_conflict=70, ctx>75%=40. 5-second tick timer (auto-stop/start). API: trackProject(), recordActivity(), recordToolDone(), recordTokenSnapshot(), getProjectHealth(), getAttentionQueue(), getHealthAggregates().
|
||||
- conflicts.svelte.ts store: per-project file overlap detection. Records Write/Edit/Bash-write tool_call file paths per session. Detects when 2+ sessions in same worktree write same file. Worktree-aware: sessions in different worktrees don't conflict. Dismissible: acknowledgeConflicts(projectId) suppresses badge until new session writes. recordFileWrite() returns true on new conflict → toast notification. clearSessionWrites() on agent completion. clearAllConflicts() on group switch. Session-scoped, no persistence.
|
||||
- conflicts.svelte.ts store: per-project file overlap + external write detection. Records Write/Edit/Bash-write tool_call file paths per session. Detects when 2+ sessions in same worktree write same file. S-1 Phase 2: inotify-based external write detection via fs_watcher.rs — uses 2s timing heuristic (AGENT_WRITE_GRACE_MS) to distinguish agent writes from external. EXTERNAL_SESSION_ID='__external__' sentinel. Worktree-aware. Dismissible. recordExternalWrite() for inotify events. FileConflict.isExternal flag, ProjectConflicts.externalConflictCount. Session-scoped, no persistence.
|
||||
- tool-files.ts utility: shared extractFilePaths(tc) → ToolFileRef[], extractWritePaths(tc) → string[], extractWorktreePath(tc) → string|null. Bash write detection via regex (>, >>, sed -i, tee, cp, mv). Used by ContextTab (all ops) and agent-dispatcher (writes + worktree tracking for conflict detection).
|
||||
- ProjectHeader shows status dot (green pulse=running, gray=idle, orange pulse=stalled, dim=inactive) + file conflict badge (red clickable button with ✕ — acknowledgeConflicts on click) + context pressure badge (>90% red, >75% orange, >50% yellow) + burn rate badge ($/hr). Health prop from ProjectBox via getProjectHealth().
|
||||
- ProjectHeader shows status dot (green pulse=running, gray=idle, orange pulse=stalled, dim=inactive) + external write badge (orange ⚡ clickable, shown when externalConflictCount > 0) + agent conflict badge (red ⚠ clickable with ✕) + context pressure badge (>90% red, >75% orange, >50% yellow) + burn rate badge ($/hr). Health prop from ProjectBox via getProjectHealth(). ProjectBox starts/stops fs watcher per project CWD via $effect.
|
||||
- session_metrics SQLite table: per-project historical session data (project_id, session_id, timestamps, peak_tokens, turn_count, tool_call_count, cost_usd, model, status, error_message). 100-row retention per project. Tauri commands: session_metric_save, session_metrics_load. Persisted on agent completion via agent-dispatcher.
|
||||
- Agent tree (AgentTree.svelte) uses SVG with recursive layout. Tree data built by `agent-tree.ts` utility from agent messages.
|
||||
- ctx integration opens `~/.claude-context/context.db` as SQLITE_OPEN_READ_ONLY — never writes. CtxDb uses Option<Connection> for graceful absence if DB doesn't exist.
|
||||
|
|
|
|||
|
|
@ -11,6 +11,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- `claude_read_skill` path traversal: added `canonicalize()` + `starts_with()` validation to prevent reading arbitrary files via crafted skill paths (lib.rs)
|
||||
|
||||
### Added
|
||||
- **S-1 Phase 2: Filesystem write detection** — inotify-based real-time file change detection via `ProjectFsWatcher` (fs_watcher.rs). Watches project CWDs recursively, filters .git/node_modules/target, debounces 100ms per-file (fs_watcher.rs, lib.rs)
|
||||
- External write conflict detection: timing heuristic (2s grace window) distinguishes agent writes from external edits. `EXTERNAL_SESSION_ID` sentinel, `recordExternalWrite()`, `getExternalConflictCount()`, `FileConflict.isExternal` flag (conflicts.svelte.ts)
|
||||
- Separate external write badge (orange ⚡) and agent conflict badge (red ⚠) in ProjectHeader (ProjectHeader.svelte)
|
||||
- `externalConflictCount` in ProjectHealth interface with attention scoring integration (health.svelte.ts)
|
||||
- Frontend bridge for filesystem watcher: `fsWatchProject()`, `fsUnwatchProject()`, `onFsWriteDetected()` (fs-watcher-bridge.ts)
|
||||
- ProjectBox `$effect` starts/stops fs watcher per project CWD on mount/unmount with toast on new external conflict (ProjectBox.svelte)
|
||||
- Collapsible text messages in AgentPane: model responses wrapped in `<details open>` (open by default, user-collapsible with first-line preview) (AgentPane.svelte)
|
||||
- Collapsible cost summary in AgentPane: `cost.result` wrapped in `<details>` (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)
|
||||
|
|
|
|||
|
|
@ -35,7 +35,8 @@ Terminal emulator with SSH and Claude Code session management. v1 (GTK3+VTE Pyth
|
|||
| `v2/bterminal-relay/` | Standalone relay binary (WebSocket server, token auth, CLI) |
|
||||
| `v2/src-tauri/src/pty.rs` | PTY backend (thin re-export from bterminal-core) |
|
||||
| `v2/src-tauri/src/groups.rs` | Groups config (load/save ~/.config/bterminal/groups.json) |
|
||||
| `v2/src-tauri/src/lib.rs` | Tauri commands (pty + agent + session + file + settings + 12 remote + 4 claude + 2 groups) |
|
||||
| `v2/src-tauri/src/fs_watcher.rs` | ProjectFsWatcher (inotify per-project recursive file change detection, S-1 Phase 2) |
|
||||
| `v2/src-tauri/src/lib.rs` | Tauri commands (pty + agent + session + file + fs_watcher + settings + 12 remote + 4 claude + 2 groups) |
|
||||
| `v2/src-tauri/src/sidecar.rs` | SidecarManager (thin re-export from bterminal-core) |
|
||||
| `v2/src-tauri/src/event_sink.rs` | TauriEventSink (implements EventSink for AppHandle) |
|
||||
| `v2/src-tauri/src/remote.rs` | RemoteManager (WebSocket client connections to relays) |
|
||||
|
|
@ -62,6 +63,7 @@ Terminal emulator with SSH and Claude Code session management. v1 (GTK3+VTE Pyth
|
|||
| `v2/src/lib/adapters/remote-bridge.ts` | Remote machine management IPC wrapper |
|
||||
| `v2/src/lib/adapters/files-bridge.ts` | File browser IPC wrapper (list_directory_children, read_file_content) |
|
||||
| `v2/src/lib/adapters/memory-adapter.ts` | Pluggable memory adapter interface (MemoryAdapter, registry) |
|
||||
| `v2/src/lib/adapters/fs-watcher-bridge.ts` | Filesystem watcher IPC wrapper (project CWD write detection) |
|
||||
| `v2/src/lib/adapters/telemetry-bridge.ts` | Frontend telemetry bridge (routes events to Rust tracing via IPC) |
|
||||
| `docker/tempo/` | Docker compose: Tempo + Grafana for trace visualization (port 9715) |
|
||||
| `v2/src/lib/stores/machines.svelte.ts` | Remote machine state store (Svelte 5 runes) |
|
||||
|
|
@ -78,7 +80,7 @@ Terminal emulator with SSH and Claude Code session management. v1 (GTK3+VTE Pyth
|
|||
| `v2/src/lib/components/Workspace/ContextTab.svelte` | LLM context window visualization (stats, token meter, file refs, turn breakdown) |
|
||||
| `v2/src/lib/components/Workspace/CodeEditor.svelte` | CodeMirror 6 wrapper (15 languages, Catppuccin theme, save/blur callbacks) |
|
||||
| `v2/src/lib/stores/health.svelte.ts` | Project health store (activity state, burn rate, context pressure, file conflicts, attention scoring) |
|
||||
| `v2/src/lib/stores/conflicts.svelte.ts` | File overlap conflict detection (per-project, session-scoped, worktree-aware, dismissible) |
|
||||
| `v2/src/lib/stores/conflicts.svelte.ts` | File overlap + external write conflict detection (per-project, session-scoped, worktree-aware, dismissible, inotify-backed) |
|
||||
| `v2/src/lib/utils/tool-files.ts` | Shared file path extraction from tool_call inputs (extractFilePaths, extractWritePaths, extractWorktreePath) |
|
||||
| `v2/src/lib/components/StatusBar/StatusBar.svelte` | Mission Control bar (agent states, $/hr burn rate, attention queue, cost) |
|
||||
| `v2/src/lib/components/Notifications/ToastContainer.svelte` | Toast notification display |
|
||||
|
|
|
|||
4
TODO.md
4
TODO.md
|
|
@ -12,12 +12,12 @@
|
|||
- [ ] **Agent Teams real-world testing** -- Env var whitelist fix done. 3 test sessions ran ($1.10, $0.69, $1.70) but model didn't spawn subagents — needs complex multi-part prompts to trigger delegation. Test with CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1.
|
||||
- [ ] **Configurable stall threshold** -- health.yaml per-project config for stall threshold (currently hardcoded 15 min). Adaptive suggestions after 50 sessions from session_metrics data.
|
||||
- [ ] **Agent provider adapter pattern** -- Abstract model interface (ProviderConfig, ProviderCapabilities) for multi-model support (Claude, Codex, Ollama). Rename agent-runner.mjs → claude-runner.mjs, capability gates in UI.
|
||||
- [ ] **S-1 Phase 2 — filesystem write detection** -- inotify-based file change detection (already have notify crate). PID attribution to distinguish BTerminal-managed vs external writes. Always-on red "write conflict" cards.
|
||||
- [ ] **S-2 — session anchors** -- Preserve first 5 turns / 2K tokens verbatim through checkpoint chains. Pin additional turns via AST conversation tree action.
|
||||
- [ ] **Worktree isolation per project (S-1 Phase 3)** -- Three parts: (1) **UI toggle**: useWorktrees checkbox in SettingsTab per-project settings, persisted in groups.json ProjectConfig. (2) **Spawn with --worktree**: when useWorktrees=true, pass `--worktree <session-slug>` flag to Claude Code CLI via sidecar AgentQueryOptions. Sidecar creates worktree at `<cwd>/.claude/worktrees/<name>/`, agent CWD is set there. (3) **Worktree detection improvement**: current extractWorktreePath checks tool_call params, but agents don't signal worktrees in tool calls — the real signal is CWD-based (path contains `.claude/worktrees/`) or from sidecar notification events (`worktreePath`/`worktreeBranch` fields, Claude Code v2.1.72+). Update agent-dispatcher to parse init event CWD or notification fields. For Codex/Cursor agents: detect `$CODEX_HOME/worktrees/` or `~/.cursor/worktrees/` CWD patterns. Conflict suppression already works once worktree is registered via setSessionWorktree().
|
||||
|
||||
## Completed
|
||||
|
||||
- [x] **Filesystem Write Detection (S-1 Phase 2)** -- inotify-based file change detection via notify crate (fs_watcher.rs). Timing heuristic (2s grace) for PID attribution — suppresses agent's own writes, surfaces external edits. EXTERNAL_SESSION_ID sentinel, recordExternalWrite(), externalConflictCount. Orange "ext write" badge + red "agent conflict" badge in ProjectHeader. ProjectBox $effect starts/stops per-project. 202/202 vitest + 39/39 cargo tests. | Done: 2026-03-11
|
||||
- [x] **Conflict Detection Enhancements (S-1 Phase 1.5)** -- Bash write detection (>, >>, sed -i, tee, cp, mv). Acknowledge/dismiss conflicts (clickable badge). Worktree-aware conflict suppression. useWorktrees ProjectConfig field. 194/194 tests. | Done: 2026-03-11
|
||||
- [x] **File Overlap Conflict Detection (S-1 Phase 1)** -- conflicts.svelte.ts store tracks per-session Write/Edit file paths. Detects 2+ agents writing same file. Health attention score=70. Toast on conflict. Red badge in ProjectHeader + StatusBar. Shared tool-files.ts utility. 170/170 tests. | Done: 2026-03-10
|
||||
- [x] **Project Health Dashboard (S-3)** -- health.svelte.ts store (activity state, burn rate, context pressure, attention scoring). Mission Control status bar (running/idle/stalled counts, $/hr, attention queue). ProjectHeader indicators (status dot, ctx%, $/hr). session_metrics SQLite table (100-row retention). Metric persistence on agent completion. | Done: 2026-03-10
|
||||
|
|
@ -27,5 +27,3 @@
|
|||
- [x] **Tab system overhaul** -- Renamed Claude→Model, Files→Docs. Added Files (VSCode-style tree+viewer), SSH (CRUD+launch), Memory (pluggable adapter) tabs. PERSISTED-EAGER/LAZY mount strategies. Rust list_directory_children + read_file_content commands. | Done: 2026-03-10
|
||||
- [x] **AgentPane collapsibles + aspect ratio** -- Text messages collapsible (open by default), cost summary collapsed by default. Project max aspect ratio setting (0.3–3.0, default 1.0) with CSS var + SettingsTab stepper. No-implicit-push rule 52. Desktop StartupWMClass. | Done: 2026-03-09
|
||||
- [x] **AgentPane + MarkdownPane UI redesign** -- AgentPane: sans-serif font, tool call/result pairing via $derived.by, hook message collapsing, context meter, muted colors via color-mix(), responsive margins via container queries. MarkdownPane: container query wrapper, shared responsive padding variable. Tribunal-elected design (S-3-R4, 88% confidence). 139/139 tests pass. | Done: 2026-03-09
|
||||
- [x] **E2E testing — consolidated & expanded** -- Consolidated 4 spec files into single bterminal.test.ts (Tauri single-session requirement). 25 tests across 4 describe blocks: Smoke(6), Workspace(8), Settings(6), Keyboard(5). Fixed WebDriver clicks on Svelte components via browser.execute(), removed tauri-plugin-log (redundant with telemetry::init()). | Done: 2026-03-08
|
||||
- [x] **Workspace teardown race fix** -- Added pendingPersistCount counter + waitForPendingPersistence() fence in agent-dispatcher.ts. switchGroup() awaits persistence before clearing state. Last open HIGH audit finding resolved. | Done: 2026-03-08
|
||||
|
|
|
|||
|
|
@ -536,3 +536,37 @@ All editor themes map to the same `--ctp-*` CSS custom property names (26 vars).
|
|||
#### Verification
|
||||
- [x] vitest: 194/194 tests pass (+24 new: 5 extractWorktreePath, 10 bash write, 9 acknowledge/worktree)
|
||||
- [x] cargo test: 34/34 pass
|
||||
|
||||
### Session: 2026-03-11 — S-1 Phase 2: Filesystem Write Detection
|
||||
|
||||
#### Rust Backend — ProjectFsWatcher
|
||||
- [x] New module `v2/src-tauri/src/fs_watcher.rs` — per-project recursive inotify watchers via notify crate v6
|
||||
- [x] Debouncing (100ms per-file), ignored dirs (.git/, node_modules/, target/, etc.)
|
||||
- [x] Emits `fs-write-detected` Tauri events with FsWritePayload { project_id, file_path, timestamp_ms }
|
||||
- [x] Two Tauri commands: `fs_watch_project`, `fs_unwatch_project`
|
||||
- [x] ProjectFsWatcher added to AppState, initialized in setup()
|
||||
- [x] 5 Rust unit tests for path filtering (should_ignore_path)
|
||||
|
||||
#### Frontend Bridge
|
||||
- [x] New `v2/src/lib/adapters/fs-watcher-bridge.ts` — fsWatchProject(), fsUnwatchProject(), onFsWriteDetected()
|
||||
|
||||
#### External Write Detection (conflicts store)
|
||||
- [x] EXTERNAL_SESSION_ID = '__external__' sentinel for non-agent writers
|
||||
- [x] agentWriteTimestamps Map — tracks when agents write files (for timing heuristic)
|
||||
- [x] recordExternalWrite(projectId, filePath, timestampMs) — 2s grace window suppresses agent's own writes
|
||||
- [x] getExternalConflictCount(projectId) — counts external-only conflicts
|
||||
- [x] FileConflict.isExternal flag, ProjectConflicts.externalConflictCount field
|
||||
- [x] clearAllConflicts/clearProjectConflicts clear timestamp state
|
||||
|
||||
#### Health Store Integration
|
||||
- [x] externalConflictCount added to ProjectHealth interface
|
||||
- [x] Attention reason includes "(N external)" note when external conflicts present
|
||||
|
||||
#### UI Updates
|
||||
- [x] ProjectBox $effect: starts/stops fs watcher per project CWD, listens for events, calls recordExternalWrite
|
||||
- [x] ProjectHeader: split conflict badge into orange "ext write" badge + red "agent conflict" badge
|
||||
- [x] Toast notification on new external write conflict
|
||||
|
||||
#### Verification
|
||||
- [x] vitest: 202/202 tests pass (+8 new external write tests)
|
||||
- [x] cargo test: 39/39 pass (+5 new fs_watcher tests)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue