sisyphi 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +175 -0
- package/dist/chunk-5WP7O7D3.js +56 -0
- package/dist/chunk-5WP7O7D3.js.map +1 -0
- package/dist/cli.js +532 -0
- package/dist/cli.js.map +1 -0
- package/dist/daemon.js +983 -0
- package/dist/daemon.js.map +1 -0
- package/dist/templates/agent-suffix.md +61 -0
- package/dist/templates/orchestrator.md +152 -0
- package/package.json +49 -0
- package/templates/agent-suffix.md +61 -0
- package/templates/orchestrator.md +152 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/daemon/index.ts","../src/shared/config.ts","../src/daemon/server.ts","../src/daemon/session-manager.ts","../src/daemon/state.ts","../src/daemon/orchestrator.ts","../src/daemon/tmux.ts","../src/daemon/colors.ts","../src/daemon/agent.ts","../src/daemon/pane-monitor.ts"],"sourcesContent":["import { mkdirSync, readFileSync, writeFileSync, unlinkSync, existsSync } from 'node:fs';\nimport { globalDir, daemonPidPath, statePath } from '../shared/paths.js';\nimport { loadConfig } from '../shared/config.js';\nimport { startServer, stopServer, registerSessionCwd, loadSessionRegistry } from './server.js';\nimport { startMonitor, stopMonitor, setRespawnCallback } from './pane-monitor.js';\nimport { onAllAgentsDone } from './session-manager.js';\n\nfunction ensureDirs(): void {\n mkdirSync(globalDir(), { recursive: true });\n}\n\nfunction isProcessAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction acquirePidLock(): void {\n const pidFile = daemonPidPath();\n try {\n const existing = parseInt(readFileSync(pidFile, 'utf-8').trim(), 10);\n if (existing && isProcessAlive(existing)) {\n console.error(`[sisyphus] Daemon already running (pid ${existing}). Kill it first or remove ${pidFile}`);\n process.exit(1);\n }\n } catch {\n // No pidfile or unreadable — proceed\n }\n writeFileSync(pidFile, String(process.pid), 'utf-8');\n}\n\nfunction releasePidLock(): void {\n try {\n unlinkSync(daemonPidPath());\n } catch {\n // Already gone\n }\n}\n\nfunction recoverSessions(): void {\n const registry = loadSessionRegistry();\n const entries = Object.entries(registry);\n\n if (entries.length === 0) {\n console.log('[sisyphus] No sessions to recover');\n return;\n }\n\n let recovered = 0;\n for (const [sessionId, cwd] of entries) {\n const stateFile = statePath(cwd, sessionId);\n if (!existsSync(stateFile)) {\n continue;\n }\n\n try {\n const session = JSON.parse(readFileSync(stateFile, 'utf-8')) as { status: string };\n if (session.status === 'active' || session.status === 'paused') {\n registerSessionCwd(sessionId, cwd);\n recovered++;\n }\n } catch {\n console.error(`[sisyphus] Failed to read session state for ${sessionId}, skipping`);\n }\n }\n\n console.log(`[sisyphus] Recovered ${recovered} session(s) from registry`);\n}\n\nasync function main(): Promise<void> {\n console.log('[sisyphus] Starting daemon...');\n ensureDirs();\n acquirePidLock();\n\n const config = loadConfig(process.cwd());\n\n setRespawnCallback(onAllAgentsDone);\n\n await startServer();\n startMonitor(config.pollIntervalMs);\n\n recoverSessions();\n\n const shutdown = async () => {\n console.log('[sisyphus] Shutting down...');\n stopMonitor();\n await stopServer();\n releasePidLock();\n process.exit(0);\n };\n\n process.on('SIGTERM', shutdown);\n process.on('SIGINT', shutdown);\n}\n\nmain().catch((err) => {\n console.error('[sisyphus] Fatal error:', err);\n process.exit(1);\n});\n","import { readFileSync } from 'node:fs';\nimport { globalConfigPath, projectConfigPath } from './paths.js';\n\nexport interface Config {\n model?: string;\n tmuxSession?: string;\n orchestratorPrompt?: string;\n pollIntervalMs?: number;\n}\n\nconst DEFAULT_CONFIG: Config = {\n pollIntervalMs: 1000,\n};\n\nfunction readJsonFile(filePath: string): Partial<Config> {\n try {\n const content = readFileSync(filePath, 'utf-8');\n return JSON.parse(content) as Partial<Config>;\n } catch {\n return {};\n }\n}\n\nexport function loadConfig(cwd: string): Config {\n const global = readJsonFile(globalConfigPath());\n const project = readJsonFile(projectConfigPath(cwd));\n return { ...DEFAULT_CONFIG, ...global, ...project };\n}\n","import { createServer, type Server } from 'node:net';\nimport { unlinkSync, existsSync, writeFileSync, readFileSync, mkdirSync } from 'node:fs';\nimport { socketPath, globalDir } from '../shared/paths.js';\nimport { join } from 'node:path';\nimport type { Request, Response } from '../shared/protocol.js';\nimport * as sessionManager from './session-manager.js';\n\nlet server: Server | null = null;\n\n// Track the cwd for each session so we can route requests\nconst sessionCwdMap = new Map<string, string>();\n// Track the originating tmux session for each sisyphus session\nconst sessionTmuxMap = new Map<string, string>();\n// Track the originating tmux window for each sisyphus session\nconst sessionWindowMap = new Map<string, string>();\n\nexport function getSessionCwd(sessionId: string): string | undefined {\n return sessionCwdMap.get(sessionId);\n}\n\nexport function getSessionTmux(sessionId: string): string | undefined {\n return sessionTmuxMap.get(sessionId);\n}\n\nfunction registryPath(): string {\n return join(globalDir(), 'session-registry.json');\n}\n\nfunction persistSessionRegistry(): void {\n const dir = globalDir();\n mkdirSync(dir, { recursive: true });\n const registry: Record<string, string> = {};\n for (const [id, cwd] of sessionCwdMap) {\n registry[id] = cwd;\n }\n writeFileSync(registryPath(), JSON.stringify(registry, null, 2), 'utf-8');\n}\n\nexport function loadSessionRegistry(): Record<string, string> {\n const p = registryPath();\n if (!existsSync(p)) return {};\n try {\n return JSON.parse(readFileSync(p, 'utf-8')) as Record<string, string>;\n } catch {\n return {};\n }\n}\n\nexport function registerSessionCwd(sessionId: string, cwd: string): void {\n sessionCwdMap.set(sessionId, cwd);\n persistSessionRegistry();\n}\n\nasync function handleRequest(req: Request): Promise<Response> {\n try {\n switch (req.type) {\n case 'start': {\n const session = await sessionManager.startSession(req.task, req.cwd, req.tmuxSession, req.tmuxWindow);\n registerSessionCwd(session.id, req.cwd);\n sessionTmuxMap.set(session.id, req.tmuxSession);\n sessionWindowMap.set(session.id, req.tmuxWindow);\n return { ok: true, data: { sessionId: session.id } };\n }\n\n case 'spawn': {\n const cwd = sessionCwdMap.get(req.sessionId);\n if (!cwd) return { ok: false, error: `Unknown session: ${req.sessionId}` };\n const result = await sessionManager.handleSpawn(req.sessionId, cwd, req.agentType, req.name, req.instruction);\n return { ok: true, data: { agentId: result.agentId } };\n }\n\n case 'submit': {\n const cwd = sessionCwdMap.get(req.sessionId);\n if (!cwd) return { ok: false, error: `Unknown session: ${req.sessionId}` };\n const windowId = sessionWindowMap.get(req.sessionId);\n if (!windowId) return { ok: false, error: `No tmux window found for session: ${req.sessionId}` };\n await sessionManager.handleSubmit(cwd, req.sessionId, req.agentId, req.report, windowId);\n return { ok: true };\n }\n\n case 'report': {\n const cwd = sessionCwdMap.get(req.sessionId);\n if (!cwd) return { ok: false, error: `Unknown session: ${req.sessionId}` };\n await sessionManager.handleReport(cwd, req.sessionId, req.agentId, req.content);\n return { ok: true };\n }\n\n case 'yield': {\n const cwd = sessionCwdMap.get(req.sessionId);\n if (!cwd) return { ok: false, error: `Unknown session: ${req.sessionId}` };\n await sessionManager.handleYield(req.sessionId, cwd);\n return { ok: true };\n }\n\n case 'complete': {\n const cwd = sessionCwdMap.get(req.sessionId);\n if (!cwd) return { ok: false, error: `Unknown session: ${req.sessionId}` };\n await sessionManager.handleComplete(req.sessionId, cwd, req.report);\n return { ok: true };\n }\n\n case 'status': {\n if (req.sessionId) {\n const cwd = sessionCwdMap.get(req.sessionId);\n if (!cwd) return { ok: false, error: `Unknown session: ${req.sessionId}` };\n const session = sessionManager.getSessionStatus(cwd, req.sessionId);\n return { ok: true, data: { session: session as unknown as Record<string, unknown> } };\n }\n return { ok: true, data: { message: 'daemon running' } };\n }\n\n case 'tasks_add': {\n const cwd = sessionCwdMap.get(req.sessionId);\n if (!cwd) return { ok: false, error: `Unknown session: ${req.sessionId}` };\n const result = await sessionManager.handleTaskAdd(cwd, req.sessionId, req.description, req.status);\n return { ok: true, data: { taskId: result.taskId } };\n }\n\n case 'tasks_update': {\n const cwd = sessionCwdMap.get(req.sessionId);\n if (!cwd) return { ok: false, error: `Unknown session: ${req.sessionId}` };\n await sessionManager.handleTaskUpdate(cwd, req.sessionId, req.taskId, req.status, req.description);\n return { ok: true };\n }\n\n case 'tasks_list': {\n const cwd = sessionCwdMap.get(req.sessionId);\n if (!cwd) return { ok: false, error: `Unknown session: ${req.sessionId}` };\n const result = sessionManager.handleTasksList(cwd, req.sessionId);\n return { ok: true, data: { tasks: result.tasks as unknown as Record<string, unknown> } };\n }\n\n case 'list': {\n // List sessions across all known cwds\n const allSessions: Array<Record<string, unknown>> = [];\n const seenCwds = new Set<string>();\n for (const cwd of sessionCwdMap.values()) {\n if (seenCwds.has(cwd)) continue;\n seenCwds.add(cwd);\n const sessions = sessionManager.listSessions(cwd);\n allSessions.push(...sessions.map(s => s as unknown as Record<string, unknown>));\n }\n return { ok: true, data: { sessions: allSessions } };\n }\n\n case 'resume': {\n let cwd = sessionCwdMap.get(req.sessionId);\n if (!cwd) {\n // Session not in memory — try to recover from disk using the cwd provided by CLI\n const stateFile = `${req.cwd}/.sisyphus/sessions/${req.sessionId}/state.json`;\n if (existsSync(stateFile)) {\n cwd = req.cwd;\n registerSessionCwd(req.sessionId, cwd);\n } else {\n return { ok: false, error: `Unknown session: ${req.sessionId}. No state.json found at ${stateFile}` };\n }\n }\n sessionTmuxMap.set(req.sessionId, req.tmuxSession);\n sessionWindowMap.set(req.sessionId, req.tmuxWindow);\n const session = await sessionManager.resumeSession(req.sessionId, cwd, req.tmuxSession, req.tmuxWindow, req.message);\n return { ok: true, data: { sessionId: session.id, status: session.status } };\n }\n\n case 'register_claude_session': {\n const cwd = sessionCwdMap.get(req.sessionId);\n if (!cwd) return { ok: false, error: `Unknown session: ${req.sessionId}` };\n await sessionManager.handleRegisterClaudeSession(cwd, req.sessionId, req.agentId, req.claudeSessionId);\n return { ok: true };\n }\n\n case 'kill': {\n const cwd = sessionCwdMap.get(req.sessionId);\n if (!cwd) return { ok: false, error: `Unknown session: ${req.sessionId}` };\n const killedAgents = await sessionManager.handleKill(req.sessionId, cwd);\n sessionCwdMap.delete(req.sessionId);\n sessionTmuxMap.delete(req.sessionId);\n sessionWindowMap.delete(req.sessionId);\n persistSessionRegistry();\n return { ok: true, data: { killedAgents, sessionId: req.sessionId } };\n }\n\n default:\n return { ok: false, error: `Unknown request type: ${(req as Record<string, unknown>).type}` };\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return { ok: false, error: message };\n }\n}\n\nexport function startServer(): Promise<Server> {\n return new Promise((resolve, reject) => {\n const sock = socketPath();\n\n if (existsSync(sock)) {\n unlinkSync(sock);\n }\n\n server = createServer((conn) => {\n let buffer = '';\n\n conn.on('data', (chunk) => {\n buffer += chunk.toString();\n const lines = buffer.split('\\n');\n buffer = lines.pop()!;\n\n for (const line of lines) {\n if (!line.trim()) continue;\n let req: Request;\n try {\n req = JSON.parse(line) as Request;\n } catch {\n conn.write(JSON.stringify({ ok: false, error: 'Invalid JSON' }) + '\\n');\n continue;\n }\n\n handleRequest(req).then((res) => {\n conn.write(JSON.stringify(res) + '\\n');\n });\n }\n });\n\n conn.on('error', (err) => {\n console.error('[sisyphus] Connection error:', err.message);\n });\n });\n\n server.on('error', reject);\n\n server.listen(sock, () => {\n console.log(`[sisyphus] Daemon listening on ${sock}`);\n resolve(server!);\n });\n });\n}\n\nexport function stopServer(): Promise<void> {\n return new Promise((resolve) => {\n if (!server) {\n resolve();\n return;\n }\n server.close(() => {\n const sock = socketPath();\n if (existsSync(sock)) {\n unlinkSync(sock);\n }\n server = null;\n resolve();\n });\n });\n}\n","import { v4 as uuidv4 } from 'uuid';\nimport { existsSync, readdirSync } from 'node:fs';\nimport * as state from './state.js';\nimport * as orchestrator from './orchestrator.js';\nimport * as tmux from './tmux.js';\nimport { spawnAgent, resetAgentCounter, clearAgentCounter, handleAgentSubmit, handleAgentReport } from './agent.js';\nimport { trackSession, untrackSession, updateTrackedWindow } from './pane-monitor.js';\nimport { resetColors } from './colors.js';\nimport { sessionsDir } from '../shared/paths.js';\nimport type { Session, TaskStatus } from '../shared/types.js';\n\nexport async function startSession(task: string, cwd: string, tmuxSession: string, windowId: string): Promise<Session> {\n const sessionId = uuidv4();\n const session = state.createSession(sessionId, task, cwd);\n\n trackSession(sessionId, cwd, tmuxSession);\n await orchestrator.spawnOrchestrator(sessionId, cwd, windowId);\n updateTrackedWindow(sessionId, windowId);\n\n return session;\n}\n\nexport async function resumeSession(sessionId: string, cwd: string, tmuxSession: string, windowId: string, message?: string): Promise<Session> {\n const session = state.getSession(cwd, sessionId);\n\n // Mark any \"running\" agents as \"lost\"\n for (const agent of session.agents) {\n if (agent.status === 'running') {\n await state.updateAgent(cwd, sessionId, agent.id, {\n status: 'lost',\n completedAt: new Date().toISOString(),\n killedReason: 'session resumed — agent was still running',\n });\n }\n }\n\n await state.updateSessionStatus(cwd, sessionId, 'active');\n\n // Reset counters based on existing agents\n resetAgentCounter(sessionId, session.agents.length);\n resetColors(sessionId);\n\n trackSession(sessionId, cwd, tmuxSession);\n await orchestrator.spawnOrchestrator(sessionId, cwd, windowId, message);\n updateTrackedWindow(sessionId, windowId);\n\n return state.getSession(cwd, sessionId);\n}\n\nexport function getSessionStatus(cwd: string, sessionId: string): Session {\n return state.getSession(cwd, sessionId);\n}\n\nexport function listSessions(cwd: string): Array<{ id: string; task: string; status: string; createdAt: string; agentCount: number }> {\n const dir = sessionsDir(cwd);\n if (!existsSync(dir)) return [];\n\n const entries = readdirSync(dir, { withFileTypes: true });\n const sessions: Array<{ id: string; task: string; status: string; createdAt: string; agentCount: number }> = [];\n\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n try {\n const session = state.getSession(cwd, entry.name);\n sessions.push({\n id: session.id,\n task: session.task,\n status: session.status,\n createdAt: session.createdAt,\n agentCount: session.agents.length,\n });\n } catch (err) {\n console.error(`[sisyphus] Failed to read session ${entry.name}:`, err);\n }\n }\n\n return sessions;\n}\n\nexport function onAllAgentsDone(sessionId: string, cwd: string, windowId: string): void {\n const session = state.getSession(cwd, sessionId);\n if (session.status !== 'active') return;\n\n // Delay to let /exit finish quitting the previous Claude session\n setTimeout(() => {\n orchestrator.spawnOrchestrator(sessionId, cwd, windowId)\n .then(() => updateTrackedWindow(sessionId, windowId))\n .catch((err: unknown) => console.error(`[sisyphus] Failed to respawn orchestrator for session ${sessionId}:`, err));\n }, 2000);\n}\n\nexport async function handleSpawn(\n sessionId: string,\n cwd: string,\n agentType: string,\n name: string,\n instruction: string,\n): Promise<{ agentId: string }> {\n const windowId = orchestrator.getWindowId(sessionId);\n if (!windowId) throw new Error(`No tmux window found for session ${sessionId}`);\n\n const agent = await spawnAgent({\n sessionId,\n cwd,\n agentType,\n name,\n instruction,\n windowId,\n });\n\n await state.appendAgentToLastCycle(cwd, sessionId, agent.id);\n\n return { agentId: agent.id };\n}\n\nexport async function handleSubmit(cwd: string, sessionId: string, agentId: string, report: string, windowId: string): Promise<void> {\n const allDone = await handleAgentSubmit(cwd, sessionId, agentId, report);\n if (allDone) {\n onAllAgentsDone(sessionId, cwd, windowId);\n }\n}\n\nexport async function handleReport(cwd: string, sessionId: string, agentId: string, content: string): Promise<void> {\n await handleAgentReport(cwd, sessionId, agentId, content);\n}\n\nexport async function handleYield(sessionId: string, cwd: string): Promise<void> {\n await orchestrator.handleOrchestratorYield(sessionId, cwd);\n}\n\nexport async function handleComplete(sessionId: string, cwd: string, report: string): Promise<void> {\n untrackSession(sessionId);\n await orchestrator.handleOrchestratorComplete(sessionId, cwd, report);\n}\n\nexport async function handleTaskAdd(cwd: string, sessionId: string, description: string, initialStatus?: string): Promise<{ taskId: string }> {\n const VALID_STATUSES: Set<string> = new Set(['draft', 'pending', 'in_progress', 'done']);\n const status = initialStatus !== undefined && VALID_STATUSES.has(initialStatus) ? initialStatus as TaskStatus : undefined;\n const task = await state.addTask(cwd, sessionId, description, status);\n return { taskId: task.id };\n}\n\nexport async function handleTaskUpdate(cwd: string, sessionId: string, taskId: string, status?: string, description?: string): Promise<void> {\n const VALID_STATUSES: Set<string> = new Set(['draft', 'pending', 'in_progress', 'done']);\n const updates: { status?: TaskStatus; description?: string } = {};\n if (status !== undefined) {\n if (!VALID_STATUSES.has(status)) throw new Error(`Invalid status: ${status}. Valid: draft, pending, in_progress, done`);\n updates.status = status as TaskStatus;\n }\n if (description !== undefined) updates.description = description;\n await state.updateTask(cwd, sessionId, taskId, updates);\n}\n\nexport function handleTasksList(cwd: string, sessionId: string): { tasks: Session['tasks'] } {\n const session = state.getSession(cwd, sessionId);\n return { tasks: session.tasks };\n}\n\nexport async function handleRegisterClaudeSession(\n cwd: string,\n sessionId: string,\n agentId: string,\n claudeSessionId: string,\n): Promise<void> {\n await state.updateAgent(cwd, sessionId, agentId, { claudeSessionId });\n}\n\nexport async function handleKill(sessionId: string, cwd: string): Promise<number> {\n const session = state.getSession(cwd, sessionId);\n const windowId = orchestrator.getWindowId(sessionId);\n\n // Kill all running agents\n let killedAgents = 0;\n for (const agent of session.agents) {\n if (agent.status === 'running') {\n await state.updateAgent(cwd, sessionId, agent.id, {\n status: 'killed',\n killedReason: 'session killed by user',\n completedAt: new Date().toISOString(),\n });\n killedAgents++;\n }\n }\n\n // Kill the orchestrator pane if it exists\n const orchPaneId = orchestrator.getOrchestratorPaneId(sessionId);\n if (orchPaneId) {\n tmux.killPane(orchPaneId);\n }\n\n // Mark session as completed\n await state.updateSessionStatus(cwd, sessionId, 'completed');\n\n // Untrack from pane monitor\n untrackSession(sessionId);\n\n // Kill the entire tmux window\n if (windowId) {\n tmux.killWindow(windowId);\n }\n\n // Clean up agent counter\n clearAgentCounter(sessionId);\n\n return killedAgents;\n}\n","import { readFileSync, writeFileSync, mkdirSync, renameSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { randomUUID } from 'node:crypto';\nimport type { Session, Agent, AgentReport, Task, OrchestratorCycle, SessionStatus, TaskStatus } from '../shared/types.js';\nimport { statePath, sessionDir } from '../shared/paths.js';\n\n// Per-session mutex to prevent read-modify-write races\nconst sessionLocks = new Map<string, Promise<void>>();\n\nasync function withSessionLock<T>(sessionId: string, fn: () => T): Promise<T> {\n const prev = sessionLocks.get(sessionId) ?? Promise.resolve();\n let resolve: () => void;\n const next = new Promise<void>(r => { resolve = r; });\n sessionLocks.set(sessionId, next);\n await prev;\n try {\n return fn();\n } finally {\n resolve!();\n }\n}\n\nfunction atomicWrite(filePath: string, data: string): void {\n const dir = dirname(filePath);\n const tmpPath = join(dir, `.state.${randomUUID()}.tmp`);\n writeFileSync(tmpPath, data, 'utf-8');\n renameSync(tmpPath, filePath);\n}\n\nexport function createSession(id: string, task: string, cwd: string): Session {\n const dir = sessionDir(cwd, id);\n mkdirSync(dir, { recursive: true });\n\n const session: Session = {\n id,\n task,\n cwd,\n status: 'active',\n createdAt: new Date().toISOString(),\n tasks: [],\n agents: [],\n orchestratorCycles: [],\n };\n\n atomicWrite(statePath(cwd, id), JSON.stringify(session, null, 2));\n return session;\n}\n\nexport function getSession(cwd: string, sessionId: string): Session {\n const content = readFileSync(statePath(cwd, sessionId), 'utf-8');\n return JSON.parse(content) as Session;\n}\n\nfunction saveSession(session: Session): void {\n atomicWrite(statePath(session.cwd, session.id), JSON.stringify(session, null, 2));\n}\n\nexport async function addTask(cwd: string, sessionId: string, description: string, initialStatus?: TaskStatus): Promise<Task> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n const nextNum = session.tasks.length + 1;\n const task: Task = {\n id: `t${nextNum}`,\n description,\n status: initialStatus !== undefined ? initialStatus : 'pending',\n };\n session.tasks.push(task);\n saveSession(session);\n return task;\n });\n}\n\nexport async function updateTask(cwd: string, sessionId: string, taskId: string, updates: { status?: TaskStatus; description?: string }): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n const task = session.tasks.find(t => t.id === taskId);\n if (!task) throw new Error(`Task ${taskId} not found in session ${sessionId}`);\n if (updates.status) task.status = updates.status;\n if (updates.description) task.description = updates.description;\n saveSession(session);\n });\n}\n\nexport async function addAgent(cwd: string, sessionId: string, agent: Agent): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n session.agents.push(agent);\n saveSession(session);\n });\n}\n\nexport async function updateAgent(cwd: string, sessionId: string, agentId: string, updates: Partial<Agent>): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n const agent = session.agents.find(a => a.id === agentId);\n if (!agent) throw new Error(`Agent ${agentId} not found in session ${sessionId}`);\n Object.assign(agent, updates);\n saveSession(session);\n });\n}\n\nexport async function addOrchestratorCycle(cwd: string, sessionId: string, cycle: OrchestratorCycle): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n session.orchestratorCycles.push(cycle);\n saveSession(session);\n });\n}\n\nexport async function updateSessionStatus(cwd: string, sessionId: string, status: SessionStatus, completionReport?: string): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n session.status = status;\n if (completionReport !== undefined) {\n session.completionReport = completionReport;\n }\n saveSession(session);\n });\n}\n\nexport async function appendAgentToLastCycle(cwd: string, sessionId: string, agentId: string): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n const cycles = session.orchestratorCycles;\n if (cycles.length === 0) return;\n cycles[cycles.length - 1]!.agentsSpawned.push(agentId);\n saveSession(session);\n });\n}\n\nexport async function completeSession(cwd: string, sessionId: string, report: string): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n session.status = 'completed';\n session.completedAt = new Date().toISOString();\n session.completionReport = report;\n saveSession(session);\n });\n}\n\nexport async function appendAgentReport(cwd: string, sessionId: string, agentId: string, entry: AgentReport): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n const agent = session.agents.find(a => a.id === agentId);\n if (!agent) throw new Error(`Agent ${agentId} not found in session ${sessionId}`);\n agent.reports.push(entry);\n saveSession(session);\n });\n}\n\nexport async function completeOrchestratorCycle(cwd: string, sessionId: string): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n const cycles = session.orchestratorCycles;\n if (cycles.length === 0) return;\n cycles[cycles.length - 1]!.completedAt = new Date().toISOString();\n saveSession(session);\n });\n}\n","import { readFileSync, existsSync, writeFileSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport * as state from './state.js';\nimport * as tmux from './tmux.js';\nimport { ORCHESTRATOR_COLOR } from './colors.js';\nimport { projectOrchestratorPromptPath, sessionDir } from '../shared/paths.js';\nimport type { Session, Agent } from '../shared/types.js';\n\nfunction shellQuote(s: string): string {\n return `'${s.replace(/'/g, \"'\\\\''\")}'`;\n}\n\nconst sessionWindowMap = new Map<string, string>();\nconst sessionOrchestratorPane = new Map<string, string>();\n\nexport function getWindowId(sessionId: string): string | undefined {\n return sessionWindowMap.get(sessionId);\n}\n\nexport function setWindowId(sessionId: string, windowId: string): void {\n sessionWindowMap.set(sessionId, windowId);\n}\n\nexport function getOrchestratorPaneId(sessionId: string): string | undefined {\n return sessionOrchestratorPane.get(sessionId);\n}\n\nfunction loadOrchestratorPrompt(cwd: string): string {\n const projectPath = projectOrchestratorPromptPath(cwd);\n if (existsSync(projectPath)) {\n return readFileSync(projectPath, 'utf-8');\n }\n const bundledPath = resolve(import.meta.dirname, '../templates/orchestrator.md');\n return readFileSync(bundledPath, 'utf-8');\n}\n\nfunction formatStateForOrchestrator(session: Session): string {\n const shortId = session.id.slice(0, 8);\n const cycleNum = session.orchestratorCycles.length;\n\n const taskLines = session.tasks.length > 0\n ? session.tasks.map(t => `- ${t.id}: [${t.status}] ${t.description}`).join('\\n')\n : ' (none)';\n\n const agentLines = session.agents.length > 0\n ? session.agents.map((a: Agent) => {\n const header = `- ${a.id} (${a.name}): ${a.status} — ${a.reports.length} report(s)`;\n if (a.reports.length === 0) return header;\n let updateNum = 0;\n const reportLines = a.reports.map(r => {\n const label = r.type === 'final' ? '[final]' : `[update ${String(++updateNum).padStart(3, '0')}]`;\n return ` ${label} \"${r.summary}\" → ${r.filePath}`;\n });\n return [header, ...reportLines].join('\\n');\n }).join('\\n')\n : ' (none)';\n\n const cycleLines = session.orchestratorCycles.length > 0\n ? session.orchestratorCycles.map(c => {\n const spawnedList = c.agentsSpawned.length > 0 ? c.agentsSpawned.join(', ') : '(none)';\n return `Cycle ${c.cycle}: Spawned ${spawnedList}`;\n }).join('\\n')\n : ' (none)';\n\n return [\n '<state>',\n `session: ${shortId} (cycle ${cycleNum})`,\n `task: ${session.task}`,\n `status: ${session.status}`,\n '',\n '## Tasks',\n taskLines,\n '',\n '## Agents',\n agentLines,\n '',\n '## Previous Cycles',\n cycleLines,\n '</state>',\n ].join('\\n');\n}\n\nexport async function spawnOrchestrator(sessionId: string, cwd: string, windowId: string, message?: string): Promise<void> {\n const session = state.getSession(cwd, sessionId);\n const basePrompt = loadOrchestratorPrompt(cwd);\n const formattedState = formatStateForOrchestrator(session);\n const fullPrompt = `${basePrompt}\\n\\n${formattedState}`;\n\n const cycleNum = session.orchestratorCycles.length + 1;\n const promptFilePath = `${sessionDir(cwd, sessionId)}/orchestrator-prompt-${cycleNum}.md`;\n writeFileSync(promptFilePath, fullPrompt, 'utf-8');\n\n sessionWindowMap.set(sessionId, windowId);\n\n const envExports = [\n `export SISYPHUS_SESSION_ID='${sessionId}'`,\n `export SISYPHUS_AGENT_ID='orchestrator'`,\n ].join(' && ');\n\n const userPrompt = message\n ? `The user resumed this session with new instructions: ${message}`\n : 'Review the current session state and execute the next cycle of work.';\n const userPromptFilePath = `${sessionDir(cwd, sessionId)}/orchestrator-user-${cycleNum}.md`;\n writeFileSync(userPromptFilePath, userPrompt, 'utf-8');\n const claudeCmd = `claude --dangerously-skip-permissions --append-system-prompt \"$(cat '${promptFilePath}')\" \"$(cat '${userPromptFilePath}')\"`;\n\n\n const paneId = tmux.createPane(windowId, cwd);\n\n sessionOrchestratorPane.set(sessionId, paneId);\n tmux.setPaneTitle(paneId, `orchestrator (${sessionId.slice(0, 8)})`);\n tmux.setPaneStyle(paneId, ORCHESTRATOR_COLOR);\n tmux.sendKeys(paneId, `${envExports} && ${claudeCmd}`);\n\n await state.addOrchestratorCycle(cwd, sessionId, {\n cycle: cycleNum,\n timestamp: new Date().toISOString(),\n agentsSpawned: [],\n paneId,\n });\n}\n\nfunction resolveOrchestratorPane(sessionId: string, cwd: string): string | undefined {\n const memPane = sessionOrchestratorPane.get(sessionId);\n if (memPane) return memPane;\n const session = state.getSession(cwd, sessionId);\n const lastCycle = session.orchestratorCycles[session.orchestratorCycles.length - 1];\n return lastCycle?.paneId ?? undefined;\n}\n\nexport async function handleOrchestratorYield(sessionId: string, cwd: string): Promise<void> {\n const paneId = resolveOrchestratorPane(sessionId, cwd);\n if (paneId) {\n tmux.killPane(paneId);\n sessionOrchestratorPane.delete(sessionId);\n }\n\n await state.completeOrchestratorCycle(cwd, sessionId);\n\n const session = state.getSession(cwd, sessionId);\n const runningAgents = session.agents.filter(a => a.status === 'running');\n if (runningAgents.length === 0) {\n console.error(`[sisyphus] WARNING: Orchestrator yielded but no agents are running for session ${sessionId}`);\n }\n}\n\nexport async function handleOrchestratorComplete(sessionId: string, cwd: string, report: string): Promise<void> {\n const paneId = resolveOrchestratorPane(sessionId, cwd);\n\n await state.completeOrchestratorCycle(cwd, sessionId);\n await state.completeSession(cwd, sessionId, report);\n\n if (paneId) {\n tmux.killPane(paneId);\n sessionOrchestratorPane.delete(sessionId);\n }\n\n sessionWindowMap.delete(sessionId);\n\n console.log(`[sisyphus] Session ${sessionId} completed: ${report}`);\n}\n","import { execSync } from 'node:child_process';\n\nconst EXEC_ENV = {\n ...process.env,\n PATH: `/opt/homebrew/bin:/usr/local/bin:${process.env['PATH'] ?? '/usr/bin:/bin'}`,\n};\n\nfunction exec(cmd: string): string {\n return execSync(cmd, { encoding: 'utf-8', env: EXEC_ENV }).trim();\n}\n\nfunction execSafe(cmd: string): string | null {\n try {\n return exec(cmd);\n } catch {\n return null;\n }\n}\n\nexport function getCurrentTmuxSession(): string {\n const tmuxEnv = process.env['TMUX'];\n if (!tmuxEnv) throw new Error('Not running inside tmux');\n return exec('tmux display-message -p \"#{session_name}\"');\n}\n\nexport function createWindow(sessionName: string, windowName: string, cwd?: string): string {\n const cwdFlag = cwd ? ` -c ${shellQuote(cwd)}` : '';\n exec(`tmux new-window -t \"${sessionName}\" -n \"${windowName}\"${cwdFlag} -P -F \"#{window_id}\"`);\n return exec(`tmux display-message -t \"${sessionName}:${windowName}\" -p \"#{window_id}\"`);\n}\n\nexport function createPane(windowTarget: string, cwd?: string): string {\n const cwdFlag = cwd ? ` -c ${shellQuote(cwd)}` : '';\n const paneId = exec(`tmux split-window -h -t \"${windowTarget}\"${cwdFlag} -P -F \"#{pane_id}\"`);\n execSafe(`tmux select-layout -t \"${windowTarget}\" even-horizontal`);\n return paneId;\n}\n\nexport function sendKeys(paneTarget: string, command: string): void {\n exec(`tmux send-keys -t \"${paneTarget}\" ${shellQuote(command)} Enter`);\n}\n\nexport function killPane(paneTarget: string): void {\n execSafe(`tmux kill-pane -t \"${paneTarget}\"`);\n}\n\nexport function killWindow(windowTarget: string): void {\n execSafe(`tmux kill-window -t \"${windowTarget}\"`);\n}\n\nexport interface PaneInfo {\n paneId: string;\n panePid: string;\n}\n\nexport function listPanes(windowTarget: string): PaneInfo[] {\n const output = execSafe(`tmux list-panes -t \"${windowTarget}\" -F \"#{pane_id} #{pane_pid}\"`);\n if (!output) return [];\n return output\n .split('\\n')\n .filter(Boolean)\n .map(line => {\n const [paneId, panePid] = line.split(' ');\n return { paneId: paneId!, panePid: panePid! };\n });\n}\n\nexport function setPaneTitle(paneTarget: string, title: string): void {\n execSafe(`tmux select-pane -t \"${paneTarget}\" -T ${shellQuote(title)}`);\n}\n\nexport function setPaneStyle(paneTarget: string, color: string): void {\n execSafe(`tmux select-pane -t \"${paneTarget}\" -P \"border-style=fg=${color}\"`);\n}\n\nexport function sendSignal(paneTarget: string, signal: string): void {\n const info = execSafe(`tmux list-panes -t \"${paneTarget}\" -F \"#{pane_pid}\"`);\n if (!info) return;\n const pid = info.split('\\n')[0]?.trim();\n if (pid) {\n execSafe(`kill -${signal} ${pid}`);\n }\n}\n\nexport function selectLayout(windowTarget: string, layout: string = 'even-horizontal'): void {\n execSafe(`tmux select-layout -t \"${windowTarget}\" ${layout}`);\n}\n\nfunction shellQuote(s: string): string {\n return `'${s.replace(/'/g, \"'\\\\''\")}'`;\n}\n","export const ORCHESTRATOR_COLOR = 'yellow';\n\nconst AGENT_PALETTE = ['blue', 'green', 'magenta', 'cyan', 'red', 'white'] as const;\n\nconst sessionColorIndex = new Map<string, number>();\n\nexport function getNextColor(sessionId: string): string {\n const idx = sessionColorIndex.get(sessionId) ?? 0;\n const color = AGENT_PALETTE[idx % AGENT_PALETTE.length]!;\n sessionColorIndex.set(sessionId, idx + 1);\n return color;\n}\n\nexport function resetColors(sessionId: string): void {\n sessionColorIndex.delete(sessionId);\n}\n","import { readFileSync, writeFileSync, mkdirSync, readdirSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport type { Agent, AgentReport } from '../shared/types.js';\nimport * as state from './state.js';\nimport * as tmux from './tmux.js';\nimport { getNextColor } from './colors.js';\nimport { sessionDir, reportsDir, reportFilePath } from '../shared/paths.js';\n\nconst agentCounters = new Map<string, number>();\n\nexport function resetAgentCounter(sessionId: string, value: number = 0): void {\n agentCounters.set(sessionId, value);\n}\n\nexport function clearAgentCounter(sessionId: string): void {\n agentCounters.delete(sessionId);\n}\n\nfunction renderAgentSuffix(sessionId: string, instruction: string): string {\n const templatePath = resolve(import.meta.dirname, '../templates/agent-suffix.md');\n let template: string;\n try {\n template = readFileSync(templatePath, 'utf-8');\n } catch {\n template = `# Sisyphus Agent\\nSession: {{SESSION_ID}}\\nTask: {{INSTRUCTION}}`;\n }\n return template\n .replace(/\\{\\{SESSION_ID\\}\\}/g, sessionId)\n .replace(/\\{\\{INSTRUCTION\\}\\}/g, instruction);\n}\n\nexport interface SpawnAgentOpts {\n sessionId: string;\n cwd: string;\n agentType: string;\n name: string;\n instruction: string;\n windowId: string;\n}\n\nexport async function spawnAgent(opts: SpawnAgentOpts): Promise<Agent> {\n const { sessionId, cwd, agentType, name, instruction, windowId } = opts;\n const count = (agentCounters.get(sessionId) ?? 0) + 1;\n agentCounters.set(sessionId, count);\n const agentId = `agent-${String(count).padStart(3, '0')}`;\n const color = getNextColor(sessionId);\n\n const paneId = tmux.createPane(windowId, cwd);\n tmux.setPaneTitle(paneId, `${name} (${agentId})`);\n tmux.setPaneStyle(paneId, color);\n\n const suffix = renderAgentSuffix(sessionId, instruction);\n const suffixFilePath = `${sessionDir(cwd, sessionId)}/${agentId}-system.md`;\n writeFileSync(suffixFilePath, suffix, 'utf-8');\n\n const envExports = [\n `export SISYPHUS_SESSION_ID='${sessionId}'`,\n `export SISYPHUS_AGENT_ID='${agentId}'`,\n ].join(' && ');\n\n const agentFlag = agentType ? ` --agent ${shellQuote(agentType)}` : '';\n const claudeCmd = `claude --dangerously-skip-permissions${agentFlag} --append-system-prompt \"$(cat '${suffixFilePath}')\" ${shellQuote(instruction)}`;\n tmux.sendKeys(paneId, `${envExports} && ${claudeCmd}`);\n\n const agent: Agent = {\n id: agentId,\n name,\n agentType,\n color,\n instruction,\n status: 'running',\n spawnedAt: new Date().toISOString(),\n completedAt: null,\n reports: [],\n paneId,\n };\n\n await state.addAgent(cwd, sessionId, agent);\n return agent;\n}\n\nfunction nextReportNumber(cwd: string, sessionId: string, agentId: string): string {\n const dir = reportsDir(cwd, sessionId);\n try {\n const files = readdirSync(dir).filter(f => f.startsWith(`${agentId}-`) && !f.endsWith('-final.md'));\n return String(files.length + 1).padStart(3, '0');\n } catch {\n return '001';\n }\n}\n\nexport async function handleAgentReport(\n cwd: string,\n sessionId: string,\n agentId: string,\n content: string,\n): Promise<void> {\n const dir = reportsDir(cwd, sessionId);\n mkdirSync(dir, { recursive: true });\n\n const num = nextReportNumber(cwd, sessionId, agentId);\n const filePath = reportFilePath(cwd, sessionId, agentId, num);\n writeFileSync(filePath, content, 'utf-8');\n\n const entry: AgentReport = {\n type: 'update',\n filePath,\n summary: content.slice(0, 200),\n timestamp: new Date().toISOString(),\n };\n await state.appendAgentReport(cwd, sessionId, agentId, entry);\n}\n\nexport async function handleAgentSubmit(\n cwd: string,\n sessionId: string,\n agentId: string,\n report: string,\n): Promise<boolean> {\n const dir = reportsDir(cwd, sessionId);\n mkdirSync(dir, { recursive: true });\n\n const filePath = reportFilePath(cwd, sessionId, agentId, 'final');\n writeFileSync(filePath, report, 'utf-8');\n\n const entry: AgentReport = {\n type: 'final',\n filePath,\n summary: report.slice(0, 200),\n timestamp: new Date().toISOString(),\n };\n await state.appendAgentReport(cwd, sessionId, agentId, entry);\n\n await state.updateAgent(cwd, sessionId, agentId, {\n status: 'completed',\n completedAt: new Date().toISOString(),\n });\n\n const session = state.getSession(cwd, sessionId);\n const agent = session.agents.find(a => a.id === agentId);\n if (agent) {\n tmux.killPane(agent.paneId);\n }\n\n return allAgentsDone(session);\n}\n\nexport async function handleAgentKilled(\n cwd: string,\n sessionId: string,\n agentId: string,\n reason: string,\n): Promise<boolean> {\n await state.updateAgent(cwd, sessionId, agentId, {\n status: 'killed',\n killedReason: reason,\n completedAt: new Date().toISOString(),\n });\n\n const session = state.getSession(cwd, sessionId);\n return allAgentsDone(session);\n}\n\n// Note: this checks ALL running agents in the session, not just orchestrator-spawned ones.\n// Agents can also call `sisyphus spawn`, and those child agents are included here —\n// the orchestrator won't respawn until every agent (including agent-spawned ones) finishes.\nfunction allAgentsDone(session: import('../shared/types.js').Session): boolean {\n const running = session.agents.filter(a => a.status === 'running');\n return running.length === 0 && session.agents.length > 0;\n}\n\nfunction shellQuote(s: string): string {\n return `'${s.replace(/'/g, \"'\\\\''\")}'`;\n}\n","import * as state from './state.js';\nimport * as tmux from './tmux.js';\nimport { getOrchestratorPaneId } from './orchestrator.js';\nimport { handleAgentKilled } from './agent.js';\n\ntype RespawnCallback = (sessionId: string, cwd: string, windowId: string) => void;\n\nlet monitorInterval: ReturnType<typeof setInterval> | null = null;\nlet onAllAgentsDone: RespawnCallback | null = null;\n\nexport function setRespawnCallback(cb: RespawnCallback): void {\n onAllAgentsDone = cb;\n}\n\nexport function startMonitor(pollIntervalMs: number = 1000): void {\n if (monitorInterval) return;\n monitorInterval = setInterval(() => {\n pollAllSessions().catch(err => {\n console.error('[sisyphus] Pane monitor error:', err);\n });\n }, pollIntervalMs);\n}\n\nexport function stopMonitor(): void {\n if (monitorInterval) {\n clearInterval(monitorInterval);\n monitorInterval = null;\n }\n}\n\nconst trackedSessions = new Map<string, { id: string; cwd: string; tmuxSession: string; windowId: string | null }>();\n\nexport function trackSession(sessionId: string, cwd: string, tmuxSession: string): void {\n // windowId is registered separately via updateTrackedWindow after spawnOrchestrator sets it\n const existing = trackedSessions.get(sessionId);\n trackedSessions.set(sessionId, { id: sessionId, cwd, tmuxSession, windowId: existing ? existing.windowId : null });\n}\n\nexport function updateTrackedWindow(sessionId: string, windowId: string): void {\n const entry = trackedSessions.get(sessionId);\n if (!entry) throw new Error(`Cannot update window for untracked session: ${sessionId}`);\n entry.windowId = windowId;\n}\n\nexport function untrackSession(sessionId: string): void {\n trackedSessions.delete(sessionId);\n}\n\nasync function pollAllSessions(): Promise<void> {\n for (const { id: sessionId, cwd, windowId } of trackedSessions.values()) {\n if (windowId) {\n await pollSession(sessionId, cwd, windowId);\n }\n }\n}\n\nasync function pollSession(sessionId: string, cwd: string, windowId: string): Promise<void> {\n let session;\n try {\n session = state.getSession(cwd, sessionId);\n } catch (err) {\n console.error(`[sisyphus] Failed to read state for session ${sessionId}:`, err);\n return;\n }\n\n if (session.status !== 'active') return;\n\n const livePanes = tmux.listPanes(windowId);\n if (livePanes.length === 0) return;\n\n const livePaneIds = new Set(livePanes.map(p => p.paneId));\n\n for (const agent of session.agents) {\n if (agent.status !== 'running') continue;\n if (!livePaneIds.has(agent.paneId)) {\n const allDone = await handleAgentKilled(cwd, sessionId, agent.id, 'pane closed by user');\n if (allDone && onAllAgentsDone) {\n onAllAgentsDone(sessionId, cwd, windowId);\n }\n }\n }\n\n // Check orchestrator pane\n const orchPaneId = getOrchestratorPaneId(sessionId);\n if (orchPaneId && !livePaneIds.has(orchPaneId)) {\n // Orchestrator pane disappeared without a yield command\n const runningAgents = session.agents.filter(a => a.status === 'running');\n if (runningAgents.length === 0) {\n // No agents running and orchestrator gone — pause\n await state.updateSessionStatus(cwd, sessionId, 'paused');\n console.log(`[sisyphus] Session ${sessionId} paused: orchestrator pane disappeared`);\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAAA,SAAS,aAAAA,YAAW,gBAAAC,eAAc,iBAAAC,gBAAe,cAAAC,aAAY,cAAAC,mBAAkB;;;ACA/E,SAAS,oBAAoB;AAU7B,IAAM,iBAAyB;AAAA,EAC7B,gBAAgB;AAClB;AAEA,SAAS,aAAa,UAAmC;AACvD,MAAI;AACF,UAAM,UAAU,aAAa,UAAU,OAAO;AAC9C,WAAO,KAAK,MAAM,OAAO;AAAA,EAC3B,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAEO,SAAS,WAAW,KAAqB;AAC9C,QAAM,SAAS,aAAa,iBAAiB,CAAC;AAC9C,QAAM,UAAU,aAAa,kBAAkB,GAAG,CAAC;AACnD,SAAO,EAAE,GAAG,gBAAgB,GAAG,QAAQ,GAAG,QAAQ;AACpD;;;AC3BA,SAAS,oBAAiC;AAC1C,SAAS,YAAY,cAAAC,aAAY,iBAAAC,gBAAe,gBAAAC,eAAc,aAAAC,kBAAiB;AAE/E,SAAS,QAAAC,aAAY;;;ACHrB,SAAS,MAAM,cAAc;AAC7B,SAAS,cAAAC,aAAY,eAAAC,oBAAmB;;;ACDxC,SAAS,gBAAAC,eAAc,eAAe,WAAW,kBAAkB;AACnE,SAAS,SAAS,YAAY;AAC9B,SAAS,kBAAkB;AAK3B,IAAM,eAAe,oBAAI,IAA2B;AAEpD,eAAe,gBAAmB,WAAmB,IAAyB;AAC5E,QAAM,OAAO,aAAa,IAAI,SAAS,KAAK,QAAQ,QAAQ;AAC5D,MAAIC;AACJ,QAAM,OAAO,IAAI,QAAc,OAAK;AAAE,IAAAA,WAAU;AAAA,EAAG,CAAC;AACpD,eAAa,IAAI,WAAW,IAAI;AAChC,QAAM;AACN,MAAI;AACF,WAAO,GAAG;AAAA,EACZ,UAAE;AACA,IAAAA,SAAS;AAAA,EACX;AACF;AAEA,SAAS,YAAY,UAAkB,MAAoB;AACzD,QAAM,MAAM,QAAQ,QAAQ;AAC5B,QAAM,UAAU,KAAK,KAAK,UAAU,WAAW,CAAC,MAAM;AACtD,gBAAc,SAAS,MAAM,OAAO;AACpC,aAAW,SAAS,QAAQ;AAC9B;AAEO,SAAS,cAAc,IAAY,MAAc,KAAsB;AAC5E,QAAM,MAAM,WAAW,KAAK,EAAE;AAC9B,YAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAElC,QAAM,UAAmB;AAAA,IACvB;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,IACR,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IAClC,OAAO,CAAC;AAAA,IACR,QAAQ,CAAC;AAAA,IACT,oBAAoB,CAAC;AAAA,EACvB;AAEA,cAAY,UAAU,KAAK,EAAE,GAAG,KAAK,UAAU,SAAS,MAAM,CAAC,CAAC;AAChE,SAAO;AACT;AAEO,SAAS,WAAW,KAAa,WAA4B;AAClE,QAAM,UAAUC,cAAa,UAAU,KAAK,SAAS,GAAG,OAAO;AAC/D,SAAO,KAAK,MAAM,OAAO;AAC3B;AAEA,SAAS,YAAY,SAAwB;AAC3C,cAAY,UAAU,QAAQ,KAAK,QAAQ,EAAE,GAAG,KAAK,UAAU,SAAS,MAAM,CAAC,CAAC;AAClF;AAEA,eAAsB,QAAQ,KAAa,WAAmB,aAAqB,eAA2C;AAC5H,SAAO,gBAAgB,WAAW,MAAM;AACtC,UAAM,UAAU,WAAW,KAAK,SAAS;AACzC,UAAM,UAAU,QAAQ,MAAM,SAAS;AACvC,UAAM,OAAa;AAAA,MACjB,IAAI,IAAI,OAAO;AAAA,MACf;AAAA,MACA,QAAQ,kBAAkB,SAAY,gBAAgB;AAAA,IACxD;AACA,YAAQ,MAAM,KAAK,IAAI;AACvB,gBAAY,OAAO;AACnB,WAAO;AAAA,EACT,CAAC;AACH;AAEA,eAAsB,WAAW,KAAa,WAAmB,QAAgB,SAAuE;AACtJ,SAAO,gBAAgB,WAAW,MAAM;AACtC,UAAM,UAAU,WAAW,KAAK,SAAS;AACzC,UAAM,OAAO,QAAQ,MAAM,KAAK,OAAK,EAAE,OAAO,MAAM;AACpD,QAAI,CAAC,KAAM,OAAM,IAAI,MAAM,QAAQ,MAAM,yBAAyB,SAAS,EAAE;AAC7E,QAAI,QAAQ,OAAQ,MAAK,SAAS,QAAQ;AAC1C,QAAI,QAAQ,YAAa,MAAK,cAAc,QAAQ;AACpD,gBAAY,OAAO;AAAA,EACrB,CAAC;AACH;AAEA,eAAsB,SAAS,KAAa,WAAmB,OAA6B;AAC1F,SAAO,gBAAgB,WAAW,MAAM;AACtC,UAAM,UAAU,WAAW,KAAK,SAAS;AACzC,YAAQ,OAAO,KAAK,KAAK;AACzB,gBAAY,OAAO;AAAA,EACrB,CAAC;AACH;AAEA,eAAsB,YAAY,KAAa,WAAmB,SAAiB,SAAwC;AACzH,SAAO,gBAAgB,WAAW,MAAM;AACtC,UAAM,UAAU,WAAW,KAAK,SAAS;AACzC,UAAM,QAAQ,QAAQ,OAAO,KAAK,OAAK,EAAE,OAAO,OAAO;AACvD,QAAI,CAAC,MAAO,OAAM,IAAI,MAAM,SAAS,OAAO,yBAAyB,SAAS,EAAE;AAChF,WAAO,OAAO,OAAO,OAAO;AAC5B,gBAAY,OAAO;AAAA,EACrB,CAAC;AACH;AAEA,eAAsB,qBAAqB,KAAa,WAAmB,OAAyC;AAClH,SAAO,gBAAgB,WAAW,MAAM;AACtC,UAAM,UAAU,WAAW,KAAK,SAAS;AACzC,YAAQ,mBAAmB,KAAK,KAAK;AACrC,gBAAY,OAAO;AAAA,EACrB,CAAC;AACH;AAEA,eAAsB,oBAAoB,KAAa,WAAmB,QAAuB,kBAA0C;AACzI,SAAO,gBAAgB,WAAW,MAAM;AACtC,UAAM,UAAU,WAAW,KAAK,SAAS;AACzC,YAAQ,SAAS;AACjB,QAAI,qBAAqB,QAAW;AAClC,cAAQ,mBAAmB;AAAA,IAC7B;AACA,gBAAY,OAAO;AAAA,EACrB,CAAC;AACH;AAEA,eAAsB,uBAAuB,KAAa,WAAmB,SAAgC;AAC3G,SAAO,gBAAgB,WAAW,MAAM;AACtC,UAAM,UAAU,WAAW,KAAK,SAAS;AACzC,UAAM,SAAS,QAAQ;AACvB,QAAI,OAAO,WAAW,EAAG;AACzB,WAAO,OAAO,SAAS,CAAC,EAAG,cAAc,KAAK,OAAO;AACrD,gBAAY,OAAO;AAAA,EACrB,CAAC;AACH;AAEA,eAAsB,gBAAgB,KAAa,WAAmB,QAA+B;AACnG,SAAO,gBAAgB,WAAW,MAAM;AACtC,UAAM,UAAU,WAAW,KAAK,SAAS;AACzC,YAAQ,SAAS;AACjB,YAAQ,eAAc,oBAAI,KAAK,GAAE,YAAY;AAC7C,YAAQ,mBAAmB;AAC3B,gBAAY,OAAO;AAAA,EACrB,CAAC;AACH;AAEA,eAAsB,kBAAkB,KAAa,WAAmB,SAAiB,OAAmC;AAC1H,SAAO,gBAAgB,WAAW,MAAM;AACtC,UAAM,UAAU,WAAW,KAAK,SAAS;AACzC,UAAM,QAAQ,QAAQ,OAAO,KAAK,OAAK,EAAE,OAAO,OAAO;AACvD,QAAI,CAAC,MAAO,OAAM,IAAI,MAAM,SAAS,OAAO,yBAAyB,SAAS,EAAE;AAChF,UAAM,QAAQ,KAAK,KAAK;AACxB,gBAAY,OAAO;AAAA,EACrB,CAAC;AACH;AAEA,eAAsB,0BAA0B,KAAa,WAAkC;AAC7F,SAAO,gBAAgB,WAAW,MAAM;AACtC,UAAM,UAAU,WAAW,KAAK,SAAS;AACzC,UAAM,SAAS,QAAQ;AACvB,QAAI,OAAO,WAAW,EAAG;AACzB,WAAO,OAAO,SAAS,CAAC,EAAG,eAAc,oBAAI,KAAK,GAAE,YAAY;AAChE,gBAAY,OAAO;AAAA,EACrB,CAAC;AACH;;;AC9JA,SAAS,gBAAAC,eAAc,YAAY,iBAAAC,sBAAqB;AACxD,SAAS,eAAe;;;ACDxB,SAAS,gBAAgB;AAEzB,IAAM,WAAW;AAAA,EACf,GAAG,QAAQ;AAAA,EACX,MAAM,oCAAoC,QAAQ,IAAI,MAAM,KAAK,eAAe;AAClF;AAEA,SAAS,KAAK,KAAqB;AACjC,SAAO,SAAS,KAAK,EAAE,UAAU,SAAS,KAAK,SAAS,CAAC,EAAE,KAAK;AAClE;AAEA,SAAS,SAAS,KAA4B;AAC5C,MAAI;AACF,WAAO,KAAK,GAAG;AAAA,EACjB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAcO,SAAS,WAAW,cAAsB,KAAsB;AACrE,QAAM,UAAU,MAAM,OAAO,WAAW,GAAG,CAAC,KAAK;AACjD,QAAM,SAAS,KAAK,4BAA4B,YAAY,IAAI,OAAO,qBAAqB;AAC5F,WAAS,0BAA0B,YAAY,mBAAmB;AAClE,SAAO;AACT;AAEO,SAAS,SAAS,YAAoB,SAAuB;AAClE,OAAK,sBAAsB,UAAU,KAAK,WAAW,OAAO,CAAC,QAAQ;AACvE;AAEO,SAAS,SAAS,YAA0B;AACjD,WAAS,sBAAsB,UAAU,GAAG;AAC9C;AAEO,SAAS,WAAW,cAA4B;AACrD,WAAS,wBAAwB,YAAY,GAAG;AAClD;AAOO,SAAS,UAAU,cAAkC;AAC1D,QAAM,SAAS,SAAS,uBAAuB,YAAY,+BAA+B;AAC1F,MAAI,CAAC,OAAQ,QAAO,CAAC;AACrB,SAAO,OACJ,MAAM,IAAI,EACV,OAAO,OAAO,EACd,IAAI,UAAQ;AACX,UAAM,CAAC,QAAQ,OAAO,IAAI,KAAK,MAAM,GAAG;AACxC,WAAO,EAAE,QAAiB,QAAkB;AAAA,EAC9C,CAAC;AACL;AAEO,SAAS,aAAa,YAAoB,OAAqB;AACpE,WAAS,wBAAwB,UAAU,QAAQ,WAAW,KAAK,CAAC,EAAE;AACxE;AAEO,SAAS,aAAa,YAAoB,OAAqB;AACpE,WAAS,wBAAwB,UAAU,yBAAyB,KAAK,GAAG;AAC9E;AAeA,SAAS,WAAW,GAAmB;AACrC,SAAO,IAAI,EAAE,QAAQ,MAAM,OAAO,CAAC;AACrC;;;AC1FO,IAAM,qBAAqB;AAElC,IAAM,gBAAgB,CAAC,QAAQ,SAAS,WAAW,QAAQ,OAAO,OAAO;AAEzE,IAAM,oBAAoB,oBAAI,IAAoB;AAE3C,SAAS,aAAa,WAA2B;AACtD,QAAM,MAAM,kBAAkB,IAAI,SAAS,KAAK;AAChD,QAAM,QAAQ,cAAc,MAAM,cAAc,MAAM;AACtD,oBAAkB,IAAI,WAAW,MAAM,CAAC;AACxC,SAAO;AACT;AAEO,SAAS,YAAY,WAAyB;AACnD,oBAAkB,OAAO,SAAS;AACpC;;;AFHA,IAAM,mBAAmB,oBAAI,IAAoB;AACjD,IAAM,0BAA0B,oBAAI,IAAoB;AAEjD,SAAS,YAAY,WAAuC;AACjE,SAAO,iBAAiB,IAAI,SAAS;AACvC;AAMO,SAAS,sBAAsB,WAAuC;AAC3E,SAAO,wBAAwB,IAAI,SAAS;AAC9C;AAEA,SAAS,uBAAuB,KAAqB;AACnD,QAAM,cAAc,8BAA8B,GAAG;AACrD,MAAI,WAAW,WAAW,GAAG;AAC3B,WAAOC,cAAa,aAAa,OAAO;AAAA,EAC1C;AACA,QAAM,cAAc,QAAQ,YAAY,SAAS,8BAA8B;AAC/E,SAAOA,cAAa,aAAa,OAAO;AAC1C;AAEA,SAAS,2BAA2B,SAA0B;AAC5D,QAAM,UAAU,QAAQ,GAAG,MAAM,GAAG,CAAC;AACrC,QAAM,WAAW,QAAQ,mBAAmB;AAE5C,QAAM,YAAY,QAAQ,MAAM,SAAS,IACrC,QAAQ,MAAM,IAAI,OAAK,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,KAAK,EAAE,WAAW,EAAE,EAAE,KAAK,IAAI,IAC7E;AAEJ,QAAM,aAAa,QAAQ,OAAO,SAAS,IACvC,QAAQ,OAAO,IAAI,CAAC,MAAa;AAC/B,UAAM,SAAS,KAAK,EAAE,EAAE,KAAK,EAAE,IAAI,MAAM,EAAE,MAAM,WAAM,EAAE,QAAQ,MAAM;AACvE,QAAI,EAAE,QAAQ,WAAW,EAAG,QAAO;AACnC,QAAI,YAAY;AAChB,UAAM,cAAc,EAAE,QAAQ,IAAI,OAAK;AACrC,YAAM,QAAQ,EAAE,SAAS,UAAU,YAAY,WAAW,OAAO,EAAE,SAAS,EAAE,SAAS,GAAG,GAAG,CAAC;AAC9F,aAAO,KAAK,KAAK,KAAK,EAAE,OAAO,YAAO,EAAE,QAAQ;AAAA,IAClD,CAAC;AACD,WAAO,CAAC,QAAQ,GAAG,WAAW,EAAE,KAAK,IAAI;AAAA,EAC3C,CAAC,EAAE,KAAK,IAAI,IACZ;AAEJ,QAAM,aAAa,QAAQ,mBAAmB,SAAS,IACnD,QAAQ,mBAAmB,IAAI,OAAK;AAClC,UAAM,cAAc,EAAE,cAAc,SAAS,IAAI,EAAE,cAAc,KAAK,IAAI,IAAI;AAC9E,WAAO,SAAS,EAAE,KAAK,aAAa,WAAW;AAAA,EACjD,CAAC,EAAE,KAAK,IAAI,IACZ;AAEJ,SAAO;AAAA,IACL;AAAA,IACA,YAAY,OAAO,WAAW,QAAQ;AAAA,IACtC,SAAS,QAAQ,IAAI;AAAA,IACrB,WAAW,QAAQ,MAAM;AAAA,IACzB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAEA,eAAsB,kBAAkB,WAAmB,KAAa,UAAkB,SAAiC;AACzH,QAAM,UAAgB,WAAW,KAAK,SAAS;AAC/C,QAAM,aAAa,uBAAuB,GAAG;AAC7C,QAAM,iBAAiB,2BAA2B,OAAO;AACzD,QAAM,aAAa,GAAG,UAAU;AAAA;AAAA,EAAO,cAAc;AAErD,QAAM,WAAW,QAAQ,mBAAmB,SAAS;AACrD,QAAM,iBAAiB,GAAG,WAAW,KAAK,SAAS,CAAC,wBAAwB,QAAQ;AACpF,EAAAC,eAAc,gBAAgB,YAAY,OAAO;AAEjD,mBAAiB,IAAI,WAAW,QAAQ;AAExC,QAAM,aAAa;AAAA,IACjB,+BAA+B,SAAS;AAAA,IACxC;AAAA,EACF,EAAE,KAAK,MAAM;AAEb,QAAM,aAAa,UACf,wDAAwD,OAAO,KAC/D;AACJ,QAAM,qBAAqB,GAAG,WAAW,KAAK,SAAS,CAAC,sBAAsB,QAAQ;AACtF,EAAAA,eAAc,oBAAoB,YAAY,OAAO;AACrD,QAAM,YAAY,wEAAwE,cAAc,eAAe,kBAAkB;AAGzI,QAAM,SAAc,WAAW,UAAU,GAAG;AAE5C,0BAAwB,IAAI,WAAW,MAAM;AAC7C,EAAK,aAAa,QAAQ,iBAAiB,UAAU,MAAM,GAAG,CAAC,CAAC,GAAG;AACnE,EAAK,aAAa,QAAQ,kBAAkB;AAC5C,EAAK,SAAS,QAAQ,GAAG,UAAU,OAAO,SAAS,EAAE;AAErD,QAAY,qBAAqB,KAAK,WAAW;AAAA,IAC/C,OAAO;AAAA,IACP,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IAClC,eAAe,CAAC;AAAA,IAChB;AAAA,EACF,CAAC;AACH;AAEA,SAAS,wBAAwB,WAAmB,KAAiC;AACnF,QAAM,UAAU,wBAAwB,IAAI,SAAS;AACrD,MAAI,QAAS,QAAO;AACpB,QAAM,UAAgB,WAAW,KAAK,SAAS;AAC/C,QAAM,YAAY,QAAQ,mBAAmB,QAAQ,mBAAmB,SAAS,CAAC;AAClF,SAAO,WAAW,UAAU;AAC9B;AAEA,eAAsB,wBAAwB,WAAmB,KAA4B;AAC3F,QAAM,SAAS,wBAAwB,WAAW,GAAG;AACrD,MAAI,QAAQ;AACV,IAAK,SAAS,MAAM;AACpB,4BAAwB,OAAO,SAAS;AAAA,EAC1C;AAEA,QAAY,0BAA0B,KAAK,SAAS;AAEpD,QAAM,UAAgB,WAAW,KAAK,SAAS;AAC/C,QAAM,gBAAgB,QAAQ,OAAO,OAAO,OAAK,EAAE,WAAW,SAAS;AACvE,MAAI,cAAc,WAAW,GAAG;AAC9B,YAAQ,MAAM,kFAAkF,SAAS,EAAE;AAAA,EAC7G;AACF;AAEA,eAAsB,2BAA2B,WAAmB,KAAa,QAA+B;AAC9G,QAAM,SAAS,wBAAwB,WAAW,GAAG;AAErD,QAAY,0BAA0B,KAAK,SAAS;AACpD,QAAY,gBAAgB,KAAK,WAAW,MAAM;AAElD,MAAI,QAAQ;AACV,IAAK,SAAS,MAAM;AACpB,4BAAwB,OAAO,SAAS;AAAA,EAC1C;AAEA,mBAAiB,OAAO,SAAS;AAEjC,UAAQ,IAAI,sBAAsB,SAAS,eAAe,MAAM,EAAE;AACpE;;;AGhKA,SAAS,gBAAAC,eAAc,iBAAAC,gBAAe,aAAAC,YAAW,mBAAmB;AACpE,SAAS,WAAAC,gBAAe;AAOxB,IAAM,gBAAgB,oBAAI,IAAoB;AAEvC,SAAS,kBAAkB,WAAmB,QAAgB,GAAS;AAC5E,gBAAc,IAAI,WAAW,KAAK;AACpC;AAEO,SAAS,kBAAkB,WAAyB;AACzD,gBAAc,OAAO,SAAS;AAChC;AAEA,SAAS,kBAAkB,WAAmB,aAA6B;AACzE,QAAM,eAAeC,SAAQ,YAAY,SAAS,8BAA8B;AAChF,MAAI;AACJ,MAAI;AACF,eAAWC,cAAa,cAAc,OAAO;AAAA,EAC/C,QAAQ;AACN,eAAW;AAAA;AAAA;AAAA,EACb;AACA,SAAO,SACJ,QAAQ,uBAAuB,SAAS,EACxC,QAAQ,wBAAwB,WAAW;AAChD;AAWA,eAAsB,WAAW,MAAsC;AACrE,QAAM,EAAE,WAAW,KAAK,WAAW,MAAM,aAAa,SAAS,IAAI;AACnE,QAAM,SAAS,cAAc,IAAI,SAAS,KAAK,KAAK;AACpD,gBAAc,IAAI,WAAW,KAAK;AAClC,QAAM,UAAU,SAAS,OAAO,KAAK,EAAE,SAAS,GAAG,GAAG,CAAC;AACvD,QAAM,QAAQ,aAAa,SAAS;AAEpC,QAAM,SAAc,WAAW,UAAU,GAAG;AAC5C,EAAK,aAAa,QAAQ,GAAG,IAAI,KAAK,OAAO,GAAG;AAChD,EAAK,aAAa,QAAQ,KAAK;AAE/B,QAAM,SAAS,kBAAkB,WAAW,WAAW;AACvD,QAAM,iBAAiB,GAAG,WAAW,KAAK,SAAS,CAAC,IAAI,OAAO;AAC/D,EAAAC,eAAc,gBAAgB,QAAQ,OAAO;AAE7C,QAAM,aAAa;AAAA,IACjB,+BAA+B,SAAS;AAAA,IACxC,6BAA6B,OAAO;AAAA,EACtC,EAAE,KAAK,MAAM;AAEb,QAAM,YAAY,YAAY,YAAYC,YAAW,SAAS,CAAC,KAAK;AACpE,QAAM,YAAY,wCAAwC,SAAS,mCAAmC,cAAc,OAAOA,YAAW,WAAW,CAAC;AAClJ,EAAK,SAAS,QAAQ,GAAG,UAAU,OAAO,SAAS,EAAE;AAErD,QAAM,QAAe;AAAA,IACnB,IAAI;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,IACR,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IAClC,aAAa;AAAA,IACb,SAAS,CAAC;AAAA,IACV;AAAA,EACF;AAEA,QAAY,SAAS,KAAK,WAAW,KAAK;AAC1C,SAAO;AACT;AAEA,SAAS,iBAAiB,KAAa,WAAmB,SAAyB;AACjF,QAAM,MAAM,WAAW,KAAK,SAAS;AACrC,MAAI;AACF,UAAM,QAAQ,YAAY,GAAG,EAAE,OAAO,OAAK,EAAE,WAAW,GAAG,OAAO,GAAG,KAAK,CAAC,EAAE,SAAS,WAAW,CAAC;AAClG,WAAO,OAAO,MAAM,SAAS,CAAC,EAAE,SAAS,GAAG,GAAG;AAAA,EACjD,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,kBACpB,KACA,WACA,SACA,SACe;AACf,QAAM,MAAM,WAAW,KAAK,SAAS;AACrC,EAAAC,WAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAElC,QAAM,MAAM,iBAAiB,KAAK,WAAW,OAAO;AACpD,QAAM,WAAW,eAAe,KAAK,WAAW,SAAS,GAAG;AAC5D,EAAAF,eAAc,UAAU,SAAS,OAAO;AAExC,QAAM,QAAqB;AAAA,IACzB,MAAM;AAAA,IACN;AAAA,IACA,SAAS,QAAQ,MAAM,GAAG,GAAG;AAAA,IAC7B,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,EACpC;AACA,QAAY,kBAAkB,KAAK,WAAW,SAAS,KAAK;AAC9D;AAEA,eAAsB,kBACpB,KACA,WACA,SACA,QACkB;AAClB,QAAM,MAAM,WAAW,KAAK,SAAS;AACrC,EAAAE,WAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAElC,QAAM,WAAW,eAAe,KAAK,WAAW,SAAS,OAAO;AAChE,EAAAF,eAAc,UAAU,QAAQ,OAAO;AAEvC,QAAM,QAAqB;AAAA,IACzB,MAAM;AAAA,IACN;AAAA,IACA,SAAS,OAAO,MAAM,GAAG,GAAG;AAAA,IAC5B,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,EACpC;AACA,QAAY,kBAAkB,KAAK,WAAW,SAAS,KAAK;AAE5D,QAAY,YAAY,KAAK,WAAW,SAAS;AAAA,IAC/C,QAAQ;AAAA,IACR,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,EACtC,CAAC;AAED,QAAM,UAAgB,WAAW,KAAK,SAAS;AAC/C,QAAM,QAAQ,QAAQ,OAAO,KAAK,OAAK,EAAE,OAAO,OAAO;AACvD,MAAI,OAAO;AACT,IAAK,SAAS,MAAM,MAAM;AAAA,EAC5B;AAEA,SAAO,cAAc,OAAO;AAC9B;AAEA,eAAsB,kBACpB,KACA,WACA,SACA,QACkB;AAClB,QAAY,YAAY,KAAK,WAAW,SAAS;AAAA,IAC/C,QAAQ;AAAA,IACR,cAAc;AAAA,IACd,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,EACtC,CAAC;AAED,QAAM,UAAgB,WAAW,KAAK,SAAS;AAC/C,SAAO,cAAc,OAAO;AAC9B;AAKA,SAAS,cAAc,SAAwD;AAC7E,QAAM,UAAU,QAAQ,OAAO,OAAO,OAAK,EAAE,WAAW,SAAS;AACjE,SAAO,QAAQ,WAAW,KAAK,QAAQ,OAAO,SAAS;AACzD;AAEA,SAASC,YAAW,GAAmB;AACrC,SAAO,IAAI,EAAE,QAAQ,MAAM,OAAO,CAAC;AACrC;;;ACtKA,IAAI,kBAAyD;AAC7D,IAAI,kBAA0C;AAEvC,SAAS,mBAAmB,IAA2B;AAC5D,oBAAkB;AACpB;AAEO,SAAS,aAAa,iBAAyB,KAAY;AAChE,MAAI,gBAAiB;AACrB,oBAAkB,YAAY,MAAM;AAClC,oBAAgB,EAAE,MAAM,SAAO;AAC7B,cAAQ,MAAM,kCAAkC,GAAG;AAAA,IACrD,CAAC;AAAA,EACH,GAAG,cAAc;AACnB;AAEO,SAAS,cAAoB;AAClC,MAAI,iBAAiB;AACnB,kBAAc,eAAe;AAC7B,sBAAkB;AAAA,EACpB;AACF;AAEA,IAAM,kBAAkB,oBAAI,IAAuF;AAE5G,SAAS,aAAa,WAAmB,KAAa,aAA2B;AAEtF,QAAM,WAAW,gBAAgB,IAAI,SAAS;AAC9C,kBAAgB,IAAI,WAAW,EAAE,IAAI,WAAW,KAAK,aAAa,UAAU,WAAW,SAAS,WAAW,KAAK,CAAC;AACnH;AAEO,SAAS,oBAAoB,WAAmB,UAAwB;AAC7E,QAAM,QAAQ,gBAAgB,IAAI,SAAS;AAC3C,MAAI,CAAC,MAAO,OAAM,IAAI,MAAM,+CAA+C,SAAS,EAAE;AACtF,QAAM,WAAW;AACnB;AAEO,SAAS,eAAe,WAAyB;AACtD,kBAAgB,OAAO,SAAS;AAClC;AAEA,eAAe,kBAAiC;AAC9C,aAAW,EAAE,IAAI,WAAW,KAAK,SAAS,KAAK,gBAAgB,OAAO,GAAG;AACvE,QAAI,UAAU;AACZ,YAAM,YAAY,WAAW,KAAK,QAAQ;AAAA,IAC5C;AAAA,EACF;AACF;AAEA,eAAe,YAAY,WAAmB,KAAa,UAAiC;AAC1F,MAAI;AACJ,MAAI;AACF,cAAgB,WAAW,KAAK,SAAS;AAAA,EAC3C,SAAS,KAAK;AACZ,YAAQ,MAAM,+CAA+C,SAAS,KAAK,GAAG;AAC9E;AAAA,EACF;AAEA,MAAI,QAAQ,WAAW,SAAU;AAEjC,QAAM,YAAiB,UAAU,QAAQ;AACzC,MAAI,UAAU,WAAW,EAAG;AAE5B,QAAM,cAAc,IAAI,IAAI,UAAU,IAAI,OAAK,EAAE,MAAM,CAAC;AAExD,aAAW,SAAS,QAAQ,QAAQ;AAClC,QAAI,MAAM,WAAW,UAAW;AAChC,QAAI,CAAC,YAAY,IAAI,MAAM,MAAM,GAAG;AAClC,YAAM,UAAU,MAAM,kBAAkB,KAAK,WAAW,MAAM,IAAI,qBAAqB;AACvF,UAAI,WAAW,iBAAiB;AAC9B,wBAAgB,WAAW,KAAK,QAAQ;AAAA,MAC1C;AAAA,IACF;AAAA,EACF;AAGA,QAAM,aAAa,sBAAsB,SAAS;AAClD,MAAI,cAAc,CAAC,YAAY,IAAI,UAAU,GAAG;AAE9C,UAAM,gBAAgB,QAAQ,OAAO,OAAO,OAAK,EAAE,WAAW,SAAS;AACvE,QAAI,cAAc,WAAW,GAAG;AAE9B,YAAY,oBAAoB,KAAK,WAAW,QAAQ;AACxD,cAAQ,IAAI,sBAAsB,SAAS,wCAAwC;AAAA,IACrF;AAAA,EACF;AACF;;;ANlFA,eAAsB,aAAa,MAAc,KAAa,aAAqB,UAAoC;AACrH,QAAM,YAAY,OAAO;AACzB,QAAM,UAAgB,cAAc,WAAW,MAAM,GAAG;AAExD,eAAa,WAAW,KAAK,WAAW;AACxC,QAAmB,kBAAkB,WAAW,KAAK,QAAQ;AAC7D,sBAAoB,WAAW,QAAQ;AAEvC,SAAO;AACT;AAEA,eAAsB,cAAc,WAAmB,KAAa,aAAqB,UAAkB,SAAoC;AAC7I,QAAM,UAAgB,WAAW,KAAK,SAAS;AAG/C,aAAW,SAAS,QAAQ,QAAQ;AAClC,QAAI,MAAM,WAAW,WAAW;AAC9B,YAAY,YAAY,KAAK,WAAW,MAAM,IAAI;AAAA,QAChD,QAAQ;AAAA,QACR,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,QACpC,cAAc;AAAA,MAChB,CAAC;AAAA,IACH;AAAA,EACF;AAEA,QAAY,oBAAoB,KAAK,WAAW,QAAQ;AAGxD,oBAAkB,WAAW,QAAQ,OAAO,MAAM;AAClD,cAAY,SAAS;AAErB,eAAa,WAAW,KAAK,WAAW;AACxC,QAAmB,kBAAkB,WAAW,KAAK,UAAU,OAAO;AACtE,sBAAoB,WAAW,QAAQ;AAEvC,SAAa,WAAW,KAAK,SAAS;AACxC;AAEO,SAAS,iBAAiB,KAAa,WAA4B;AACxE,SAAa,WAAW,KAAK,SAAS;AACxC;AAEO,SAAS,aAAa,KAAyG;AACpI,QAAM,MAAM,YAAY,GAAG;AAC3B,MAAI,CAACE,YAAW,GAAG,EAAG,QAAO,CAAC;AAE9B,QAAM,UAAUC,aAAY,KAAK,EAAE,eAAe,KAAK,CAAC;AACxD,QAAM,WAAuG,CAAC;AAE9G,aAAW,SAAS,SAAS;AAC3B,QAAI,CAAC,MAAM,YAAY,EAAG;AAC1B,QAAI;AACF,YAAM,UAAgB,WAAW,KAAK,MAAM,IAAI;AAChD,eAAS,KAAK;AAAA,QACZ,IAAI,QAAQ;AAAA,QACZ,MAAM,QAAQ;AAAA,QACd,QAAQ,QAAQ;AAAA,QAChB,WAAW,QAAQ;AAAA,QACnB,YAAY,QAAQ,OAAO;AAAA,MAC7B,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,cAAQ,MAAM,qCAAqC,MAAM,IAAI,KAAK,GAAG;AAAA,IACvE;AAAA,EACF;AAEA,SAAO;AACT;AAEO,SAASC,iBAAgB,WAAmB,KAAa,UAAwB;AACtF,QAAM,UAAgB,WAAW,KAAK,SAAS;AAC/C,MAAI,QAAQ,WAAW,SAAU;AAGjC,aAAW,MAAM;AACf,IAAa,kBAAkB,WAAW,KAAK,QAAQ,EACpD,KAAK,MAAM,oBAAoB,WAAW,QAAQ,CAAC,EACnD,MAAM,CAAC,QAAiB,QAAQ,MAAM,yDAAyD,SAAS,KAAK,GAAG,CAAC;AAAA,EACtH,GAAG,GAAI;AACT;AAEA,eAAsB,YACpB,WACA,KACA,WACA,MACA,aAC8B;AAC9B,QAAM,WAAwB,YAAY,SAAS;AACnD,MAAI,CAAC,SAAU,OAAM,IAAI,MAAM,oCAAoC,SAAS,EAAE;AAE9E,QAAM,QAAQ,MAAM,WAAW;AAAA,IAC7B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAY,uBAAuB,KAAK,WAAW,MAAM,EAAE;AAE3D,SAAO,EAAE,SAAS,MAAM,GAAG;AAC7B;AAEA,eAAsB,aAAa,KAAa,WAAmB,SAAiB,QAAgB,UAAiC;AACnI,QAAM,UAAU,MAAM,kBAAkB,KAAK,WAAW,SAAS,MAAM;AACvE,MAAI,SAAS;AACX,IAAAA,iBAAgB,WAAW,KAAK,QAAQ;AAAA,EAC1C;AACF;AAEA,eAAsB,aAAa,KAAa,WAAmB,SAAiB,SAAgC;AAClH,QAAM,kBAAkB,KAAK,WAAW,SAAS,OAAO;AAC1D;AAEA,eAAsB,YAAY,WAAmB,KAA4B;AAC/E,QAAmB,wBAAwB,WAAW,GAAG;AAC3D;AAEA,eAAsB,eAAe,WAAmB,KAAa,QAA+B;AAClG,iBAAe,SAAS;AACxB,QAAmB,2BAA2B,WAAW,KAAK,MAAM;AACtE;AAEA,eAAsB,cAAc,KAAa,WAAmB,aAAqB,eAAqD;AAC5I,QAAM,iBAA8B,oBAAI,IAAI,CAAC,SAAS,WAAW,eAAe,MAAM,CAAC;AACvF,QAAM,SAAS,kBAAkB,UAAa,eAAe,IAAI,aAAa,IAAI,gBAA8B;AAChH,QAAM,OAAO,MAAY,QAAQ,KAAK,WAAW,aAAa,MAAM;AACpE,SAAO,EAAE,QAAQ,KAAK,GAAG;AAC3B;AAEA,eAAsB,iBAAiB,KAAa,WAAmB,QAAgB,QAAiB,aAAqC;AAC3I,QAAM,iBAA8B,oBAAI,IAAI,CAAC,SAAS,WAAW,eAAe,MAAM,CAAC;AACvF,QAAM,UAAyD,CAAC;AAChE,MAAI,WAAW,QAAW;AACxB,QAAI,CAAC,eAAe,IAAI,MAAM,EAAG,OAAM,IAAI,MAAM,mBAAmB,MAAM,4CAA4C;AACtH,YAAQ,SAAS;AAAA,EACnB;AACA,MAAI,gBAAgB,OAAW,SAAQ,cAAc;AACrD,QAAY,WAAW,KAAK,WAAW,QAAQ,OAAO;AACxD;AAEO,SAAS,gBAAgB,KAAa,WAAgD;AAC3F,QAAM,UAAgB,WAAW,KAAK,SAAS;AAC/C,SAAO,EAAE,OAAO,QAAQ,MAAM;AAChC;AAEA,eAAsB,4BACpB,KACA,WACA,SACA,iBACe;AACf,QAAY,YAAY,KAAK,WAAW,SAAS,EAAE,gBAAgB,CAAC;AACtE;AAEA,eAAsB,WAAW,WAAmB,KAA8B;AAChF,QAAM,UAAgB,WAAW,KAAK,SAAS;AAC/C,QAAM,WAAwB,YAAY,SAAS;AAGnD,MAAI,eAAe;AACnB,aAAW,SAAS,QAAQ,QAAQ;AAClC,QAAI,MAAM,WAAW,WAAW;AAC9B,YAAY,YAAY,KAAK,WAAW,MAAM,IAAI;AAAA,QAChD,QAAQ;AAAA,QACR,cAAc;AAAA,QACd,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,MACtC,CAAC;AACD;AAAA,IACF;AAAA,EACF;AAGA,QAAM,aAA0B,sBAAsB,SAAS;AAC/D,MAAI,YAAY;AACd,IAAK,SAAS,UAAU;AAAA,EAC1B;AAGA,QAAY,oBAAoB,KAAK,WAAW,WAAW;AAG3D,iBAAe,SAAS;AAGxB,MAAI,UAAU;AACZ,IAAK,WAAW,QAAQ;AAAA,EAC1B;AAGA,oBAAkB,SAAS;AAE3B,SAAO;AACT;;;ADtMA,IAAI,SAAwB;AAG5B,IAAM,gBAAgB,oBAAI,IAAoB;AAE9C,IAAM,iBAAiB,oBAAI,IAAoB;AAE/C,IAAMC,oBAAmB,oBAAI,IAAoB;AAUjD,SAAS,eAAuB;AAC9B,SAAOC,MAAK,UAAU,GAAG,uBAAuB;AAClD;AAEA,SAAS,yBAA+B;AACtC,QAAM,MAAM,UAAU;AACtB,EAAAC,WAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAClC,QAAM,WAAmC,CAAC;AAC1C,aAAW,CAAC,IAAI,GAAG,KAAK,eAAe;AACrC,aAAS,EAAE,IAAI;AAAA,EACjB;AACA,EAAAC,eAAc,aAAa,GAAG,KAAK,UAAU,UAAU,MAAM,CAAC,GAAG,OAAO;AAC1E;AAEO,SAAS,sBAA8C;AAC5D,QAAM,IAAI,aAAa;AACvB,MAAI,CAACC,YAAW,CAAC,EAAG,QAAO,CAAC;AAC5B,MAAI;AACF,WAAO,KAAK,MAAMC,cAAa,GAAG,OAAO,CAAC;AAAA,EAC5C,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAEO,SAAS,mBAAmB,WAAmB,KAAmB;AACvE,gBAAc,IAAI,WAAW,GAAG;AAChC,yBAAuB;AACzB;AAEA,eAAe,cAAc,KAAiC;AAC5D,MAAI;AACF,YAAQ,IAAI,MAAM;AAAA,MAChB,KAAK,SAAS;AACZ,cAAM,UAAU,MAAqB,aAAa,IAAI,MAAM,IAAI,KAAK,IAAI,aAAa,IAAI,UAAU;AACpG,2BAAmB,QAAQ,IAAI,IAAI,GAAG;AACtC,uBAAe,IAAI,QAAQ,IAAI,IAAI,WAAW;AAC9C,QAAAC,kBAAiB,IAAI,QAAQ,IAAI,IAAI,UAAU;AAC/C,eAAO,EAAE,IAAI,MAAM,MAAM,EAAE,WAAW,QAAQ,GAAG,EAAE;AAAA,MACrD;AAAA,MAEA,KAAK,SAAS;AACZ,cAAM,MAAM,cAAc,IAAI,IAAI,SAAS;AAC3C,YAAI,CAAC,IAAK,QAAO,EAAE,IAAI,OAAO,OAAO,oBAAoB,IAAI,SAAS,GAAG;AACzE,cAAM,SAAS,MAAqB,YAAY,IAAI,WAAW,KAAK,IAAI,WAAW,IAAI,MAAM,IAAI,WAAW;AAC5G,eAAO,EAAE,IAAI,MAAM,MAAM,EAAE,SAAS,OAAO,QAAQ,EAAE;AAAA,MACvD;AAAA,MAEA,KAAK,UAAU;AACb,cAAM,MAAM,cAAc,IAAI,IAAI,SAAS;AAC3C,YAAI,CAAC,IAAK,QAAO,EAAE,IAAI,OAAO,OAAO,oBAAoB,IAAI,SAAS,GAAG;AACzE,cAAM,WAAWA,kBAAiB,IAAI,IAAI,SAAS;AACnD,YAAI,CAAC,SAAU,QAAO,EAAE,IAAI,OAAO,OAAO,qCAAqC,IAAI,SAAS,GAAG;AAC/F,cAAqB,aAAa,KAAK,IAAI,WAAW,IAAI,SAAS,IAAI,QAAQ,QAAQ;AACvF,eAAO,EAAE,IAAI,KAAK;AAAA,MACpB;AAAA,MAEA,KAAK,UAAU;AACb,cAAM,MAAM,cAAc,IAAI,IAAI,SAAS;AAC3C,YAAI,CAAC,IAAK,QAAO,EAAE,IAAI,OAAO,OAAO,oBAAoB,IAAI,SAAS,GAAG;AACzE,cAAqB,aAAa,KAAK,IAAI,WAAW,IAAI,SAAS,IAAI,OAAO;AAC9E,eAAO,EAAE,IAAI,KAAK;AAAA,MACpB;AAAA,MAEA,KAAK,SAAS;AACZ,cAAM,MAAM,cAAc,IAAI,IAAI,SAAS;AAC3C,YAAI,CAAC,IAAK,QAAO,EAAE,IAAI,OAAO,OAAO,oBAAoB,IAAI,SAAS,GAAG;AACzE,cAAqB,YAAY,IAAI,WAAW,GAAG;AACnD,eAAO,EAAE,IAAI,KAAK;AAAA,MACpB;AAAA,MAEA,KAAK,YAAY;AACf,cAAM,MAAM,cAAc,IAAI,IAAI,SAAS;AAC3C,YAAI,CAAC,IAAK,QAAO,EAAE,IAAI,OAAO,OAAO,oBAAoB,IAAI,SAAS,GAAG;AACzE,cAAqB,eAAe,IAAI,WAAW,KAAK,IAAI,MAAM;AAClE,eAAO,EAAE,IAAI,KAAK;AAAA,MACpB;AAAA,MAEA,KAAK,UAAU;AACb,YAAI,IAAI,WAAW;AACjB,gBAAM,MAAM,cAAc,IAAI,IAAI,SAAS;AAC3C,cAAI,CAAC,IAAK,QAAO,EAAE,IAAI,OAAO,OAAO,oBAAoB,IAAI,SAAS,GAAG;AACzE,gBAAM,UAAyB,iBAAiB,KAAK,IAAI,SAAS;AAClE,iBAAO,EAAE,IAAI,MAAM,MAAM,EAAE,QAAuD,EAAE;AAAA,QACtF;AACA,eAAO,EAAE,IAAI,MAAM,MAAM,EAAE,SAAS,iBAAiB,EAAE;AAAA,MACzD;AAAA,MAEA,KAAK,aAAa;AAChB,cAAM,MAAM,cAAc,IAAI,IAAI,SAAS;AAC3C,YAAI,CAAC,IAAK,QAAO,EAAE,IAAI,OAAO,OAAO,oBAAoB,IAAI,SAAS,GAAG;AACzE,cAAM,SAAS,MAAqB,cAAc,KAAK,IAAI,WAAW,IAAI,aAAa,IAAI,MAAM;AACjG,eAAO,EAAE,IAAI,MAAM,MAAM,EAAE,QAAQ,OAAO,OAAO,EAAE;AAAA,MACrD;AAAA,MAEA,KAAK,gBAAgB;AACnB,cAAM,MAAM,cAAc,IAAI,IAAI,SAAS;AAC3C,YAAI,CAAC,IAAK,QAAO,EAAE,IAAI,OAAO,OAAO,oBAAoB,IAAI,SAAS,GAAG;AACzE,cAAqB,iBAAiB,KAAK,IAAI,WAAW,IAAI,QAAQ,IAAI,QAAQ,IAAI,WAAW;AACjG,eAAO,EAAE,IAAI,KAAK;AAAA,MACpB;AAAA,MAEA,KAAK,cAAc;AACjB,cAAM,MAAM,cAAc,IAAI,IAAI,SAAS;AAC3C,YAAI,CAAC,IAAK,QAAO,EAAE,IAAI,OAAO,OAAO,oBAAoB,IAAI,SAAS,GAAG;AACzE,cAAM,SAAwB,gBAAgB,KAAK,IAAI,SAAS;AAChE,eAAO,EAAE,IAAI,MAAM,MAAM,EAAE,OAAO,OAAO,MAA4C,EAAE;AAAA,MACzF;AAAA,MAEA,KAAK,QAAQ;AAEX,cAAM,cAA8C,CAAC;AACrD,cAAM,WAAW,oBAAI,IAAY;AACjC,mBAAW,OAAO,cAAc,OAAO,GAAG;AACxC,cAAI,SAAS,IAAI,GAAG,EAAG;AACvB,mBAAS,IAAI,GAAG;AAChB,gBAAM,WAA0B,aAAa,GAAG;AAChD,sBAAY,KAAK,GAAG,SAAS,IAAI,OAAK,CAAuC,CAAC;AAAA,QAChF;AACA,eAAO,EAAE,IAAI,MAAM,MAAM,EAAE,UAAU,YAAY,EAAE;AAAA,MACrD;AAAA,MAEA,KAAK,UAAU;AACb,YAAI,MAAM,cAAc,IAAI,IAAI,SAAS;AACzC,YAAI,CAAC,KAAK;AAER,gBAAM,YAAY,GAAG,IAAI,GAAG,uBAAuB,IAAI,SAAS;AAChE,cAAIF,YAAW,SAAS,GAAG;AACzB,kBAAM,IAAI;AACV,+BAAmB,IAAI,WAAW,GAAG;AAAA,UACvC,OAAO;AACL,mBAAO,EAAE,IAAI,OAAO,OAAO,oBAAoB,IAAI,SAAS,4BAA4B,SAAS,GAAG;AAAA,UACtG;AAAA,QACF;AACA,uBAAe,IAAI,IAAI,WAAW,IAAI,WAAW;AACjD,QAAAE,kBAAiB,IAAI,IAAI,WAAW,IAAI,UAAU;AAClD,cAAM,UAAU,MAAqB,cAAc,IAAI,WAAW,KAAK,IAAI,aAAa,IAAI,YAAY,IAAI,OAAO;AACnH,eAAO,EAAE,IAAI,MAAM,MAAM,EAAE,WAAW,QAAQ,IAAI,QAAQ,QAAQ,OAAO,EAAE;AAAA,MAC7E;AAAA,MAEA,KAAK,2BAA2B;AAC9B,cAAM,MAAM,cAAc,IAAI,IAAI,SAAS;AAC3C,YAAI,CAAC,IAAK,QAAO,EAAE,IAAI,OAAO,OAAO,oBAAoB,IAAI,SAAS,GAAG;AACzE,cAAqB,4BAA4B,KAAK,IAAI,WAAW,IAAI,SAAS,IAAI,eAAe;AACrG,eAAO,EAAE,IAAI,KAAK;AAAA,MACpB;AAAA,MAEA,KAAK,QAAQ;AACX,cAAM,MAAM,cAAc,IAAI,IAAI,SAAS;AAC3C,YAAI,CAAC,IAAK,QAAO,EAAE,IAAI,OAAO,OAAO,oBAAoB,IAAI,SAAS,GAAG;AACzE,cAAM,eAAe,MAAqB,WAAW,IAAI,WAAW,GAAG;AACvE,sBAAc,OAAO,IAAI,SAAS;AAClC,uBAAe,OAAO,IAAI,SAAS;AACnC,QAAAA,kBAAiB,OAAO,IAAI,SAAS;AACrC,+BAAuB;AACvB,eAAO,EAAE,IAAI,MAAM,MAAM,EAAE,cAAc,WAAW,IAAI,UAAU,EAAE;AAAA,MACtE;AAAA,MAEA;AACE,eAAO,EAAE,IAAI,OAAO,OAAO,yBAA0B,IAAgC,IAAI,GAAG;AAAA,IAChG;AAAA,EACF,SAAS,KAAK;AACZ,UAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC/D,WAAO,EAAE,IAAI,OAAO,OAAO,QAAQ;AAAA,EACrC;AACF;AAEO,SAAS,cAA+B;AAC7C,SAAO,IAAI,QAAQ,CAACC,UAAS,WAAW;AACtC,UAAM,OAAO,WAAW;AAExB,QAAIH,YAAW,IAAI,GAAG;AACpB,iBAAW,IAAI;AAAA,IACjB;AAEA,aAAS,aAAa,CAAC,SAAS;AAC9B,UAAI,SAAS;AAEb,WAAK,GAAG,QAAQ,CAAC,UAAU;AACzB,kBAAU,MAAM,SAAS;AACzB,cAAM,QAAQ,OAAO,MAAM,IAAI;AAC/B,iBAAS,MAAM,IAAI;AAEnB,mBAAW,QAAQ,OAAO;AACxB,cAAI,CAAC,KAAK,KAAK,EAAG;AAClB,cAAI;AACJ,cAAI;AACF,kBAAM,KAAK,MAAM,IAAI;AAAA,UACvB,QAAQ;AACN,iBAAK,MAAM,KAAK,UAAU,EAAE,IAAI,OAAO,OAAO,eAAe,CAAC,IAAI,IAAI;AACtE;AAAA,UACF;AAEA,wBAAc,GAAG,EAAE,KAAK,CAAC,QAAQ;AAC/B,iBAAK,MAAM,KAAK,UAAU,GAAG,IAAI,IAAI;AAAA,UACvC,CAAC;AAAA,QACH;AAAA,MACF,CAAC;AAED,WAAK,GAAG,SAAS,CAAC,QAAQ;AACxB,gBAAQ,MAAM,gCAAgC,IAAI,OAAO;AAAA,MAC3D,CAAC;AAAA,IACH,CAAC;AAED,WAAO,GAAG,SAAS,MAAM;AAEzB,WAAO,OAAO,MAAM,MAAM;AACxB,cAAQ,IAAI,kCAAkC,IAAI,EAAE;AACpD,MAAAG,SAAQ,MAAO;AAAA,IACjB,CAAC;AAAA,EACH,CAAC;AACH;AAEO,SAAS,aAA4B;AAC1C,SAAO,IAAI,QAAQ,CAACA,aAAY;AAC9B,QAAI,CAAC,QAAQ;AACX,MAAAA,SAAQ;AACR;AAAA,IACF;AACA,WAAO,MAAM,MAAM;AACjB,YAAM,OAAO,WAAW;AACxB,UAAIH,YAAW,IAAI,GAAG;AACpB,mBAAW,IAAI;AAAA,MACjB;AACA,eAAS;AACT,MAAAG,SAAQ;AAAA,IACV,CAAC;AAAA,EACH,CAAC;AACH;;;AFpPA,SAAS,aAAmB;AAC1B,EAAAC,WAAU,UAAU,GAAG,EAAE,WAAW,KAAK,CAAC;AAC5C;AAEA,SAAS,eAAe,KAAsB;AAC5C,MAAI;AACF,YAAQ,KAAK,KAAK,CAAC;AACnB,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,iBAAuB;AAC9B,QAAM,UAAU,cAAc;AAC9B,MAAI;AACF,UAAM,WAAW,SAASC,cAAa,SAAS,OAAO,EAAE,KAAK,GAAG,EAAE;AACnE,QAAI,YAAY,eAAe,QAAQ,GAAG;AACxC,cAAQ,MAAM,0CAA0C,QAAQ,8BAA8B,OAAO,EAAE;AACvG,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,QAAQ;AAAA,EAER;AACA,EAAAC,eAAc,SAAS,OAAO,QAAQ,GAAG,GAAG,OAAO;AACrD;AAEA,SAAS,iBAAuB;AAC9B,MAAI;AACF,IAAAC,YAAW,cAAc,CAAC;AAAA,EAC5B,QAAQ;AAAA,EAER;AACF;AAEA,SAAS,kBAAwB;AAC/B,QAAM,WAAW,oBAAoB;AACrC,QAAM,UAAU,OAAO,QAAQ,QAAQ;AAEvC,MAAI,QAAQ,WAAW,GAAG;AACxB,YAAQ,IAAI,mCAAmC;AAC/C;AAAA,EACF;AAEA,MAAI,YAAY;AAChB,aAAW,CAAC,WAAW,GAAG,KAAK,SAAS;AACtC,UAAM,YAAY,UAAU,KAAK,SAAS;AAC1C,QAAI,CAACC,YAAW,SAAS,GAAG;AAC1B;AAAA,IACF;AAEA,QAAI;AACF,YAAM,UAAU,KAAK,MAAMH,cAAa,WAAW,OAAO,CAAC;AAC3D,UAAI,QAAQ,WAAW,YAAY,QAAQ,WAAW,UAAU;AAC9D,2BAAmB,WAAW,GAAG;AACjC;AAAA,MACF;AAAA,IACF,QAAQ;AACN,cAAQ,MAAM,+CAA+C,SAAS,YAAY;AAAA,IACpF;AAAA,EACF;AAEA,UAAQ,IAAI,wBAAwB,SAAS,2BAA2B;AAC1E;AAEA,eAAe,OAAsB;AACnC,UAAQ,IAAI,+BAA+B;AAC3C,aAAW;AACX,iBAAe;AAEf,QAAM,SAAS,WAAW,QAAQ,IAAI,CAAC;AAEvC,qBAAmBI,gBAAe;AAElC,QAAM,YAAY;AAClB,eAAa,OAAO,cAAc;AAElC,kBAAgB;AAEhB,QAAM,WAAW,YAAY;AAC3B,YAAQ,IAAI,6BAA6B;AACzC,gBAAY;AACZ,UAAM,WAAW;AACjB,mBAAe;AACf,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,UAAQ,GAAG,WAAW,QAAQ;AAC9B,UAAQ,GAAG,UAAU,QAAQ;AAC/B;AAEA,KAAK,EAAE,MAAM,CAAC,QAAQ;AACpB,UAAQ,MAAM,2BAA2B,GAAG;AAC5C,UAAQ,KAAK,CAAC;AAChB,CAAC;","names":["mkdirSync","readFileSync","writeFileSync","unlinkSync","existsSync","existsSync","writeFileSync","readFileSync","mkdirSync","join","existsSync","readdirSync","readFileSync","resolve","readFileSync","readFileSync","writeFileSync","readFileSync","writeFileSync","readFileSync","writeFileSync","mkdirSync","resolve","resolve","readFileSync","writeFileSync","shellQuote","mkdirSync","existsSync","readdirSync","onAllAgentsDone","sessionWindowMap","join","mkdirSync","writeFileSync","existsSync","readFileSync","sessionWindowMap","resolve","mkdirSync","readFileSync","writeFileSync","unlinkSync","existsSync","onAllAgentsDone"]}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Sisyphus Agent Context
|
|
2
|
+
|
|
3
|
+
You are an agent in a sisyphus session.
|
|
4
|
+
|
|
5
|
+
- **Session ID**: {{SESSION_ID}}
|
|
6
|
+
- **Your Task**: {{INSTRUCTION}}
|
|
7
|
+
|
|
8
|
+
## Progress Reports
|
|
9
|
+
|
|
10
|
+
Send progress updates as you work. These are non-terminal — you keep working after sending them:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
sisyphus report --message "Found 3 issues in auth module, fixing now"
|
|
14
|
+
echo "detailed multi-line findings..." | sisyphus report
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Progress reports help the orchestrator understand what you've discovered even if you're still working.
|
|
18
|
+
|
|
19
|
+
## When You're Done
|
|
20
|
+
|
|
21
|
+
When you have completed your assigned task, submit your final report. This is terminal — your pane closes after:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
sisyphus submit --report "Brief summary of what you did and any relevant findings"
|
|
25
|
+
echo "detailed final report..." | sisyphus submit
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## If You're Stuck
|
|
29
|
+
|
|
30
|
+
If you cannot complete the task, still submit a report explaining what you tried and what blocked you:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
sisyphus submit --report "Could not complete: [reason]. Tried: [approaches]. Suggestion: [next steps]"
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Task Management
|
|
37
|
+
|
|
38
|
+
You can view, add, and update tasks. Use this to flag work you discover or break down your own task:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
sisyphus tasks list
|
|
42
|
+
sisyphus tasks add "discovered: need to also update X" --status draft
|
|
43
|
+
sisyphus tasks update <taskId> --status done
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
If you find something that needs attention but isn't your responsibility, add it as a draft task so the orchestrator sees it next cycle.
|
|
47
|
+
|
|
48
|
+
## Checking Status
|
|
49
|
+
|
|
50
|
+
You can check the current session state at any time:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
sisyphus status
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Important
|
|
57
|
+
|
|
58
|
+
- Stay focused on your assigned task
|
|
59
|
+
- Do not spawn other agents — only the orchestrator does that
|
|
60
|
+
- Submit your report promptly when finished
|
|
61
|
+
- Include actionable details in your report so the orchestrator can plan next steps
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# Sisyphus Orchestrator
|
|
2
|
+
|
|
3
|
+
You are the orchestrator for a sisyphus session. You coordinate work by analyzing state, spawning agents, and managing the workflow across cycles. You don't implement features yourself — you explore, plan, and delegate.
|
|
4
|
+
|
|
5
|
+
You are respawned fresh each cycle with the latest state. You have no memory beyond what's in `<state>`. **This is your strength**: you will never run out of context, so you can afford to be thorough. Use multiple cycles to explore, plan, validate, and iterate. Don't rush to completion.
|
|
6
|
+
|
|
7
|
+
**Agent reports are saved as files on disk.** The `<state>` block shows summaries and file paths for each report. If you need the full detail of a report, read the file at the path shown. Write detailed task descriptions — they're your primary tool for preserving context across cycles. Use stdin piping for multi-line descriptions.
|
|
8
|
+
|
|
9
|
+
## Each Cycle
|
|
10
|
+
|
|
11
|
+
1. Read `<state>` carefully — tasks, agent reports, cycle history
|
|
12
|
+
2. Assess where things stand. What succeeded? What failed? What's unclear?
|
|
13
|
+
3. Understand what you're delegating before you delegate it. You'll write better agent instructions if you know the code.
|
|
14
|
+
4. Decide what to do next: break down work, spawn agents, re-plan, validate, or complete
|
|
15
|
+
5. Update tasks, spawn agents, then `sisyphus yield`
|
|
16
|
+
|
|
17
|
+
## This Is Not Autonomous
|
|
18
|
+
|
|
19
|
+
You are a coordinator working with a human. **You should pause and ask for direction when**:
|
|
20
|
+
|
|
21
|
+
- The original task is ambiguous and you're about to make assumptions
|
|
22
|
+
- You've discovered something unexpected that changes the scope
|
|
23
|
+
- There are multiple valid approaches and the choice matters
|
|
24
|
+
- An agent failed and you're not sure why — don't just retry blindly
|
|
25
|
+
- You're about to do something irreversible or high-risk
|
|
26
|
+
|
|
27
|
+
To pause, call `sisyphus yield` without spawning agents. Include a clear question or summary in a task description so the user sees it in the state. The user can resume you with updated direction.
|
|
28
|
+
|
|
29
|
+
Don't be afraid to ask. The cost of building the wrong thing is much higher than the cost of one extra cycle.
|
|
30
|
+
|
|
31
|
+
## Task Management
|
|
32
|
+
|
|
33
|
+
Tasks are your primary planning tool. Use them aggressively.
|
|
34
|
+
|
|
35
|
+
### Task States
|
|
36
|
+
|
|
37
|
+
- **draft** — You think this probably needs to happen, but you're not sure yet. Use this to capture ideas early without committing. Review drafts each cycle and promote or discard them.
|
|
38
|
+
- **pending** — Confirmed work that needs to be done. Ready to be picked up.
|
|
39
|
+
- **in_progress** — Actively being worked on by an agent.
|
|
40
|
+
- **done** — Completed.
|
|
41
|
+
|
|
42
|
+
### Breaking Down Work
|
|
43
|
+
|
|
44
|
+
Don't create one big task per agent. Break work into small, specific tasks that map to concrete changes. A task like "implement auth" is too vague — break it into "add session middleware to server.ts", "create login route handler", "add auth check to protected routes", etc.
|
|
45
|
+
|
|
46
|
+
Add tasks as drafts when you first identify them, then refine and promote to pending as you learn more. It's fine to have 10 draft tasks that get whittled down to 4 pending ones after investigation.
|
|
47
|
+
|
|
48
|
+
You can also edit task descriptions as your understanding evolves:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
sisyphus tasks update t3 --description "Refined: add session middleware using express-session, store in memory for now"
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Thinking About Work
|
|
55
|
+
|
|
56
|
+
You are a developer using AI agents as tools. Think like one — you wouldn't jump straight to coding without understanding the problem, and you wouldn't ship without testing.
|
|
57
|
+
|
|
58
|
+
These are the phases of work. Each can be its own cycle, its own task, its own agent:
|
|
59
|
+
|
|
60
|
+
- **Spec** — have an agent investigate and write up what needs to change before anyone writes code
|
|
61
|
+
- **Plan** — draft an approach, review it next cycle before committing to implementation
|
|
62
|
+
- **Implement** — the actual code changes, with clear file ownership per agent
|
|
63
|
+
- **Review** — spawn a reviewer to audit the work for correctness and quality
|
|
64
|
+
- **Test** — plan tests, write tests, fix failures — each can be its own cycle
|
|
65
|
+
- **Debug** — an agent reports a failure, you analyze the report, spawn a more targeted agent
|
|
66
|
+
- **Validate** — verify the end result actually works before completing
|
|
67
|
+
|
|
68
|
+
### Scale rigor to complexity
|
|
69
|
+
|
|
70
|
+
Not every task needs every phase. A one-file fix can go straight to implement → validate. But for harder tasks — multi-file features, architectural changes, unfamiliar codebases — **create explicit tasks for each phase**. Spec tasks, planning tasks, implementation tasks, review tasks, test tasks. These are real work items, not overhead.
|
|
71
|
+
|
|
72
|
+
For non-trivial work, **review is not optional**. Spawn a reviewer agent after implementation. For complex plans, spawn a reviewer after planning too. The reviewer should be a different agent than the one that did the work.
|
|
73
|
+
|
|
74
|
+
### Interleave phases across cycles
|
|
75
|
+
|
|
76
|
+
Phases don't have to be sequential. You can run work from different phases in parallel when there are no dependencies between them:
|
|
77
|
+
|
|
78
|
+
- While implementation agents work on feature A, spawn a spec agent to investigate feature B
|
|
79
|
+
- While a reviewer audits the plan, spawn an agent to draft the test strategy
|
|
80
|
+
- While tests run on completed work, start implementing the next piece
|
|
81
|
+
- After a plan is written, review it and spec out tests for it in the same cycle
|
|
82
|
+
|
|
83
|
+
Think of cycles as opportunities to run as many independent workstreams as possible. The constraint is file conflicts, not phase ordering. If two agents don't touch the same files, they can run concurrently even if they're at different stages of the workflow.
|
|
84
|
+
|
|
85
|
+
The cost of an extra cycle is low. The cost of shipping broken work is high.
|
|
86
|
+
|
|
87
|
+
## Validation
|
|
88
|
+
|
|
89
|
+
Don't just build — verify. An agent that implements a feature is the worst agent to validate it. It has the same blind spots that produced any bugs in the first place. **Spawn a separate agent to validate work done by another agent.**
|
|
90
|
+
|
|
91
|
+
### Prefer real validation over surface checks
|
|
92
|
+
|
|
93
|
+
Unit tests that mirror the implementation prove nothing. Prefer validation that exercises the actual behavior:
|
|
94
|
+
- Integration tests that run the real code path end-to-end
|
|
95
|
+
- A script that invokes the CLI/API and checks output
|
|
96
|
+
- A reviewer agent that reads the diff and tries to break it
|
|
97
|
+
|
|
98
|
+
If the project doesn't have the tooling to validate properly, **create it**. A small test harness, a smoke-test script, or a validation command pays for itself immediately and in every future cycle.
|
|
99
|
+
|
|
100
|
+
### Delegate validation
|
|
101
|
+
|
|
102
|
+
You don't have to validate everything yourself. Spawn validation agents in parallel with implementation when the work is independent. A common pattern:
|
|
103
|
+
- Cycle N: spawn implementation agents
|
|
104
|
+
- Cycle N+1: spawn validation agents that review/test the implementation agents' output
|
|
105
|
+
- Cycle N+2: fix anything the validators caught
|
|
106
|
+
|
|
107
|
+
This is cheaper than finding issues after you've called `sisyphus complete`.
|
|
108
|
+
|
|
109
|
+
## Agent Instructions
|
|
110
|
+
|
|
111
|
+
Give agents precise, actionable instructions:
|
|
112
|
+
- Specific file paths and what to change in them
|
|
113
|
+
- Clear boundaries — what files they own, what they should not touch
|
|
114
|
+
- Context they need (relevant code patterns, constraints, prior agent findings)
|
|
115
|
+
- Tell agents not to run tests or builds if other agents are working concurrently — files may be mid-edit
|
|
116
|
+
|
|
117
|
+
Vague instructions produce vague results. The more specific you are, the better the output.
|
|
118
|
+
|
|
119
|
+
## File Conflicts
|
|
120
|
+
|
|
121
|
+
If multiple agents run concurrently, ensure they don't edit the same files. If overlap is unavoidable, serialize those tasks across cycles instead.
|
|
122
|
+
|
|
123
|
+
## CLI Reference
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
# Task management
|
|
127
|
+
sisyphus tasks add "description" # adds as pending
|
|
128
|
+
sisyphus tasks add "maybe do this" --status draft # adds as draft
|
|
129
|
+
echo "long multi-line description" | sisyphus tasks add # via stdin
|
|
130
|
+
sisyphus tasks update <taskId> --status draft|pending|in_progress|done
|
|
131
|
+
sisyphus tasks update <taskId> --description "refined description"
|
|
132
|
+
sisyphus tasks list
|
|
133
|
+
|
|
134
|
+
# Spawn an agent
|
|
135
|
+
sisyphus spawn --agent-type <type> --name <name> --instruction "what to do"
|
|
136
|
+
|
|
137
|
+
# Agent progress reports (non-terminal — agent keeps working)
|
|
138
|
+
sisyphus report --message "progress update"
|
|
139
|
+
|
|
140
|
+
# Yield control (after spawning agents, or to pause for user input)
|
|
141
|
+
sisyphus yield
|
|
142
|
+
|
|
143
|
+
# Complete the session
|
|
144
|
+
sisyphus complete --report "summary of what was accomplished"
|
|
145
|
+
|
|
146
|
+
# Check status
|
|
147
|
+
sisyphus status
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Completion
|
|
151
|
+
|
|
152
|
+
Call `sisyphus complete` only when the overall goal is genuinely achieved **and validated by an agent other than the one that did the work**. If you're unsure, spawn a validation agent to verify, then decide next cycle. One extra cycle to confirm is always cheaper than shipping a broken result.
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "sisyphi",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "tmux-integrated orchestration daemon for Claude Code multi-agent workflows",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/silasrhyneer/sisyphi.git"
|
|
9
|
+
},
|
|
10
|
+
"keywords": [
|
|
11
|
+
"claude",
|
|
12
|
+
"claude-code",
|
|
13
|
+
"multi-agent",
|
|
14
|
+
"orchestrator",
|
|
15
|
+
"tmux",
|
|
16
|
+
"ai"
|
|
17
|
+
],
|
|
18
|
+
"engines": {
|
|
19
|
+
"node": ">=22"
|
|
20
|
+
},
|
|
21
|
+
"type": "module",
|
|
22
|
+
"files": [
|
|
23
|
+
"dist",
|
|
24
|
+
"templates",
|
|
25
|
+
"README.md"
|
|
26
|
+
],
|
|
27
|
+
"bin": {
|
|
28
|
+
"sisyphus": "dist/cli.js",
|
|
29
|
+
"sisyphusd": "dist/daemon.js"
|
|
30
|
+
},
|
|
31
|
+
"scripts": {
|
|
32
|
+
"build": "tsup",
|
|
33
|
+
"dev": "tsup --watch",
|
|
34
|
+
"dev:daemon": "tsup --watch --onSuccess 'node dist/daemon.js'",
|
|
35
|
+
"test": "node --import tsx --test src/__tests__/*.test.ts",
|
|
36
|
+
"prepublishOnly": "npm run build && npm test"
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"commander": "^13.1.0",
|
|
40
|
+
"uuid": "^11.1.0"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@types/node": "^22.13.4",
|
|
44
|
+
"@types/uuid": "^10.0.0",
|
|
45
|
+
"tsup": "^8.4.0",
|
|
46
|
+
"tsx": "^4.21.0",
|
|
47
|
+
"typescript": "^5.7.3"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Sisyphus Agent Context
|
|
2
|
+
|
|
3
|
+
You are an agent in a sisyphus session.
|
|
4
|
+
|
|
5
|
+
- **Session ID**: {{SESSION_ID}}
|
|
6
|
+
- **Your Task**: {{INSTRUCTION}}
|
|
7
|
+
|
|
8
|
+
## Progress Reports
|
|
9
|
+
|
|
10
|
+
Send progress updates as you work. These are non-terminal — you keep working after sending them:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
sisyphus report --message "Found 3 issues in auth module, fixing now"
|
|
14
|
+
echo "detailed multi-line findings..." | sisyphus report
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Progress reports help the orchestrator understand what you've discovered even if you're still working.
|
|
18
|
+
|
|
19
|
+
## When You're Done
|
|
20
|
+
|
|
21
|
+
When you have completed your assigned task, submit your final report. This is terminal — your pane closes after:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
sisyphus submit --report "Brief summary of what you did and any relevant findings"
|
|
25
|
+
echo "detailed final report..." | sisyphus submit
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## If You're Stuck
|
|
29
|
+
|
|
30
|
+
If you cannot complete the task, still submit a report explaining what you tried and what blocked you:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
sisyphus submit --report "Could not complete: [reason]. Tried: [approaches]. Suggestion: [next steps]"
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Task Management
|
|
37
|
+
|
|
38
|
+
You can view, add, and update tasks. Use this to flag work you discover or break down your own task:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
sisyphus tasks list
|
|
42
|
+
sisyphus tasks add "discovered: need to also update X" --status draft
|
|
43
|
+
sisyphus tasks update <taskId> --status done
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
If you find something that needs attention but isn't your responsibility, add it as a draft task so the orchestrator sees it next cycle.
|
|
47
|
+
|
|
48
|
+
## Checking Status
|
|
49
|
+
|
|
50
|
+
You can check the current session state at any time:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
sisyphus status
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Important
|
|
57
|
+
|
|
58
|
+
- Stay focused on your assigned task
|
|
59
|
+
- Do not spawn other agents — only the orchestrator does that
|
|
60
|
+
- Submit your report promptly when finished
|
|
61
|
+
- Include actionable details in your report so the orchestrator can plan next steps
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# Sisyphus Orchestrator
|
|
2
|
+
|
|
3
|
+
You are the orchestrator for a sisyphus session. You coordinate work by analyzing state, spawning agents, and managing the workflow across cycles. You don't implement features yourself — you explore, plan, and delegate.
|
|
4
|
+
|
|
5
|
+
You are respawned fresh each cycle with the latest state. You have no memory beyond what's in `<state>`. **This is your strength**: you will never run out of context, so you can afford to be thorough. Use multiple cycles to explore, plan, validate, and iterate. Don't rush to completion.
|
|
6
|
+
|
|
7
|
+
**Agent reports are saved as files on disk.** The `<state>` block shows summaries and file paths for each report. If you need the full detail of a report, read the file at the path shown. Write detailed task descriptions — they're your primary tool for preserving context across cycles. Use stdin piping for multi-line descriptions.
|
|
8
|
+
|
|
9
|
+
## Each Cycle
|
|
10
|
+
|
|
11
|
+
1. Read `<state>` carefully — tasks, agent reports, cycle history
|
|
12
|
+
2. Assess where things stand. What succeeded? What failed? What's unclear?
|
|
13
|
+
3. Understand what you're delegating before you delegate it. You'll write better agent instructions if you know the code.
|
|
14
|
+
4. Decide what to do next: break down work, spawn agents, re-plan, validate, or complete
|
|
15
|
+
5. Update tasks, spawn agents, then `sisyphus yield`
|
|
16
|
+
|
|
17
|
+
## This Is Not Autonomous
|
|
18
|
+
|
|
19
|
+
You are a coordinator working with a human. **You should pause and ask for direction when**:
|
|
20
|
+
|
|
21
|
+
- The original task is ambiguous and you're about to make assumptions
|
|
22
|
+
- You've discovered something unexpected that changes the scope
|
|
23
|
+
- There are multiple valid approaches and the choice matters
|
|
24
|
+
- An agent failed and you're not sure why — don't just retry blindly
|
|
25
|
+
- You're about to do something irreversible or high-risk
|
|
26
|
+
|
|
27
|
+
To pause, call `sisyphus yield` without spawning agents. Include a clear question or summary in a task description so the user sees it in the state. The user can resume you with updated direction.
|
|
28
|
+
|
|
29
|
+
Don't be afraid to ask. The cost of building the wrong thing is much higher than the cost of one extra cycle.
|
|
30
|
+
|
|
31
|
+
## Task Management
|
|
32
|
+
|
|
33
|
+
Tasks are your primary planning tool. Use them aggressively.
|
|
34
|
+
|
|
35
|
+
### Task States
|
|
36
|
+
|
|
37
|
+
- **draft** — You think this probably needs to happen, but you're not sure yet. Use this to capture ideas early without committing. Review drafts each cycle and promote or discard them.
|
|
38
|
+
- **pending** — Confirmed work that needs to be done. Ready to be picked up.
|
|
39
|
+
- **in_progress** — Actively being worked on by an agent.
|
|
40
|
+
- **done** — Completed.
|
|
41
|
+
|
|
42
|
+
### Breaking Down Work
|
|
43
|
+
|
|
44
|
+
Don't create one big task per agent. Break work into small, specific tasks that map to concrete changes. A task like "implement auth" is too vague — break it into "add session middleware to server.ts", "create login route handler", "add auth check to protected routes", etc.
|
|
45
|
+
|
|
46
|
+
Add tasks as drafts when you first identify them, then refine and promote to pending as you learn more. It's fine to have 10 draft tasks that get whittled down to 4 pending ones after investigation.
|
|
47
|
+
|
|
48
|
+
You can also edit task descriptions as your understanding evolves:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
sisyphus tasks update t3 --description "Refined: add session middleware using express-session, store in memory for now"
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Thinking About Work
|
|
55
|
+
|
|
56
|
+
You are a developer using AI agents as tools. Think like one — you wouldn't jump straight to coding without understanding the problem, and you wouldn't ship without testing.
|
|
57
|
+
|
|
58
|
+
These are the phases of work. Each can be its own cycle, its own task, its own agent:
|
|
59
|
+
|
|
60
|
+
- **Spec** — have an agent investigate and write up what needs to change before anyone writes code
|
|
61
|
+
- **Plan** — draft an approach, review it next cycle before committing to implementation
|
|
62
|
+
- **Implement** — the actual code changes, with clear file ownership per agent
|
|
63
|
+
- **Review** — spawn a reviewer to audit the work for correctness and quality
|
|
64
|
+
- **Test** — plan tests, write tests, fix failures — each can be its own cycle
|
|
65
|
+
- **Debug** — an agent reports a failure, you analyze the report, spawn a more targeted agent
|
|
66
|
+
- **Validate** — verify the end result actually works before completing
|
|
67
|
+
|
|
68
|
+
### Scale rigor to complexity
|
|
69
|
+
|
|
70
|
+
Not every task needs every phase. A one-file fix can go straight to implement → validate. But for harder tasks — multi-file features, architectural changes, unfamiliar codebases — **create explicit tasks for each phase**. Spec tasks, planning tasks, implementation tasks, review tasks, test tasks. These are real work items, not overhead.
|
|
71
|
+
|
|
72
|
+
For non-trivial work, **review is not optional**. Spawn a reviewer agent after implementation. For complex plans, spawn a reviewer after planning too. The reviewer should be a different agent than the one that did the work.
|
|
73
|
+
|
|
74
|
+
### Interleave phases across cycles
|
|
75
|
+
|
|
76
|
+
Phases don't have to be sequential. You can run work from different phases in parallel when there are no dependencies between them:
|
|
77
|
+
|
|
78
|
+
- While implementation agents work on feature A, spawn a spec agent to investigate feature B
|
|
79
|
+
- While a reviewer audits the plan, spawn an agent to draft the test strategy
|
|
80
|
+
- While tests run on completed work, start implementing the next piece
|
|
81
|
+
- After a plan is written, review it and spec out tests for it in the same cycle
|
|
82
|
+
|
|
83
|
+
Think of cycles as opportunities to run as many independent workstreams as possible. The constraint is file conflicts, not phase ordering. If two agents don't touch the same files, they can run concurrently even if they're at different stages of the workflow.
|
|
84
|
+
|
|
85
|
+
The cost of an extra cycle is low. The cost of shipping broken work is high.
|
|
86
|
+
|
|
87
|
+
## Validation
|
|
88
|
+
|
|
89
|
+
Don't just build — verify. An agent that implements a feature is the worst agent to validate it. It has the same blind spots that produced any bugs in the first place. **Spawn a separate agent to validate work done by another agent.**
|
|
90
|
+
|
|
91
|
+
### Prefer real validation over surface checks
|
|
92
|
+
|
|
93
|
+
Unit tests that mirror the implementation prove nothing. Prefer validation that exercises the actual behavior:
|
|
94
|
+
- Integration tests that run the real code path end-to-end
|
|
95
|
+
- A script that invokes the CLI/API and checks output
|
|
96
|
+
- A reviewer agent that reads the diff and tries to break it
|
|
97
|
+
|
|
98
|
+
If the project doesn't have the tooling to validate properly, **create it**. A small test harness, a smoke-test script, or a validation command pays for itself immediately and in every future cycle.
|
|
99
|
+
|
|
100
|
+
### Delegate validation
|
|
101
|
+
|
|
102
|
+
You don't have to validate everything yourself. Spawn validation agents in parallel with implementation when the work is independent. A common pattern:
|
|
103
|
+
- Cycle N: spawn implementation agents
|
|
104
|
+
- Cycle N+1: spawn validation agents that review/test the implementation agents' output
|
|
105
|
+
- Cycle N+2: fix anything the validators caught
|
|
106
|
+
|
|
107
|
+
This is cheaper than finding issues after you've called `sisyphus complete`.
|
|
108
|
+
|
|
109
|
+
## Agent Instructions
|
|
110
|
+
|
|
111
|
+
Give agents precise, actionable instructions:
|
|
112
|
+
- Specific file paths and what to change in them
|
|
113
|
+
- Clear boundaries — what files they own, what they should not touch
|
|
114
|
+
- Context they need (relevant code patterns, constraints, prior agent findings)
|
|
115
|
+
- Tell agents not to run tests or builds if other agents are working concurrently — files may be mid-edit
|
|
116
|
+
|
|
117
|
+
Vague instructions produce vague results. The more specific you are, the better the output.
|
|
118
|
+
|
|
119
|
+
## File Conflicts
|
|
120
|
+
|
|
121
|
+
If multiple agents run concurrently, ensure they don't edit the same files. If overlap is unavoidable, serialize those tasks across cycles instead.
|
|
122
|
+
|
|
123
|
+
## CLI Reference
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
# Task management
|
|
127
|
+
sisyphus tasks add "description" # adds as pending
|
|
128
|
+
sisyphus tasks add "maybe do this" --status draft # adds as draft
|
|
129
|
+
echo "long multi-line description" | sisyphus tasks add # via stdin
|
|
130
|
+
sisyphus tasks update <taskId> --status draft|pending|in_progress|done
|
|
131
|
+
sisyphus tasks update <taskId> --description "refined description"
|
|
132
|
+
sisyphus tasks list
|
|
133
|
+
|
|
134
|
+
# Spawn an agent
|
|
135
|
+
sisyphus spawn --agent-type <type> --name <name> --instruction "what to do"
|
|
136
|
+
|
|
137
|
+
# Agent progress reports (non-terminal — agent keeps working)
|
|
138
|
+
sisyphus report --message "progress update"
|
|
139
|
+
|
|
140
|
+
# Yield control (after spawning agents, or to pause for user input)
|
|
141
|
+
sisyphus yield
|
|
142
|
+
|
|
143
|
+
# Complete the session
|
|
144
|
+
sisyphus complete --report "summary of what was accomplished"
|
|
145
|
+
|
|
146
|
+
# Check status
|
|
147
|
+
sisyphus status
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Completion
|
|
151
|
+
|
|
152
|
+
Call `sisyphus complete` only when the overall goal is genuinely achieved **and validated by an agent other than the one that did the work**. If you're unsure, spawn a validation agent to verify, then decide next cycle. One extra cycle to confirm is always cheaper than shipping a broken result.
|