refactor(hooks): fix empty catches and remove AI slop from code comments

This commit is contained in:
YeonGyu-Kim
2026-04-03 21:37:16 +09:00
parent 6b431c5522
commit 5c7299830d
17 changed files with 900 additions and 565 deletions
@@ -0,0 +1,298 @@
import { statSync } from "node:fs"
import {
appendSessionId,
clearBoulderState,
createBoulderState,
findPrometheusPlans,
getPlanName,
getPlanProgress,
getTaskSessionState,
readBoulderState,
readCurrentTopLevelTask,
upsertTaskSessionState,
writeBoulderState,
} from "../../features/boulder-state"
import { log } from "../../shared/logger"
import type { PluginInput } from "@opencode-ai/plugin"
import { HOOK_NAME } from "./start-work-hook"
function findPlanByName(plans: string[], requestedName: string): string | null {
const lowerName = requestedName.toLowerCase()
const exactMatch = plans.find((p) => getPlanName(p).toLowerCase() === lowerName)
if (exactMatch) return exactMatch
const partialMatch = plans.find((p) => getPlanName(p).toLowerCase().includes(lowerName))
return partialMatch || null
}
function buildAutoSelectedPlanContext(params: {
planPath: string
sessionId: string
timestamp: string
activeAgent: string
worktreePath: string | undefined
worktreeBlock: string
directory: string
}): string {
const { planPath, sessionId, timestamp, activeAgent, worktreePath, worktreeBlock, directory } = params
const progress = getPlanProgress(planPath)
const newState = createBoulderState(planPath, sessionId, activeAgent, worktreePath)
writeBoulderState(directory, newState)
return `
## Auto-Selected Plan
**Plan**: ${getPlanName(planPath)}
**Path**: ${planPath}
**Progress**: ${progress.completed}/${progress.total} tasks
**Session ID**: ${sessionId}
**Started**: ${timestamp}
${worktreeBlock}
boulder.json has been created. Read the plan and begin execution.`
}
function buildMissingPlanContext(explicitPlanName: string, allPlans: string[]): string {
const incompletePlans = allPlans.filter((p) => !getPlanProgress(p).isComplete)
if (incompletePlans.length > 0) {
const planList = incompletePlans
.map((p, i) => {
const prog = getPlanProgress(p)
return `${i + 1}. [${getPlanName(p)}] - Progress: ${prog.completed}/${prog.total}`
})
.join("\n")
return `
## Plan Not Found
Could not find a plan matching "${explicitPlanName}".
Available incomplete plans:
${planList}
Ask the user which plan to work on.`
}
return `
## Plan Not Found
Could not find a plan matching "${explicitPlanName}".
No incomplete plans available. Create a new plan with: /plan "your task"`
}
function buildExplicitPlanContext(params: {
explicitPlanName: string
existingState: ReturnType<typeof readBoulderState>
sessionId: string
timestamp: string
activeAgent: string
worktreePath: string | undefined
worktreeBlock: string
directory: string
}): string {
const { explicitPlanName, existingState, sessionId, timestamp, activeAgent, worktreePath, worktreeBlock, directory } = params
log(`[${HOOK_NAME}] Explicit plan name requested: ${explicitPlanName}`, { sessionID: sessionId })
const allPlans = findPrometheusPlans(directory)
const matchedPlan = findPlanByName(allPlans, explicitPlanName)
if (!matchedPlan) {
return buildMissingPlanContext(explicitPlanName, allPlans)
}
const progress = getPlanProgress(matchedPlan)
if (progress.isComplete) {
return `
## Plan Already Complete
The requested plan "${getPlanName(matchedPlan)}" has been completed.
All ${progress.total} tasks are done. Create a new plan with: /plan "your task"`
}
if (existingState) {
clearBoulderState(directory)
}
return buildAutoSelectedPlanContext({
planPath: matchedPlan,
sessionId,
timestamp,
activeAgent,
worktreePath,
worktreeBlock,
directory,
})
}
function buildExistingSessionContext(params: {
existingState: NonNullable<ReturnType<typeof readBoulderState>>
sessionId: string
activeAgent: string
worktreePath: string | undefined
worktreeBlock: string
directory: string
}): string {
const { existingState, sessionId, activeAgent, worktreePath, worktreeBlock, directory } = params
const progress = getPlanProgress(existingState.active_plan)
if (progress.isComplete) {
return `
## Previous Work Complete
The previous plan (${existingState.plan_name}) has been completed.
Looking for new plans...`
}
const effectiveWorktree = worktreePath ?? existingState.worktree_path
const sessionAlreadyTracked = existingState.session_ids.includes(sessionId)
const updatedSessions = sessionAlreadyTracked
? existingState.session_ids
: [...existingState.session_ids, sessionId]
const shouldRewriteState = existingState.agent !== activeAgent || worktreePath !== undefined
if (shouldRewriteState) {
writeBoulderState(directory, {
...existingState,
agent: activeAgent,
...(worktreePath !== undefined ? { worktree_path: worktreePath } : {}),
session_ids: updatedSessions,
})
} else if (!sessionAlreadyTracked) {
appendSessionId(directory, sessionId)
}
const worktreeDisplay = effectiveWorktree ? worktreeBlock.replace(worktreePath ?? "", effectiveWorktree) : worktreeBlock
return `
## Active Work Session Found
**Status**: RESUMING existing work
**Plan**: ${existingState.plan_name}
**Path**: ${existingState.active_plan}
**Progress**: ${progress.completed}/${progress.total} tasks completed
**Sessions**: ${existingState.session_ids.length + 1} (current session appended)
**Started**: ${existingState.started_at}
${worktreeDisplay}
The current session (${sessionId}) has been added to session_ids.
Read the plan file and continue from the first unchecked task.`
}
function shouldDiscoverPlans(
existingState: ReturnType<typeof readBoulderState>,
explicitPlanName: string | null,
): boolean {
return (!existingState && !explicitPlanName)
|| (existingState !== null && !explicitPlanName && getPlanProgress(existingState.active_plan).isComplete)
}
function buildPlanDiscoveryContext(params: {
contextInfo: string
sessionId: string
timestamp: string
activeAgent: string
worktreePath: string | undefined
worktreeBlock: string
directory: string
}): string {
const { contextInfo, sessionId, timestamp, activeAgent, worktreePath, worktreeBlock, directory } = params
const plans = findPrometheusPlans(directory)
const incompletePlans = plans.filter((p) => !getPlanProgress(p).isComplete)
if (plans.length === 0) {
return contextInfo + `
## No Plans Found
No Prometheus plan files found at .sisyphus/plans/
Use Prometheus to create a work plan first: /plan "your task"`
}
if (incompletePlans.length === 0) {
return contextInfo + `
## All Plans Complete
All ${plans.length} plan(s) are complete. Create a new plan with: /plan "your task"`
}
if (incompletePlans.length === 1) {
return contextInfo + buildAutoSelectedPlanContext({
planPath: incompletePlans[0],
sessionId,
timestamp,
activeAgent,
worktreePath,
worktreeBlock,
directory,
})
}
const planList = incompletePlans
.map((p, i) => {
const progress = getPlanProgress(p)
const modified = new Date(statSync(p).mtimeMs).toISOString()
return `${i + 1}. [${getPlanName(p)}] - Modified: ${modified} - Progress: ${progress.completed}/${progress.total}`
})
.join("\n")
return contextInfo + `
<system-reminder>
## Multiple Plans Found
Current Time: ${timestamp}
Session ID: ${sessionId}
${planList}
Ask the user which plan to work on. Present the options above and wait for their response.
${worktreeBlock}
</system-reminder>`
}
export function buildStartWorkContextInfo(params: {
ctx: PluginInput
explicitPlanName: string | null
existingState: ReturnType<typeof readBoulderState>
sessionId: string
timestamp: string
activeAgent: string
worktreePath: string | undefined
worktreeBlock: string
}): string {
const { ctx, explicitPlanName, existingState, sessionId, timestamp, activeAgent, worktreePath, worktreeBlock } = params
let contextInfo = ""
if (explicitPlanName) {
contextInfo = buildExplicitPlanContext({
explicitPlanName,
existingState,
sessionId,
timestamp,
activeAgent,
worktreePath,
worktreeBlock,
directory: ctx.directory,
})
} else if (existingState) {
contextInfo = buildExistingSessionContext({
existingState,
sessionId,
activeAgent,
worktreePath,
worktreeBlock,
directory: ctx.directory,
})
}
if (shouldDiscoverPlans(existingState, explicitPlanName)) {
return buildPlanDiscoveryContext({
contextInfo,
sessionId,
timestamp,
activeAgent,
worktreePath,
worktreeBlock,
directory: ctx.directory,
})
}
return contextInfo
}
+13 -178
View File
@@ -23,6 +23,7 @@ import {
} from "../../features/claude-code-session-state"
import { detectWorktreePath } from "./worktree-detector"
import { parseUserRequest } from "./parse-user-request"
import { buildStartWorkContextInfo } from "./context-info-builder"
export const HOOK_NAME = "start-work" as const
const START_WORK_TEMPLATE_MARKER = "You are starting a Sisyphus work session."
@@ -43,24 +44,16 @@ interface StartWorkHookOutput {
parts: Array<{ type: string; text?: string }>
}
function findPlanByName(plans: string[], requestedName: string): string | null {
const lowerName = requestedName.toLowerCase()
const exactMatch = plans.find((p) => getPlanName(p).toLowerCase() === lowerName)
if (exactMatch) return exactMatch
const partialMatch = plans.find((p) => getPlanName(p).toLowerCase().includes(lowerName))
return partialMatch || null
}
function createWorktreeActiveBlock(worktreePath: string): string {
return `
## Worktree Active
**Worktree**: \`${worktreePath}\`
**CRITICAL DO NOT FORGET**: You are working inside a git worktree. ALL operations MUST be performed exclusively within this worktree directory.
**CRITICAL - DO NOT FORGET**: You are working inside a git worktree. ALL operations MUST be performed exclusively within this worktree directory.
- Every file read, write, edit, and git operation MUST target paths under: \`${worktreePath}\`
- When delegating tasks to subagents, you MUST include the worktree path in your delegation prompt so they also operate exclusively within the worktree
- NEVER operate on the main repository directory always use the worktree path above`
- NEVER operate on the main repository directory - always use the worktree path above`
}
function resolveWorktreeContext(
@@ -129,174 +122,16 @@ export function createStartWorkHook(ctx: PluginInput) {
const { planName: explicitPlanName, explicitWorktreePath } = parseUserRequest(promptText)
const { worktreePath, block: worktreeBlock } = resolveWorktreeContext(explicitWorktreePath)
let contextInfo = ""
if (explicitPlanName) {
log(`[${HOOK_NAME}] Explicit plan name requested: ${explicitPlanName}`, { sessionID: input.sessionID })
const allPlans = findPrometheusPlans(ctx.directory)
const matchedPlan = findPlanByName(allPlans, explicitPlanName)
if (matchedPlan) {
const progress = getPlanProgress(matchedPlan)
if (progress.isComplete) {
contextInfo = `
## Plan Already Complete
The requested plan "${getPlanName(matchedPlan)}" has been completed.
All ${progress.total} tasks are done. Create a new plan with: /plan "your task"`
} else {
if (existingState) clearBoulderState(ctx.directory)
const newState = createBoulderState(matchedPlan, sessionId, activeAgent, worktreePath)
writeBoulderState(ctx.directory, newState)
contextInfo = `
## Auto-Selected Plan
**Plan**: ${getPlanName(matchedPlan)}
**Path**: ${matchedPlan}
**Progress**: ${progress.completed}/${progress.total} tasks
**Session ID**: ${sessionId}
**Started**: ${timestamp}
${worktreeBlock}
boulder.json has been created. Read the plan and begin execution.`
}
} else {
const incompletePlans = allPlans.filter((p) => !getPlanProgress(p).isComplete)
if (incompletePlans.length > 0) {
const planList = incompletePlans
.map((p, i) => {
const prog = getPlanProgress(p)
return `${i + 1}. [${getPlanName(p)}] - Progress: ${prog.completed}/${prog.total}`
})
.join("\n")
contextInfo = `
## Plan Not Found
Could not find a plan matching "${explicitPlanName}".
Available incomplete plans:
${planList}
Ask the user which plan to work on.`
} else {
contextInfo = `
## Plan Not Found
Could not find a plan matching "${explicitPlanName}".
No incomplete plans available. Create a new plan with: /plan "your task"`
}
}
} else if (existingState) {
const progress = getPlanProgress(existingState.active_plan)
if (!progress.isComplete) {
const effectiveWorktree = worktreePath ?? existingState.worktree_path
const sessionAlreadyTracked = existingState.session_ids.includes(sessionId)
const updatedSessions = sessionAlreadyTracked
? existingState.session_ids
: [...existingState.session_ids, sessionId]
const shouldRewriteState = existingState.agent !== activeAgent || worktreePath !== undefined
if (shouldRewriteState) {
writeBoulderState(ctx.directory, {
...existingState,
agent: activeAgent,
...(worktreePath !== undefined ? { worktree_path: worktreePath } : {}),
session_ids: updatedSessions,
})
} else if (!sessionAlreadyTracked) {
appendSessionId(ctx.directory, sessionId)
}
const worktreeDisplay = effectiveWorktree ? createWorktreeActiveBlock(effectiveWorktree) : worktreeBlock
contextInfo = `
## Active Work Session Found
**Status**: RESUMING existing work
**Plan**: ${existingState.plan_name}
**Path**: ${existingState.active_plan}
**Progress**: ${progress.completed}/${progress.total} tasks completed
**Sessions**: ${existingState.session_ids.length + 1} (current session appended)
**Started**: ${existingState.started_at}
${worktreeDisplay}
The current session (${sessionId}) has been added to session_ids.
Read the plan file and continue from the first unchecked task.`
} else {
contextInfo = `
## Previous Work Complete
The previous plan (${existingState.plan_name}) has been completed.
Looking for new plans...`
}
}
if (
(!existingState && !explicitPlanName) ||
(existingState && !explicitPlanName && getPlanProgress(existingState.active_plan).isComplete)
) {
const plans = findPrometheusPlans(ctx.directory)
const incompletePlans = plans.filter((p) => !getPlanProgress(p).isComplete)
if (plans.length === 0) {
contextInfo += `
## No Plans Found
No Prometheus plan files found at .sisyphus/plans/
Use Prometheus to create a work plan first: /plan "your task"`
} else if (incompletePlans.length === 0) {
contextInfo += `
## All Plans Complete
All ${plans.length} plan(s) are complete. Create a new plan with: /plan "your task"`
} else if (incompletePlans.length === 1) {
const planPath = incompletePlans[0]
const progress = getPlanProgress(planPath)
const newState = createBoulderState(planPath, sessionId, activeAgent, worktreePath)
writeBoulderState(ctx.directory, newState)
contextInfo += `
## Auto-Selected Plan
**Plan**: ${getPlanName(planPath)}
**Path**: ${planPath}
**Progress**: ${progress.completed}/${progress.total} tasks
**Session ID**: ${sessionId}
**Started**: ${timestamp}
${worktreeBlock}
boulder.json has been created. Read the plan and begin execution.`
} else {
const planList = incompletePlans
.map((p, i) => {
const progress = getPlanProgress(p)
const modified = new Date(statSync(p).mtimeMs).toISOString()
return `${i + 1}. [${getPlanName(p)}] - Modified: ${modified} - Progress: ${progress.completed}/${progress.total}`
})
.join("\n")
contextInfo += `
<system-reminder>
## Multiple Plans Found
Current Time: ${timestamp}
Session ID: ${sessionId}
${planList}
Ask the user which plan to work on. Present the options above and wait for their response.
${worktreeBlock}
</system-reminder>`
}
}
const contextInfo = buildStartWorkContextInfo({
ctx,
explicitPlanName,
existingState,
sessionId,
timestamp,
activeAgent,
worktreePath,
worktreeBlock,
})
const idx = output.parts.findIndex((p) => p.type === "text" && p.text)
if (idx >= 0 && output.parts[idx].text) {