YeonGyu-Kim 2925402c4f refactor(hooks): remove duplicate verification enforcement from start-work hook
Verification reminders are now centralized in sisyphus-orchestrator hook,
eliminating redundant code in start-work. The orchestrator hook handles all
verification messaging across both boulder and standalone modes.
2026-01-08 23:07:05 +09:00

145 lines
4.1 KiB
TypeScript

import type { PluginInput } from "@opencode-ai/plugin"
import {
readBoulderState,
writeBoulderState,
appendSessionId,
findPrometheusPlans,
getPlanProgress,
createBoulderState,
getPlanName,
} from "../../features/boulder-state"
import { log } from "../../shared/logger"
export const HOOK_NAME = "start-work"
interface StartWorkHookInput {
sessionID: string
messageID?: string
}
interface StartWorkHookOutput {
parts: Array<{ type: string; text?: string }>
}
export function createStartWorkHook(ctx: PluginInput) {
return {
"chat.message": async (
input: StartWorkHookInput,
output: StartWorkHookOutput
): Promise<void> => {
const parts = output.parts
const promptText = parts
?.filter((p) => p.type === "text" && p.text)
.map((p) => p.text)
.join("\n")
.trim() || ""
const isStartWorkCommand =
promptText.includes("Start Sisyphus work session") ||
promptText.includes("<session-context>")
if (!isStartWorkCommand) {
return
}
log(`[${HOOK_NAME}] Processing start-work command`, {
sessionID: input.sessionID,
})
const existingState = readBoulderState(ctx.directory)
const sessionId = input.sessionID
const timestamp = new Date().toISOString()
let contextInfo = ""
if (existingState) {
const progress = getPlanProgress(existingState.active_plan)
if (!progress.isComplete) {
appendSessionId(ctx.directory, sessionId)
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}
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 || getPlanProgress(existingState.active_plan).isComplete) {
const plans = findPrometheusPlans(ctx.directory)
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 (plans.length === 1) {
const planPath = plans[0]
const progress = getPlanProgress(planPath)
const newState = createBoulderState(planPath, sessionId)
writeBoulderState(ctx.directory, newState)
contextInfo += `
## Auto-Selected Plan
**Plan**: ${getPlanName(planPath)}
**Path**: ${planPath}
**Progress**: ${progress.completed}/${progress.total} tasks
**Session ID**: ${sessionId}
**Started**: ${timestamp}
boulder.json has been created. Read the plan and begin execution.`
} else {
const planList = plans.map((p, i) => {
const progress = getPlanProgress(p)
const stat = require("node:fs").statSync(p)
const modified = new Date(stat.mtimeMs).toISOString()
return `${i + 1}. [${getPlanName(p)}] - Modified: ${modified} - Progress: ${progress.completed}/${progress.total}`
}).join("\n")
contextInfo += `
## Multiple Plans Found
Current Time: ${timestamp}
Session ID: ${sessionId}
${planList}
Which plan would you like to work on? Reply with the number or plan name.`
}
}
const idx = output.parts.findIndex((p) => p.type === "text" && p.text)
if (idx >= 0 && output.parts[idx].text) {
output.parts[idx].text = output.parts[idx].text
.replace(/\$SESSION_ID/g, sessionId)
.replace(/\$TIMESTAMP/g, timestamp)
output.parts[idx].text += `\n\n---\n${contextInfo}`
}
log(`[${HOOK_NAME}] Context injected`, {
sessionID: input.sessionID,
hasExistingState: !!existingState,
})
},
}
}