You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add engine-neutral [DEVLOG_STAGE] and [DEVLOG_GATE] stdout parsing with persisted current_stage / gate_status state on tasks and sessions.
Add human gate pause/resume handling through a dedicated resolve_gate session action, keeping approval replies isolated from the normal send queue.
Surface stage and needs-input state on task cards, task details, session cards, and session headers, with global control-plane stream refresh for task/session lists.
[must-fix] Duplicate parseGateStatus with diverging fallback — control-plane-state.ts (exported, used by UI) and control-plane-protocol.ts (private, used internally when reading gate_status back from DB) both implement parseGateStatus independently. They differ: the state module returns created_at: "" for a missing field; the protocol module returns new Date(0).toISOString(). Any future fix to one won't propagate to the other. The UI module should import from one canonical source. control-plane-state.ts:1-39 vs control-plane-protocol.ts:212-232. Fix this →
[must-fix] migrateControlPlaneColumns called twice in getDb() — db.ts calls migrateControlPlaneColumns(_db) at line 40 (before the idle-status migration block) and again at line 179 (after the agent column migrations). On every cold start the PRAGMA table_info queries run twice and the columns-exist check runs twice per table. More importantly it's a correctness hazard: if any future migration between those two call sites modifies schema, the second call will see different state than expected. Fix this →
[must-fix] resolveGate leaves isProcessing = true if writeGateResponse fails — process-manager.ts:1267 sets sp.isProcessing = true before calling writeGateResponse. writeGateResponse has an early-return error path (stdin not writable, line 1297–1302) that logs a warning but does not reset isProcessing. The session then blocks all new messages until the 3-minute watchdog fires. The gate_status has already been cleared from DB at this point, so the gate won't reappear. The fix is to reset sp.isProcessing = false in the early-return path of writeGateResponse, or reset it in the caller on write failure. Fix this →
[should-fix] Gate resolve failure is silent in the UI — task-detail-dialog.tsx:209 returns early when !res.ok with no error state or toast shown to the user. If the gate resolve API returns a 409 (e.g., "no pending gate" — possible if the session was killed between render and submit), the button just stops spinning with no feedback. Add an error display. Fix this →
[should-fix] Dual EventSource connections on pages that mount both hooks — use-tasks.ts and use-sessions.ts each independently open new EventSource("/api/devlog/stream"). On the Kanban board (/tasks), if both hooks are mounted simultaneously there are two SSE connections to the same endpoint. Each control-plane event triggers two independent refetch calls. This doubles backend load and causes brief double-render. A shared context or a single global SSE hook would fix this.
[nit] Global status: running emit lacks session context — process-manager.ts:1290 emits streamManager.emit("global", { type: "status", status: "running" }). The status event shape doesn't include session_id, so a global subscriber can't tell which session went running. The per-session emit on line 1289 is fine; the global one is ambiguous. Compare to the control_plane_gate_resolved event on line 1280 which correctly includes session_id.
[nit] isRecord helper defined three times — identical implementations in control-plane-protocol.ts:204, control-plane-state.ts:37, and process-manager.ts:515. Consider a shared @/core/utils export.
Overall assessment: The core architecture is clean — single-line marker parsing, safe JSON validation at boundaries, idempotent DB migrations, and proper SIGSTOP/SIGCONT gate pause are all well-done. Tests cover the protocol and state transitions thoroughly. The three must-fix items above are real defects (not just style); the rest are quality improvements.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
[DEVLOG_STAGE]and[DEVLOG_GATE]stdout parsing with persistedcurrent_stage/gate_statusstate on tasks and sessions.resolve_gatesession action, keeping approval replies isolated from the normal send queue.needs-inputstate on task cards, task details, session cards, and session headers, with global control-plane stream refresh for task/session lists.Closes #37
Test Plan
git diff --check origin/main..HEADTZ=Asia/Shanghai bun run test src/core/__tests__/quality-gates.test.tsbun run typecheckbun run quality:cihttp://127.0.0.1:3000/tasksand/sessions: no console errors, no horizontal overflowAudit Notes
/api/devlog/streamcontrol-plane events instead of relying only on polling.docs/superpowers/plans/2026-06-03-session-agent-activity-stream.mdout of the branch.