Add Amp agent support and centralize agent registry - #72
Conversation
Replace hardcoded class:agent-* bindings in App.svelte with a single
dynamic style:background={agentColor()} driven by the centralized
agentColor() utility. This eliminates the need to add new CSS classes
per agent and removes dead per-agent CSS rules.
Fix CommandPalette.svelte nested ternary dot-color logic to use
agentColor(), resolving incorrect colors for Gemini and Cursor sessions.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add AgentAmp agent type and ParseAmpSession() for ~/.local/share/amp/threads/T-*.json files. - Session ID namespaced as "amp:<thread-id>" - Start time from epoch-ms "created" field via time.UnixMilli - End time from meta.traces[last].endTime (zero when absent) - Project from env.initial.trees[0].displayName, fallback "amp" - FirstMessage prefers title field; falls back to first user message - Calls ExtractTextContent() for all content blocks (no custom extractor) - Returns nil for empty threads (non-interactive) - AmpThreadID() helper for fast ID extraction without full parse Tests cover: basic thread, tool use + thinking, no env, no title, no meta.traces, empty thread, first message truncation, error paths. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Config:
- Add AmpDir field (default ~/.local/share/amp/threads, env AMP_DIR)
Discovery:
- Add DiscoverAmpSessions(): matches T-*.json in the threads dir
- Add FindAmpSourceFile() for single-session re-sync lookup
Engine:
- Add ampDir field and parameter to NewEngine()
- Add case parser.AgentAmp to processFile() switch
- Add processAmp() modeled after processGemini()
- Update syncAllLocked() to discover and include Amp files
- Add amp: prefix handling to FindSourceFile() and SyncSingleSession()
Server (main):
- Pass cfg.AmpDir to NewEngine()
- Watch AmpDir for file changes
- Warn on missing AmpDir
- Update help text to include Amp and AMP_DIR env var
Frontend:
- Add --accent-coral (#f34e3f) CSS variable for Amp brand color
- Add { name: "amp", color: "var(--accent-coral)" } to KNOWN_AGENTS
- Update agents.test.ts to cover amp color
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Amp uses different field names than Claude Code for the same logical tools (cmd vs command for Bash, path vs file_path for Read) and has agent-specific tools (edit_file, create_file, shell_command, glob, look_at, apply_patch, undo_edit, finder, read_web_page, skill) that were falling through to the generic [Tool: name] fallback. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
roborev: Combined Review (
|
When the last trace lacks an endTime but earlier traces have one, EndedAt was incorrectly left as zero. Scan backward instead of only checking the last trace.
roborev: Combined Review (
|
Update all agent lists, supported agents table, env var references, and parser/project structure descriptions to include Amp. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
roborev: Combined Review (
|
Render edit_file as [Write: ...] in content.go to match Gemini's display and taxonomy mapping, keeping behavior consistent across agents. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Keeping edit_file consistent with Gemini — both display and taxonomy map to "Write". |
roborev: Combined Review (
|
|
Thanks, I'm going to work on some refactoring to make it easier to add new agents |
Replace per-agent fields across Config, Engine, and main.go with a central AgentDef registry that drives configuration, discovery, sync, and file watching. Move DiscoveredFile and all discover/findSource functions from sync to parser, adding them as function fields on AgentDef to eliminate separate dispatch tables. Adding a new agent now requires only a Registry entry in parser/types.go instead of modifying 13+ locations across 6+ files. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Use AgentByType(AgentClaude) instead of fragile Registry[0] positional fallback in AgentByPrefix - Add findContainingDir helper so processCursor validates containment against the correct root when multiple Cursor dirs are configured (was hardcoded to cursorDirs[0]) - Add integration test for multi-dir Cursor covering SyncAll, SyncPaths, and FindSourceFile across non-first directories Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Deep-copy cfg.AgentDirs in NewEngine to prevent callers from mutating the engine's state after construction - Log a warning when a config file key can't be parsed as a string array instead of silently ignoring it Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add TestNewEngineDefensiveCopy: mutates the original AgentDirs map after NewEngine and verifies the engine still syncs correctly - Add TestLoadFile_MalformedDirValueLogsWarning: writes a string instead of []string for claude_project_dirs and asserts the warning is logged and defaults are preserved Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Restore previous log.Writer() instead of hardcoding os.Stderr, preventing test-order-dependent logger state - Add slice-element mutation path to TestNewEngineDefensiveCopy to catch regressions where the map is copied but slices are shared Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
roborev: Combined Review (
|
classifyOnePath's Cursor and Claude-subagent blocks returned false immediately when a path was under their root but didn't match the expected structure. This prevented later agent blocks from checking the path, silently dropping valid files when roots overlap. Change both to continue so classification falls through to subsequent agents. Add TestSyncPathsClassifyFallsThrough covering an Amp file under a nested Cursor root. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Cover the Claude-subagent continue path (non-agent- filename in a subagents dir) with an overlapping-roots test that verifies classification falls through to Amp. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
roborev: Combined Review (
|
ParseAmpSession accepted any non-empty JSON id, but FindAmpSourceFile and SyncSingleSession require the T-<valid> pattern. A malformed in-file id would be ingested successfully but later fail source lookup and resync. Validate the JSON id with isValidAmpThreadID at parse time and fall back to the filename-derived ID when invalid or missing. Add regression tests for mismatched and missing id scenarios. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
roborev: Combined Review (
|
When both the filename and JSON id are valid but differ, FindAmpSourceFile constructs the path from the session ID, so using the JSON id would fail source lookup. Always prefer the filename-derived ID; fall back to JSON id only when the filename doesn't yield a valid T-<id> pattern. Add test for valid-but-mismatched JSON id vs filename case. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add subtest for valid JSON id with non-matching filename (bad-name.json + id:"T-from-json") to lock in the fallback behavior where the JSON id is used when the filename doesn't yield a valid Amp thread ID. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
roborev: Combined Review (
|
|
thanks! |
## Summary **Amp agent support:** - Add Amp as a supported agent type, syncing sessions from `~/.local/share/amp/threads/` with a dedicated parser, file discovery, and sync engine wiring - Parse Amp's JSON thread format (`T-*.json`), extracting user messages, assistant responses, and tool calls (with skill name extraction from Amp's lowercase `skill` tool) - Extend shared tool content extraction to handle Amp's field name variants (`path` vs `file_path`, `cmd` vs `command`) and add display formatting for Amp-native tools (`edit_file`, `shell_command`, `look_at`, `apply_patch`, etc.) **Agent registry refactor:** - Introduce `AgentDef` struct and `parser.Registry` as a central source of truth for all agent metadata (type, display name, env var, config key, default dirs, ID prefix, watch subdir, file-based flag, discover/findSource functions) - Replace per-agent fields in `Config` and `Engine` with `AgentDirs map[parser.AgentType][]string` driven by the registry - Replace `NewEngine`'s 9 positional parameters with `EngineConfig` struct - Move all discovery and findSource functions from `sync` to `parser` so they can be referenced directly from `AgentDef` - Registry-driven loops in `main.go` for missing-dir warnings and file watcher setup - Adding a new agent now requires one `Registry` entry and a parser — no changes to config, engine, or main **Other fixes:** - Use `agentColor()` consistently across App.svelte and CommandPalette, fixing wrong colors for Gemini and Cursor sessions - Fix incorrect test expectation in `setProjectFilter` — agent filter is preserved across project switches, not reset - Defensive deep-copy of `AgentDirs` in `NewEngine` to prevent post-construction mutation - Log warning on malformed config file array values instead of silently ignoring Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: Wes McKinney <wesmckinn+git@gmail.com>
Summary
Amp agent support:
~/.local/share/amp/threads/with a dedicated parser, file discovery, and sync engine wiringT-*.json), extracting user messages, assistant responses, and tool calls (with skill name extraction from Amp's lowercaseskilltool)pathvsfile_path,cmdvscommand) and add display formatting for Amp-native tools (edit_file,shell_command,look_at,apply_patch, etc.)Agent registry refactor:
AgentDefstruct andparser.Registryas a central source of truth for all agent metadata (type, display name, env var, config key, default dirs, ID prefix, watch subdir, file-based flag, discover/findSource functions)ConfigandEnginewithAgentDirs map[parser.AgentType][]stringdriven by the registryNewEngine's 9 positional parameters withEngineConfigstructsynctoparserso they can be referenced directly fromAgentDefmain.gofor missing-dir warnings and file watcher setupRegistryentry and a parser — no changes to config, engine, or mainOther fixes:
agentColor()consistently across App.svelte and CommandPalette, fixing wrong colors for Gemini and Cursor sessionssetProjectFilter— agent filter is preserved across project switches, not resetAgentDirsinNewEngineto prevent post-construction mutationGenerated with Claude Code