feat: competitive parity with Copilot CLI and Claude Code#2
feat: competitive parity with Copilot CLI and Claude Code#2
Conversation
- Upgrade github.com/GoCodeAlone/workflow to v0.3.40 - ratchet (v0.1.15) and workflow-plugin-agent (v0.3.1) already at latest - No breaking API changes required (module.PipelineContext etc. unchanged) - All tests pass Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add PlanStep, Plan, ApprovePlanReq, RejectPlanReq messages - Add plan_proposed and plan_step_update to ChatEvent oneof - Add ApprovePlan (streaming) and RejectPlan RPCs Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add CronJob, CreateCronReq, CronJobList, CronJobReq proto messages
- Add CreateCron/ListCrons/PauseCron/ResumeCron/StopCron RPCs
- Implement CronScheduler with SQLite persistence and goroutine-per-job
- Support Go duration strings ("5m") and simple cron expressions ("*/10 * * * *")
- Reload active jobs from DB on daemon restart (Start method)
- Add cron_jobs table to initDB
- Wire CronScheduler into Service; implement all 5 RPCs in service.go
- Add client methods for all cron RPCs
- Add /loop <interval> <cmd> and /cron subcommands to TUI commands
- Add 6 tests: CreateInterval, Pause, Resume, Stop, PersistReload, ParseSchedule
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…oken-limit) Add 8 new event constants and AllEvents slice for documentation/validation. Update Run() docs to list new template data keys (plan_id, fleet_id, agent_name, agent_role, cron_id, tokens_used, tokens_limit). Add tests: NewEvents, TemplateExpansion_NewKeys, AllEventsComplete. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add PlanManager with Create/Get/ForSession/Approve/Reject/UpdateStep - Wire plans into Service struct (NewService initializes PlanManager) - Implement ApprovePlan and RejectPlan RPCs on Service - Add PlanView component with step navigation, skip toggle, approve/reject keybinds (↑↓/jk navigate, space toggle skip, Enter approve, Esc reject) - Add ApprovePlan/RejectPlan client methods - Handle ChatEvent_PlanProposed and ChatEvent_PlanStepUpdate in chat page - Route PlanApproveMsg/PlanRejectMsg from PlanView to daemon RPCs - Add /plan, /approve, /reject slash commands - Fix cron_test.go field name: job.Id → job.ID - Also fix proto regeneration to regenerate with fleet+cron types - Fix build: remove duplicate cron function definitions Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
**Hooks (Task 16):**
- Add PrePlan, PostPlan, PreFleet, PostFleet, OnAgentSpawn, OnAgentComplete,
OnTokenLimit, OnCronTick event constants
- Add AllEvents slice for documentation; update Run() docs for new template keys
- Tests: NewEvents, TemplateExpansion_NewKeys, AllEventsComplete
**MCP CLI discovery (Task 17):**
- New internal/mcp package: Discoverer checks exec.LookPath for gh, docker, kubectl
- Registers CLI-wrapping plugin.Tool implementations via ToolRegistry.RegisterMCP
- Caches discovery results; InvalidateCache/Enable/Disable for runtime control
- Wire MCPDiscoverer into EngineContext; runs discovery in background goroutine
- Add /mcp list|enable|disable slash commands
- Tests: GHFound, NoCLIs, CacheResults, Enable, Disable
**Model routing (Task 18):**
- Add ModelRouting{SimpleTaskModel, ComplexTaskModel, ReviewModel} to config.Config
- internal/daemon/model_routing.go: ClassifyStep heuristic + ModelForStep mapper
- FleetManager stores routing config; workers get model assigned at creation
- NewEngineContext loads ModelRouting from config; NewService passes to FleetManager
- Tests: Classification, ModelForStep, EmptyConfig
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add FleetPanel component (internal/tui/components/fleet.go) with: - Worker table: Name | Step | Status | Model | Elapsed - Spinner/checkmark/X status icons for running/completed/failed - Keybind K to kill selected worker - FleetWorkerKillMsg and FleetStatusUpdatedMsg messages - Add fleet TUI tests (4 passing) - Add config.ModelRouting struct (SimpleTaskModel, ComplexTaskModel, ReviewModel) for per-step model selection Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…k 13) - Add LoadBuiltins() with go:embed for internal/agent/builtins/*.yaml - Add code-reviewer.yaml with correct ratchetplugin tool names - Add /compact and /review slash commands - Fix teamStart() to use correct StartTeam client signature - Add TestBuiltinAgents_CodeReviewerLoads, TestParseCompact, TestReviewCommand_Parse Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add Feedback field to Plan proto message (field 7) - Reject(): add state guard (approved/executing/completed/rejected → error), store feedback - Move ApprovePlan/RejectPlan RPC handlers from plans.go to service.go - Update tests: verify feedback stored, verify state guard for reject Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add ContextCompressedEvent message to proto (field 13 in ChatEvent oneof) - Add tokens *TokenTracker to Service struct, initialized in NewService - Wire into handleChat: AddTokens after each exchange, ShouldCompress check, Compress + replaceHistory when threshold exceeded, stream context_compressed event - Add replaceHistory() helper to persist compressed message history Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add Job/JobList/JobReq proto messages and ListJobs/PauseJob/ResumeJob/KillJob RPCs - Implement JobRegistry with SessionJobProvider, FleetJobProvider, TeamJobProvider, CronJobProvider - Add ListJobs/PauseJob/ResumeJob/KillJob service RPCs wired to job registry - Create JobPanel TUI component with auto-refresh, navigation, pause/kill actions - Add Ctrl+J toggle in app.go to show/hide job panel - Add /jobs slash command to list active jobs Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fixes UTF-8 multi-byte character truncation in buildFallbackSummary. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- cron.go: store parent context in CronScheduler; Resume now propagates it to restarted goroutines instead of using context.Background() - hooks.go: escape template data values with single-quoting before sh -c substitution to prevent shell injection attacks - discovery.go: split extra args via strings.Fields so multi-word args like "exec mycontainer ls" are passed as separate tokens, not one Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- fleet.go: deep-copy FleetWorker structs in GetStatus and sendFleetStatus to eliminate data race between goroutines sharing *FleetWorker pointers - teams.go: use ag.mu.Lock() on write path when marking agents complete, consistent with ag.mu.RLock() used in GetStatus read path - teams.go: set orchestrator model to "" instead of provider name string - pages/team.go: wire 'k' key to emit KillAgentMsg (was shown in hint but never dispatched) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- integration_cron_test.go: full gRPC lifecycle test (create→list→ pause→resume→stop) and tick test verifying run_count increments - cron.go: fix startEntry to use parentCtx instead of the RPC request context; request context cancels on RPC return, killing the goroutine before any ticks fire - cron.go: Stop now returns an error for non-existent job IDs Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Covers task 10 integration test coverage for fleet lifecycle and worker kill, team agent spawning and message routing, cron create/pause/resume/stop lifecycle, and job registry aggregate/unknown-type error paths. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Team view 'k' key now actually calls the daemon to kill the agent, instead of dispatching a message that was never handled.
- Replace providerMessage with provider.Message from workflow-plugin-agent - Replace compressMessages with Compress (exported function) - Replace loadBuiltinAgentDefs with agent.LoadBuiltins() - Add missing fmt and agent imports All 8 QA tests (Tasks 29-32) pass; full race suite clean. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add qa_helpers_test.go with type aliases and wrapper functions (providerMessage, compressMessages, loadBuiltinAgentDefs) so qa_test.go can reference compression and agent builtin APIs without import cycles in package daemon. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Also verifies KillAgentMsg handler in app.go is already wired to client.KillAgent (confirmed present, no further change needed). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…r ctx - pages/team.go: Add ID field to AgentCard, populate from Agent.Id in TeamStatusMsg, dispatch KillAgentMsg with "team_agent:<uuid>" so kill routes correctly through the job registry. - daemon/jobs.go: Add ResumeJob to JobProvider interface; implement real resume for CronJobProvider (calls cs.Resume), no-op errors for others. - tui/app.go: Call tea.Batch(chat.Init(), jobPanel.Init()) in transitionToChat so job panel ticker starts immediately. - daemon/actors.go: Accept context.Context in NewActorManager and propagate to sys.Start and rehydrateSessions instead of Background(). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Runs on push to master and PRs: - Build: verifies compilation - Test: race detector + coverage upload - Lint: golangci-lint - Vet: go vet Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…flow 1. oauth.go:115 — reflected XSS: user-controlled 'error' query param was rendered as raw HTML. Fixed with html.EscapeString(). 2. fleet.go:22 — integer overflow: strconv.Atoi returns platform-dependent int, cast to int32 without bounds check. Added math.MaxInt32 guard. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR adds 12 major features to ratchet-cli for competitive parity with GitHub Copilot CLI and Claude Code, including plan mode, fleet mode, team mode, context auto-compression, code review agent, cron/loop scheduling, enhanced hooks, MCP CLI discovery, per-agent model routing, session actors (goakt v4), and a job control panel. It also upgrades the workflow dependency from v0.3.30 to v0.3.40.
Changes:
- Adds new daemon subsystems:
PlanManager,FleetManager,CronScheduler,TeamManager,TokenTracker,JobRegistry,ActorManager, andDiscovererwith full gRPC service wiring - Adds TUI components (
PlanView,FleetPanel,JobPanel) and slash commands (/plan,/approve,/reject,/fleet,/team,/loop,/cron,/jobs,/compact,/review,/mcp,/cost) with keyboard shortcuts (Ctrl+J,Ctrl+T) - Adds comprehensive test coverage across all new subsystems including unit, integration, and QA validation tests
Reviewed changes
Copilot reviewed 59 out of 60 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| internal/tui/components/plan.go, plan_test.go | New PlanView TUI component with step navigation, skip toggle, approve/reject |
| internal/tui/components/fleet.go, fleet_test.go | New FleetPanel TUI component for fleet worker status display |
| internal/tui/components/jobpanel.go, jobpanel_test.go | New JobPanel TUI component for unified job control |
| internal/tui/pages/team.go | Adds agent ID field, kill-agent support, TeamStatusMsg refresh |
| internal/tui/pages/chat.go | Integrates PlanView into chat, handles plan approve/reject messages |
| internal/tui/app.go | Adds JobPanel toggle (Ctrl+J), KillAgentMsg routing |
| internal/tui/commands/commands.go | Adds 12 new slash commands and help entries |
| internal/tui/commands/plan.go, fleet.go, jobs.go, review.go | New command handlers for plan, fleet, jobs, review, compact |
| internal/daemon/plans.go, plans_test.go | PlanManager with create/approve/reject/update-step lifecycle |
| internal/daemon/fleet.go, fleet_test.go | FleetManager with parallel worker execution and concurrency cap |
| internal/daemon/cron.go, cron_test.go | CronScheduler with SQLite persistence, pause/resume/stop |
| internal/daemon/teams.go, teams_test.go | TeamManager with agent spawning, message routing, kill |
| internal/daemon/jobs.go, jobs_test.go | JobRegistry aggregating jobs from all providers |
| internal/daemon/compression.go, compression_test.go | TokenTracker and Compress function for context window management |
| internal/daemon/actors.go, actors_test.go | goakt v4 actor system with SessionActor and ApprovalActor |
| internal/daemon/model_routing.go, model_routing_test.go | Step complexity classification and per-agent model routing |
| internal/daemon/service.go | Wires all new managers and implements new gRPC RPCs |
| internal/daemon/chat.go | Adds token tracking and auto-compression to chat flow |
| internal/daemon/engine.go | Adds MCP discovery, actor system init, cron_jobs DDL |
| internal/daemon/integration_*.go | Integration tests for plan, fleet, cron, team, jobs |
| internal/daemon/qa_test.go, qa_helpers_test.go | QA validation tests for job control, cron, compression, review |
| internal/mcp/discovery.go, discovery_test.go | MCP CLI tool discovery and registration |
| internal/hooks/hooks.go, hooks_test.go | 8 new lifecycle events, shell injection prevention |
| internal/config/config.go | Adds ModelRouting and ContextConfig structs |
| internal/client/client.go | Client methods for all new gRPC RPCs |
| internal/agent/definitions.go, builtins_test.go | Builtin agent loader with embedded code-reviewer YAML |
| internal/agent/builtins/code-reviewer.yaml | Built-in code-reviewer agent definition |
| internal/provider/models_test.go, auth_test.go | Provider model listing and auth tests |
| internal/proto/ratchet.proto | New proto messages and RPCs for all features |
| go.mod | Upgrade workflow to v0.3.40, add goakt/v4 dependency |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Fix help text indentation: /loop, /compact, /review, /exit lines had single tab instead of double tab in the help string slice - Remove custom max() function from fleet.go; Go 1.26 has builtin max - Add shell metachar validation in mcp/discovery.go for AI-supplied exec args; document the exec.Command vs shell boundary - Fix TeamJobProvider.KillJob lock ordering: collect team instances under p.tm.mu.RLock then release before acquiring ti.mu.Lock to eliminate potential deadlock from lock order inversion - /compact now calls CompactSession on the daemon (via TriggerCompact result flag + compactSession() Cmd in chat.go) instead of returning static text; daemon handleChat detects the sentinel and runs handleCompact directly - /mcp list/enable/disable now call mcp.AvailableCLIs() and mcp.KnownCLINames() to show actual PATH-discovered tools instead of hardcoded strings - Add .golangci.yml: exclude idiomatic defer Close/Rollback/Send patterns from errcheck; apply golangci-lint v2.11.3 auto-fixes across the codebase - Pin golangci-lint-action to v8 with explicit version v2.11.3 in CI Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR adds 12 major features to ratchet-cli for competitive parity with GitHub Copilot CLI and Claude Code, including plan mode, fleet mode, team mode, context auto-compression, code review agent, cron/loop scheduling, enhanced hooks, MCP CLI discovery, per-agent model routing, session actors, and a job control panel. It also upgrades the workflow dependency from v0.3.30 to v0.3.40.
Changes:
- Adds new daemon managers (PlanManager, FleetManager, CronScheduler, TeamManager, JobRegistry, TokenTracker, ActorManager) with gthis RPC endpoints and comprehensive test coverage
- Adds new TUI components (PlanView, FleetPanel, JobPanel) with keyboard navigation and corresponding chat integration
- Adds MCP CLI discovery, model routing, context compression, code-reviewer builtin agent, and CI workflow
Reviewed changes
Copilot reviewed 70 out of 71 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| internal/daemon/plans.go, plans_test.go | Plan lifecycle management with approve/reject/step-update |
| internal/daemon/fleet.go, fleet_test.go | Fleet worker management with concurrency cap and deep-copy safety |
| internal/daemon/cron.go, cron_test.go | SQLite-persisted cron scheduler with pause/resume/stop |
| internal/daemon/teams.go, teams_test.go | Team agent spawning with message routing |
| internal/daemon/jobs.go, jobs_test.go | Unified job registry aggregating all manager types |
| internal/daemon/compression.go, compression_test.go | Token tracking and context compression |
| internal/daemon/actors.go, actors_test.go | goakt v4 actor system with session/approval actors |
| internal/daemon/model_routing.go, model_routing_test.go | Step complexity classification and model routing |
| internal/daemon/service.go | Wires all new managers into the gRPC service |
| internal/daemon/chat.go | Auto-compression and manual compact support |
| internal/daemon/engine.go | MCP discovery, actor system init, cron table DDL |
| internal/tui/components/plan.go, plan_test.go | Plan view TUI component |
| internal/tui/components/fleet.go, fleet_test.go | Fleet panel TUI component |
| internal/tui/components/jobpanel.go, jobpanel_test.go | Job control panel TUI component |
| internal/tui/pages/chat.go | Plan view integration and compact session support |
| internal/tui/pages/team.go | Agent kill support and team status refresh |
| internal/tui/pages/splash.go | Type switch cleanup |
| internal/tui/app.go | Job panel toggle (Ctrl+J) and lifecycle |
| internal/tui/commands/*.go | New slash commands: /fleet, /compact, /review, /jobs, /plan |
| internal/mcp/discovery.go, discovery_test.go | CLI auto-detection with shell metachar validation |
| internal/hooks/hooks.go, hooks_test.go | 8 new lifecycle events and shell escaping |
| internal/client/client.go | Client methods for all new RPCs |
| internal/config/config.go | ModelRouting and ContextConfig |
| internal/agent/definitions.go, builtins/ | Embedded code-reviewer agent definition |
| internal/proto/ratchet.proto | All new protobuf messages and RPCs |
| go.mod | workflow v0.3.40, goakt v4 dependency |
| .golangci.yml | Linter configuration |
| .github/workflows/ci.yml | CI pipeline |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
internal/tui/components/jobpanel.go
Outdated
| if len(sessionID) > 8 && sessionID != "" { | ||
| sessionID = sessionID[:8] |
There was a problem hiding this comment.
Fixed in 0d6e731. Removed the redundant && sessionID != "" check — if len(sessionID) > 8 the string is guaranteed non-empty.
internal/daemon/chat.go
Outdated
| // Track token usage (approximate: 1 token ≈ 4 chars) | ||
| inputTokens := (len(userMessage) + 3) / 4 | ||
| outputTokens := (len(fullResponse) + 3) / 4 |
There was a problem hiding this comment.
Fixed in 0d6e731. Changed len(userMessage) and len(fullResponse) to len([]rune(...)) so multi-byte UTF-8 characters count as a single unit rather than multiple bytes, making the estimate more accurate.
internal/tui/pages/chat.go
Outdated
| ctx, cancel := context.WithCancel(m.ctx) | ||
| m.cancelChat = cancel |
There was a problem hiding this comment.
Fixed in 0d6e731. Added a chatCancelSetMsg{cancel} type. Both sendMessage and compactSession now use tea.Batch to immediately dispatch that message alongside the stream Cmd. The Update handler stores the cancel on the real model when it receives chatCancelSetMsg, avoiding the value-receiver copy problem.
| if c == nil { | ||
| return &Result{Lines: []string{"Not connected to daemon"}} | ||
| } | ||
| planID := args[0] |
There was a problem hiding this comment.
Fixed in 0d6e731. Added an early len(args) == 0 guard at the top of fleetCmd that returns a usage message before any slice access.
| _, _ = c.StartFleet(context.Background(), &pb.StartFleetReq{ | ||
| PlanId: planID, | ||
| MaxWorkers: maxWorkers, | ||
| }) |
There was a problem hiding this comment.
Fixed in 0d6e731. Threaded sessionID through Parse (variadic param) → fleetCmd → StartFleetReq.SessionId. The chat page already holds m.sessionID and now passes it when calling commands.Parse.
internal/tui/pages/splash.go
Outdated
| @@ -64,12 +65,12 @@ func (m SplashModel) Update(msg tea.Msg) (SplashModel, tea.Cmd) { | |||
| return splashTickMsg(t) | |||
| }) | |||
| case tea.KeyPressMsg: | |||
| _ = msg | |||
There was a problem hiding this comment.
Fixed in 0d6e731. Removed both _ = msg statements from the splashTickMsg and tea.KeyPressMsg cases in splash.go.
internal/tui/commands/jobs.go
Outdated
| func truncateStr(s string, n int) string { | ||
| if len([]rune(s)) <= n { | ||
| return s | ||
| } | ||
| return string([]rune(s)[:n-1]) + "…" | ||
| } |
There was a problem hiding this comment.
Fixed in 0d6e731. Moved truncateStr to a new internal/tui/commands/util.go shared within the commands package, and removed the duplicate definition from jobs.go.
| case "k": | ||
| if m.cursor < len(m.agents) { | ||
| idx := m.cursor | ||
| return m, func() tea.Msg { | ||
| return KillAgentMsg{AgentID: "team_agent:" + m.agents[idx].ID} | ||
| } |
There was a problem hiding this comment.
Fixed in 0d6e731. Removed the "team_agent:" prefix — KillJob expects the raw job ID as returned by the daemon, not a type-prefixed composite. Also added a guard that skips the kill when AgentCard.ID is empty (agents populated from TeamEvent_AgentSpawned before a TeamStatusMsg arrives don't have an ID yet).
| // reviewCmd runs the built-in code-reviewer agent on the current git diff. | ||
| func reviewCmd(c *client.Client) *Result { | ||
| diff, err := gitDiff() | ||
| if err != nil { | ||
| return &Result{Lines: []string{fmt.Sprintf("Error getting git diff: %v", err)}} | ||
| } | ||
| if diff == "" { | ||
| return &Result{Lines: []string{"No uncommitted changes to review."}} | ||
| } | ||
| lines := []string{ | ||
| "Starting code review on current git diff...", | ||
| "", | ||
| "Diff summary:", | ||
| } | ||
| // Show a trimmed preview of the diff | ||
| diffLines := strings.Split(diff, "\n") | ||
| preview := diffLines | ||
| if len(preview) > 20 { | ||
| preview = diffLines[:20] | ||
| preview = append(preview, fmt.Sprintf("... (%d more lines)", len(diffLines)-20)) | ||
| } | ||
| lines = append(lines, preview...) | ||
| lines = append(lines, | ||
| "", | ||
| "Use the code-reviewer agent via /agents to see full review results.", | ||
| ) | ||
| return &Result{Lines: lines} | ||
| } |
There was a problem hiding this comment.
Fixed in 0d6e731. Added TriggerReview bool and ReviewDiff string to Result. reviewCmd now sets both fields. The chat page detects TriggerReview and calls m.sendMessage with the diff wrapped in a code-reviewer prompt, invoking the agent directly via the existing streaming message path.
- jobpanel.go: remove redundant `&& sessionID != ""` (len > 8 implies non-empty) - daemon/chat.go: use len([]rune()) for token estimation to handle multi-byte UTF-8 - chat.go: fix cancel assigned to value receiver copy in sendMessage/compactSession by returning cancel via chatCancelSetMsg so it persists on the real model - commands/fleet.go: add len(args) guard to prevent panic on bare /fleet - commands/fleet.go: thread sessionID through Parse → fleetCmd → StartFleetReq - splash.go: remove dead `_ = msg` statements on lines 58 and 68 - commands/jobs.go: extract truncateStr to commands/util.go, removing duplicate - commands/review.go: wire /review to invoke code-reviewer agent via sendMessage with git diff as context (TriggerReview + ReviewDiff on Result) - pages/team.go: remove "team_agent:" prefix from KillAgentMsg.AgentID since KillJob expects the raw job ID; guard against empty ID when not yet populated Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Summary
Upgrades ratchet-cli to workflow v0.3.40 and adds 12 major features to achieve competitive parity with GitHub Copilot CLI and Claude Code.
New Features
/plan,/approve,/reject: structured planning before execution with numbered step tracking/fleet: auto-decompose plans into parallel workers with fan-out/fan-in/team,Ctrl+T: named agents with roles and direct peer messaging/compactfor manual trigger/review: built-in agent using CodeReviewTool with Critical/Important/Minor output/loop <interval> <cmd>,/cron <expr> <cmd>: SQLite-persisted, pause/resume/stopgh,docker,kubectland register as tools/costshows per-worker breakdownCtrl+J//jobs: unified view of all sessions, fleet workers, team agents, cron jobs with pause/kill actionsEngine Upgrade
Bugs Found and Fixed During Development
Test plan
go build ./...passesgo test ./... -race -count=1— 13 packages, 0 failures, 0 data races🤖 Generated with Claude Code