mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-09-30 12:39:42 +02:00
400 lines
32 KiB
JSON
400 lines
32 KiB
JSON
{
|
|
"items": [
|
|
{
|
|
"id": "P0-001",
|
|
"content": "Write failing tests for SessionMode type extension — verify 'opencode' is accepted as a valid mode in SessionMode, OpenCodeConfig interface exists with model/provider/autoAllowTools/continueSession/serverPort fields, and MuxSession.mode accepts 'opencode'",
|
|
"priority": "P0",
|
|
"tddPhase": "test",
|
|
"verificationCriteria": "test/opencode-types.test.ts exists, tests fail because SessionMode doesn't include 'opencode' and OpenCodeConfig doesn't exist",
|
|
"testCommand": "npx vitest run test/opencode-types.test.ts",
|
|
"dependencies": []
|
|
},
|
|
{
|
|
"id": "P0-002",
|
|
"content": "Implement SessionMode type extension — extend SessionMode from 'claude' | 'shell' to 'claude' | 'shell' | 'opencode' in types.ts (line 162), add OpenCodeConfig interface with fields: model?: string, provider?: string, autoAllowTools?: boolean, continueSession?: string, serverPort?: number. Update MuxSession.mode and createSession/respawnPane signatures in mux-interface.ts to accept 'opencode' and optional openCodeConfig param",
|
|
"priority": "P0",
|
|
"tddPhase": "impl",
|
|
"verificationCriteria": "npx vitest run test/opencode-types.test.ts passes, tsc --noEmit succeeds",
|
|
"pairedWith": "P0-001",
|
|
"dependencies": ["P0-001"]
|
|
},
|
|
{
|
|
"id": "P0-003",
|
|
"content": "Review type system changes — verify OpenCodeConfig follows existing type conventions (optional fields, no Claude-specific coupling), SessionMode union is used consistently across types.ts/mux-interface.ts/session.ts, no breaking changes to existing code",
|
|
"priority": "P0",
|
|
"tddPhase": "review",
|
|
"verificationCriteria": "tsc --noEmit passes with no errors, grep confirms SessionMode used consistently, no 'claude' | 'shell' hardcoded literals remain in interface definitions",
|
|
"reviewChecklist": ["Type consistency across files", "No breaking changes to existing Claude/shell modes", "OpenCodeConfig fields match opencode CLI flags", "Optional fields properly typed"],
|
|
"pairedWith": "P0-002",
|
|
"dependencies": ["P0-002"]
|
|
},
|
|
{
|
|
"id": "P0-004",
|
|
"content": "Write failing tests for OpenCode CLI resolver — test resolveOpenCodeDir() returns directory when opencode binary exists, returns null when not found, caches result after first call, isOpenCodeAvailable() returns boolean, getOpenCodeAugmentedPath() prepends directory to PATH. Mock filesystem and execSync. Port: none (pure unit test)",
|
|
"priority": "P0",
|
|
"tddPhase": "test",
|
|
"verificationCriteria": "test/opencode-resolver.test.ts exists with 5+ test cases, all fail because opencode-cli-resolver.ts doesn't exist",
|
|
"testCommand": "npx vitest run test/opencode-resolver.test.ts",
|
|
"dependencies": []
|
|
},
|
|
{
|
|
"id": "P0-005",
|
|
"content": "Implement opencode-cli-resolver.ts — create src/utils/opencode-cli-resolver.ts mirroring claude-cli-resolver.ts pattern. Functions: resolveOpenCodeDir() (checks which opencode, then ~/.local/bin, /usr/local/bin, ~/.bun/bin, ~/.npm-global/bin, ~/bin, ~/.opencode/bin), isOpenCodeAvailable(), getOpenCodeAugmentedPath(). Cache results. Add re-export in src/utils/index.ts",
|
|
"priority": "P0",
|
|
"tddPhase": "impl",
|
|
"verificationCriteria": "npx vitest run test/opencode-resolver.test.ts passes, tsc --noEmit succeeds",
|
|
"pairedWith": "P0-004",
|
|
"dependencies": ["P0-004"]
|
|
},
|
|
{
|
|
"id": "P0-006",
|
|
"content": "Review CLI resolver implementation — verify no command injection in execSync('which opencode'), timeout set to 5s, graceful fallback when binary not found, caching works correctly (null vs empty string sentinel), PATH augmentation doesn't duplicate entries",
|
|
"priority": "P0",
|
|
"tddPhase": "review",
|
|
"verificationCriteria": "Code review passes: no shell injection, proper error handling, cache invalidation, consistent with claude-cli-resolver.ts patterns",
|
|
"reviewChecklist": ["No command injection in execSync", "Proper timeout handling", "Cache sentinel value for 'not found'", "PATH deduplication", "Re-export in utils/index.ts"],
|
|
"pairedWith": "P0-005",
|
|
"dependencies": ["P0-005"]
|
|
},
|
|
{
|
|
"id": "P0-007",
|
|
"content": "Write failing tests for Zod schema validation — test CreateSessionSchema accepts mode: 'opencode', accepts openCodeConfig object with model/provider/autoAllowTools/continueSession fields, rejects invalid model strings (shell metacharacters), rejects overly long model names (>100 chars), validates provider field. Port: none (pure unit test)",
|
|
"priority": "P0",
|
|
"tddPhase": "test",
|
|
"verificationCriteria": "test/opencode-schema.test.ts exists, tests fail because schema doesn't accept 'opencode' mode or openCodeConfig field",
|
|
"testCommand": "npx vitest run test/opencode-schema.test.ts",
|
|
"dependencies": ["P0-002"]
|
|
},
|
|
{
|
|
"id": "P0-008",
|
|
"content": "Implement schema validation changes — update CreateSessionSchema in src/web/schemas.ts: extend mode enum to include 'opencode', add openCodeConfig z.object with model (string, max 100, regex /^[a-zA-Z0-9._\\-/]+$/), provider (string, max 50), autoAllowTools (boolean), continueSession (string, max 100, regex /^[a-zA-Z0-9_-]+$/). All fields optional",
|
|
"priority": "P0",
|
|
"tddPhase": "impl",
|
|
"verificationCriteria": "npx vitest run test/opencode-schema.test.ts passes, tsc --noEmit succeeds",
|
|
"pairedWith": "P0-007",
|
|
"dependencies": ["P0-007"]
|
|
},
|
|
{
|
|
"id": "P0-009",
|
|
"content": "Review schema validation — verify model regex blocks shell metacharacters (;|&$`), continueSession regex blocks path traversal, no overly permissive patterns, consistent with existing SAFE_PATH_PATTERN security approach in schemas.ts",
|
|
"priority": "P0",
|
|
"tddPhase": "review",
|
|
"verificationCriteria": "Schema rejects all dangerous inputs: model with semicolons, backticks, pipes; continueSession with ../; empty strings handled properly",
|
|
"reviewChecklist": ["Shell metacharacter blocking", "Path traversal prevention", "Consistent with existing security patterns", "Zod v4 API usage correct"],
|
|
"pairedWith": "P0-008",
|
|
"dependencies": ["P0-008"]
|
|
},
|
|
{
|
|
"id": "P1-001",
|
|
"content": "Write failing tests for TmuxManager opencode command construction — test buildOpenCodeCommand() generates correct CLI: basic 'opencode' command, with --model flag, with --session flag for continue, validates model string safety, validates session ID safety. Test that createSession() with mode 'opencode' builds correct tmux respawn-pane command with opencode env vars (CLAUDEMAN_MUX, API keys passthrough). Mock execAsync. Port: none (unit test with mocks)",
|
|
"priority": "P1",
|
|
"tddPhase": "test",
|
|
"verificationCriteria": "test/opencode-tmux.test.ts exists with 8+ test cases covering command construction, env var setup, and PATH augmentation for opencode mode",
|
|
"testCommand": "npx vitest run test/opencode-tmux.test.ts",
|
|
"dependencies": ["P0-002", "P0-005"]
|
|
},
|
|
{
|
|
"id": "P1-002",
|
|
"content": "Implement TmuxManager opencode support — in src/tmux-manager.ts: (1) import resolveOpenCodeDir from utils, (2) add buildOpenCodeCommand(sessionId, config?) helper that constructs 'opencode [--model X] [--session Y]' with input validation, (3) extend createSession() command construction to handle mode === 'opencode' alongside existing claude/shell branches, (4) add opencode-specific env exports (CLAUDEMAN_MUX, CLAUDEMAN_SESSION_ID, API key passthrough for ANTHROPIC/OPENAI/GOOGLE_API_KEY, optional OPENCODE_CONFIG_CONTENT), (5) use resolveOpenCodeDir() for PATH augmentation when mode is opencode, (6) throw clear error if opencode binary not found, (7) apply same changes to respawnPane()",
|
|
"priority": "P1",
|
|
"tddPhase": "impl",
|
|
"verificationCriteria": "npx vitest run test/opencode-tmux.test.ts passes, tsc --noEmit succeeds",
|
|
"pairedWith": "P1-001",
|
|
"dependencies": ["P1-001"]
|
|
},
|
|
{
|
|
"id": "P1-003",
|
|
"content": "Review TmuxManager opencode integration — verify command injection prevention in buildOpenCodeCommand (model and sessionId validated before interpolation), env var escaping for OPENCODE_CONFIG_CONTENT (single quotes properly escaped), API key passthrough doesn't leak other env vars, respawnPane changes mirror createSession exactly, error messages are actionable",
|
|
"priority": "P1",
|
|
"tddPhase": "review",
|
|
"verificationCriteria": "No command injection vectors, env vars properly escaped, consistent with existing Claude command construction security, error messages guide user to install opencode",
|
|
"reviewChecklist": ["Command injection prevention", "Env var escaping (single quotes in config content)", "API key passthrough scope limited", "respawnPane mirrors createSession", "Error message includes install instructions"],
|
|
"pairedWith": "P1-002",
|
|
"dependencies": ["P1-002"]
|
|
},
|
|
{
|
|
"id": "P1-004",
|
|
"content": "Write failing tests for Session class opencode mode — test that Session constructor accepts mode: 'opencode' with openCodeConfig, test startInteractive() dispatches to opencode-specific startup (not Claude CLI), test that Claude-specific features are disabled for opencode sessions (hooks config skipped, subagent watcher Claude patterns skipped), test that writeViaMux() works identically for opencode mode (tmux send-keys is mode-agnostic). Port: 3161",
|
|
"priority": "P1",
|
|
"tddPhase": "test",
|
|
"verificationCriteria": "test/opencode-session.test.ts exists with 6+ test cases, tests fail because Session doesn't support opencode mode",
|
|
"testCommand": "npx vitest run test/opencode-session.test.ts",
|
|
"dependencies": ["P0-002", "P1-002"]
|
|
},
|
|
{
|
|
"id": "P1-005",
|
|
"content": "Implement Session class opencode support — in src/session.ts: (1) accept openCodeConfig in constructor options and store as private field, (2) in startInteractive(), when mode is 'opencode', pass openCodeConfig to mux.createSession(), (3) skip hooks config generation for opencode sessions (no .claude/settings.local.json hooks), (4) add waitForOpenCodeReady() method using output-silence detection (wait for TUI paint: 500ms of stable output after initial burst, max 8s), (5) skip Claude-specific status line parsing for opencode mode, (6) add mode getter to Session for downstream consumers",
|
|
"priority": "P1",
|
|
"tddPhase": "impl",
|
|
"verificationCriteria": "npx vitest run test/opencode-session.test.ts passes, tsc --noEmit succeeds",
|
|
"pairedWith": "P1-004",
|
|
"dependencies": ["P1-004"]
|
|
},
|
|
{
|
|
"id": "P1-006",
|
|
"content": "Review Session class opencode integration — verify opencode mode doesn't break existing Claude/shell sessions (no regressions), waitForOpenCodeReady timeout is reasonable (8s), hooks are properly skipped without breaking Claude hooks, no memory leaks from new fields, toState() includes opencode-relevant state",
|
|
"priority": "P1",
|
|
"tddPhase": "review",
|
|
"verificationCriteria": "Existing session tests still pass, opencode-specific logic properly guarded with mode checks, no side effects on Claude sessions",
|
|
"reviewChecklist": ["No regression on Claude/shell modes", "waitForOpenCodeReady timeout appropriate", "Hooks skipped cleanly", "toState() serialization works", "No memory leak from new fields"],
|
|
"pairedWith": "P1-005",
|
|
"dependencies": ["P1-005"]
|
|
},
|
|
{
|
|
"id": "P1-007",
|
|
"content": "Write failing tests for opencode idle detection — test getIdleDetectionConfig() returns opencode-specific config (silenceThresholdMs: 5000, no prompt pattern, no AI checker), test that session emits 'idle' after 5s of output silence in opencode mode, test that session emits 'working' when output resumes, test that idle detection works during respawn cycles. Port: 3162",
|
|
"priority": "P1",
|
|
"tddPhase": "test",
|
|
"verificationCriteria": "test/opencode-idle.test.ts exists with 4+ test cases testing silence-based idle detection for opencode mode",
|
|
"testCommand": "npx vitest run test/opencode-idle.test.ts",
|
|
"dependencies": ["P1-005"]
|
|
},
|
|
{
|
|
"id": "P1-008",
|
|
"content": "Implement opencode idle detection — in src/session.ts: (1) add getIdleDetectionConfig() method returning mode-specific config: for opencode — silenceThresholdMs: 5000, promptPattern: null, useAIChecker: false; for claude — existing values, (2) modify idle detection logic to use silence-based detection when promptPattern is null (track lastOutputTime, timer-based idle check), (3) ensure 'working' event fires on any new output after idle state, (4) make IDLE_DETECTION_DELAY_MS configurable per mode",
|
|
"priority": "P1",
|
|
"tddPhase": "impl",
|
|
"verificationCriteria": "npx vitest run test/opencode-idle.test.ts passes, opencode sessions correctly transition idle→working→idle based on output silence",
|
|
"pairedWith": "P1-007",
|
|
"dependencies": ["P1-007"]
|
|
},
|
|
{
|
|
"id": "P1-009",
|
|
"content": "Review idle detection implementation — verify silence timer is properly cleaned up on session stop/exit (no leaked timers), timer doesn't fire after session disposal, idle threshold is tunable per session, working→idle transition doesn't spam events, existing Claude idle detection unchanged",
|
|
"priority": "P1",
|
|
"tddPhase": "review",
|
|
"verificationCriteria": "Timer cleanup verified, no event spam, Claude idle detection regression-free, CleanupManager tracks new timer",
|
|
"reviewChecklist": ["Timer cleanup on session.stop()", "No event spam on rapid output", "Claude idle detection unchanged", "CleanupManager integration", "Configurable threshold"],
|
|
"pairedWith": "P1-008",
|
|
"dependencies": ["P1-008"]
|
|
},
|
|
{
|
|
"id": "P1-010",
|
|
"content": "Write failing tests for API routes — test POST /api/sessions creates opencode session when mode: 'opencode', test returns 400 when opencode not installed, test GET /api/opencode/status returns availability info, test POST /api/sessions/:id/interactive works for opencode sessions, test openCodeConfig is persisted in session state. Port: 3163",
|
|
"priority": "P1",
|
|
"tddPhase": "test",
|
|
"verificationCriteria": "test/opencode-api.test.ts exists with 5+ test cases, tests fail because server doesn't handle opencode mode",
|
|
"testCommand": "npx vitest run test/opencode-api.test.ts",
|
|
"dependencies": ["P0-008", "P1-005"]
|
|
},
|
|
{
|
|
"id": "P1-011",
|
|
"content": "Implement API routes for opencode — in src/web/server.ts: (1) in POST /api/sessions handler, check isOpenCodeAvailable() when mode is 'opencode' and return 400 if not installed, pass openCodeConfig from request body to Session constructor, (2) add GET /api/opencode/status route returning { available: boolean, path: string | null }, (3) ensure POST /api/sessions/:id/interactive works for opencode mode (startInteractive already handles mode dispatch), (4) include mode in session state broadcast events, (5) persist openCodeConfig in state store",
|
|
"priority": "P1",
|
|
"tddPhase": "impl",
|
|
"verificationCriteria": "npx vitest run test/opencode-api.test.ts passes, curl GET /api/opencode/status returns valid JSON",
|
|
"pairedWith": "P1-010",
|
|
"dependencies": ["P1-010"]
|
|
},
|
|
{
|
|
"id": "P1-012",
|
|
"content": "Review API routes — verify /api/opencode/status doesn't expose sensitive info (only binary path, not env vars), session creation validates all openCodeConfig fields before passing to Session, error messages don't leak internal paths, SSE events include mode for frontend routing, state persistence includes openCodeConfig",
|
|
"priority": "P1",
|
|
"tddPhase": "review",
|
|
"verificationCriteria": "No info leakage, proper validation, error messages user-friendly, SSE events tagged with mode",
|
|
"reviewChecklist": ["No sensitive info in /api/opencode/status", "openCodeConfig validated before use", "Error messages actionable", "SSE events include mode", "State persistence round-trips correctly"],
|
|
"pairedWith": "P1-011",
|
|
"dependencies": ["P1-011"]
|
|
},
|
|
{
|
|
"id": "P1-013",
|
|
"content": "Write failing tests for frontend mode selector — Playwright test: load app, verify session creation dialog includes 'OpenCode' option alongside 'Claude Code' and 'Shell', verify selecting OpenCode shows model input field, verify OpenCode option is disabled when /api/opencode/status returns available: false, verify tab shows 'OC' badge for opencode sessions. Port: 3164",
|
|
"priority": "P1",
|
|
"tddPhase": "test",
|
|
"verificationCriteria": "test/opencode-frontend.test.ts (Playwright) exists with 4+ assertions, tests fail because UI doesn't have OpenCode option",
|
|
"testCommand": "npx vitest run test/opencode-frontend.test.ts",
|
|
"dependencies": ["P1-011"]
|
|
},
|
|
{
|
|
"id": "P1-014",
|
|
"content": "Implement frontend UI changes — in src/web/public/app.js: (1) add OpenCode to session creation mode selector (in quick-start modal and/or new session dialog), with icon and 'Multi-model AI agent' description, (2) when opencode mode selected, show model text input with autocomplete for common models (anthropic/claude-sonnet-4-5, openai/gpt-5.2, google/gemini-3-pro, ollama/codellama), (3) check /api/opencode/status on load and disable option if unavailable, (4) add tab badge rendering: 'OC' badge with green (#10b981) background for opencode sessions, 'SH' for shell, none for claude, (5) gate Claude-specific UI panels for opencode sessions (disable hooks panel, auto-compact button)",
|
|
"priority": "P1",
|
|
"tddPhase": "impl",
|
|
"verificationCriteria": "npx vitest run test/opencode-frontend.test.ts passes, manual verification: mode selector shows OpenCode option, tab badge renders",
|
|
"pairedWith": "P1-013",
|
|
"dependencies": ["P1-013"]
|
|
},
|
|
{
|
|
"id": "P1-015",
|
|
"content": "Review frontend implementation — verify mode selector accessibility (keyboard navigable, ARIA labels), model autocomplete doesn't make excessive API calls, tab badge CSS follows existing z-index layering, disabled state has clear visual indicator, no XSS from model name rendering (text content, not innerHTML), feature gating doesn't break Claude session UI",
|
|
"priority": "P1",
|
|
"tddPhase": "review",
|
|
"verificationCriteria": "Accessible UI, no XSS vectors, existing Claude UI unchanged, CSS consistent with design system",
|
|
"reviewChecklist": ["Keyboard accessibility", "No XSS from model names", "CSS z-index consistent", "Claude UI regression-free", "Disabled state visual clarity", "Mobile layout compatibility"],
|
|
"pairedWith": "P1-014",
|
|
"dependencies": ["P1-014"]
|
|
},
|
|
{
|
|
"id": "P1-016",
|
|
"content": "Write failing tests for respawn controller opencode adaptation — using MockSession from test/respawn-test-utils.ts: test respawn controller accepts opencode sessions, test completion detection uses output silence (not 'Worked for' pattern) for opencode, test prompt sending via writeViaMux works for opencode, test circuit breaker works identically for opencode sessions. Port: none (uses MockSession)",
|
|
"priority": "P1",
|
|
"tddPhase": "test",
|
|
"verificationCriteria": "test/opencode-respawn.test.ts exists with 4+ test cases using MockSession, tests fail because respawn controller doesn't handle opencode idle detection",
|
|
"testCommand": "npx vitest run test/opencode-respawn.test.ts",
|
|
"dependencies": ["P1-008"]
|
|
},
|
|
{
|
|
"id": "P1-017",
|
|
"content": "Implement respawn controller opencode adaptation — in src/respawn-controller.ts: (1) add mode-aware completion detection: for opencode, use output silence threshold instead of COMPLETION_TIME_PATTERN regex, (2) skip plan mode detection patterns for opencode (OpenCode has different plan mode), (3) skip AI idle checker for opencode sessions initially (prompt is Claude-specific), (4) ensure prompt sending via writeViaMux works without modification (it's mode-agnostic), (5) keep circuit breaker, health scoring, and cycle metrics unchanged (they're mode-agnostic)",
|
|
"priority": "P1",
|
|
"tddPhase": "impl",
|
|
"verificationCriteria": "npx vitest run test/opencode-respawn.test.ts passes, respawn cycles work with silence-based completion detection",
|
|
"pairedWith": "P1-016",
|
|
"dependencies": ["P1-016"]
|
|
},
|
|
{
|
|
"id": "P1-018",
|
|
"content": "Review respawn controller changes — verify existing Claude respawn behavior unchanged (run existing respawn tests), silence-based detection has reasonable timeout (matches idle detection config), no race conditions between idle detection and respawn timer, circuit breaker still functions correctly for opencode sessions",
|
|
"priority": "P1",
|
|
"tddPhase": "review",
|
|
"verificationCriteria": "Existing respawn tests pass, no regressions, silence timeout configurable, race conditions addressed",
|
|
"reviewChecklist": ["Existing Claude respawn tests pass", "Silence timeout reasonable", "No race conditions", "Circuit breaker works for opencode", "Respawn config serialization includes mode"],
|
|
"pairedWith": "P1-017",
|
|
"dependencies": ["P1-017"]
|
|
},
|
|
{
|
|
"id": "P1-019",
|
|
"content": "Write failing tests for state persistence round-trip — test that opencode sessions are correctly serialized to ~/.claudeman/state.json (mode, openCodeConfig preserved), test that sessions are restored on server restart with correct mode and config, test that session lifecycle log records opencode mode. Port: none (unit test)",
|
|
"priority": "P1",
|
|
"tddPhase": "test",
|
|
"verificationCriteria": "test/opencode-state.test.ts exists with 3+ test cases, tests verify serialization/deserialization of opencode session state",
|
|
"testCommand": "npx vitest run test/opencode-state.test.ts",
|
|
"dependencies": ["P1-005"]
|
|
},
|
|
{
|
|
"id": "P1-020",
|
|
"content": "Implement state persistence for opencode sessions — in src/state-store.ts: ensure openCodeConfig is included in SessionState serialization, in session.ts toState() method include openCodeConfig, in server.ts restoreSession() handle mode: 'opencode' and pass openCodeConfig through, update session-lifecycle-log.ts to record opencode mode in lifecycle entries",
|
|
"priority": "P1",
|
|
"tddPhase": "impl",
|
|
"verificationCriteria": "npx vitest run test/opencode-state.test.ts passes, state.json correctly stores and restores opencode sessions",
|
|
"pairedWith": "P1-019",
|
|
"dependencies": ["P1-019"]
|
|
},
|
|
{
|
|
"id": "P1-021",
|
|
"content": "Review state persistence — verify openCodeConfig doesn't contain sensitive data (API keys not serialized to disk), state.json schema is backward compatible (existing sessions load fine without openCodeConfig), lifecycle log entries are queryable by mode",
|
|
"priority": "P1",
|
|
"tddPhase": "review",
|
|
"verificationCriteria": "No API keys in state.json, backward compatibility verified, lifecycle log works",
|
|
"reviewChecklist": ["No secrets in state.json", "Backward compatibility", "Lifecycle log queryable by mode", "toState() round-trip fidelity"],
|
|
"pairedWith": "P1-020",
|
|
"dependencies": ["P1-020"]
|
|
},
|
|
{
|
|
"id": "P2-001",
|
|
"content": "Write failing tests for feature gating — test that hooks config is NOT generated for opencode sessions, test that subagent watcher skips Claude-specific transcript patterns for opencode, test that auto-compact sends correct slash command per mode (/compact for claude, /clear for opencode), test that token tracking is disabled for opencode sessions (no status line parsing). Port: none (unit tests)",
|
|
"priority": "P2",
|
|
"tddPhase": "test",
|
|
"verificationCriteria": "test/opencode-feature-gating.test.ts exists with 4+ test cases verifying mode-aware feature behavior",
|
|
"testCommand": "npx vitest run test/opencode-feature-gating.test.ts",
|
|
"dependencies": ["P1-005"]
|
|
},
|
|
{
|
|
"id": "P2-002",
|
|
"content": "Implement feature gating for opencode sessions — (1) in hooks-config.ts: guard generateHooksConfig() to skip when session mode is 'opencode', (2) in session.ts: skip token tracking / status line parsing for opencode mode, (3) in session.ts: make auto-compact command mode-aware (Claude: /compact, OpenCode: skip or /clear), (4) in subagent-watcher.ts: skip Claude-specific transcript parsing for opencode sessions but still watch for generic agent activity patterns",
|
|
"priority": "P2",
|
|
"tddPhase": "impl",
|
|
"verificationCriteria": "npx vitest run test/opencode-feature-gating.test.ts passes, Claude features properly disabled for opencode sessions",
|
|
"pairedWith": "P2-001",
|
|
"dependencies": ["P2-001"]
|
|
},
|
|
{
|
|
"id": "P2-003",
|
|
"content": "Review feature gating — verify all mode checks are consistent (use session.mode, not hardcoded string comparisons scattered everywhere), no Claude features accidentally leak into opencode sessions, no opencode-specific code paths break Claude sessions",
|
|
"priority": "P2",
|
|
"tddPhase": "review",
|
|
"verificationCriteria": "Consistent mode checking pattern, no feature leakage, no Claude regressions",
|
|
"reviewChecklist": ["Consistent mode check pattern", "No feature leakage", "No Claude regressions", "Auto-compact behavior correct per mode"],
|
|
"pairedWith": "P2-002",
|
|
"dependencies": ["P2-002"]
|
|
},
|
|
{
|
|
"id": "P2-004",
|
|
"content": "Write end-to-end integration test — Playwright test that creates an opencode session via the web UI (if opencode is installed) or via API with mocked binary, verifies terminal renders, sends input, receives output, verifies tab badge shows 'OC', verifies session appears in /api/sessions with mode: 'opencode', cleans up session. Port: 3165",
|
|
"priority": "P2",
|
|
"tddPhase": "test",
|
|
"verificationCriteria": "test/opencode-e2e.test.ts exists with full session lifecycle test, skips gracefully if opencode binary not installed",
|
|
"testCommand": "npx vitest run test/opencode-e2e.test.ts",
|
|
"dependencies": ["P1-014", "P1-011"]
|
|
},
|
|
{
|
|
"id": "P2-005",
|
|
"content": "Fix any issues found during E2E testing — address xterm.js rendering issues with OpenCode's Bubble Tea TUI (if any), fix signal handling (SIGWINCH for resize), resolve any env var passthrough issues, ensure cleanup on session delete works correctly for opencode sessions",
|
|
"priority": "P2",
|
|
"tddPhase": "impl",
|
|
"verificationCriteria": "npx vitest run test/opencode-e2e.test.ts passes end-to-end, manual smoke test confirms TUI renders correctly in browser",
|
|
"pairedWith": "P2-004",
|
|
"dependencies": ["P2-004"]
|
|
},
|
|
{
|
|
"id": "P2-006",
|
|
"content": "Review E2E integration — verify session cleanup doesn't leave orphaned tmux sessions, no zombie processes, state.json is clean after deletion, SSE events fire correctly for all lifecycle phases (created, interactive, idle, working, exit, deleted)",
|
|
"priority": "P2",
|
|
"tddPhase": "review",
|
|
"verificationCriteria": "No orphaned tmux sessions, no zombies, clean state.json after delete, all SSE events fire",
|
|
"reviewChecklist": ["No orphaned tmux sessions", "No zombie processes", "State cleanup complete", "SSE event lifecycle complete", "Resource usage reasonable"],
|
|
"pairedWith": "P2-005",
|
|
"dependencies": ["P2-005"]
|
|
},
|
|
{
|
|
"id": "P2-007",
|
|
"content": "Write tests for Ralph Loop opencode compatibility — test that Ralph Loop can send prompts to opencode sessions via writeViaMux, test that completion detection uses silence-based approach, test that todo tracking is disabled for opencode (no TodoWrite tool parsing), test that Ralph queue processes tasks for opencode sessions",
|
|
"priority": "P2",
|
|
"tddPhase": "test",
|
|
"verificationCriteria": "test/opencode-ralph.test.ts exists with 4+ test cases using MockSession configured in opencode mode",
|
|
"testCommand": "npx vitest run test/opencode-ralph.test.ts",
|
|
"dependencies": ["P1-017"]
|
|
},
|
|
{
|
|
"id": "P2-008",
|
|
"content": "Implement Ralph Loop opencode compatibility — in ralph-loop.ts: (1) allow opencode sessions to be Ralph Loop targets, (2) skip promise phrase detection for opencode (no <promise> tags), (3) use silence-based completion detection matching respawn controller approach, (4) skip TodoWrite parsing for opencode sessions, (5) keep task queue and priority logic unchanged (mode-agnostic)",
|
|
"priority": "P2",
|
|
"tddPhase": "impl",
|
|
"verificationCriteria": "npx vitest run test/opencode-ralph.test.ts passes, Ralph Loop can drive opencode sessions through task queues",
|
|
"pairedWith": "P2-007",
|
|
"dependencies": ["P2-007"]
|
|
},
|
|
{
|
|
"id": "P2-009",
|
|
"content": "Review Ralph Loop adaptation — verify Ralph Loop reliability for opencode (silence detection may be less precise than completion phrase), verify no Ralph features accidentally break for Claude sessions, verify circuit breaker properly handles opencode-specific failure modes",
|
|
"priority": "P2",
|
|
"tddPhase": "review",
|
|
"verificationCriteria": "Ralph Loop works reliably for both modes, no Claude regressions, clear documentation of opencode limitations",
|
|
"reviewChecklist": ["Silence detection reliability", "No Claude regressions in Ralph", "Circuit breaker handles opencode failures", "Task queue mode-agnostic"],
|
|
"pairedWith": "P2-008",
|
|
"dependencies": ["P2-008"]
|
|
},
|
|
{
|
|
"id": "P2-010",
|
|
"content": "Final typecheck and comprehensive review — run tsc --noEmit across entire project, verify all new files follow import conventions (utils from ./utils, types via type imports), verify no unused imports/variables (noUnusedLocals/noUnusedParameters), run existing test files individually to confirm no regressions, update CLAUDE.md with opencode session documentation",
|
|
"priority": "P2",
|
|
"tddPhase": "review",
|
|
"verificationCriteria": "tsc --noEmit passes with zero errors, existing tests pass, CLAUDE.md updated with opencode section",
|
|
"reviewChecklist": ["tsc --noEmit clean", "Import conventions followed", "No unused variables", "Existing tests pass", "CLAUDE.md updated", "No TODO/FIXME left unaddressed"],
|
|
"dependencies": ["P2-003", "P2-006", "P2-009"]
|
|
}
|
|
],
|
|
"gaps": [
|
|
"OpenCode binary not currently installed on this machine — manual installation required before integration testing",
|
|
"OpenCode's exact TUI escape sequence behavior with xterm.js is unknown — may need rendering fixes",
|
|
"OpenCode's signal handling (SIGWINCH for resize, SIGTERM for graceful shutdown) needs empirical testing",
|
|
"OpenCode's stdin behavior for pasted/programmatic text input is unverified — writeViaMux may need adaptation",
|
|
"Token/cost tracking for opencode sessions is deferred — no structured way to get this from TUI output",
|
|
"OpenCode's 'opencode serve' API integration (Strategy B) is not included in this plan — it's a separate follow-up project",
|
|
"OpenCode was archived in September 2025 and moved to 'Crush' — long-term maintenance risk",
|
|
"Multi-line input compatibility with OpenCode's TUI is unknown (Claudeman sends single-line via writeViaMux)",
|
|
"AI idle checker prompt needs OpenCode-specific variant if AI-based idle detection is desired later",
|
|
"Agent Teams integration with OpenCode sessions is not covered — teams are Claude Code-specific"
|
|
],
|
|
"warnings": [
|
|
"OpenCode's GitHub repository was archived (Sep 2025) and the project moved to 'Crush' — consider whether to target opencode or crush",
|
|
"Silence-based idle detection is less precise than Claude's prompt marker detection — may cause false positives (TUI animation) or false negatives (long-running quiet operations)",
|
|
"The respawn controller's AI idle checker uses a Claude-specific prompt — it will be disabled for opencode, reducing idle detection reliability",
|
|
"OpenCode's Bubble Tea TUI uses alternate screen buffer which may interact poorly with xterm.js buffer capture",
|
|
"API key passthrough in tmux env exports means keys appear in tmux's process tree — security consideration for shared machines",
|
|
"opencode.json in the project root may conflict with Claudeman's CLI flag overrides — need clear precedence documentation",
|
|
"Ralph Loop with opencode may be less reliable without completion phrase detection — silence-based detection has higher error margin",
|
|
"Test port allocation: this plan uses ports 3161-3165 — verify no conflicts with existing tests before implementation"
|
|
]
|
|
}
|