Revert "feat: 添加 /goal 命令,支持长时间运行任务的目标管理 (#1222)" (#1236)

This reverts commit d66a6f6124.
This commit is contained in:
claude-code-best
2026-05-17 10:06:09 +08:00
committed by GitHub
parent d66a6f6124
commit 2cc9a7daef
10 changed files with 0 additions and 483 deletions

View File

@@ -167,7 +167,6 @@ import thinkbackPlay from './commands/thinkback-play/index.js'
import permissions from './commands/permissions/index.js'
import plan from './commands/plan/index.js'
import fast from './commands/fast/index.js'
import goal from './commands/goal/index.js'
import passes from './commands/passes/index.js'
import privacySettings from './commands/privacy-settings/index.js'
import hooks from './commands/hooks/index.js'
@@ -317,7 +316,6 @@ const COMMANDS = memoize((): Command[] => [
exit,
fast,
files,
goal,
heapDump,
help,
ide,

View File

@@ -1,66 +0,0 @@
import type { LocalCommandCall } from '../../types/command.js'
import {
clearGoal,
completeGoal,
formatGoalStatus,
getGoal,
pauseGoal,
resumeGoal,
setGoal,
} from '../../services/goal/goalState.js'
export const call: LocalCommandCall = async args => {
const trimmed = args.trim()
// No arguments — show current goal status
if (!trimmed) {
return { type: 'text', value: formatGoalStatus() }
}
const lower = trimmed.toLowerCase()
// Control subcommands
if (lower === 'clear') {
const goal = getGoal()
if (!goal) {
return { type: 'text', value: 'No active goal to clear.' }
}
clearGoal()
return { type: 'text', value: 'Goal cleared.' }
}
if (lower === 'pause') {
if (pauseGoal()) {
return { type: 'text', value: 'Goal paused.' }
}
return { type: 'text', value: 'No active goal to pause.' }
}
if (lower === 'resume') {
if (resumeGoal()) {
return { type: 'text', value: 'Goal resumed.' }
}
return { type: 'text', value: 'No paused goal to resume.' }
}
if (lower === 'complete') {
if (completeGoal()) {
return { type: 'text', value: 'Goal marked as complete.' }
}
return { type: 'text', value: 'No active goal to complete.' }
}
// Set a new goal
const existing = getGoal()
if (existing && existing.status === 'active') {
// Replace existing active goal
setGoal(trimmed)
return {
type: 'text',
value: `Goal replaced.\n\n${formatGoalStatus()}`,
}
}
setGoal(trimmed)
return { type: 'text', value: `Goal set.\n\n${formatGoalStatus()}` }
}

View File

@@ -1,12 +0,0 @@
import type { Command } from '../../commands.js'
const goal = {
type: 'local',
name: 'goal',
description: 'Set or view the goal for a long-running task',
supportsNonInteractive: true,
argumentHint: '<objective> | clear | pause | resume',
load: () => import('./goal.js'),
} satisfies Command
export default goal

View File

@@ -57,7 +57,6 @@ import {
resolveSystemPromptSections,
} from './systemPromptSections.js'
import { SLEEP_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/SleepTool/prompt.js'
import { getGoalContinuationPrompt } from '../services/goal/goalState.js'
import { TICK_TAG } from './xml.js'
import { logForDebugging } from '../utils/debug.js'
import { loadMemoryPrompt } from '../memdir/memdir.js'
@@ -506,11 +505,6 @@ ${CYBER_RISK_INSTRUCTION}`,
...(feature('KAIROS') || feature('KAIROS_BRIEF')
? [systemPromptSection('brief', () => getBriefSection())]
: []),
DANGEROUS_uncachedSystemPromptSection(
'goal_continuation',
() => getGoalContinuationPrompt(),
'Goal state changes between turns',
),
]
const resolvedDynamicSections =

View File

@@ -5,7 +5,6 @@ import type {
} from '@anthropic-ai/sdk/resources/index.mjs'
import type { CanUseToolFn } from './hooks/useCanUseTool.js'
import { FallbackTriggeredError } from './services/api/withRetry.js'
import { updateGoalTokens } from './services/goal/goalState.js'
import {
calculateTokenWarningState,
estimateMaxTurnGrowth,
@@ -1266,13 +1265,6 @@ async function* queryLoop(
if (warningInfo) {
yield createCacheWarningMessage(warningInfo)
}
// Update goal token usage
const totalTokens =
usage.input_tokens +
(usage.cache_creation_input_tokens ?? 0) +
(usage.cache_read_input_tokens ?? 0)
updateGoalTokens(totalTokens)
}
}

View File

@@ -1,156 +0,0 @@
import { getSessionId } from '../../bootstrap/state.js'
export type GoalStatus = 'active' | 'paused' | 'budget_limited' | 'complete'
export type GoalState = {
objective: string
status: GoalStatus
tokenBudget: number | null
tokensUsed: number
startTime: number
pausedAt: number | null
accumulatedActiveMs: number
}
const goals: Map<string, GoalState> = new Map()
export function getGoal(sessionId?: string): GoalState | null {
return goals.get(sessionId ?? getSessionId()) ?? null
}
export function setGoal(
objective: string,
tokenBudget?: number,
sessionId?: string,
): GoalState {
const validBudget =
tokenBudget !== undefined &&
Number.isFinite(tokenBudget) &&
tokenBudget >= 0
? tokenBudget
: null
const state: GoalState = {
objective,
status: 'active',
tokenBudget: validBudget,
tokensUsed: 0,
startTime: Date.now(),
pausedAt: null,
accumulatedActiveMs: 0,
}
goals.set(sessionId ?? getSessionId(), state)
return state
}
export function clearGoal(sessionId?: string): void {
goals.delete(sessionId ?? getSessionId())
}
export function pauseGoal(sessionId?: string): boolean {
const goal = getGoal(sessionId)
if (!goal || goal.status !== 'active') return false
goal.accumulatedActiveMs += Date.now() - goal.startTime
goal.pausedAt = Date.now()
goal.status = 'paused'
return true
}
export function resumeGoal(sessionId?: string): boolean {
const goal = getGoal(sessionId)
if (!goal || goal.status !== 'paused') return false
goal.pausedAt = null
goal.startTime = Date.now()
goal.status = 'active'
return true
}
export function completeGoal(sessionId?: string): boolean {
const goal = getGoal(sessionId)
if (!goal) return false
goal.status = 'complete'
return true
}
export function updateGoalTokens(usage: number, sessionId?: string): void {
const goal = getGoal(sessionId)
if (!goal || goal.status !== 'active') return
const validUsage = Number.isFinite(usage) && usage >= 0 ? usage : 0
goal.tokensUsed += validUsage
if (goal.tokenBudget !== null && goal.tokensUsed >= goal.tokenBudget) {
goal.status = 'budget_limited'
}
}
export function getActiveElapsedMs(goal: GoalState): number {
const ongoing =
goal.status === 'active' && goal.pausedAt === null
? Date.now() - goal.startTime
: 0
return goal.accumulatedActiveMs + ongoing
}
export function getGoalContinuationPrompt(sessionId?: string): string | null {
const goal = getGoal(sessionId)
if (!goal || goal.status !== 'active') return null
const elapsedSeconds = Math.floor(getActiveElapsedMs(goal) / 1000)
const budgetDisplay =
goal.tokenBudget !== null ? `${goal.tokenBudget}` : 'unlimited'
const remainingDisplay =
goal.tokenBudget !== null
? `${Math.max(0, goal.tokenBudget - goal.tokensUsed)}`
: 'unlimited'
return `Continue working toward the active goal.
<objective>
${goal.objective}
</objective>
Budget:
- Time spent: ${elapsedSeconds} seconds
- Tokens used: ${goal.tokensUsed}
- Token budget: ${budgetDisplay}
- Tokens remaining: ${remainingDisplay}
Avoid repeating work that is already done. Choose the next concrete action toward the objective.
Before deciding that the goal is achieved, perform a completion audit:
- Restate the objective as concrete deliverables or success criteria.
- Inspect relevant files, command output, test results, or other real evidence.
- Do not accept proxy signals as completion by themselves.
- Treat uncertainty as not achieved; do more verification or continue the work.
- Only mark the goal achieved when the objective has actually been achieved and no required work remains.
If the objective is achieved, call the goal tool with action "complete" so usage accounting is preserved.`
}
export function formatGoalStatus(sessionId?: string): string {
const goal = getGoal(sessionId)
if (!goal) return 'No active goal.'
const elapsed = Math.floor(getActiveElapsedMs(goal) / 1000)
const minutes = Math.floor(elapsed / 60)
const seconds = elapsed % 60
const timeStr = minutes > 0 ? `${minutes}m ${seconds}s` : `${seconds}s`
const statusLabel: Record<GoalStatus, string> = {
active: 'Active',
paused: 'Paused',
budget_limited: 'Budget Limited',
complete: 'Complete',
}
const lines = [
`Goal: ${goal.objective}`,
`Status: ${statusLabel[goal.status]}`,
`Time: ${timeStr}`,
`Tokens: ${goal.tokensUsed}${goal.tokenBudget !== null ? ` / ${goal.tokenBudget}` : ''}`,
]
return lines.join('\n')
}
export function clearAllGoals(): void {
goals.clear()
}

View File

@@ -87,7 +87,6 @@ import { EnterPlanModeTool } from '@claude-code-best/builtin-tools/tools/EnterPl
import { EnterWorktreeTool } from '@claude-code-best/builtin-tools/tools/EnterWorktreeTool/EnterWorktreeTool.js'
import { ExitWorktreeTool } from '@claude-code-best/builtin-tools/tools/ExitWorktreeTool/ExitWorktreeTool.js'
import { ConfigTool } from '@claude-code-best/builtin-tools/tools/ConfigTool/ConfigTool.js'
import { GoalTool } from '@claude-code-best/builtin-tools/tools/GoalTool/GoalTool.js'
import { LocalMemoryRecallTool } from '@claude-code-best/builtin-tools/tools/LocalMemoryRecallTool/LocalMemoryRecallTool.js'
import { VaultHttpFetchTool } from '@claude-code-best/builtin-tools/tools/VaultHttpFetchTool/VaultHttpFetchTool.js'
import { TaskCreateTool } from '@claude-code-best/builtin-tools/tools/TaskCreateTool/TaskCreateTool.js'
@@ -262,7 +261,6 @@ export function getAllBaseTools(): Tools {
...(RemoteTriggerTool ? [RemoteTriggerTool] : []),
...(MonitorTool ? [MonitorTool] : []),
BriefTool,
GoalTool,
...(SendUserFileTool ? [SendUserFileTool] : []),
...(PushNotificationTool ? [PushNotificationTool] : []),
...(SubscribePRTool ? [SubscribePRTool] : []),