feat: 添加 /goal 命令,支持长时间运行任务的目标管理#1222
Conversation
从 Codex 项目移植 /goal 命令到 Claude Code,实现: - Goal 状态管理模块(active/paused/budget_limited/complete) - /goal 斜杠命令(set/clear/pause/resume/complete) - Goal 模型工具(get/set/complete) - Continuation prompt 自动注入系统提示 - Token 用量自动追踪 Co-Authored-By: mimo-v2.5-pro <XiaomiMiMo@claude-code-best.win>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
📝 WalkthroughWalkthroughAdds session-scoped goal state, a GoalTool (get/set/complete), a local /goal command with subcommands, and integrations for token accounting and a dynamic system-prompt section reflecting goal state between turns. ChangesGoal Management Feature
Sequence Diagram(s)sequenceDiagram
participant User
participant GoalTool
participant GoalState
User->>GoalTool: call(action: "set", objective, tokenBudget?, sessionId?)
GoalTool->>GoalState: setGoal(objective, tokenBudget, sessionId?)
GoalState-->>GoalTool: GoalState
GoalTool-->>User: Output(success)
User->>GoalTool: call(action: "get", sessionId?)
GoalTool->>GoalState: getGoal(sessionId?)
GoalState-->>GoalTool: GoalState (elapsed,tokens)
GoalTool-->>User: Output(get payload)
User->>GoalTool: call(action: "complete", message?, sessionId?)
GoalTool->>GoalState: completeGoal(sessionId?)
GoalState-->>GoalTool: boolean
GoalTool-->>User: Output(completed)
🎯 3 (Moderate) | ⏱️ ~25 minutes
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Tip 💬 Introducing Slack Agent: The best way for teams to turn conversations into code.Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.
Built for teams:
One agent for your entire SDLC. Right inside Slack. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
src/commands/goal/goal.ts (1)
54-62: ⚡ Quick winInclude the previous goal objective in the replacement message.
When replacing an existing active goal, the user only sees "Goal replaced" without being reminded what they just overwrote. This could be surprising if they forgot they had an active goal.
💬 Suggested enhancement
if (existing && existing.status === 'active') { // Replace existing active goal + const previousObjective = existing.objective setGoal(trimmed) return { type: 'text', - value: `Goal replaced.\n\n${formatGoalStatus()}`, + value: `Goal replaced (was: "${previousObjective}").\n\n${formatGoalStatus()}`, } }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/commands/goal/goal.ts` around lines 54 - 62, When replacing an existing active goal in the block that calls getGoal(), include the previous goal's objective in the replacement response: read the existing goal from getGoal(), save it (e.g., existing.objective), then call setGoal(trimmed) as before and return a message that includes both the previous objective and the new formatted status from formatGoalStatus(); update the returned value in that branch so the user sees what was overwritten along with the new goal status.src/services/goal/goalState.ts (1)
11-30: 🏗️ Heavy liftConsider persisting goal state for long-running tasks.
The goal state is purely in-memory and will be lost if the process restarts (crash, upgrade, or user stops/resumes the session). For long-running tasks, this means:
- Token usage accounting resets to zero
- Budget enforcement breaks (user could exceed budget after restart)
- Goal progress tracking is lost
For an MVP this may be acceptable, but if goals are meant to survive across days or session restarts, consider persisting to the session file (similar to how message history is persisted).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/services/goal/goalState.ts` around lines 11 - 30, The currentGoal in goalState.ts is only in-memory and should be persisted so goals survive restarts; update getGoal, setGoal, and clearGoal (and the module-level currentGoal/GoalState usage) to read/write the goal state to the session persistence used for message history (load persisted goal on module init, write the new goal on setGoal, and remove it on clearGoal), ensuring tokenBudget/tokensUsed/startTime are saved and restored atomically so budget accounting and status survive process restarts.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/services/goal/goalState.ts`:
- Line 11: current module-level currentGoal: GoalState | null is global to the
process and will leak between concurrent daemon/background sessions; replace it
with a session-scoped store (e.g., const goals = new Map<string, GoalState>())
and update the module's public helpers (replace or overload functions that
currently read/write currentGoal) to accept a sessionId parameter or to resolve
sessionId internally, following the pattern in
src/services/api/sessionIngress.ts; specifically: remove the single
"currentGoal" symbol, introduce "goals: Map<sessionId, GoalState>", implement
getGoal(sessionId), setGoal(sessionId, goal), clearGoal(sessionId) and update
any existing functions that reference currentGoal to use these new helpers so
each session has isolated GoalState.
---
Nitpick comments:
In `@src/commands/goal/goal.ts`:
- Around line 54-62: When replacing an existing active goal in the block that
calls getGoal(), include the previous goal's objective in the replacement
response: read the existing goal from getGoal(), save it (e.g.,
existing.objective), then call setGoal(trimmed) as before and return a message
that includes both the previous objective and the new formatted status from
formatGoalStatus(); update the returned value in that branch so the user sees
what was overwritten along with the new goal status.
In `@src/services/goal/goalState.ts`:
- Around line 11-30: The currentGoal in goalState.ts is only in-memory and
should be persisted so goals survive restarts; update getGoal, setGoal, and
clearGoal (and the module-level currentGoal/GoalState usage) to read/write the
goal state to the session persistence used for message history (load persisted
goal on module init, write the new goal on setGoal, and remove it on clearGoal),
ensuring tokenBudget/tokensUsed/startTime are saved and restored atomically so
budget accounting and status survive process restarts.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: f3dc8d76-d36e-4548-9275-42e428983b6f
📒 Files selected for processing (10)
packages/builtin-tools/src/index.tspackages/builtin-tools/src/tools/GoalTool/GoalTool.tspackages/builtin-tools/src/tools/GoalTool/prompt.tssrc/commands.tssrc/commands/goal/goal.tssrc/commands/goal/index.tssrc/constants/prompts.tssrc/query.tssrc/services/goal/goalState.tssrc/tools.ts
将 currentGoal 单例替换为 Map<string, GoalState>,按 sessionId 隔离, 遵循 sessionIngress.ts 的模式。所有函数支持可选 sessionId 参数。 Co-Authored-By: mimo-v2.5-pro <XiaomiMiMo@claude-code-best.win>
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/services/goal/goalState.ts`:
- Around line 39-50: The elapsed time continues to count while a goal is paused
because formatters still compute elapsed from the original startTime; fix by
tracking paused intervals on the Goal object and using an accumulated active
duration. Specifically, add fields like pausedAt: number | null and
accumulatedActiveMs: number to the goal returned by getGoal, update
pauseGoal(sessionId) to set pausedAt = now and leave accumulatedActiveMs
unchanged, and update resumeGoal(sessionId) to add (now - pausedAt) to a
lastPausedDuration or adjust accumulatedActiveMs then clear pausedAt and keep
status = 'active'. Finally, change the elapsed-time calculations in the
status/formatting code (the code that reads startTime to compute "Time spent")
to use accumulatedActiveMs + (if status === 'active' and pausedAt == null ? now
- lastResumedAt : 0) instead of raw now - startTime so paused intervals are
excluded.
- Around line 19-31: The setGoal function currently accepts tokenBudget and
tokensUsed without validation which allows NaN/Infinity/negative values to
corrupt GoalState; before creating and mutating the state in setGoal validate
tokenBudget with Number.isFinite and >= 0 (treat invalid values as null) and
ensure tokensUsed is a finite non-negative number (default/clamp to 0); apply
the same guards anywhere else in this module that writes GoalState.tokensUsed or
tokenBudget (search for assignments to tokensUsed and tokenBudget) so those
mutations also coerce/validate inputs before updating the map.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 129f2bcd-df1e-4a84-8d76-b46a0c48e9a5
📒 Files selected for processing (1)
src/services/goal/goalState.ts
setGoal 中 tokenBudget 非 finite 或负数时归零; updateGoalTokens 中 usage 非 finite 或负数时归零。 Co-Authored-By: mimo-v2.5-pro <XiaomiMiMo@claude-code-best.win>
新增 pausedAt/accumulatedActiveMs 字段,pauseGoal 累积已活跃时间, resumeGoal 重置 startTime,计时统一使用 getActiveElapsedMs()。 Co-Authored-By: mimo-v2.5-pro <XiaomiMiMo@claude-code-best.win>
从 Codex 项目移植 /goal 命令到 Claude Code,实现:
Need help on this PR? Tag
@codesmithwith what you need.Summary by CodeRabbit