feat(features): add TaskToastManager for consolidated task notifications
- Create task-toast-manager feature with singleton pattern - Show running task list (newest first) when new task starts - Track queued tasks status from ConcurrencyManager - Integrate with BackgroundManager and sisyphus-task tool 🤖 Generated with [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) assistance
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
import type { PluginInput } from "@opencode-ai/plugin"
|
||||
import { existsSync, readdirSync } from "node:fs"
|
||||
import { join } from "node:path"
|
||||
import { HOOK_NAME, PROMETHEUS_AGENTS, ALLOWED_EXTENSIONS, ALLOWED_PATH_PREFIX, BLOCKED_TOOLS, PLANNING_CONSULT_WARNING } from "./constants"
|
||||
import { findNearestMessageWithFields, MESSAGE_STORAGE } from "../../features/hook-message-injector"
|
||||
import { log } from "../../shared/logger"
|
||||
|
||||
export * from "./constants"
|
||||
@@ -10,15 +13,35 @@ function isAllowedFile(filePath: string): boolean {
|
||||
return hasAllowedExtension && isInAllowedPath
|
||||
}
|
||||
|
||||
function getMessageDir(sessionID: string): string | null {
|
||||
if (!existsSync(MESSAGE_STORAGE)) return null
|
||||
|
||||
const directPath = join(MESSAGE_STORAGE, sessionID)
|
||||
if (existsSync(directPath)) return directPath
|
||||
|
||||
for (const dir of readdirSync(MESSAGE_STORAGE)) {
|
||||
const sessionPath = join(MESSAGE_STORAGE, dir, sessionID)
|
||||
if (existsSync(sessionPath)) return sessionPath
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
const TASK_TOOLS = ["sisyphus_task", "task", "call_omo_agent"]
|
||||
|
||||
function getAgentFromSession(sessionID: string): string | undefined {
|
||||
const messageDir = getMessageDir(sessionID)
|
||||
if (!messageDir) return undefined
|
||||
return findNearestMessageWithFields(messageDir)?.agent
|
||||
}
|
||||
|
||||
export function createPrometheusMdOnlyHook(_ctx: PluginInput) {
|
||||
return {
|
||||
"tool.execute.before": async (
|
||||
input: { tool: string; sessionID: string; callID: string; agent?: string },
|
||||
input: { tool: string; sessionID: string; callID: string },
|
||||
output: { args: Record<string, unknown>; message?: string }
|
||||
): Promise<void> => {
|
||||
const agentName = input.agent
|
||||
const agentName = getAgentFromSession(input.sessionID)
|
||||
|
||||
if (!agentName || !PROMETHEUS_AGENTS.includes(agentName)) {
|
||||
return
|
||||
|
||||
@@ -14,6 +14,37 @@ import type { BackgroundManager } from "../../features/background-agent"
|
||||
|
||||
export const HOOK_NAME = "sisyphus-orchestrator"
|
||||
|
||||
const ALLOWED_PATH_PREFIX = ".sisyphus/"
|
||||
const WRITE_EDIT_TOOLS = ["Write", "Edit", "write", "edit"]
|
||||
|
||||
const DIRECT_WORK_REMINDER = `
|
||||
|
||||
---
|
||||
|
||||
[SYSTEM REMINDER - DELEGATION REQUIRED]
|
||||
|
||||
You just performed direct file modifications outside \`.sisyphus/\`.
|
||||
|
||||
**Sisyphus is an ORCHESTRATOR, not an IMPLEMENTER.**
|
||||
|
||||
As an orchestrator, you should:
|
||||
- **DELEGATE** implementation work to subagents via \`sisyphus_task\`
|
||||
- **VERIFY** the work done by subagents
|
||||
- **COORDINATE** multiple tasks and ensure completion
|
||||
|
||||
You should NOT:
|
||||
- Write code directly (except for \`.sisyphus/\` files like plans and notepads)
|
||||
- Make direct file edits outside \`.sisyphus/\`
|
||||
- Implement features yourself
|
||||
|
||||
**If you need to make changes:**
|
||||
1. Use \`sisyphus_task\` to delegate to an appropriate subagent
|
||||
2. Provide clear instructions in the prompt
|
||||
3. Verify the subagent's work after completion
|
||||
|
||||
---
|
||||
`
|
||||
|
||||
const BOULDER_CONTINUATION_PROMPT = `[SYSTEM REMINDER - BOULDER CONTINUATION]
|
||||
|
||||
You have an active work plan with incomplete tasks. Continue working.
|
||||
@@ -208,12 +239,20 @@ interface ToolExecuteInput {
|
||||
agent?: string
|
||||
}
|
||||
|
||||
interface ToolExecuteOutput {
|
||||
interface ToolExecuteAfterInput {
|
||||
tool: string
|
||||
sessionID?: string
|
||||
callID?: string
|
||||
}
|
||||
|
||||
interface ToolExecuteAfterOutput {
|
||||
title: string
|
||||
output: string
|
||||
metadata: unknown
|
||||
metadata: Record<string, unknown>
|
||||
}
|
||||
|
||||
type ToolExecuteOutput = ToolExecuteAfterOutput
|
||||
|
||||
function getMessageDir(sessionID: string): string | null {
|
||||
if (!existsSync(MESSAGE_STORAGE)) return null
|
||||
|
||||
@@ -427,9 +466,26 @@ export function createSisyphusOrchestratorHook(
|
||||
},
|
||||
|
||||
"tool.execute.after": async (
|
||||
input: ToolExecuteInput,
|
||||
output: ToolExecuteOutput
|
||||
input: ToolExecuteAfterInput,
|
||||
output: ToolExecuteAfterOutput
|
||||
): Promise<void> => {
|
||||
if (!isCallerOrchestrator(input.sessionID)) {
|
||||
return
|
||||
}
|
||||
|
||||
if (WRITE_EDIT_TOOLS.includes(input.tool)) {
|
||||
const filePath = output.metadata?.filePath as string | undefined
|
||||
if (filePath && !filePath.includes(ALLOWED_PATH_PREFIX)) {
|
||||
output.output = (output.output || "") + DIRECT_WORK_REMINDER
|
||||
log(`[${HOOK_NAME}] Direct work reminder appended`, {
|
||||
sessionID: input.sessionID,
|
||||
tool: input.tool,
|
||||
filePath,
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (input.tool !== "sisyphus_task") {
|
||||
return
|
||||
}
|
||||
@@ -440,10 +496,6 @@ export function createSisyphusOrchestratorHook(
|
||||
if (isBackgroundLaunch) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!isCallerOrchestrator(input.sessionID)) {
|
||||
return
|
||||
}
|
||||
|
||||
if (output.output && typeof output.output === "string") {
|
||||
const gitStats = getGitDiffStats(ctx.directory)
|
||||
|
||||
Reference in New Issue
Block a user