@integrity-labs/agt-cli 0.7.4 → 0.7.5
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/lib/manager-worker.ts","../../src/lib/gateway-client.ts","../../src/lib/persistent-session.ts","../../src/lib/realtime-chat.ts"],"sourcesContent":["/**\n * Manager Worker — forked child process that polls the API for agent config\n * changes and local file drift. Communicates with the watchdog parent via IPC.\n *\n * This file is a standalone entry point built by tsup so `fork()` can target it.\n */\n\nimport { createHash } from 'node:crypto';\nimport { readFileSync, writeFileSync, mkdirSync, existsSync, rmSync, readdirSync, statSync, unlinkSync } from 'node:fs';\nimport https from 'node:https';\nimport { join } from 'node:path';\nimport {\n extractFrontmatter,\n resolveChannels,\n getFramework,\n type FrameworkAdapter,\n type CharterFrontmatter,\n type ToolsFrontmatter,\n type ChannelId,\n type ChannelPolicy,\n type OrgChannelPolicy,\n type DeploymentTarget,\n type ProvisionInput,\n} from '@augmented/core';\nimport { provision } from '@augmented/core/provisioning/provisioner.js';\n\n// Register framework adapters (side-effect imports)\nimport '@augmented/core/provisioning/frameworks/openclaw/index.js';\nimport '@augmented/core/provisioning/frameworks/nemoclaw/index.js';\nimport '@augmented/core/provisioning/frameworks/claudecode/index.js';\n\nimport { api, getHostId, exchangeApiKey } from './api-client.js';\nimport { getApiKey, requireHost } from './config.js';\nimport { GatewayClientPool, type PooledGatewayEvent } from './gateway-client.js';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ninterface WorkerConfig {\n intervalMs: number;\n configDir: string;\n gatewayPort?: number;\n gatewayToken?: string;\n}\n\ninterface AcpSessionSummary {\n sessionId: string;\n agentCommand: string;\n sessionName?: string;\n queueState: string;\n turnCount: number;\n startedAt: string;\n}\n\ninterface AgentState {\n agentId: string;\n codeName: string;\n status: string;\n charterVersion: string;\n toolsVersion: string;\n secretsHash: string | null;\n lastRefreshAt: string | null;\n lastProvisionAt: string | null;\n lastDriftCheckAt: string | null;\n lastSecretsProvisionAt: string | null;\n gatewayPort: number | null;\n gatewayPid: number | null;\n gatewayRunning: boolean;\n acpSessions: AcpSessionSummary[];\n}\n\ninterface ManagerState {\n pid: number;\n startedAt: string;\n lastPollAt: string | null;\n pollCount: number;\n errorCount: number;\n agents: AgentState[];\n}\n\n// Event types (formerly IPC messages, now just internal events)\ntype ManagerEvent =\n | { type: 'ready' }\n | { type: 'state-update'; state: ManagerState }\n | { type: 'provisioned'; agentId: string; codeName: string }\n | { type: 'drift-detected'; agentId: string; codeName: string; files: string[] }\n | { type: 'gateway-event'; event: string; payload: unknown; agentCodeName?: string }\n | { type: 'error'; message: string }\n | { type: 'shutdown' };\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\n// OpenClaw gateway binds the specified port + a few additional ports above it,\n// so we space allocations 10 apart to avoid collisions.\nconst GATEWAY_PORT_BASE = 18800;\nconst GATEWAY_PORT_STEP = 10;\nconst GATEWAY_PORT_MAX = 18899;\nconst AUGMENTED_DIR = join(process.env['HOME'] ?? '/tmp', '.augmented');\nconst GATEWAY_PORTS_FILE = join(AUGMENTED_DIR, 'gateway-ports.json');\n\n// ---------------------------------------------------------------------------\n// State\n// ---------------------------------------------------------------------------\n\nlet config: WorkerConfig | null = null;\nlet running = false;\nlet pollTimer: ReturnType<typeof setTimeout> | null = null;\n\n// Track last-known versions + hashes per agent to detect changes\nconst knownVersions = new Map<string, { charterVersion: string; toolsVersion: string }>();\nconst knownStatuses = new Map<string, string>();\nconst knownChannels = new Map<string, Set<string>>();\nconst writtenHashes = new Map<string, Map<string, string>>();\nconst knownSecretsHashes = new Map<string, string>();\nconst knownChannelConfigHashes = new Map<string, string>();\nconst knownModels = new Map<string, string>();\nconst knownTasksHashes = new Map<string, string>();\nconst knownIntegrationHashes = new Map<string, string>();\nconst losslessClawInstalled = new Map<string, boolean>();\nconst knownSkillHashes = new Map<string, string>();\n// Track last-seen cron run timestamps per job to avoid re-processing\nconst lastCronRunTs = new Map<string, number>();\n// Track last work_trigger_at per agent to avoid duplicate triggers\nconst lastWorkTriggerAt = new Map<string, number>();\n// Track which in_progress items we've already alerted as stale\nconst alertedStaleItems = new Set<string>();\n// Track agents with known API key errors (avoid spamming the API)\nconst apiKeyStatusCache = new Map<string, boolean>();\nconst STALE_TASK_THRESHOLD_MS = 30 * 60 * 1000; // 30 minutes\n\n// Alert webhook URL — cached from first agent's team settings\nlet alertSlackWebhook: string | null = null;\n// Track alerted job IDs to avoid duplicate alerts within a session\nconst alertedJobs = new Set<string>();\n// Map cron job name (aug:template:uuid) → human-readable task info\nconst taskDisplayInfo = new Map<string, { taskName: string; schedule: string; agentDisplayName: string }>();\n// Map agent code_name → display_name for alerts\nconst agentDisplayNames = new Map<string, string>();\n// Map code_name → agent_id for kanban updates\nconst codeNameToAgentId = new Map<string, string>();\n// Map code_name → channel bot tokens (from channel_configs)\nconst agentChannelTokens = new Map<string, { slack?: string; telegram?: string; telegramAllowedChats?: string[] }>();\n\n// Per-cycle channel tracking — populated by processAgent, reconciled after all agents\nconst activeChannels = new Map<string, Set<string>>(); // channelId -> Set<codeName>\n\n// Gateways started this poll cycle — skip health-check restarts for these\nconst gatewaysStartedThisCycle = new Set<string>();\n\n// Cumulative state for the parent\nlet state: ManagerState = {\n pid: process.pid,\n startedAt: new Date().toISOString(),\n lastPollAt: null,\n pollCount: 0,\n errorCount: 0,\n agents: [],\n};\n\n// Cache registered agents per framework per poll cycle\nconst registeredAgentsCache = new Map<string, Set<string>>();\n\n// Per-agent framework ID cache (populated from API response and refresh data)\nconst agentFrameworkCache = new Map<string, string>();\n\n// Track which framework binaries we've already checked/installed this session\nconst frameworkBinaryChecked = new Set<string>();\n\n/** Resolve the framework adapter for a given agent, using the cache or defaulting to 'openclaw'. */\nfunction resolveAgentFramework(codeName: string): FrameworkAdapter {\n const frameworkId = agentFrameworkCache.get(codeName) ?? 'openclaw';\n return getFramework(frameworkId);\n}\n\n// Gateway client pool — replaces single GatewayClient\nlet gatewayPool: GatewayClientPool | null = null;\n\n/**\n * Clear all per-agent caches when an agent is unassigned, revoked, or needs\n * a full reprovision. Keeps the cleanup in one place instead of scattering\n * .delete() calls for every new Map we add.\n */\nfunction clearAgentCaches(agentId: string, codeName: string): void {\n // ID-keyed caches\n knownVersions.delete(agentId);\n knownStatuses.delete(agentId);\n knownChannels.delete(agentId);\n writtenHashes.delete(agentId);\n knownSecretsHashes.delete(agentId);\n knownModels.delete(agentId);\n knownTasksHashes.delete(agentId);\n knownIntegrationHashes.delete(agentId);\n\n // codeName-keyed caches\n losslessClawInstalled.delete(codeName);\n agentDisplayNames.delete(codeName);\n codeNameToAgentId.delete(codeName);\n agentFrameworkCache.delete(codeName);\n kanbanBoardCache.delete(codeName);\n lastHarvestAt.delete(codeName);\n claudeSchedulerStates.delete(codeName);\n claudeTaskConcurrency.delete(codeName);\n\n // Compound-keyed caches (agentId:suffix)\n for (const key of knownChannelConfigHashes.keys()) {\n if (key.startsWith(`${agentId}:`)) knownChannelConfigHashes.delete(key);\n }\n for (const key of knownSkillHashes.keys()) {\n if (key.startsWith(`${agentId}:`)) knownSkillHashes.delete(key);\n }\n for (const key of taskDisplayInfo.keys()) {\n if (key.startsWith(`${codeName}:`)) taskDisplayInfo.delete(key);\n }\n}\n\n// Cached framework version (detected once at startup, refreshed periodically)\nlet cachedFrameworkVersion: string | null = null;\nlet lastVersionCheckAt = 0;\nconst VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1000; // Re-check every 5 minutes\n\n// ---------------------------------------------------------------------------\n// Framework binary install / upgrade\n// ---------------------------------------------------------------------------\n\n/**\n * Ensure a Homebrew formula is installed. Used for framework dependencies\n * like tmux that are required but not part of the framework itself.\n * Returns true if the binary is available after the check.\n */\nasync function ensureBrewDependency(binary: string, formula: string): Promise<boolean> {\n if (frameworkBinaryChecked.has(`dep:${binary}`)) return true;\n\n const { execFileSync } = await import('node:child_process');\n\n try {\n execFileSync('which', [binary], { timeout: 5_000 });\n frameworkBinaryChecked.add(`dep:${binary}`);\n return true;\n } catch {\n // Binary not found — try to install\n }\n\n let brewPath: string;\n try {\n brewPath = execFileSync('which', ['brew'], { timeout: 5_000 }).toString().trim();\n } catch {\n log(`${binary} not found and Homebrew not available — install manually: brew install ${formula}`);\n frameworkBinaryChecked.add(`dep:${binary}`);\n return false;\n }\n\n log(`${binary} not found — installing via Homebrew...`);\n try {\n execFileSync(brewPath, ['install', formula], { timeout: 120_000, stdio: 'pipe' });\n } catch (err) {\n log(`Failed to install ${formula}: ${(err as Error).message}`);\n frameworkBinaryChecked.add(`dep:${binary}`);\n return false;\n }\n\n try {\n execFileSync('which', [binary], { timeout: 5_000 });\n log(`${binary} installed successfully`);\n frameworkBinaryChecked.add(`dep:${binary}`);\n return true;\n } catch {\n log(`${formula} install completed but ${binary} not found on PATH`);\n frameworkBinaryChecked.add(`dep:${binary}`);\n return false;\n }\n}\n\n/**\n * Ensure the CLI binary for a framework is available. Currently only handles\n * `claude-code` via Homebrew. Called once per session when we first see an\n * agent using that framework.\n */\nasync function ensureFrameworkBinary(frameworkId: string): Promise<void> {\n if (frameworkId !== 'claude-code') return;\n if (frameworkBinaryChecked.has(frameworkId)) return;\n frameworkBinaryChecked.add(frameworkId);\n\n // Ensure tmux is available (needed for ACP sessions)\n await ensureBrewDependency('tmux', 'tmux');\n\n const { execFileSync } = await import('node:child_process');\n\n // Check if Homebrew is available\n let brewPath: string;\n try {\n brewPath = execFileSync('which', ['brew'], { timeout: 5_000 }).toString().trim();\n } catch {\n log('Homebrew not found — cannot auto-install/upgrade Claude Code. Install manually: https://claude.ai/download');\n return;\n }\n\n // Check if claude binary exists\n let claudeExists = false;\n try {\n execFileSync('which', ['claude'], { timeout: 5_000 });\n claudeExists = true;\n } catch {\n // Not found\n }\n\n if (!claudeExists) {\n // Install\n log('Claude Code binary not found — installing via Homebrew...');\n try {\n execFileSync(brewPath, ['install', '--cask', 'claude-code'], {\n timeout: 120_000,\n stdio: 'pipe',\n });\n } catch (err) {\n log(`Claude Code install failed: ${(err as Error).message}`);\n return;\n }\n\n // Verify\n try {\n execFileSync('which', ['claude'], { timeout: 5_000 });\n log('Claude Code installed successfully');\n } catch {\n log('Claude Code install completed but binary not found on PATH — you may need to restart your terminal');\n }\n } else {\n // Upgrade\n log('Checking for Claude Code updates...');\n try {\n const output = execFileSync(brewPath, ['upgrade', '--cask', 'claude-code'], {\n timeout: 120_000,\n stdio: 'pipe',\n }).toString();\n\n if (output.includes('already installed') || output.includes('up-to-date')) {\n log('Claude Code is already up to date');\n } else {\n log('Claude Code upgraded successfully');\n }\n } catch (err) {\n const msg = (err as Error).message;\n // brew upgrade exits non-zero when already up to date on some versions\n if (msg.includes('already installed') || msg.includes('up-to-date') || msg.includes('not upgraded')) {\n log('Claude Code is already up to date');\n } else {\n log(`Claude Code upgrade failed: ${msg}`);\n }\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Port allocation\n// ---------------------------------------------------------------------------\n\nfunction loadGatewayPorts(): Record<string, number> {\n try {\n return JSON.parse(readFileSync(GATEWAY_PORTS_FILE, 'utf-8'));\n } catch {\n return {};\n }\n}\n\nfunction saveGatewayPorts(ports: Record<string, number>): void {\n mkdirSync(AUGMENTED_DIR, { recursive: true });\n writeFileSync(GATEWAY_PORTS_FILE, JSON.stringify(ports, null, 2));\n}\n\nfunction allocatePort(codeName: string): number {\n const ports = loadGatewayPorts();\n\n // Already allocated\n if (ports[codeName]) return ports[codeName];\n\n // Find next free port (spaced by GATEWAY_PORT_STEP to avoid OpenClaw's extra port binds)\n const usedPorts = new Set(Object.values(ports));\n for (let port = GATEWAY_PORT_BASE; port <= GATEWAY_PORT_MAX; port += GATEWAY_PORT_STEP) {\n if (!usedPorts.has(port)) {\n ports[codeName] = port;\n saveGatewayPorts(ports);\n return port;\n }\n }\n\n throw new Error(`No free gateway ports in range ${GATEWAY_PORT_BASE}-${GATEWAY_PORT_MAX}`);\n}\n\nfunction freePort(codeName: string): void {\n const ports = loadGatewayPorts();\n if (ports[codeName]) {\n delete ports[codeName];\n saveGatewayPorts(ports);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n// State file for external status queries (replaces IPC state-update)\nconst STATE_FILE = join(process.env['HOME'] ?? '/tmp', '.augmented', 'manager-state.json');\n\nfunction send(msg: ManagerEvent): void {\n // Write state updates to file for `agt manager status` to read\n if (msg.type === 'state-update') {\n try {\n writeFileSync(STATE_FILE, JSON.stringify(msg.state, null, 2));\n } catch { /* non-fatal */ }\n }\n // Log notable events\n if (msg.type === 'provisioned') {\n log(`Provisioned ${msg.codeName}`);\n } else if (msg.type === 'drift-detected') {\n log(`Drift detected: ${msg.codeName} (${msg.files?.join(', ')})`);\n } else if (msg.type === 'error') {\n log(`Error: ${msg.message}`);\n }\n}\n\nfunction log(msg: string): void {\n const ts = new Date().toISOString();\n process.stderr.write(`[manager-worker ${ts}] ${msg}\\n`);\n}\n\nfunction sha256(content: string): string {\n return createHash('sha256').update(content, 'utf8').digest('hex');\n}\n\nfunction hashFile(filePath: string): string | null {\n try {\n const content = readFileSync(filePath, 'utf-8');\n return sha256(content);\n } catch {\n return null;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Migration: shared config → per-agent profiles\n// ---------------------------------------------------------------------------\n\nasync function migrateToProfiles(): Promise<void> {\n const homeDir = process.env['HOME'] ?? '/tmp';\n const sharedConfigPath = join(homeDir, '.openclaw', 'openclaw.json');\n\n // Check if shared config exists\n let sharedConfig: Record<string, unknown>;\n try {\n sharedConfig = JSON.parse(readFileSync(sharedConfigPath, 'utf-8'));\n } catch {\n return; // No shared config — nothing to migrate\n }\n\n // Check if there are multiple agents registered in shared config\n const agents = sharedConfig['agents'] as Record<string, unknown> | undefined;\n const agentList = (agents?.['list'] as Array<Record<string, unknown>>) ?? [];\n if (agentList.length === 0) return;\n\n const adapter = getFramework('openclaw');\n let migrated = 0;\n\n for (const agentEntry of agentList) {\n const codeName = agentEntry['id'] as string;\n if (!codeName) continue;\n\n // Skip 'main' — that's the interactive CLI agent, not managed by Augmented\n if (codeName === 'main') continue;\n\n const profileDir = join(homeDir, `.openclaw-${codeName}`);\n\n // Skip agents that already have profile dirs\n if (existsSync(join(profileDir, 'openclaw.json'))) continue;\n\n log(`Migrating agent '${codeName}' to per-agent profile`);\n\n // Seed profile config from shared config\n if (adapter.seedProfileConfig) {\n adapter.seedProfileConfig(codeName);\n }\n\n // Copy auth profiles from shared to profile dir\n const sharedAuthDir = join(homeDir, '.openclaw', 'agents', codeName, 'agent');\n const profileAuthDir = join(profileDir, 'agents', codeName, 'agent');\n const authFile = join(sharedAuthDir, 'auth-profiles.json');\n if (existsSync(authFile)) {\n mkdirSync(profileAuthDir, { recursive: true });\n const authContent = readFileSync(authFile, 'utf-8');\n writeFileSync(join(profileAuthDir, 'auth-profiles.json'), authContent);\n }\n\n // Allocate a gateway port\n allocatePort(codeName);\n\n migrated++;\n }\n\n if (migrated > 0) {\n log(`Migration complete: ${migrated} agent(s) migrated to per-agent profiles`);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Gateway lifecycle\n// ---------------------------------------------------------------------------\n\n/**\n * Resolve model tiers through the inheritance chain:\n * Agent override → Org default → Platform default\n */\nfunction resolveModelChain(refreshData: Record<string, unknown>): { primary?: string; secondary?: string; tertiary?: string } {\n const agent = refreshData.agent as Record<string, unknown> | undefined;\n const modelDefaults = refreshData.model_defaults as { platform?: Record<string, unknown> | null; org?: Record<string, unknown> | null } | undefined;\n const platform = modelDefaults?.platform ?? {};\n const org = modelDefaults?.org ?? {};\n\n function resolve(tier: 'primary' | 'secondary' | 'tertiary'): string | undefined {\n const agentField = `${tier}_model`;\n const platformField = `default_${tier}_model`;\n\n // 1. Agent override\n const agentVal = agent?.[agentField] as string | undefined;\n if (agentVal) return agentVal;\n\n // 2. Org default\n const orgVal = org?.[platformField] as string | undefined;\n if (orgVal) return orgVal;\n\n // 3. Platform default\n const platformVal = platform?.[platformField] as string | undefined;\n if (platformVal) return platformVal;\n\n return undefined;\n }\n\n return {\n primary: resolve('primary'),\n secondary: resolve('secondary'),\n tertiary: resolve('tertiary'),\n };\n}\n\nfunction readGatewayToken(codeName: string): string | undefined {\n const adapter = resolveAgentFramework(codeName);\n if (adapter.readGatewayToken) {\n return adapter.readGatewayToken(codeName);\n }\n // Fallback for adapters without readGatewayToken\n const homeDir = process.env['HOME'] ?? '/tmp';\n try {\n const cfg = JSON.parse(readFileSync(join(homeDir, `.openclaw-${codeName}`, 'openclaw.json'), 'utf-8'));\n return cfg?.gateway?.auth?.token as string | undefined;\n } catch {\n return undefined;\n }\n}\n\nconst GATEWAY_HUNG_TIMEOUT_MS = 5 * 60_000; // 5 minutes\n\n/**\n * Detect if a gateway is hung by checking for cron jobs stuck in \"running\" state.\n * Reads the cron jobs.json directly (no gateway communication needed since the\n * gateway itself may be unresponsive).\n */\nfunction isGatewayHung(codeName: string): boolean {\n const homeDir = process.env['HOME'] ?? '/tmp';\n const jobsPath = join(homeDir, `.openclaw-${codeName}`, 'cron', 'jobs.json');\n if (!existsSync(jobsPath)) return false;\n\n try {\n const data = JSON.parse(readFileSync(jobsPath, 'utf-8')) as Record<string, unknown>;\n const jobs = (data.jobs ?? data) as Array<Record<string, unknown>>;\n if (!Array.isArray(jobs)) return false;\n\n const now = Date.now();\n for (const job of jobs) {\n const state = job.state as Record<string, unknown> | undefined;\n if (!state) continue;\n const runStartedAt = state.runStartedAtMs as number | undefined;\n const isRunning = state.status === 'running' || state.running === true;\n if (isRunning && runStartedAt && (now - runStartedAt) > GATEWAY_HUNG_TIMEOUT_MS) {\n return true;\n }\n }\n } catch { /* non-fatal */ }\n\n return false;\n}\n\nasync function ensureGatewayRunning(codeName: string, adapter: FrameworkAdapter): Promise<{ pid: number | null; port: number | null; running: boolean }> {\n if (!adapter.isGatewayRunning || !adapter.startGateway) {\n return { pid: null, port: null, running: false };\n }\n\n const status = await adapter.isGatewayRunning(codeName);\n if (status.running) {\n // Check if gateway is hung — if a cron has been \"running\" for too long,\n // the gateway is likely stuck and needs a restart\n if (await isGatewayHung(codeName)) {\n log(`Gateway for '${codeName}' appears hung (cron stuck >5min) — restarting`);\n if (adapter.stopGateway) {\n try { await adapter.stopGateway(codeName); } catch { /* force kill below */ }\n }\n // Give it a moment to die\n await new Promise((r) => setTimeout(r, 2000));\n // Clear stale cron state so it doesn't immediately re-hang\n const homeDir = process.env['HOME'] ?? '/tmp';\n const cronJobsPath = join(homeDir, `.openclaw-${codeName}`, 'cron', 'jobs.json');\n clearStaleCronRunState(cronJobsPath);\n // Fall through to start a new gateway below\n } else {\n // Update config port in case it changed (e.g. after manual restart)\n if (status.port) {\n try {\n const homeDir = process.env['HOME'] ?? '/tmp';\n const configPath = join(homeDir, `.openclaw-${codeName}`, 'openclaw.json');\n if (existsSync(configPath)) {\n const cfg = JSON.parse(readFileSync(configPath, 'utf-8'));\n if (cfg.gateway?.port !== status.port) {\n if (!cfg.gateway) cfg.gateway = {};\n cfg.gateway.port = status.port;\n writeFileSync(configPath, JSON.stringify(cfg, null, 2));\n }\n }\n } catch { /* Non-fatal */ }\n }\n // Ensure pool has a connection to this gateway\n if (gatewayPool && status.port && !gatewayPool.hasAgent(codeName)) {\n const token = readGatewayToken(codeName);\n gatewayPool.addAgent(codeName, status.port, token);\n }\n return { pid: status.pid ?? null, port: status.port ?? null, running: true };\n }\n }\n\n // Allocate port and start\n const port = allocatePort(codeName);\n try {\n const result = await adapter.startGateway(codeName, port);\n log(`Gateway started for '${codeName}' on port ${port} (PID ${result.pid})`);\n gatewaysStartedThisCycle.add(codeName);\n\n // Write port to profile config so `openclaw cron run` can find the gateway\n try {\n const homeDir = process.env['HOME'] ?? '/tmp';\n const configPath = join(homeDir, `.openclaw-${codeName}`, 'openclaw.json');\n if (existsSync(configPath)) {\n const cfg = JSON.parse(readFileSync(configPath, 'utf-8'));\n if (!cfg.gateway) cfg.gateway = {};\n cfg.gateway.port = port;\n writeFileSync(configPath, JSON.stringify(cfg, null, 2));\n }\n } catch { /* Non-fatal */ }\n\n // Connect gateway client pool — the client silently handles ECONNREFUSED\n // on first attempt and retries with backoff while the gateway boots.\n if (gatewayPool) {\n const token = readGatewayToken(codeName);\n gatewayPool.addAgent(codeName, port, token);\n }\n\n return { pid: result.pid, port, running: true };\n } catch (err) {\n log(`Failed to start gateway for '${codeName}': ${(err as Error).message}`);\n return { pid: null, port, running: false };\n }\n}\n\nasync function stopGatewayIfRunning(codeName: string, adapter: FrameworkAdapter): Promise<void> {\n if (!adapter.stopGateway) return;\n\n try {\n const stopped = await adapter.stopGateway(codeName);\n if (stopped) {\n log(`Gateway stopped for '${codeName}'`);\n }\n } catch (err) {\n log(`Failed to stop gateway for '${codeName}': ${(err as Error).message}`);\n }\n\n // Disconnect from pool\n if (gatewayPool) {\n gatewayPool.removeAgent(codeName);\n }\n}\n\nasync function stopAllGateways(): Promise<void> {\n const ports = loadGatewayPorts();\n\n for (const codeName of Object.keys(ports)) {\n const adapter = resolveAgentFramework(codeName);\n await stopGatewayIfRunning(codeName, adapter);\n }\n\n if (gatewayPool) {\n gatewayPool.disconnectAll();\n }\n}\n\nasync function healthCheckGateways(agentStates: AgentState[]): Promise<void> {\n for (const agentState of agentStates) {\n if (agentState.status !== 'active' || !agentState.gatewayPort) continue;\n\n const adapter = resolveAgentFramework(agentState.codeName);\n if (!adapter.isGatewayRunning || !adapter.startGateway) continue;\n\n // Skip gateways that were just started this cycle — they may still be booting\n if (gatewaysStartedThisCycle.has(agentState.codeName)) continue;\n\n const status = await adapter.isGatewayRunning(agentState.codeName);\n if (!status.running && agentState.gatewayRunning) {\n // Gateway crashed — alert and restart\n const displayName = agentDisplayNames.get(agentState.codeName) ?? agentState.codeName;\n log(`Gateway for '${agentState.codeName}' crashed, restarting...`);\n sendSlackWebhookMessage(\n `:red_circle: *Host Down* — *${displayName}* (\\`${agentState.codeName}\\`)\\nOpenClaw gateway crashed. Attempting automatic restart...`,\n ).catch(() => {});\n\n try {\n const result = await adapter.startGateway(agentState.codeName, agentState.gatewayPort);\n agentState.gatewayPid = result.pid;\n agentState.gatewayRunning = true;\n log(`Gateway restarted for '${agentState.codeName}' (PID ${result.pid})`);\n\n // Give the gateway process time to bind the port before connecting WebSocket\n await new Promise((resolve) => setTimeout(resolve, 2000));\n\n // Reconnect pool client\n if (gatewayPool) {\n const token = readGatewayToken(agentState.codeName);\n gatewayPool.addAgent(agentState.codeName, agentState.gatewayPort, token);\n }\n\n sendSlackWebhookMessage(\n `:large_green_circle: *Host Recovered* — *${displayName}* (\\`${agentState.codeName}\\`)\\nGateway restarted successfully (PID ${result.pid}).`,\n ).catch(() => {});\n } catch (err) {\n agentState.gatewayRunning = false;\n log(`Failed to restart gateway for '${agentState.codeName}': ${(err as Error).message}`);\n sendSlackWebhookMessage(\n `:x: *Host Restart Failed* — *${displayName}* (\\`${agentState.codeName}\\`)\\nAutomatic restart failed: ${(err as Error).message}`,\n ).catch(() => {});\n }\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Poll cycle\n// ---------------------------------------------------------------------------\n\nasync function pollCycle(): Promise<void> {\n if (!config) return;\n\n try {\n // Clear per-cycle caches\n registeredAgentsCache.clear();\n gatewaysStartedThisCycle.clear();\n\n // 1. Discover assigned agents\n const hostId = await getHostId();\n if (!hostId) {\n send({ type: 'error', message: 'Could not resolve host ID from API key' });\n return;\n }\n\n // 1b. Detect framework version (cached, refreshed every 5 min)\n const now = Date.now();\n if (now - lastVersionCheckAt > VERSION_CHECK_INTERVAL_MS) {\n try {\n // Use the first known agent's framework, or default to openclaw\n const firstAgent = state.agents[0];\n const versionAdapter = firstAgent ? resolveAgentFramework(firstAgent.codeName) : getFramework('openclaw');\n if (versionAdapter.getVersion) {\n cachedFrameworkVersion = await versionAdapter.getVersion();\n }\n } catch {\n // Non-fatal — version detection is supplementary\n }\n lastVersionCheckAt = now;\n }\n\n // 1c. Heartbeat — update last_seen_at, framework_version, and host security\n try {\n const { detectHostSecurity } = await import('./host-security.js');\n await api.post('/host/heartbeat', {\n host_id: hostId,\n framework_version: cachedFrameworkVersion ?? undefined,\n host_security: detectHostSecurity() ?? undefined,\n });\n } catch (err) {\n log(`Heartbeat failed: ${(err as Error).message}`);\n }\n\n const data = await api.post<{\n agents: Array<{\n agent_id: string;\n code_name: string;\n display_name: string;\n status: string;\n environment: string;\n framework?: string;\n }>;\n }>('/host/agents', { host_id: hostId });\n\n const agents = data.agents ?? [];\n\n // Ensure framework binaries are installed/upgraded for any new frameworks\n const frameworksThisCycle = new Set(agents.map((a) => a.framework).filter(Boolean));\n for (const fw of frameworksThisCycle) {\n await ensureFrameworkBinary(fw!);\n }\n\n // Track which channels have at least one active agent per profile\n activeChannels.clear();\n\n // Update state agents list\n const agentStates: AgentState[] = [];\n\n for (const agent of agents) {\n try {\n await processAgent(agent, agentStates);\n } catch (err) {\n log(`Error processing agent '${agent.code_name}': ${(err as Error).message}`);\n // Preserve existing state for this agent on error\n const existing = state.agents.find((a) => a.agentId === agent.agent_id);\n if (existing) {\n agentStates.push(existing);\n } else {\n agentStates.push({\n agentId: agent.agent_id,\n codeName: agent.code_name,\n status: agent.status,\n charterVersion: '',\n toolsVersion: '',\n secretsHash: null,\n lastRefreshAt: null,\n lastProvisionAt: null,\n lastDriftCheckAt: null,\n lastSecretsProvisionAt: null,\n gatewayPort: null,\n gatewayPid: null,\n gatewayRunning: false,\n acpSessions: [],\n });\n }\n }\n }\n\n // Reconcile channel enabled state per profile.\n // Each agent has its own profile config, so enable/disable within that profile.\n try {\n for (const [channelId, codeNames] of activeChannels) {\n for (const codeName of codeNames) {\n const adapter = resolveAgentFramework(codeName);\n if (adapter.setChannelEnabled) {\n adapter.setChannelEnabled(channelId, true, codeName);\n }\n }\n }\n } catch { /* non-fatal */ }\n\n // Detect unassigned agents (were in state but not in current list)\n const currentIds = new Set(agents.map((a) => a.agent_id));\n for (const prev of state.agents) {\n if (!currentIds.has(prev.agentId)) {\n log(`Agent '${prev.codeName}' unassigned from host`);\n // Stop gateway for unassigned agent (resolve before clearing caches)\n const adapter = resolveAgentFramework(prev.codeName);\n clearAgentCaches(prev.agentId, prev.codeName);\n await stopGatewayIfRunning(prev.codeName, adapter);\n }\n }\n\n // Health check: restart crashed gateways\n await healthCheckGateways(agentStates);\n\n // Monitor cron health — detect late/failed jobs and alert (throttled)\n const lastHealthCheck = lastHarvestAt.get('__cron_health__') ?? 0;\n if (Date.now() - lastHealthCheck >= HARVEST_INTERVAL_MS) {\n lastHarvestAt.set('__cron_health__', Date.now());\n monitorCronHealth(agentStates).catch((err) => {\n log(`Cron health monitor error: ${(err as Error).message}`);\n });\n }\n\n // Direct chat: use Realtime if connected, fall back to polling\n if (!isRealtimeConnected()) {\n pollDirectChatMessages(agentStates).catch((err) => {\n log(`Direct chat poll error: ${(err as Error).message}`);\n });\n }\n\n // Start Realtime subscription if not yet started and we have Supabase config\n ensureRealtimeStarted(agentStates);\n ensureRealtimeDriftStarted(agentStates);\n ensureRealtimeAssignStarted(agentStates);\n ensureRealtimeConfigStarted(agentStates);\n ensureRealtimeKanbanStarted(agentStates);\n\n // Spawn due recurring kanban templates\n try {\n const spawnData = await api.post<{ spawned: number }>('/host/kanban/recurring/spawn');\n if (spawnData.spawned > 0) {\n log(`Spawned ${spawnData.spawned} recurring kanban item(s)`);\n }\n } catch { /* non-fatal */ }\n\n state = {\n ...state,\n lastPollAt: new Date().toISOString(),\n pollCount: state.pollCount + 1,\n agents: agentStates,\n };\n\n send({ type: 'state-update', state });\n } catch (err) {\n state.errorCount++;\n const message = (err as Error).message;\n log(`Poll error: ${message}`);\n send({ type: 'error', message });\n\n // Fatal auth error — exit so watchdog can restart with backoff\n if (message.includes('exchange failed') || message.includes('401')) {\n log('Fatal auth error, exiting for watchdog restart');\n send({ type: 'shutdown' });\n process.exit(1);\n }\n }\n}\n\nasync function getOrCacheRegisteredAgents(adapter: FrameworkAdapter, profile?: string): Promise<Set<string>> {\n const cacheKey = profile ? `${adapter.id}:${profile}` : adapter.id;\n let cached = registeredAgentsCache.get(cacheKey);\n if (!cached) {\n cached = await adapter.getRegisteredAgents(profile);\n registeredAgentsCache.set(cacheKey, cached);\n }\n return cached;\n}\n\nasync function processAgent(\n agent: { agent_id: string; code_name: string; display_name: string; status: string; environment: string; framework?: string },\n agentStates: AgentState[],\n): Promise<void> {\n if (!config) return;\n\n log(`==================== ${agent.display_name} (${agent.code_name}) ====================`);\n agentDisplayNames.set(agent.code_name, agent.display_name);\n codeNameToAgentId.set(agent.code_name, agent.agent_id);\n\n // Cache the framework from the agent list response (refreshAgentConfig may override with more specific data)\n if (agent.framework) {\n agentFrameworkCache.set(agent.code_name, agent.framework);\n }\n\n const now = new Date().toISOString();\n const agentDir = join(config.configDir, agent.code_name, 'provision');\n const adapter = resolveAgentFramework(agent.code_name);\n\n // 1a. Status-aware branching\n if (agent.status === 'draft' || agent.status === 'paused') {\n log(`Agent '${agent.code_name}' is ${agent.status}, skipping provisioning`);\n await stopGatewayIfRunning(agent.code_name, adapter);\n // Kill persistent tmux session if it exists (prevents paused agents responding on channels)\n // Must use tmux kill-session directly — the sessions Map doesn't track sessions from previous manager runs\n stopPersistentSession(agent.code_name, log);\n try {\n const { execSync: es } = await import('node:child_process');\n es(`tmux kill-session -t agt-${agent.code_name} 2>/dev/null`, { stdio: 'ignore' });\n log(`Killed tmux session for paused agent '${agent.code_name}'`);\n } catch { /* no session to kill */ }\n agentStates.push({\n agentId: agent.agent_id,\n codeName: agent.code_name,\n status: agent.status,\n charterVersion: '',\n toolsVersion: '',\n secretsHash: null,\n lastRefreshAt: now,\n lastProvisionAt: null,\n lastDriftCheckAt: null,\n lastSecretsProvisionAt: null,\n gatewayPort: null,\n gatewayPid: null,\n gatewayRunning: false,\n acpSessions: [],\n });\n return;\n }\n\n if (agent.status === 'revoked') {\n log(`Agent '${agent.code_name}' is revoked, cleaning up`);\n await stopGatewayIfRunning(agent.code_name, adapter);\n stopPersistentSession(agent.code_name, log);\n try { const { execSync: es } = await import('node:child_process'); es(`tmux kill-session -t agt-${agent.code_name} 2>/dev/null`, { stdio: 'ignore' }); } catch { /* no session */ }\n freePort(agent.code_name);\n await cleanupAgentFiles(agent.code_name, agentDir);\n clearAgentCaches(agent.agent_id, agent.code_name);\n knownStatuses.set(agent.agent_id, agent.status);\n agentStates.push({\n agentId: agent.agent_id,\n codeName: agent.code_name,\n status: agent.status,\n charterVersion: '',\n toolsVersion: '',\n secretsHash: null,\n lastRefreshAt: now,\n lastProvisionAt: null,\n lastDriftCheckAt: null,\n lastSecretsProvisionAt: null,\n gatewayPort: null,\n gatewayPid: null,\n gatewayRunning: false,\n acpSessions: [],\n });\n return;\n }\n\n // 1b. Detect status change → force reprovision and channel re-evaluation\n const previousStatus = knownStatuses.get(agent.agent_id);\n if (previousStatus && previousStatus !== agent.status) {\n log(`Agent '${agent.code_name}' status changed: ${previousStatus} → ${agent.status}`);\n knownVersions.delete(agent.agent_id); // Force reprovision\n // Invalidate channel config hashes so credentials/bindings/enabled state get rewritten\n for (const key of knownChannelConfigHashes.keys()) {\n if (key.startsWith(`${agent.agent_id}:`)) knownChannelConfigHashes.delete(key);\n }\n }\n knownStatuses.set(agent.agent_id, agent.status);\n\n // 2. Refresh — get latest charter/tools from API\n let refreshData: {\n agent: Record<string, unknown>;\n charter: { raw_content: string; version: string } | null;\n tools: { raw_content: string; version: string } | null;\n channel_configs: Record<string, { config: unknown; status: string }> | null;\n team_channel_policy: {\n team_id: string;\n allowed_channels: string[];\n denied_channels: string[];\n require_elevated_for_pii: boolean;\n } | null;\n team: { name: string; description: string | null; settings?: Record<string, unknown> } | null;\n scheduled_tasks: Array<{\n id: string;\n template_id: string;\n name: string;\n schedule_kind: string;\n schedule_expr: string | null;\n schedule_every: string | null;\n schedule_at: string | null;\n timezone: string;\n prompt: string;\n session_target: string;\n delivery_mode: string;\n delivery_channel: string;\n delivery_to: string | null;\n enabled: boolean;\n }> | null;\n };\n\n try {\n refreshData = await api.post<typeof refreshData>('/host/refresh', {\n agent_id: agent.agent_id,\n });\n } catch (err) {\n log(`Refresh failed for '${agent.code_name}': ${(err as Error).message}`);\n const existing = state.agents.find((a) => a.agentId === agent.agent_id);\n agentStates.push(existing ?? {\n agentId: agent.agent_id,\n codeName: agent.code_name,\n status: agent.status,\n charterVersion: '',\n toolsVersion: '',\n secretsHash: null,\n lastRefreshAt: null,\n lastProvisionAt: null,\n lastDriftCheckAt: null,\n lastSecretsProvisionAt: null,\n gatewayPort: null,\n gatewayPid: null,\n gatewayRunning: false,\n acpSessions: [],\n });\n return;\n }\n\n // Cache alert webhook from team settings (first agent wins)\n if (!alertSlackWebhook && refreshData.team?.settings) {\n const webhook = refreshData.team.settings['alert_slack_webhook'];\n if (typeof webhook === 'string' && webhook.startsWith('https://')) {\n alertSlackWebhook = webhook;\n }\n }\n\n if (!refreshData.charter || !refreshData.tools) {\n log(`No charter/tools for '${agent.code_name}', skipping`);\n agentStates.push({\n agentId: agent.agent_id,\n codeName: agent.code_name,\n status: agent.status,\n charterVersion: '',\n toolsVersion: '',\n secretsHash: null,\n lastRefreshAt: now,\n lastProvisionAt: null,\n lastDriftCheckAt: null,\n lastSecretsProvisionAt: null,\n gatewayPort: null,\n gatewayPid: null,\n gatewayRunning: false,\n acpSessions: [],\n });\n return;\n }\n\n // Resolve framework adapter from agent data and update cache\n const frameworkId = (refreshData.agent.framework as string) ?? 'openclaw';\n agentFrameworkCache.set(agent.code_name, frameworkId);\n const frameworkAdapter = getFramework(frameworkId);\n\n // Ensure per-agent profile config exists\n if (frameworkAdapter.seedProfileConfig) {\n frameworkAdapter.seedProfileConfig(agent.code_name);\n }\n\n const charterVersion = refreshData.charter.version;\n const toolsVersion = refreshData.tools.version;\n const known = knownVersions.get(agent.agent_id);\n\n let lastProvisionAt = state.agents.find((a) => a.agentId === agent.agent_id)?.lastProvisionAt ?? null;\n\n // Detect channel changes\n const currentChannelIds = new Set(Object.keys(refreshData.channel_configs ?? {}));\n const previousChannelIds = knownChannels.get(agent.agent_id);\n const channelsChanged = !previousChannelIds ||\n currentChannelIds.size !== previousChannelIds.size ||\n [...currentChannelIds].some((ch) => !previousChannelIds.has(ch)) ||\n [...previousChannelIds].some((ch) => !currentChannelIds.has(ch));\n\n // Remove credentials for channels that were unbound\n if (previousChannelIds && channelsChanged && frameworkAdapter.removeChannelCredentials) {\n for (const ch of previousChannelIds) {\n if (!currentChannelIds.has(ch)) {\n try {\n frameworkAdapter.removeChannelCredentials(agent.code_name, ch);\n log(`Removed ${ch} credentials for '${agent.code_name}'`);\n } catch (err) {\n log(`Failed to remove ${ch} credentials for '${agent.code_name}': ${(err as Error).message}`);\n }\n }\n }\n }\n\n knownChannels.set(agent.agent_id, currentChannelIds);\n\n // 3. Content-based re-provisioning: always generate artifacts, compare against\n // what's on disk, and only write files that actually changed. This catches\n // template code changes, DB data changes (role, description), and version bumps.\n try {\n const artifacts = generateArtifacts(agent, refreshData, frameworkAdapter);\n const changedFiles: { relativePath: string; content: string }[] = [];\n\n mkdirSync(agentDir, { recursive: true });\n for (const artifact of artifacts) {\n const filePath = join(agentDir, artifact.relativePath);\n const newHash = sha256(artifact.content);\n const existingHash = hashFile(filePath);\n\n if (newHash !== existingHash) {\n changedFiles.push(artifact);\n }\n }\n\n if (changedFiles.length > 0) {\n const isFirst = !existsSync(join(agentDir, 'CHARTER.md'));\n const verb = isFirst ? 'Provisioning' : 'Updating';\n const fileNames = changedFiles.map((f) => f.relativePath).join(', ');\n log(`${verb} '${agent.code_name}': ${fileNames}`);\n\n for (const file of changedFiles) {\n writeFileSync(join(agentDir, file.relativePath), file.content);\n }\n lastProvisionAt = new Date().toISOString();\n\n knownVersions.set(agent.agent_id, { charterVersion, toolsVersion });\n\n // Update written hashes for drift detection\n const trackedFiles = frameworkAdapter.driftTrackedFiles();\n const hashes = new Map<string, string>();\n for (const file of trackedFiles) {\n const h = hashFile(join(agentDir, file));\n if (h) hashes.set(file, h);\n }\n writtenHashes.set(agent.agent_id, hashes);\n\n // Register in framework runtime if not already present\n const resolvedModelsForRegistration = resolveModelChain(refreshData);\n const primaryModel = resolvedModelsForRegistration.primary ?? (refreshData.agent.primary_model as string | null | undefined);\n const registeredAgents = await getOrCacheRegisteredAgents(frameworkAdapter, agent.code_name);\n if (!registeredAgents.has(agent.code_name)) {\n const registered = await frameworkAdapter.registerAgent(agent.code_name, agentDir, primaryModel);\n if (registered) {\n registeredAgents.add(agent.code_name);\n log(`Registered '${agent.code_name}' in ${frameworkAdapter.label}`);\n }\n }\n\n send({ type: 'provisioned', agentId: agent.agent_id, codeName: agent.code_name });\n }\n\n // Always deploy artifacts to project dir — the provision dir is the source\n // of truth, and channel MCP servers are merged from a separate path.\n // This must run outside changedFiles so the merge always produces a\n // complete .mcp.json (base servers + channel servers).\n if (frameworkAdapter.deployArtifactsToProject) {\n frameworkAdapter.deployArtifactsToProject(agent.code_name, agentDir);\n }\n } catch (err) {\n log(`Provision failed for '${agent.code_name}': ${(err as Error).message}`);\n }\n\n // 3b. Ensure model is set correctly in per-agent profile (on first run and on change)\n const resolvedForModel = resolveModelChain(refreshData);\n const primaryModel = resolvedForModel.primary ?? (refreshData.agent.primary_model as string | null | undefined);\n if (primaryModel && frameworkAdapter.updateAgentModel) {\n const previousModel = knownModels.get(agent.agent_id);\n if (previousModel !== primaryModel) {\n try {\n const updated = await frameworkAdapter.updateAgentModel(agent.code_name, primaryModel);\n if (updated) {\n if (previousModel) {\n log(`Model updated for '${agent.code_name}': ${previousModel} → ${primaryModel}`);\n } else {\n log(`Model set for '${agent.code_name}': ${primaryModel}`);\n }\n }\n } catch (err) {\n log(`Failed to update model for '${agent.code_name}': ${(err as Error).message}`);\n }\n }\n knownModels.set(agent.agent_id, primaryModel);\n }\n\n // 4. Drift check — hash local files and compare\n let lastDriftCheckAt = now;\n const written = writtenHashes.get(agent.agent_id);\n\n if (written && existsSync(agentDir)) {\n const driftedFiles: string[] = [];\n\n for (const [file, expectedHash] of written) {\n const localHash = hashFile(join(agentDir, file));\n if (localHash && localHash !== expectedHash) {\n driftedFiles.push(file);\n }\n }\n\n if (driftedFiles.length > 0) {\n log(`Drift detected for '${agent.code_name}': ${driftedFiles.join(', ')}`);\n send({ type: 'drift-detected', agentId: agent.agent_id, codeName: agent.code_name, files: driftedFiles });\n\n // Report drift to API\n try {\n const localHashes: Record<string, string | null> = {};\n for (const file of driftedFiles) {\n localHashes[file] = hashFile(join(agentDir, file));\n }\n await api.post('/host/drift', {\n agent_id: agent.agent_id,\n drifted_files: driftedFiles,\n local_hashes: localHashes,\n });\n } catch (err) {\n log(`Failed to report drift for '${agent.code_name}': ${(err as Error).message}`);\n }\n }\n }\n\n // Cache bot tokens from channel_configs for notification delivery\n if (refreshData.channel_configs) {\n const tokens: { slack?: string; telegram?: string; telegramAllowedChats?: string[] } = {};\n const slackCfg = refreshData.channel_configs['slack'];\n if (slackCfg?.config) {\n const bt = (slackCfg.config as Record<string, unknown>).bot_token;\n if (typeof bt === 'string' && bt) tokens.slack = bt;\n }\n const tgCfg = refreshData.channel_configs['telegram'];\n if (tgCfg?.config) {\n const tgConfig = tgCfg.config as Record<string, unknown>;\n const bt = tgConfig.bot_token;\n if (typeof bt === 'string' && bt) tokens.telegram = bt;\n const allowedChats = tgConfig.allowed_chat_ids;\n if (Array.isArray(allowedChats)) tokens.telegramAllowedChats = allowedChats as string[];\n }\n if (tokens.slack || tokens.telegram) {\n agentChannelTokens.set(agent.code_name, tokens);\n } else {\n agentChannelTokens.delete(agent.code_name);\n }\n }\n\n let needsGatewayRestart = false;\n\n // 5. Write channel credentials to per-agent profile config (only if changed)\n const hasChannelConfigs = refreshData.channel_configs && Object.keys(refreshData.channel_configs).length > 0;\n\n if (refreshData.channel_configs && frameworkAdapter.writeChannelCredentials) {\n if (agent.status === 'active') {\n for (const [channelId, entry] of Object.entries(refreshData.channel_configs)) {\n if ((entry.status === 'active' || entry.status === 'pending') && entry.config) {\n // Track that this channel is active for this agent's profile\n if (!activeChannels.has(channelId)) {\n activeChannels.set(channelId, new Set());\n }\n activeChannels.get(channelId)!.add(agent.code_name);\n\n // Hash the config to detect changes — skip credential write if identical to last poll\n const configHash = createHash('sha256').update(JSON.stringify(entry.config)).digest('hex');\n const cacheKey = `${agent.agent_id}:${channelId}`;\n if (knownChannelConfigHashes.get(cacheKey) === configHash) {\n continue;\n }\n try {\n const sessionMode = (refreshData.agent as Record<string, unknown>).session_mode as string | undefined;\n frameworkAdapter.writeChannelCredentials(agent.code_name, channelId, entry.config as Record<string, unknown>, { sessionMode });\n knownChannelConfigHashes.set(cacheKey, configHash);\n log(`Channel credentials written for '${agent.code_name}/${channelId}'`);\n } catch (err) {\n log(`Failed to write channel credentials for '${agent.code_name}/${channelId}': ${(err as Error).message}`);\n }\n }\n }\n } else if (agent.status === 'paused') {\n // Paused agents: disable channels in their profile\n if (frameworkAdapter.setChannelEnabled) {\n for (const channelId of Object.keys(refreshData.channel_configs)) {\n frameworkAdapter.setChannelEnabled(channelId, false, agent.code_name);\n }\n }\n }\n }\n\n // 6. Fetch and write auth profiles (secrets)\n let lastSecretsProvisionAt = state.agents.find((a) => a.agentId === agent.agent_id)?.lastSecretsProvisionAt ?? null;\n let secretsHash = knownSecretsHashes.get(agent.agent_id) ?? null;\n\n try {\n const secretsData = await api.post<{\n profiles: Array<{\n provider: string;\n profile_name: string;\n auth_type: string;\n api_key?: string;\n metadata: Record<string, unknown>;\n }>;\n secrets_hash: string | null;\n }>('/host/secrets', { agent_id: agent.agent_id });\n\n const newHash = secretsData.secrets_hash;\n const hashChanged = newHash !== secretsHash;\n\n if (hashChanged && secretsData.profiles.length > 0) {\n frameworkAdapter.writeAuthProfiles(agent.code_name, secretsData.profiles);\n lastSecretsProvisionAt = new Date().toISOString();\n log(`Secrets updated for '${agent.code_name}'`);\n }\n\n if (newHash) {\n knownSecretsHashes.set(agent.agent_id, newHash);\n secretsHash = newHash;\n } else {\n knownSecretsHashes.delete(agent.agent_id);\n secretsHash = null;\n }\n } catch (err) {\n // Non-fatal — secrets are supplementary to provisioning\n log(`Secrets fetch failed for '${agent.code_name}': ${(err as Error).message}`);\n }\n\n // 6b. Integration provisioning — fetch integrations, resolve satisfied capabilities,\n // install skills + CLI tools\n try {\n const integrationsData = await api.post<{\n integrations: Array<{\n id: string;\n definition_id: string;\n credentials: Record<string, unknown>;\n config: Record<string, unknown>;\n capabilities: Array<{ id: string; name: string; description: string; access: string }>;\n auth_type: string;\n display_name: string;\n scope: string;\n }>;\n }>('/host/agent-integrations', { agent_id: agent.agent_id });\n\n const integrations = integrationsData.integrations ?? [];\n\n // 6b-i. Refresh OAuth tokens nearing expiry (< 10 min remaining)\n for (const integration of integrations) {\n if (integration.auth_type !== 'oauth2') continue;\n const expiresAt = integration.credentials?.token_expires_at as string | undefined;\n const refreshToken = integration.credentials?.refresh_token as string | undefined;\n if (!expiresAt || !refreshToken) continue;\n\n const msRemaining = new Date(expiresAt).getTime() - Date.now();\n if (msRemaining > 10 * 60 * 1000) continue; // Still valid for > 10 min\n\n try {\n const integrationId = integration.id;\n if (!integrationId) continue;\n const refreshResult = await api.post<{ ok: boolean; expires_at?: string; access_token?: string }>(\n `/integrations/oauth/${integrationId}/refresh`,\n {},\n );\n if (refreshResult.ok) {\n // Update in-memory credentials so writeIntegrations() uses the new token\n integration.credentials.token_expires_at = refreshResult.expires_at;\n if (refreshResult.access_token) {\n integration.credentials.access_token = refreshResult.access_token;\n }\n log(`OAuth token refreshed for '${agent.code_name}/${integration.definition_id}'`);\n\n // Write live token file as fallback for agents not yet using the\n // token_refresh MCP tool. Agents with the plugin can call token.refresh\n // on demand instead of relying on this file-based handoff.\n if (frameworkAdapter.writeTokenFile) {\n frameworkAdapter.writeTokenFile(agent.code_name, integrations as Parameters<typeof frameworkAdapter.writeTokenFile>[1]);\n }\n }\n } catch (err) {\n log(`OAuth token refresh failed for '${agent.code_name}/${integration.definition_id}': ${(err as Error).message}`);\n }\n }\n\n if (integrations.length > 0) {\n // Hash integration credentials to detect credential changes\n const intHash = createHash('sha256')\n .update(JSON.stringify(integrations.map((i) => `${i.definition_id}:${JSON.stringify(i.credentials)}`)))\n .digest('hex')\n .slice(0, 16);\n const prevIntHash = knownIntegrationHashes.get(agent.agent_id);\n\n if (intHash !== prevIntHash) {\n // Write integration credentials via framework adapter\n if (frameworkAdapter.writeIntegrations) {\n frameworkAdapter.writeIntegrations(agent.code_name, integrations as Parameters<typeof frameworkAdapter.writeIntegrations>[1]);\n }\n knownIntegrationHashes.set(agent.agent_id, intHash);\n log(`Integrations provisioned for '${agent.code_name}' (${integrations.length} integration(s))`);\n\n // Flag: restart gateway later (step 8) so new env vars take effect\n needsGatewayRestart = true;\n\n // Auto-install lossless-claw plugin if integration is present\n const hasLcm = integrations.some((i) => i.definition_id === 'lossless-claw');\n if (hasLcm && !losslessClawInstalled.get(agent.code_name)) {\n try {\n const { execFileSync } = await import('node:child_process');\n // Check if plugin is already installed\n let pluginList: string;\n try {\n pluginList = execFileSync(\n 'openclaw',\n ['--profile', agent.code_name, 'plugins', 'list', '--json'],\n { timeout: 15_000 },\n ).toString();\n } catch {\n pluginList = '[]';\n }\n const installed = JSON.parse(pluginList) as Array<{ name: string }>;\n const alreadyInstalled = installed.some(\n (p) => p.name === 'lossless-claw' || p.name === '@martian-engineering/lossless-claw',\n );\n if (!alreadyInstalled) {\n log(`Installing lossless-claw plugin for '${agent.code_name}'...`);\n execFileSync(\n 'openclaw',\n ['--profile', agent.code_name, 'plugins', 'install', '@martian-engineering/lossless-claw'],\n { stdio: 'ignore', timeout: 60_000 },\n );\n log(`lossless-claw plugin installed for '${agent.code_name}'`);\n }\n losslessClawInstalled.set(agent.code_name, true);\n } catch (pluginErr) {\n log(`lossless-claw plugin install failed for '${agent.code_name}': ${(pluginErr as Error).message}`);\n }\n }\n }\n\n // Sync capability skill files — hashed separately so skill content\n // updates get deployed even when credentials haven't changed.\n const resolvedDefIds = new Set(integrations.map((i) => i.definition_id));\n\n for (const capId of resolvedDefIds) {\n try {\n const capData = await api.post<{\n capability_id: string;\n requiredIntegrations: string[];\n skills: Array<{\n id: string;\n name: string;\n allowedTools: string[];\n files: Array<{ relativePath: string; content: string }>;\n }>;\n cliTools: Array<{ package: string; binary: string; envKey: string; fromIntegration: string }>;\n }>('/host/capability-skill', { definition_id: capId });\n\n // Check all required integrations are satisfied\n const allSatisfied = capData.requiredIntegrations.every((reqId) => resolvedDefIds.has(reqId));\n if (!allSatisfied) {\n const missing = capData.requiredIntegrations.filter((reqId) => !resolvedDefIds.has(reqId));\n log(`Capability '${capId}' skipped — missing integration(s): ${missing.join(', ')}`);\n continue;\n }\n\n // Hash skill file content to detect changes\n const skillContent = JSON.stringify(capData.skills.map((s) => s.files.map((f) => `${f.relativePath}:${f.content}`)));\n const skillHash = createHash('sha256').update(skillContent).digest('hex').slice(0, 16);\n const skillKey = `${agent.agent_id}:${capId}`;\n const prevSkillHash = knownSkillHashes.get(skillKey);\n\n if (skillHash !== prevSkillHash) {\n // Install skill files via framework adapter\n if (frameworkAdapter.installSkillFiles && capData.skills) {\n for (const skill of capData.skills) {\n if (skill.files.length > 0) {\n frameworkAdapter.installSkillFiles(agent.code_name, skill.id, skill.files);\n log(`Installed skill '${skill.id}' for '${agent.code_name}' (${skill.files.length} file(s))`);\n }\n }\n }\n knownSkillHashes.set(skillKey, skillHash);\n }\n\n // Install CLI tools — each tool declares which integration provides its credential\n // Only packages on the explicit allowlist may be auto-installed (deny-by-default)\n const ALLOWED_CLI_PACKAGES = new Set([\n 'xero-cli',\n '@openapitools/openapi-generator-cli',\n 'gh',\n '@schpet/linear-cli',\n '@googleworkspace/cli',\n '@tobilu/qmd',\n ]);\n\n if (intHash !== prevIntHash) {\n const { execFileSync } = await import('node:child_process');\n for (const tool of capData.cliTools) {\n if (!ALLOWED_CLI_PACKAGES.has(tool.package)) {\n log(`Skipping CLI tool '${tool.package}' for '${agent.code_name}' — not on the allowed packages list`);\n continue;\n }\n // Check if binary is already on PATH, install if not\n try {\n execFileSync('which', [tool.binary], { stdio: 'ignore' });\n } catch {\n log(`Installing CLI tool '${tool.package}' for '${agent.code_name}'...`);\n try {\n execFileSync('npm', ['install', '-g', tool.package], { stdio: 'ignore', timeout: 60_000 });\n log(`CLI tool '${tool.binary}' installed successfully`);\n } catch (installErr) {\n log(`Failed to install CLI tool '${tool.package}': ${(installErr as Error).message}`);\n }\n }\n\n // Post-install setup hooks (run whether freshly installed or already present)\n if (tool.binary === 'qmd') {\n try {\n // qmd collection add uses CWD-relative paths — run from the agent's\n // parent dir with 'project' as relative path for correct resolution\n const agentDir = join(process.env['HOME'] ?? '/tmp', '.augmented', agent.code_name);\n execFileSync('qmd', ['collection', 'add', agent.code_name, 'project'], {\n stdio: 'ignore', timeout: 30_000, cwd: agentDir,\n });\n log(`QMD collection '${agent.code_name}' configured`);\n } catch { /* collection may already exist — non-fatal */ }\n }\n }\n }\n } catch (skillErr) {\n // Non-fatal — capability may not have a package yet (e.g. github, xero)\n const msg = (skillErr as Error).message ?? '';\n if (!msg.includes('404') && !msg.includes('Unknown capability')) {\n log(`Capability fetch failed for '${capId}': ${msg}`);\n }\n }\n }\n }\n } catch (err) {\n // Non-fatal — integration provisioning is supplementary\n log(`Integration provisioning failed for '${agent.code_name}': ${(err as Error).message}`);\n }\n\n // 7. Gateway lifecycle — ensure running for active agents with channels\n let gatewayPort: number | null = null;\n let gatewayPid: number | null = null;\n let gatewayRunning = false;\n\n if (agent.status === 'active' && hasChannelConfigs) {\n const gwStatus = await ensureGatewayRunning(agent.code_name, frameworkAdapter);\n gatewayPort = gwStatus.port;\n gatewayPid = gwStatus.pid;\n gatewayRunning = gwStatus.running;\n } else if (agent.status === 'paused') {\n // Stop gateway for paused agents\n await stopGatewayIfRunning(agent.code_name, frameworkAdapter);\n }\n\n // Note: gateway restart after integration changes removed — was killing gateways.\n // New env vars take effect on next gateway restart (manual or via manager cycle).\n\n // 7b. Auto-provision org/team default schedules\n let tasks = refreshData.scheduled_tasks ?? [];\n const existingTemplateIds = new Set(tasks.map((t) => t.template_id));\n\n try {\n const defaultsData = await api.post<{\n schedules: Array<{\n template_id: string;\n name: string;\n schedule_expr: string;\n prompt: string;\n session_target?: string;\n enabled?: boolean;\n }>;\n team_id: string;\n timezone: string;\n }>('/host/resolve-default-schedules', { agent_id: agent.agent_id });\n\n const missing = (defaultsData.schedules ?? []).filter(\n (s) => !existingTemplateIds.has(s.template_id),\n );\n\n // Always call ensure-default-schedules to insert missing tasks and\n // fix delivery_mode on existing tasks that don't match the template default.\n const allSchedules = defaultsData.schedules ?? [];\n if (allSchedules.length > 0) {\n await api.post('/host/ensure-default-schedules', {\n agent_id: agent.agent_id,\n team_id: defaultsData.team_id,\n timezone: defaultsData.timezone,\n schedules: allSchedules,\n });\n if (missing.length > 0) {\n log(`Auto-provisioned ${missing.length} default schedule(s) for '${agent.code_name}': ${missing.map((s) => s.template_id).join(', ')}`);\n }\n\n // Re-fetch tasks since schedules may have changed\n const freshData = await api.post<{ scheduled_tasks?: typeof tasks }>('/host/refresh', { agent_id: agent.agent_id });\n tasks = freshData.scheduled_tasks ?? tasks;\n }\n } catch (err) {\n log(`Default schedule provisioning failed for '${agent.code_name}': ${(err as Error).message}`);\n }\n\n // 7c. Auto-provision Augmented plugin and kanban skill for all active agents\n if (agent.status === 'active') {\n // Augmented OpenClaw plugin — provides kanban_list, kanban_add, kanban_move,\n // kanban_update, kanban_done, status_standup, status_update tools natively\n if (frameworkAdapter.installPlugin) {\n try {\n const pluginPath = join(process.cwd(), 'packages', 'openclaw-plugin-augmented', 'src', 'index.ts');\n if (existsSync(pluginPath)) {\n frameworkAdapter.installPlugin(agent.code_name, 'augmented', pluginPath, {\n agtHost: requireHost(),\n agtApiKey: getApiKey() ?? undefined,\n agentId: agent.agent_id,\n });\n }\n } catch (err) {\n log(`Augmented plugin install failed for '${agent.code_name}': ${(err as Error).message}`);\n }\n }\n\n // Kanban skill files\n if (frameworkAdapter.installSkillFiles) {\n try {\n const skillContent = getBuiltInSkillContent('kanban');\n if (skillContent) {\n frameworkAdapter.installSkillFiles(agent.code_name, 'kanban', skillContent);\n }\n } catch (err) {\n log(`Kanban skill install failed for '${agent.code_name}': ${(err as Error).message}`);\n }\n }\n }\n\n // 7d. Fetch kanban board for prompt injection into board-aware templates\n let boardItems: BoardItem[] = [];\n const hasBoardTemplates = tasks.some((t) => BOARD_INJECT_TEMPLATES.has(t.template_id));\n if (hasBoardTemplates) {\n try {\n const boardData = await api.post<{ items?: BoardItem[] }>('/host/my-kanban', { agent_id: agent.agent_id });\n boardItems = (boardData.items ?? []).map(sanitizeBoardItem);\n kanbanBoardCache.set(agent.code_name, boardItems);\n } catch {\n // Non-fatal — board may not exist yet\n boardItems = kanbanBoardCache.get(agent.code_name) ?? [];\n }\n }\n\n // Resolve framework once for sections 8-11\n const agentFw = agentFrameworkCache.get(agent.code_name) ?? 'openclaw';\n\n // 8. Sync scheduled tasks\n const sessionMode = (refreshData.agent as Record<string, unknown>).session_mode as string ?? 'oneshot';\n\n if (agentFw === 'claude-code' && sessionMode === 'persistent') {\n // Claude Code persistent mode: manage long-running session with channels\n await ensurePersistentSession(agent, tasks, boardItems, refreshData);\n } else if (agentFw === 'claude-code' && tasks.length > 0) {\n // Claude Code oneshot mode: fire-and-forget via claude -p\n await syncAndCheckClaudeScheduler(agent, tasks, boardItems, refreshData);\n } else if (frameworkAdapter.syncScheduledTasks && gatewayRunning && gatewayPort) {\n // Hash ONLY stable task fields (without board-injected prompts) to decide\n // whether a re-sync is needed. Board context changes every poll cycle as\n // kanban items move around — hashing it caused syncScheduledTasks to fire\n // on every cycle, spawning duplicate openclaw-cron processes.\n const stableTasksHash = createHash('sha256')\n .update(JSON.stringify(tasks))\n .digest('hex')\n .slice(0, 16);\n\n // Board context hash — triggers a re-sync when the board meaningfully changes\n // (items added/removed, moved between columns, reprioritised, or renamed)\n const boardHash = boardItems.length > 0\n ? createHash('sha256')\n .update(JSON.stringify(boardItems.map((b) => ({ id: b.id, title: b.title, status: b.status, priority: b.priority, deliverable: b.deliverable }))))\n .digest('hex')\n .slice(0, 16)\n : 'empty';\n\n // Include resolved models in the hash so default changes trigger resync\n const resolvedModels = resolveModelChain(refreshData);\n const modelsHash = createHash('sha256')\n .update(JSON.stringify(resolvedModels))\n .digest('hex')\n .slice(0, 16);\n\n const combinedHash = `${stableTasksHash}:${boardHash}:${modelsHash}`;\n const prevTasksHash = knownTasksHashes.get(agent.agent_id);\n\n if (combinedHash !== prevTasksHash) {\n // Inject board context into prompts for board-aware templates\n const enrichedTasks = tasks.map((t) => {\n if (BOARD_INJECT_TEMPLATES.has(t.template_id) && boardItems.length > 0) {\n const template = PLAN_TEMPLATES.has(t.template_id) ? 'morning-plan' : 'follow-up';\n const boardPrefix = formatBoardForPrompt(boardItems, template);\n return { ...t, prompt: boardPrefix + t.prompt };\n }\n return t;\n });\n\n try {\n const token = readGatewayToken(agent.code_name);\n await frameworkAdapter.syncScheduledTasks(\n agent.code_name,\n enrichedTasks.map((t) => ({\n id: t.id,\n template_id: t.template_id,\n name: t.name,\n schedule_kind: t.schedule_kind as 'cron' | 'every' | 'at',\n schedule_expr: t.schedule_expr,\n schedule_every: t.schedule_every,\n schedule_at: t.schedule_at,\n timezone: t.timezone,\n prompt: t.prompt,\n session_target: t.session_target as 'main' | 'isolated',\n delivery_mode: t.delivery_mode as 'announce' | 'none',\n delivery_channel: t.delivery_channel,\n delivery_to: t.delivery_to,\n enabled: t.enabled,\n model_tier: ((t as Record<string, unknown>).model_tier as 'primary' | 'secondary' | 'tertiary' | undefined) ?? 'primary',\n })),\n gatewayPort,\n token,\n {\n models: resolvedModels,\n },\n );\n knownTasksHashes.set(agent.agent_id, combinedHash);\n log(`Scheduled tasks synced for '${agent.code_name}' (${enrichedTasks.length} task(s))`);\n } catch (err) {\n log(`Failed to sync scheduled tasks for '${agent.code_name}': ${(err as Error).message}`);\n }\n }\n }\n\n // Update task display info map for cron health alerts\n for (const t of tasks) {\n const jobName = `aug:${t.template_id}:${t.id ?? t.name.toLowerCase().replace(/\\s+/g, '-')}`;\n taskDisplayInfo.set(`${agent.code_name}:${jobName}`, {\n taskName: t.name,\n schedule: t.schedule_expr ?? t.schedule_every ?? '',\n agentDisplayName: agent.display_name,\n });\n }\n\n // 9. Harvest cron run results for standup/task updates (throttled to reduce process spawning)\n const ccInFlight = agentFw === 'claude-code' ? (claudeTaskConcurrency.get(agent.code_name) ?? 0) : null;\n log(`[${agent.code_name}] Harvest gate: gatewayRunning=${gatewayRunning} gatewayPort=${gatewayPort} tasks=${tasks.length} fw=${agentFw}${ccInFlight !== null ? ` claude-p=${ccInFlight}/${MAX_CLAUDE_CONCURRENCY}` : ''}`);\n if (agentFw === 'openclaw' && gatewayRunning && gatewayPort && tasks.length > 0) {\n const lastHarvest = lastHarvestAt.get(agent.code_name) ?? 0;\n if (Date.now() - lastHarvest >= HARVEST_INTERVAL_MS) {\n lastHarvestAt.set(agent.code_name, Date.now());\n harvestCronResults(agent.code_name, tasks, gatewayPort).catch((err) => {\n log(`Cron result harvest failed for '${agent.code_name}': ${(err as Error).message}`);\n });\n }\n }\n\n // 10. Immediate work trigger — if webapp signalled a new task, fire kanban-work now\n {\n const triggerAt = (refreshData.agent as Record<string, unknown>).work_trigger_at as string | null;\n if (triggerAt) {\n const triggerTs = new Date(triggerAt).getTime();\n const lastTrigger = lastWorkTriggerAt.get(agent.code_name) ?? 0;\n if (triggerTs > lastTrigger) {\n lastWorkTriggerAt.set(agent.code_name, triggerTs);\n\n if (agentFw === 'openclaw' && gatewayRunning && gatewayPort) {\n // OpenClaw: find kanban-work job ID from cron jobs file\n const homeDir = process.env['HOME'] ?? '/tmp';\n const jobsPath = join(homeDir, `.openclaw-${agent.code_name}`, 'cron', 'jobs.json');\n if (existsSync(jobsPath)) {\n try {\n const jobsData = JSON.parse(readFileSync(jobsPath, 'utf-8'));\n const kanbanJob = (jobsData.jobs ?? []).find((j: Record<string, unknown>) =>\n typeof j.name === 'string' && j.name.includes('kanban-work'),\n );\n if (kanbanJob?.id) {\n const cliBin = resolveAgentFramework(agent.code_name).cliBinary ?? 'openclaw';\n log(`Work trigger: firing kanban-work for '${agent.code_name}'`);\n execFilePromise(cliBin, ['--profile', agent.code_name, 'cron', 'run', kanbanJob.id])\n .then(() => log(`Work trigger succeeded for '${agent.code_name}'`))\n .catch((err) => log(`Work trigger failed for '${agent.code_name}': ${(err as Error).message}`));\n }\n } catch { /* jobs.json read failed — non-fatal */ }\n }\n } else if (agentFw === 'claude-code') {\n // Claude Code: find kanban-work task in scheduler state and fire immediately\n fireClaudeWorkTrigger(agent.code_name, agent.agent_id, boardItems);\n }\n }\n }\n }\n\n // 11. Clean up stale cron session files to prevent context overflow (OpenClaw only)\n if (agentFw === 'openclaw') {\n cleanupStaleSessions(agent.code_name);\n }\n\n // 12. Detect newly-done kanban items and send notifications (runs every cycle)\n {\n const agentId = codeNameToAgentId.get(agent.code_name);\n if (agentId) {\n try {\n const boardData = await api.post<{ items?: BoardItem[] }>('/host/my-kanban', { agent_id: agentId });\n const freshBoard = (boardData.items ?? []).map(sanitizeBoardItem);\n const freshDoneIds = new Set(freshBoard.filter((b) => b.status === 'done' || b.status === 'failed').map((b) => b.id));\n\n const previousDoneIds = notifyBoardCache.get(agent.code_name);\n notifyBoardCache.set(agent.code_name, freshDoneIds);\n\n // Skip first cycle — no previous state to compare against\n if (!previousDoneIds) {\n log(`[${agent.code_name}] Board diff: initial cache (${freshDoneIds.size} done items)`);\n } else {\n const newlyDone = freshBoard.filter(\n (b) => (b.status === 'done' || b.status === 'failed') && !previousDoneIds.has(b.id),\n );\n\n log(`[${agent.code_name}] Board diff: ${previousDoneIds.size} prev done → ${freshDoneIds.size} now, ${newlyDone.length} newly done`);\n\n if (newlyDone.length > 0) {\n const displayName = agentDisplayNames.get(agent.code_name) ?? agent.code_name;\n for (const item of newlyDone) {\n log(`Newly done: '${item.title}' notify_channel=${item.notify_channel ?? 'none'} notify_to=${item.notify_to ?? 'none'}`);\n if (item.notify_channel && item.notify_to) {\n const isFailed = item.status === 'failed';\n const resultLine = item.result ? `\\n${isFailed ? 'Reason' : 'Result'}: ${item.result}` : '';\n const emoji = isFailed ? '❌' : '✅';\n const message = `${emoji} ${isFailed ? 'Task Failed' : 'Task Complete'} — ${displayName}\\n${item.title}${resultLine}`;\n sendTaskNotification(agent.code_name, item.notify_channel, item.notify_to, message).catch((err) => {\n log(`sendTaskNotification failed for '${agent.code_name}': ${(err as Error).message}`);\n });\n }\n }\n }\n }\n // Check for stale in_progress items\n const staleItems = freshBoard.filter((b) => {\n if (b.status !== 'in_progress' || !b.updated_at) return false;\n const age = Date.now() - new Date(b.updated_at).getTime();\n return age > STALE_TASK_THRESHOLD_MS && !alertedStaleItems.has(`${agent.code_name}:${b.id}`);\n });\n\n if (staleItems.length > 0) {\n const displayName = agentDisplayNames.get(agent.code_name) ?? agent.code_name;\n for (const item of staleItems) {\n const age = Math.round((Date.now() - new Date(item.updated_at!).getTime()) / 60_000);\n log(`Stale task: '${item.title}' (id=${item.id}) in_progress for ${age}m — auto-failing for '${agent.code_name}'`);\n alertedStaleItems.add(`${agent.code_name}:${item.id}`);\n\n // Auto-fail the task via API (try ID first, fallback to title)\n try {\n const failResult = await api.post<{ ok?: boolean; updated?: number; error?: string }>('/host/kanban', {\n agent_id: agentId,\n update: [{ id: item.id, title: item.title, status: 'failed', result: `Timed out — in progress for ${age} minutes with no update` }],\n });\n log(`Auto-fail result for '${item.title}': updated=${failResult.updated}`);\n // Mark as done only when mutation actually succeeded,\n // so we don't suppress legitimate later notifications.\n if ((failResult.updated ?? 0) > 0 || failResult.ok === true) {\n freshDoneIds.add(item.id);\n }\n } catch (err) {\n log(`Auto-fail API error for '${item.title}': ${(err as Error).message}`);\n }\n\n // Notify\n const message = `⏳ Task Timed Out — ${displayName}\\n${item.title}\\nIn progress for ${age} minutes with no update — auto-failed`;\n if (item.notify_channel && item.notify_to) {\n sendTaskNotification(agent.code_name, item.notify_channel, item.notify_to, message).catch(() => {});\n }\n sendSlackWebhookMessage(`⏳ *Task Timed Out* — *${displayName}*\\n*${item.title}*\\nIn progress for ${age} minutes — auto-failed`).catch(() => {});\n }\n }\n\n // Clear stale alerts for items no longer in_progress (scoped to this agent)\n const prefix = `${agent.code_name}:`;\n for (const key of alertedStaleItems) {\n if (key.startsWith(prefix)) {\n const itemId = key.slice(prefix.length);\n if (!freshBoard.some((b) => b.id === itemId && b.status === 'in_progress')) {\n alertedStaleItems.delete(key);\n }\n }\n }\n } catch (err) {\n log(`Board diff failed for '${agent.code_name}': ${(err as Error).message}`);\n }\n }\n }\n\n agentStates.push({\n agentId: agent.agent_id,\n codeName: agent.code_name,\n status: agent.status,\n charterVersion,\n toolsVersion,\n secretsHash,\n lastRefreshAt: now,\n lastProvisionAt,\n lastDriftCheckAt,\n lastSecretsProvisionAt,\n gatewayPort,\n gatewayPid,\n gatewayRunning,\n acpSessions: [],\n });\n}\n\n// ---------------------------------------------------------------------------\n// Session cleanup — prevent context overflow from accumulated cron sessions\n// ---------------------------------------------------------------------------\n\nconst CRON_SESSION_KEEP_COUNT = 10;\nconst CRON_RUN_RETENTION_DAYS = 7;\nconst lastCleanupAt = new Map<string, number>();\nconst CLEANUP_INTERVAL_MS = 60_000; // Run cleanup every 1 minute per agent\n\nfunction cleanupStaleSessions(codeName: string): void {\n // Run immediately on first poll (lastRun defaults to 0), then throttle\n const lastRun = lastCleanupAt.get(codeName) ?? 0;\n if (lastRun > 0 && Date.now() - lastRun < CLEANUP_INTERVAL_MS) return;\n lastCleanupAt.set(codeName, Date.now());\n\n const homeDir = process.env['HOME'] ?? '/tmp';\n\n // 1. Clean CRON session files only (preserve chat/Slack/Telegram sessions)\n for (const agentDir of ['main', codeName]) {\n const sessionsDir = join(homeDir, `.openclaw-${codeName}`, 'agents', agentDir, 'sessions');\n cleanupCronSessions(sessionsDir, CRON_SESSION_KEEP_COUNT);\n }\n\n // 2. Clean cron run logs older than 7 days\n const cronRunsDir = join(homeDir, `.openclaw-${codeName}`, 'cron', 'runs');\n cleanupOldFiles(cronRunsDir, CRON_RUN_RETENTION_DAYS, '.jsonl');\n\n // 3. Clear stale \"running\" state from cron jobs.json.\n // If a cron run was in progress when the gateway crashed, the state persists\n // as \"running\" and blocks all future runs with \"already-running\". Reset any\n // run that's been \"running\" for more than 5 minutes.\n const cronJobsPath = join(homeDir, `.openclaw-${codeName}`, 'cron', 'jobs.json');\n clearStaleCronRunState(cronJobsPath);\n}\n\n/**\n * Clean up cron session entries from sessions.json and their corresponding\n * .jsonl files. Preserves chat, Slack, Telegram, and other non-cron sessions.\n *\n * Cron sessions have keys matching `agent:*:cron:*:run:*` in sessions.json.\n */\nfunction cleanupCronSessions(sessionsDir: string, keepCount: number): void {\n const indexPath = join(sessionsDir, 'sessions.json');\n if (!existsSync(indexPath)) return;\n\n try {\n const raw = readFileSync(indexPath, 'utf-8');\n const index = JSON.parse(raw) as Record<string, { sessionId?: string; updatedAt?: number }>;\n\n // Find cron run entries (pattern: agent:*:cron:*:run:*)\n const cronRunKeys = Object.keys(index)\n .filter((k) => k.includes(':cron:') && k.includes(':run:'))\n .map((k) => ({\n key: k,\n sessionId: index[k]?.sessionId,\n updatedAt: index[k]?.updatedAt ?? 0,\n }))\n .sort((a, b) => b.updatedAt - a.updatedAt); // newest first\n\n if (cronRunKeys.length <= keepCount) return;\n\n // Keep the most recent N, delete the rest\n const toDelete = cronRunKeys.slice(keepCount);\n let deletedFiles = 0;\n\n for (const entry of toDelete) {\n // Remove from index\n delete index[entry.key];\n\n // Delete the session .jsonl file\n if (entry.sessionId) {\n const sessionFile = join(sessionsDir, `${entry.sessionId}.jsonl`);\n try {\n if (existsSync(sessionFile)) {\n unlinkSync(sessionFile);\n deletedFiles++;\n }\n } catch { /* ignore */ }\n }\n }\n\n // Also clean up parent cron session keys that have no remaining runs\n const cronParentKeys = Object.keys(index).filter(\n (k) => k.includes(':cron:') && !k.includes(':run:') && k !== 'agent:main:main',\n );\n for (const parentKey of cronParentKeys) {\n const hasRuns = Object.keys(index).some(\n (k) => k.startsWith(parentKey + ':run:'),\n );\n if (!hasRuns) {\n const parentSessionId = index[parentKey]?.sessionId;\n delete index[parentKey];\n if (parentSessionId) {\n try {\n const f = join(sessionsDir, `${parentSessionId}.jsonl`);\n if (existsSync(f)) { unlinkSync(f); deletedFiles++; }\n } catch { /* ignore */ }\n }\n }\n }\n\n // Write updated index\n writeFileSync(indexPath, JSON.stringify(index));\n\n if (toDelete.length > 0) {\n log(`Cleaned ${toDelete.length} cron session(s) and ${deletedFiles} file(s) from ${sessionsDir}`);\n }\n } catch { /* non-fatal */ }\n}\n\nconst STALE_RUN_TIMEOUT_MS = 5 * 60_000; // 5 minutes\n\nfunction clearStaleCronRunState(jobsPath: string): void {\n if (!existsSync(jobsPath)) return;\n\n try {\n const raw = readFileSync(jobsPath, 'utf-8');\n const data = JSON.parse(raw) as Record<string, unknown>;\n const jobs = (data.jobs ?? data) as Array<Record<string, unknown>>;\n if (!Array.isArray(jobs)) return;\n\n let changed = false;\n const now = Date.now();\n\n for (const job of jobs) {\n const state = job.state as Record<string, unknown> | undefined;\n if (!state) continue;\n\n // Check if a run is stuck in \"running\" state\n // OpenClaw uses `running: true` + `runningAtMs` (not `runStartedAtMs`)\n const runStartedAt = (state.runningAtMs ?? state.runStartedAtMs) as number | undefined;\n const isRunning = state.running === true || state.status === 'running';\n\n if (isRunning && runStartedAt && (now - runStartedAt) > STALE_RUN_TIMEOUT_MS) {\n state.running = false;\n delete state.status;\n delete state.runStartedAtMs;\n delete state.currentRunId;\n changed = true;\n log(`Cleared stale running state for cron job '${job.name}' (stuck for ${Math.round((now - runStartedAt) / 60_000)}min)`);\n } else if (isRunning && !runStartedAt) {\n // running=true but no timestamp — clear it\n state.running = false;\n changed = true;\n log(`Cleared stale running state for cron job '${job.name}' (no start timestamp)`);\n }\n }\n\n if (changed) {\n writeFileSync(jobsPath, JSON.stringify(data, null, 2));\n }\n } catch { /* non-fatal */ }\n}\n\nfunction cleanupOldFiles(dir: string, maxAgeDays: number, ext: string): void {\n if (!existsSync(dir)) return;\n\n const cutoff = Date.now() - maxAgeDays * 24 * 60 * 60 * 1000;\n let removed = 0;\n\n try {\n for (const f of readdirSync(dir)) {\n if (!f.endsWith(ext)) continue;\n const fullPath = join(dir, f);\n try {\n const st = statSync(fullPath);\n if (st.mtimeMs < cutoff) {\n unlinkSync(fullPath);\n removed++;\n }\n } catch { /* ignore */ }\n }\n\n if (removed > 0) {\n log(`Cleaned ${removed} old cron run log(s) from ${dir}`);\n }\n } catch { /* non-fatal */ }\n}\n\n// ---------------------------------------------------------------------------\n// Claude Code in-process scheduler\n// ---------------------------------------------------------------------------\n\nimport {\n syncTasksToScheduler,\n getReadyTasks,\n markTaskFired,\n loadSchedulerState,\n findTaskByTemplate,\n getProjectDir as ccGetProjectDir,\n type SchedulerTaskInput,\n type SchedulerTaskState,\n} from './claude-scheduler.js';\n\n// Track in-flight Claude scheduled tasks and concurrency per agent\nconst inFlightClaudeTasks = new Set<string>();\nconst claudeTaskConcurrency = new Map<string, number>();\nconst MAX_CLAUDE_CONCURRENCY = 2;\n\n// In-memory scheduler states (loaded from disk on first access)\nconst claudeSchedulerStates = new Map<string, ReturnType<typeof loadSchedulerState>>();\n\nasync function syncAndCheckClaudeScheduler(\n agent: { agent_id: string; code_name: string; display_name: string },\n tasks: Array<Record<string, unknown>>,\n boardItems: Array<{ id: string; title: string; status: string; priority: number; estimated_minutes?: number; deliverable?: string; result?: string; notify_channel?: string; notify_to?: string }>,\n refreshData: Record<string, unknown>,\n): Promise<void> {\n const codeName = agent.code_name;\n\n // Hash-based change detection (same as OpenClaw path)\n const stableTasksHash = createHash('sha256')\n .update(JSON.stringify(tasks))\n .digest('hex')\n .slice(0, 16);\n\n const boardHash = boardItems.length > 0\n ? createHash('sha256')\n .update(JSON.stringify(boardItems.map((b) => ({ id: b.id, title: b.title, status: b.status, priority: b.priority, deliverable: b.deliverable }))))\n .digest('hex')\n .slice(0, 16)\n : 'empty';\n\n const resolvedModels = resolveModelChain(refreshData);\n const modelsHash = createHash('sha256')\n .update(JSON.stringify(resolvedModels))\n .digest('hex')\n .slice(0, 16);\n\n const combinedHash = `${stableTasksHash}:${boardHash}:${modelsHash}`;\n const prevHash = knownTasksHashes.get(agent.agent_id);\n\n if (combinedHash !== prevHash) {\n // Sync tasks to scheduler state\n const taskInputs: SchedulerTaskInput[] = tasks.map((t) => ({\n id: t.id as string,\n template_id: t.template_id as string,\n name: t.name as string,\n schedule_kind: t.schedule_kind as 'cron' | 'every' | 'at',\n schedule_expr: (t.schedule_expr as string) ?? null,\n schedule_every: (t.schedule_every as string) ?? null,\n schedule_at: (t.schedule_at as string) ?? null,\n timezone: (t.timezone as string) ?? 'UTC',\n prompt: (t.prompt as string) ?? '',\n session_target: (t.session_target as string) ?? 'isolated',\n delivery_mode: (t.delivery_mode as string) ?? 'none',\n delivery_channel: (t.delivery_channel as string) ?? null,\n delivery_to: (t.delivery_to as string) ?? null,\n enabled: (t.enabled as boolean) ?? true,\n }));\n\n const state = syncTasksToScheduler(codeName, agent.agent_id, taskInputs);\n claudeSchedulerStates.set(codeName, state);\n knownTasksHashes.set(agent.agent_id, combinedHash);\n log(`[claude-scheduler] Tasks synced for '${codeName}' (${taskInputs.length} task(s))`);\n }\n\n // Load state if not cached\n if (!claudeSchedulerStates.has(codeName)) {\n claudeSchedulerStates.set(codeName, loadSchedulerState(codeName));\n }\n\n const state = claudeSchedulerStates.get(codeName)!;\n const ready = getReadyTasks(state);\n if (ready.length === 0) return;\n\n for (const task of ready) {\n if (inFlightClaudeTasks.has(task.taskId)) continue;\n if ((claudeTaskConcurrency.get(codeName) ?? 0) >= MAX_CLAUDE_CONCURRENCY) break;\n\n // Enrich prompt with board context\n let prompt = task.prompt;\n if (BOARD_INJECT_TEMPLATES.has(task.templateId) && boardItems.length > 0) {\n const template = PLAN_TEMPLATES.has(task.templateId) ? 'morning-plan' : 'follow-up';\n const boardPrefix = formatBoardForPrompt(boardItems, template);\n prompt = boardPrefix + prompt;\n }\n\n // For kanban-work: move the top \"today\" item to in_progress before starting\n if (KANBAN_WORK_TEMPLATES.has(task.templateId)) {\n const todayItem = boardItems.find((b) => b.status === 'today');\n if (todayItem) {\n try {\n await api.post('/host/kanban', {\n agent_id: agent.agent_id,\n update: [{ id: todayItem.id, title: todayItem.title, status: 'in_progress' }],\n });\n log(`[claude-scheduler] Moved '${todayItem.title}' to in_progress for '${codeName}'`);\n } catch (err) {\n log(`[claude-scheduler] Failed to move item to in_progress: ${(err as Error).message}`);\n }\n }\n }\n\n inFlightClaudeTasks.add(task.taskId);\n claudeTaskConcurrency.set(codeName, (claudeTaskConcurrency.get(codeName) ?? 0) + 1);\n\n log(`[claude-scheduler] Firing '${task.name}' for '${codeName}'`);\n\n executeAndProcessClaudeTask(codeName, agent.agent_id, task, prompt)\n .finally(() => {\n inFlightClaudeTasks.delete(task.taskId);\n claudeTaskConcurrency.set(codeName, Math.max(0, (claudeTaskConcurrency.get(codeName) ?? 1) - 1));\n });\n }\n}\n\nasync function executeAndProcessClaudeTask(\n codeName: string,\n agentId: string,\n task: SchedulerTaskState,\n prompt: string,\n): Promise<void> {\n const projectDir = ccGetProjectDir(codeName);\n const mcpConfigPath = join(projectDir, '.mcp.json');\n try {\n const claudeMdPath = join(projectDir, 'CLAUDE.md');\n const claudeArgs = [\n '-p', prompt,\n '--output-format', 'text',\n '--mcp-config', mcpConfigPath,\n '--allowedTools', 'mcp__augmented__*,Bash,Read,Write,Edit,Grep,Glob',\n ];\n // Inject agent identity as system prompt so personality is always present\n if (existsSync(claudeMdPath)) {\n claudeArgs.push('--system-prompt-file', claudeMdPath);\n }\n const { stdout, stderr } = await execFilePromiseLong('claude', claudeArgs, {\n cwd: projectDir, timeout: 300_000, stdin: 'ignore',\n });\n\n if (stderr) {\n log(`[claude-scheduler] Task '${task.name}' stderr for '${codeName}': ${stderr.slice(0, 500)}`);\n }\n\n const output = stdout.trim();\n log(`[claude-scheduler] Task '${task.name}' completed for '${codeName}' (${output.length} chars): ${output.slice(0, 300)}`);\n\n // Route result based on template\n await processClaudeTaskResult(codeName, agentId, task.templateId, output);\n\n // Update scheduler state\n const updated = markTaskFired(codeName, task.taskId, 'ok');\n claudeSchedulerStates.set(codeName, updated);\n } catch (err) {\n const errMsg = err instanceof Error ? err.message : String(err);\n log(`[claude-scheduler] Task '${task.name}' failed for '${codeName}': ${errMsg}`);\n const updated = markTaskFired(codeName, task.taskId, 'error');\n claudeSchedulerStates.set(codeName, updated);\n }\n}\n\nasync function processClaudeTaskResult(\n codeName: string,\n agentId: string,\n templateId: string,\n output: string,\n): Promise<void> {\n try {\n if (STANDUP_TEMPLATES.has(templateId)) {\n const standup = parseStandupSummary(output);\n await api.post('/host/agent-status', {\n agent_id: agentId,\n standup,\n current_status: 'idle',\n });\n log(`[claude-scheduler] Standup posted for '${codeName}'`);\n } else if (TASK_UPDATE_TEMPLATES.has(templateId)) {\n await api.post('/host/agent-status', {\n agent_id: agentId,\n current_tasks: output.slice(0, 2000),\n });\n log(`[claude-scheduler] Task update posted for '${codeName}'`);\n } else if (PLAN_TEMPLATES.has(templateId)) {\n const planItems = parsePlanItems(output);\n if (planItems.length > 0) {\n await api.post('/host/kanban', {\n agent_id: agentId,\n add: planItems,\n });\n log(`[claude-scheduler] Plan items posted for '${codeName}' (${planItems.length} items)`);\n }\n } else if (KANBAN_WORK_TEMPLATES.has(templateId)) {\n const kanbanUpdates = parseKanbanUpdates(output);\n if (kanbanUpdates.length > 0) {\n await api.post('/host/kanban', {\n agent_id: agentId,\n update: kanbanUpdates,\n });\n log(`[claude-scheduler] Kanban updates posted for '${codeName}' (${kanbanUpdates.length} updates)`);\n }\n }\n } catch (err) {\n log(`[claude-scheduler] Failed to post result for '${codeName}': ${(err as Error).message}`);\n }\n}\n\nfunction fireClaudeWorkTrigger(\n codeName: string,\n agentId: string,\n boardItems: Array<{ id: string; title: string; status: string; priority: number; estimated_minutes?: number; deliverable?: string; result?: string }>,\n): void {\n const state = claudeSchedulerStates.get(codeName) ?? loadSchedulerState(codeName);\n const kanbanTask = findTaskByTemplate(state, 'kanban-work');\n if (!kanbanTask) {\n log(`[claude-scheduler] Work trigger: no kanban-work task found for '${codeName}'`);\n return;\n }\n if (inFlightClaudeTasks.has(kanbanTask.taskId)) {\n log(`[claude-scheduler] Work trigger: kanban-work already in-flight for '${codeName}'`);\n return;\n }\n\n let prompt = kanbanTask.prompt;\n if (boardItems.length > 0) {\n const boardPrefix = formatBoardForPrompt(boardItems, 'follow-up');\n prompt = boardPrefix + prompt;\n }\n\n inFlightClaudeTasks.add(kanbanTask.taskId);\n claudeTaskConcurrency.set(codeName, (claudeTaskConcurrency.get(codeName) ?? 0) + 1);\n log(`[claude-scheduler] Work trigger: firing kanban-work for '${codeName}'`);\n\n executeAndProcessClaudeTask(codeName, agentId, kanbanTask, prompt)\n .finally(() => {\n inFlightClaudeTasks.delete(kanbanTask.taskId);\n claudeTaskConcurrency.set(codeName, Math.max(0, (claudeTaskConcurrency.get(codeName) ?? 1) - 1));\n });\n}\n\n// ---------------------------------------------------------------------------\n// Persistent session management (session_mode = 'persistent')\n// ---------------------------------------------------------------------------\n\nimport {\n startPersistentSession,\n stopPersistentSession,\n injectMessage,\n isSessionHealthy,\n getSessionState,\n resetRestartCount,\n stopAllSessions,\n getProjectDir as psGetProjectDir,\n} from './persistent-session.js';\n\n// Track which agents have persistent sessions started\nconst persistentSessionAgents = new Set<string>();\n\nasync function ensurePersistentSession(\n agent: { agent_id: string; code_name: string; display_name: string },\n tasks: Array<Record<string, unknown>>,\n boardItems: Array<{ id: string; title: string; status: string; priority: number; estimated_minutes?: number; deliverable?: string; result?: string }>,\n refreshData: Record<string, unknown>,\n): Promise<void> {\n const codeName = agent.code_name;\n const projectDir = psGetProjectDir(codeName);\n const mcpConfigPath = join(projectDir, '.mcp.json');\n const claudeMdPath = join(projectDir, 'CLAUDE.md');\n\n // Resolve channel plugins from agent's channel configs\n const channelConfigs = refreshData.channel_configs as Record<string, { config: unknown; status: string }> | null;\n const channels: string[] = [];\n\n // Map known channel types to their Claude Code channel plugins\n const devChannels: string[] = []; // custom channels needing --dangerously-load-development-channels\n if (channelConfigs) {\n if ('telegram' in channelConfigs) {\n channels.push('plugin:telegram@claude-plugins-official');\n }\n if ('discord' in channelConfigs) {\n channels.push('plugin:discord@claude-plugins-official');\n }\n // Slack uses our custom channel server loaded from .mcp-channels.json\n // (separate from .mcp.json to avoid duplicate loading)\n if ('slack' in channelConfigs) {\n devChannels.push('server:slack');\n }\n }\n\n // Start or maintain the persistent session\n if (!isSessionHealthy(codeName)) {\n if (persistentSessionAgents.has(codeName)) {\n log(`[persistent-session] Session for '${codeName}' is unhealthy, will restart`);\n }\n\n startPersistentSession({\n codeName,\n agentId: agent.agent_id,\n projectDir,\n mcpConfigPath,\n claudeMdPath,\n channels,\n devChannels,\n log,\n });\n persistentSessionAgents.add(codeName);\n return; // Wait for next cycle to inject tasks (session needs time to boot)\n }\n\n // Session is healthy — reset restart counter\n resetRestartCount(codeName);\n\n // Inject scheduled tasks that are due\n const state = claudeSchedulerStates.get(codeName);\n if (state) {\n const ready = getReadyTasks(state);\n if (ready.length > 0) {\n log(`[persistent-session] ${ready.length} ready task(s) for '${codeName}': ${ready.map(t => `${t.name}(next=${t.nextFireAt ? new Date(t.nextFireAt).toISOString() : 'null'})`).join(', ')}`);\n }\n for (const task of ready) {\n\n // Enrich prompt with board context\n let prompt = task.prompt;\n if (BOARD_INJECT_TEMPLATES.has(task.templateId) && boardItems.length > 0) {\n const template = PLAN_TEMPLATES.has(task.templateId) ? 'morning-plan' : 'follow-up';\n const boardPrefix = formatBoardForPrompt(boardItems, template);\n prompt = boardPrefix + prompt;\n }\n\n // For kanban-work: move top today item to in_progress\n if (KANBAN_WORK_TEMPLATES.has(task.templateId)) {\n const todayItem = boardItems.find((b) => b.status === 'today');\n if (todayItem) {\n try {\n await api.post('/host/kanban', {\n agent_id: agent.agent_id,\n update: [{ id: todayItem.id, title: todayItem.title, status: 'in_progress' }],\n });\n log(`[persistent-session] Moved '${todayItem.title}' to in_progress for '${codeName}'`);\n } catch { /* non-fatal */ }\n }\n }\n\n log(`[persistent-session] Injecting task '${task.name}' into '${codeName}'`);\n\n const injected = await injectMessage(codeName, 'task', prompt, {\n task_id: task.taskId,\n template_id: task.templateId,\n task_name: task.name,\n });\n\n if (injected) {\n // Mark as fired — this advances nextFireAt to the next scheduled time\n const updated = markTaskFired(codeName, task.taskId, 'ok');\n claudeSchedulerStates.set(codeName, updated);\n log(`[persistent-session] Task '${task.name}' injected, next fire at ${new Date(updated.tasks[task.taskId]?.nextFireAt ?? 0).toISOString()}`);\n }\n\n // Only inject one task per cycle in persistent mode\n break;\n }\n }\n\n // Sync scheduler state (same hash-based detection as oneshot)\n const stableTasksHash = createHash('sha256')\n .update(JSON.stringify(tasks))\n .digest('hex')\n .slice(0, 16);\n const prevHash = knownTasksHashes.get(agent.agent_id);\n if (stableTasksHash !== prevHash) {\n const taskInputs: SchedulerTaskInput[] = tasks.map((t) => ({\n id: t.id as string,\n template_id: t.template_id as string,\n name: t.name as string,\n schedule_kind: t.schedule_kind as 'cron' | 'every' | 'at',\n schedule_expr: (t.schedule_expr as string) ?? null,\n schedule_every: (t.schedule_every as string) ?? null,\n schedule_at: (t.schedule_at as string) ?? null,\n timezone: (t.timezone as string) ?? 'UTC',\n prompt: (t.prompt as string) ?? '',\n session_target: (t.session_target as string) ?? 'isolated',\n delivery_mode: (t.delivery_mode as string) ?? 'none',\n delivery_channel: (t.delivery_channel as string) ?? null,\n delivery_to: (t.delivery_to as string) ?? null,\n enabled: (t.enabled as boolean) ?? true,\n }));\n const schedulerState = syncTasksToScheduler(codeName, agent.agent_id, taskInputs);\n claudeSchedulerStates.set(codeName, schedulerState);\n knownTasksHashes.set(agent.agent_id, stableTasksHash);\n log(`[persistent-session] Tasks synced for '${codeName}' (${taskInputs.length} task(s))`);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Supabase Realtime for direct chat (replaces 2s polling)\n// ---------------------------------------------------------------------------\n\nimport {\n startRealtimeChat,\n startRealtimeDrift,\n startRealtimeAssignments,\n startRealtimeConfig,\n startRealtimeKanban,\n stopRealtimeChat,\n isRealtimeConnected,\n updateRealtimeToken,\n} from './realtime-chat.js';\n\nlet realtimeStarted = false;\nlet realtimeDriftStarted = false;\nlet realtimeKanbanStarted = false;\nlet realtimeAssignStarted = false;\nlet realtimeConfigStarted = false;\n\nfunction ensureRealtimeStarted(agentStates: AgentState[]): void {\n if (realtimeStarted) return;\n\n const activeAgentIds = agentStates\n .filter((a) => a.status === 'active')\n .map((a) => a.agentId);\n\n if (activeAgentIds.length === 0) return;\n\n const apiKey = process.env['AGT_API_KEY'];\n if (!apiKey) return;\n\n // Get Supabase config + token from the cached exchange result\n void exchangeApiKey(apiKey).then((exchange) => {\n if (!exchange.supabaseUrl || !exchange.supabaseAnonKey) {\n log('[realtime-chat] No Supabase URL/key from exchange — staying on polling');\n return;\n }\n\n startRealtimeChat({\n supabaseUrl: exchange.supabaseUrl,\n supabaseAnonKey: exchange.supabaseAnonKey,\n token: exchange.token,\n agentIds: activeAgentIds,\n onMessage: (msg) => {\n const agent = agentStates.find((a) => a.agentId === msg.agent_id);\n if (!agent) return;\n\n if (directChatInFlight.has(msg.id)) return;\n directChatInFlight.add(msg.id);\n\n processDirectChatMessage(agent, {\n id: msg.id,\n session_id: msg.session_id,\n content: msg.content,\n }).finally(() => {\n directChatInFlight.delete(msg.id);\n });\n },\n onError: (err) => {\n log(`[realtime-chat] Error: ${err.message}`);\n },\n onStatusChange: (status) => {\n if (status === 'disconnected' || status === 'error') {\n log('[realtime] Disconnected — falling back to polling, will reconnect next cycle');\n // Reset all subscription flags so they reconnect with a fresh client\n realtimeStarted = false;\n realtimeDriftStarted = false;\n realtimeAssignStarted = false;\n realtimeConfigStarted = false;\n realtimeKanbanStarted = false;\n }\n },\n log,\n });\n\n realtimeStarted = true;\n log(`[realtime-chat] Started for ${activeAgentIds.length} agent(s)`);\n }).catch((err) => {\n log(`[realtime-chat] Failed to start: ${(err as Error).message}`);\n });\n}\n\nfunction ensureRealtimeDriftStarted(agentStates: AgentState[]): void {\n if (realtimeDriftStarted) return;\n\n const activeAgentIds = agentStates.filter((a) => a.status === 'active').map((a) => a.agentId);\n if (activeAgentIds.length === 0) return;\n\n const apiKey = process.env['AGT_API_KEY'];\n if (!apiKey) return;\n\n void exchangeApiKey(apiKey).then((exchange) => {\n if (!exchange.supabaseUrl || !exchange.supabaseAnonKey) return;\n\n startRealtimeDrift({\n supabaseUrl: exchange.supabaseUrl,\n supabaseAnonKey: exchange.supabaseAnonKey,\n token: exchange.token,\n agentIds: activeAgentIds,\n onDrift: (doc) => {\n // Invalidate the known version so next poll cycle re-provisions\n const agentState = agentStates.find((a) => a.agentId === doc.agent_id);\n if (agentState) {\n knownVersions.delete(doc.agent_id);\n log(`[realtime] Drift invalidated for '${agentState.codeName}' — will re-provision next cycle`);\n }\n },\n log,\n });\n\n realtimeDriftStarted = true;\n log(`[realtime] Drift subscription started for ${activeAgentIds.length} agent(s)`);\n }).catch((err) => {\n log(`[realtime] Drift subscription failed: ${(err as Error).message}`);\n });\n}\n\nfunction ensureRealtimeAssignStarted(agentStates: AgentState[]): void {\n if (realtimeAssignStarted) return;\n\n const apiKey = process.env['AGT_API_KEY'];\n if (!apiKey) return;\n\n void exchangeApiKey(apiKey).then((exchange) => {\n if (!exchange.supabaseUrl || !exchange.supabaseAnonKey || !exchange.hostId) return;\n\n startRealtimeAssignments({\n supabaseUrl: exchange.supabaseUrl,\n supabaseAnonKey: exchange.supabaseAnonKey,\n token: exchange.token,\n hostId: exchange.hostId,\n onAssign: (payload) => {\n log(`[realtime] Agent ${payload.agent_id} assigned — will pick up next cycle`);\n // No cache invalidation needed — the next poll cycle will discover the new agent\n },\n onUnassign: (payload) => {\n log(`[realtime] Agent ${payload.agent_id} unassigned`);\n clearAgentCaches(payload.agent_id, '');\n },\n log,\n });\n\n realtimeAssignStarted = true;\n log(`[realtime] Assignment subscription started for host ${exchange.hostId}`);\n }).catch((err) => {\n log(`[realtime] Assignment subscription failed: ${(err as Error).message}`);\n });\n}\n\nfunction ensureRealtimeConfigStarted(agentStates: AgentState[]): void {\n if (realtimeConfigStarted) return;\n\n const activeAgentIds = agentStates.filter((a) => a.status === 'active').map((a) => a.agentId);\n if (activeAgentIds.length === 0) return;\n\n const apiKey = process.env['AGT_API_KEY'];\n if (!apiKey) return;\n\n void exchangeApiKey(apiKey).then((exchange) => {\n if (!exchange.supabaseUrl || !exchange.supabaseAnonKey) return;\n\n startRealtimeConfig({\n supabaseUrl: exchange.supabaseUrl,\n supabaseAnonKey: exchange.supabaseAnonKey,\n token: exchange.token,\n agentIds: activeAgentIds,\n onConfigChange: (agent) => {\n // Only invalidate status cache — version/provision caches are handled by drift subscription.\n // Don't invalidate knownVersions here as that triggers re-provision which updates\n // updated_at, creating a feedback loop with this Realtime subscription.\n knownStatuses.delete(agent.agent_id);\n },\n log,\n });\n\n realtimeConfigStarted = true;\n log(`[realtime] Config subscription started for ${activeAgentIds.length} agent(s)`);\n }).catch((err) => {\n log(`[realtime] Config subscription failed: ${(err as Error).message}`);\n });\n}\n\nfunction ensureRealtimeKanbanStarted(agentStates: AgentState[]): void {\n if (realtimeKanbanStarted) return;\n\n const activeAgentIds = agentStates.filter((a) => a.status === 'active').map((a) => a.agentId);\n if (activeAgentIds.length === 0) return;\n\n const apiKey = process.env['AGT_API_KEY'];\n if (!apiKey) return;\n\n void exchangeApiKey(apiKey).then((exchange) => {\n if (!exchange.supabaseUrl || !exchange.supabaseAnonKey) return;\n\n startRealtimeKanban({\n supabaseUrl: exchange.supabaseUrl,\n supabaseAnonKey: exchange.supabaseAnonKey,\n token: exchange.token,\n agentIds: activeAgentIds,\n onTodayItem: (item) => {\n // Trigger kanban-work immediately for this agent\n const agent = agentStates.find((a) => a.agentId === item.agent_id);\n if (!agent) return;\n\n const agentFw = agentFrameworkCache.get(agent.codeName) ?? 'openclaw';\n\n if (agentFw === 'claude-code') {\n // For persistent sessions, inject via tmux; for oneshot, fire claude -p\n const boardItems = kanbanBoardCache.get(agent.codeName) ?? [];\n if (isSessionHealthy(agent.codeName)) {\n injectMessage(agent.codeName, 'task', `New task added to your board: \"${item.title}\" (priority ${item.priority}). Pick it up — move to in_progress and start working.`, {\n task_name: 'kanban-work-trigger',\n });\n log(`[realtime] Injected kanban-work trigger for '${agent.codeName}': \"${item.title}\"`);\n } else {\n fireClaudeWorkTrigger(agent.codeName, agent.agentId, boardItems);\n log(`[realtime] Fired kanban-work for '${agent.codeName}': \"${item.title}\"`);\n }\n }\n },\n log,\n });\n\n realtimeKanbanStarted = true;\n log(`[realtime] Kanban subscription started for ${activeAgentIds.length} agent(s)`);\n }).catch((err) => {\n log(`[realtime] Kanban subscription failed: ${(err as Error).message}`);\n });\n}\n\n// ---------------------------------------------------------------------------\n// Direct chat — poll for pending messages (fallback when Realtime is down)\n// ---------------------------------------------------------------------------\n\n// Track in-flight direct chat messages to avoid double-processing\nconst directChatInFlight = new Set<string>();\n\nasync function pollDirectChatMessages(agentStates: AgentState[]): Promise<void> {\n for (const agent of agentStates) {\n if (agent.status !== 'active') continue;\n const fw = agentFrameworkCache.get(agent.codeName) ?? 'openclaw';\n // OpenClaw requires a running gateway; Claude Code does not\n if (fw === 'openclaw' && (!agent.gatewayRunning || !agent.gatewayPort)) continue;\n\n try {\n const data = await api.post<{\n messages: Array<{\n id: string;\n session_id: string;\n content: string;\n created_at: string;\n }>;\n }>('/host/direct-chat/poll', { agent_id: agent.agentId });\n\n for (const msg of data.messages) {\n if (directChatInFlight.has(msg.id)) continue;\n directChatInFlight.add(msg.id);\n\n // Process async so we don't block the poll cycle\n processDirectChatMessage(agent, msg).finally(() => {\n directChatInFlight.delete(msg.id);\n });\n }\n } catch (err) {\n log(`Direct chat poll failed for '${agent.codeName}': ${(err as Error).message}`);\n }\n }\n}\n\nasync function processDirectChatMessage(\n agent: AgentState,\n msg: { id: string; session_id: string; content: string },\n): Promise<void> {\n const fw = agentFrameworkCache.get(agent.codeName) ?? 'openclaw';\n log(`[direct-chat] Processing message for '${agent.codeName}' (fw=${fw}): id=${msg.id} len=${msg.content.length}`);\n\n try {\n let reply: string;\n\n if (fw === 'claude-code') {\n // Always use claude -p for webapp direct chat so the reply comes back\n // through the API. The persistent session handles Slack/Telegram channels.\n const { getProjectDir: ccProjectDir } = await import('./claude-scheduler.js');\n const projDir = ccProjectDir(agent.codeName);\n const chatArgs = [\n '-p', msg.content,\n '--output-format', 'text',\n '--mcp-config', join(projDir, '.mcp.json'),\n '--allowedTools', 'mcp__augmented__*,Bash,Read,Write,Edit,Grep,Glob',\n ];\n const chatClaudeMd = join(projDir, 'CLAUDE.md');\n if (existsSync(chatClaudeMd)) {\n chatArgs.push('--system-prompt-file', chatClaudeMd);\n }\n const { stdout } = await execFilePromiseLong('claude', chatArgs, { cwd: projDir, stdin: 'ignore' });\n reply = stdout.trim() || '[No response from agent]';\n } else {\n // OpenClaw: use profile-based agent invocation\n const { stdout } = await execFilePromiseLong('openclaw', [\n '--profile', agent.codeName,\n 'agent',\n '--local',\n '--agent', agent.codeName,\n '--message', msg.content,\n '--session-id', msg.session_id,\n '--json',\n ]);\n\n // OpenClaw agent --json returns either:\n // { payloads: [{ text }], meta: {...} } (success)\n // { result: { payloads: [{ text }] }, meta: {...} } (some versions)\n try {\n const parsed = JSON.parse(stdout);\n const payloads = (parsed?.payloads ?? parsed?.result?.payloads) as Array<{ text?: string }> | undefined;\n reply = payloads?.[0]?.text ?? parsed?.reply ?? parsed?.text ?? parsed?.message ?? stdout;\n } catch {\n reply = stdout.trim() || '[No response from agent]';\n }\n }\n\n // Post the reply back\n await api.post('/host/direct-chat/reply', {\n agent_id: agent.agentId,\n session_id: msg.session_id,\n content: reply,\n });\n\n log(`[direct-chat] Reply sent for '${agent.codeName}'`);\n } catch (err) {\n const errMsg = err instanceof Error ? err.message : String(err);\n const errorId = createHash('sha256').update(errMsg).digest('hex').slice(0, 12);\n log(`[direct-chat] Failed to process message for '${agent.codeName}': error_id=${errorId}`);\n\n // Post an error reply so the webapp doesn't poll forever\n try {\n await api.post('/host/direct-chat/reply', {\n agent_id: agent.agentId,\n session_id: msg.session_id,\n content: `[Error] Failed to process message (ref: ${errorId}). Please retry.`,\n });\n } catch {\n // Last resort — nothing more we can do\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Cron result harvesting — polls cron run history and updates agent status\n// ---------------------------------------------------------------------------\n\n// Template IDs that map to agent field updates\nconst STANDUP_TEMPLATES = new Set(['daily-standup', 'end-of-day-summary']);\nconst TASK_UPDATE_TEMPLATES = new Set(['hourly-status', 'task-update']);\nconst PLAN_TEMPLATES = new Set(['morning-plan']);\nconst KANBAN_WORK_TEMPLATES = new Set(['kanban-work']);\nconst BOARD_INJECT_TEMPLATES = new Set(['morning-plan', 'task-update', 'hourly-status', 'end-of-day-summary', 'kanban-work']);\n\n// Throttle harvest — no need to check cron results every 30s cycle\nconst lastHarvestAt = new Map<string, number>();\nconst HARVEST_INTERVAL_MS = 3 * 60 * 1000; // 3 minutes\n\n// Cache kanban board per agent per poll cycle\ntype BoardItem = { id: string; title: string; status: string; priority: number; estimated_minutes?: number; deliverable?: string; result?: string; notify_channel?: string; notify_to?: string; updated_at?: string };\nconst kanbanBoardCache = new Map<string, BoardItem[]>();\n// Separate cache for notification board diff — not pre-populated by step 7d\nconst notifyBoardCache = new Map<string, Set<string>>();\n\ninterface CronRunEntry {\n ts: number;\n jobId: string;\n action: string;\n status: string;\n summary?: string;\n}\n\nasync function harvestCronResults(\n codeName: string,\n tasks: Array<{ id: string; template_id: string; name: string }>,\n gatewayPort: number,\n): Promise<void> {\n const token = readGatewayToken(codeName);\n const gwArgs = ['--url', `ws://127.0.0.1:${gatewayPort}`, ...(token ? ['--token', token] : [])];\n\n // List current jobs to map job IDs to template IDs\n let gatewayJobs: Array<{ id: string; name: string }> = [];\n try {\n const cliBin = resolveAgentFramework(codeName).cliBinary ?? 'openclaw';\n const { stdout } = await execFilePromise(cliBin, ['--profile', codeName, 'cron', 'list', '--json', ...gwArgs]);\n const parsed = JSON.parse(stdout);\n gatewayJobs = (parsed.jobs ?? []) as Array<{ id: string; name: string }>;\n } catch {\n return; // Gateway not ready\n }\n\n // Build a map from gateway job ID → DB task template_id\n const jobTemplateMap = new Map<string, string>();\n for (const job of gatewayJobs) {\n if (!job.name.startsWith('aug:')) continue;\n // Name format: aug:{template_id}:{task_uuid}\n const parts = job.name.split(':');\n if (parts.length >= 3) {\n jobTemplateMap.set(job.id, parts[1]!);\n }\n }\n\n // Check each relevant job for new completed runs\n for (const [jobId, templateId] of jobTemplateMap) {\n if (!STANDUP_TEMPLATES.has(templateId) && !TASK_UPDATE_TEMPLATES.has(templateId) && !PLAN_TEMPLATES.has(templateId) && !KANBAN_WORK_TEMPLATES.has(templateId)) continue;\n\n let runs: CronRunEntry[] = [];\n try {\n const cliBin2 = resolveAgentFramework(codeName).cliBinary ?? 'openclaw';\n const { stdout } = await execFilePromise(cliBin2, ['--profile', codeName, 'cron', 'runs', '--id', jobId, ...gwArgs]);\n const parsed = JSON.parse(stdout);\n runs = (parsed.entries ?? []) as CronRunEntry[];\n } catch {\n continue;\n }\n\n // Detect API key errors from failed runs\n const latestRun = runs.filter((r) => r.action === 'finished').sort((a, b) => b.ts - a.ts)[0];\n if (latestRun) {\n const agentId = codeNameToAgentId.get(codeName);\n const summary = latestRun.summary ?? '';\n const isKeyError = summary.includes('Key limit exceeded') || summary.includes('key limit') ||\n summary.includes('rate limit') || summary.includes('insufficient_quota') ||\n summary.includes('billing') || summary.includes('402');\n if (agentId) {\n if (latestRun.status === 'error' && isKeyError) {\n const errorMsg = summary.slice(0, 200);\n if (!apiKeyStatusCache.get(codeName)) {\n apiKeyStatusCache.set(codeName, true);\n api.post('/host/agent-api-key-status', { agent_id: agentId, status: 'rate_limited', error: errorMsg }).catch(() => {});\n log(`API key error detected for '${codeName}': ${errorMsg}`);\n }\n } else if (latestRun.status === 'ok' && apiKeyStatusCache.get(codeName)) {\n apiKeyStatusCache.delete(codeName);\n api.post('/host/agent-api-key-status', { agent_id: agentId, status: null, error: null }).catch(() => {});\n log(`API key status cleared for '${codeName}' — run succeeded`);\n }\n }\n }\n\n // Find the latest successful run\n const completed = runs\n .filter((r) => r.action === 'finished' && r.status === 'ok' && r.summary)\n .sort((a, b) => b.ts - a.ts);\n\n if (completed.length === 0) continue;\n\n const latest = completed[0]!;\n const lastSeen = lastCronRunTs.get(jobId) ?? 0;\n if (latest.ts <= lastSeen) continue; // Already processed\n\n lastCronRunTs.set(jobId, latest.ts);\n\n // POST result to API\n const statusUpdate: Record<string, unknown> = { agent_code_name: codeName };\n\n if (STANDUP_TEMPLATES.has(templateId)) {\n // Parse standup summary into structured fields\n const summary = latest.summary ?? '';\n statusUpdate.standup = parseStandupSummary(summary);\n }\n\n if (TASK_UPDATE_TEMPLATES.has(templateId)) {\n statusUpdate.current_tasks = latest.summary ?? '';\n }\n\n // Only POST agent-status if we have something to update (standup or current_tasks)\n if (statusUpdate.standup || statusUpdate.current_tasks !== undefined) {\n try {\n await api.post('/host/agent-status', statusUpdate);\n log(`Updated ${templateId} for '${codeName}' from cron result`);\n } catch (err) {\n log(`Failed to update ${templateId} for '${codeName}': ${(err as Error).message}`);\n }\n }\n\n // Kanban: Parse plan items from morning-plan template\n if (PLAN_TEMPLATES.has(templateId)) {\n const summary = latest.summary ?? '';\n const planItems = parsePlanItems(summary);\n if (planItems.length > 0) {\n // Look up agent_id from code_name\n try {\n const agentId = codeNameToAgentId.get(codeName);\n if (agentId) {\n await api.post('/host/kanban', {\n agent_id: agentId,\n add: planItems,\n archive_days: 7,\n });\n log(`Added ${planItems.length} kanban items for '${codeName}' from morning-plan`);\n }\n } catch (err) {\n log(`Failed to update kanban for '${codeName}': ${(err as Error).message}`);\n }\n }\n }\n\n // Kanban: Parse status updates from task-update/hourly/kanban-work templates\n if (TASK_UPDATE_TEMPLATES.has(templateId) || KANBAN_WORK_TEMPLATES.has(templateId)) {\n const summary = latest.summary ?? '';\n const kanbanUpdates = parseKanbanUpdates(summary);\n if (kanbanUpdates.length > 0) {\n try {\n const agentId = codeNameToAgentId.get(codeName);\n if (agentId) {\n await api.post('/host/kanban', {\n agent_id: agentId,\n update: kanbanUpdates,\n });\n log(`Updated ${kanbanUpdates.length} kanban items for '${codeName}'`);\n }\n } catch (err) {\n log(`Failed to update kanban for '${codeName}': ${(err as Error).message}`);\n }\n }\n\n // Board diff notification detection moved to step 12 in processAgent\n // (runs every poll cycle, not just on cron harvest)\n }\n }\n}\n\nfunction parseStandupSummary(summary: string): { yesterday: string; today: string; blockers: string } {\n // Try to extract sections from the standup text\n const lines = summary.split('\\n');\n let yesterday = '';\n let today = '';\n let blockers = '';\n let currentSection: 'yesterday' | 'today' | 'blockers' | null = null;\n\n for (const line of lines) {\n const lower = line.toLowerCase();\n if (lower.includes('yesterday') || lower.includes('accomplished')) {\n currentSection = 'yesterday';\n continue;\n } else if (lower.includes('today') || lower.includes('working on')) {\n currentSection = 'today';\n continue;\n } else if (lower.includes('blocker')) {\n currentSection = 'blockers';\n continue;\n }\n\n const trimmed = line.replace(/^[-*•]\\s*/, '').trim();\n if (!trimmed) continue;\n\n switch (currentSection) {\n case 'yesterday': yesterday += (yesterday ? '\\n' : '') + trimmed; break;\n case 'today': today += (today ? '\\n' : '') + trimmed; break;\n case 'blockers': blockers += (blockers ? '\\n' : '') + trimmed; break;\n }\n }\n\n // Fallback: if parsing didn't find sections, use full summary\n if (!yesterday && !today && !blockers) {\n today = summary;\n }\n\n return { yesterday, today, blockers };\n}\n\nfunction parsePlanItems(summary: string): Array<{\n title: string;\n description?: string;\n priority: number;\n estimated_minutes?: number;\n status: string;\n}> {\n const items: Array<{\n title: string;\n description?: string;\n priority: number;\n estimated_minutes?: number;\n status: string;\n }> = [];\n\n const lines = summary.split('\\n');\n let currentItem: (typeof items)[0] | null = null;\n\n for (const line of lines) {\n const trimmed = line.trim();\n\n // Match numbered/bulleted items: \"1. [HIGH] Task title (~30min)\" or \"- [MEDIUM] Task (~2hr)\"\n const itemMatch = trimmed.match(/^(?:\\d+[\\.\\)]\\s*|[-*•]\\s*)\\[?(HIGH|MEDIUM|LOW|MED)\\]?\\s*(.+)/i);\n\n if (itemMatch) {\n // Push previous item\n if (currentItem) items.push(currentItem);\n\n const priorityStr = itemMatch[1]!.toUpperCase();\n const rest = itemMatch[2]!;\n\n // Extract time estimate\n let estimatedMinutes: number | undefined;\n const timeMatch = rest.match(/\\(~?(\\d+)\\s*(min(?:utes?)?|hr?(?:ours?)?|h)\\)/i);\n if (timeMatch) {\n const val = parseInt(timeMatch[1]!, 10);\n const unit = timeMatch[2]!.toLowerCase();\n estimatedMinutes = unit.startsWith('h') ? val * 60 : val;\n }\n\n // Title is everything except the time estimate — sanitize LLM output\n const title = sanitizeKanbanString(\n rest.replace(/\\(~?\\d+\\s*(?:min(?:utes?)?|hr?(?:ours?)?|h)\\)/i, ''),\n MAX_KANBAN_TITLE_LENGTH,\n );\n if (!title) continue;\n\n const priorityMap: Record<string, number> = { HIGH: 1, MEDIUM: 2, MED: 2, LOW: 3 };\n const priority = priorityMap[priorityStr] ?? 2;\n if (![1, 2, 3].includes(priority)) continue;\n\n currentItem = {\n title,\n priority,\n estimated_minutes: estimatedMinutes,\n status: 'today',\n };\n } else if (currentItem && trimmed && !trimmed.match(/^(?:PLAN|---)/i)) {\n // Non-numbered line after a plan item = description (length-limited)\n const descLine = sanitizeKanbanString(trimmed, MAX_KANBAN_NOTES_LENGTH);\n currentItem.description = currentItem.description\n ? sanitizeKanbanString(currentItem.description + '\\n' + descLine, MAX_KANBAN_NOTES_LENGTH)\n : descLine;\n }\n }\n\n if (currentItem) items.push(currentItem);\n return items;\n}\n\nconst VALID_KANBAN_STATUSES = new Set(['backlog', 'today', 'in_progress', 'done']);\nconst MAX_KANBAN_TITLE_LENGTH = 500;\nconst MAX_KANBAN_NOTES_LENGTH = 2000;\n\n/** Sanitize a string from LLM output: trim + length limit */\nfunction sanitizeKanbanString(value: string, maxLen: number): string {\n if (!value) return '';\n return value\n .replace(/[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F\\x7F]/g, '') // strip control chars (keep \\n, \\r, \\t)\n .replace(/\\{\\{.*?\\}\\}/g, '') // strip template injection markers\n .replace(/^(System|Assistant|Human):\\s*/gmi, '') // strip prompt-role prefixes\n .replace(/#{2,}/g, '') // strip markdown heading markers\n .replace(/\\s+/g, ' ') // collapse whitespace\n .trim()\n .slice(0, maxLen);\n}\n\n/** Sanitize all external fields on a board item before caching / prompt injection */\nfunction sanitizeBoardItem<T extends { title: string; status: string; deliverable?: string }>(item: T): T {\n return {\n ...item,\n title: sanitizeKanbanString(item.title, 200),\n status: sanitizeKanbanString(item.status, 50),\n ...(item.deliverable ? { deliverable: sanitizeKanbanString(item.deliverable, 500) } : {}),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Built-in skill files — bundled for auto-deployment to all agents\n// ---------------------------------------------------------------------------\n\nconst builtInSkillCache = new Map<string, Array<{ relativePath: string; content: string }> | null>();\n\nfunction getBuiltInSkillContent(skillId: string): Array<{ relativePath: string; content: string }> | null {\n if (builtInSkillCache.has(skillId)) return builtInSkillCache.get(skillId)!;\n\n try {\n // Resolve skill directory relative to the CLI package root\n // In dev: skills/<skillId>/SKILL.md is in the monorepo root\n // When bundled: skills are embedded at build time or read from cwd\n const candidates = [\n join(process.cwd(), 'skills', skillId, 'SKILL.md'),\n join(new URL('.', import.meta.url).pathname, '..', '..', '..', '..', 'skills', skillId, 'SKILL.md'),\n ];\n\n for (const candidate of candidates) {\n if (existsSync(candidate)) {\n const content = readFileSync(candidate, 'utf-8');\n const files = [{ relativePath: 'SKILL.md', content }];\n builtInSkillCache.set(skillId, files);\n return files;\n }\n }\n\n builtInSkillCache.set(skillId, null);\n return null;\n } catch {\n builtInSkillCache.set(skillId, null);\n return null;\n }\n}\n\n// ---------------------------------------------------------------------------\n\nfunction parseKanbanUpdates(summary: string): Array<{\n title: string;\n status: string;\n notes?: string;\n result?: string;\n}> {\n const updates: Array<{ title: string; status: string; notes?: string; result?: string }> = [];\n\n // Look for \"KANBAN UPDATE:\" section\n const kanbanIdx = summary.indexOf('KANBAN UPDATE:');\n if (kanbanIdx === -1) return updates;\n\n const kanbanSection = summary.slice(kanbanIdx + 'KANBAN UPDATE:'.length);\n const lines = kanbanSection.split('\\n');\n\n for (const line of lines) {\n const trimmed = line.trim();\n // Match: - \"item title\": status (optional notes/result)\n const match = trimmed.match(/^[-*•]\\s*\"([^\"]+)\":\\s*(backlog|today|in_progress|done)(?:\\s*\\((.+)\\))?/i);\n if (match) {\n const status = match[2]!.toLowerCase();\n // Validate status is in the allowed set\n if (!VALID_KANBAN_STATUSES.has(status)) continue;\n\n const title = sanitizeKanbanString(match[1]!, MAX_KANBAN_TITLE_LENGTH);\n if (!title) continue;\n\n const parenthetical = match[3] ?? undefined;\n\n // Extract result from parenthetical when status is done\n // Pattern: \"result: <value>\" or just the whole parenthetical as notes\n let notes: string | undefined;\n let result: string | undefined;\n\n if (parenthetical && status === 'done') {\n const resultMatch = parenthetical.match(/^result:\\s*(.+)/i);\n if (resultMatch) {\n result = sanitizeKanbanString(resultMatch[1]!, MAX_KANBAN_NOTES_LENGTH);\n } else {\n notes = sanitizeKanbanString(parenthetical, MAX_KANBAN_NOTES_LENGTH);\n }\n } else if (parenthetical) {\n notes = sanitizeKanbanString(parenthetical, MAX_KANBAN_NOTES_LENGTH);\n }\n\n updates.push({\n title,\n status,\n notes,\n result,\n });\n }\n }\n\n return updates;\n}\n\nfunction formatBoardForPrompt(\n items: Array<{ title: string; status: string; priority: number; estimated_minutes?: number; deliverable?: string }>,\n template: 'morning-plan' | 'follow-up',\n): string {\n if (items.length === 0) return '';\n\n const priorityLabel = (p: number) => p === 1 ? 'HIGH' : p === 3 ? 'LOW' : 'MED';\n const timeLabel = (m?: number) => m ? ` (~${m >= 60 ? `${Math.round(m / 60)}hr` : `${m}min`})` : '';\n const deliverableLine = (d?: string) => d ? `\\n Deliverable: ${d}` : '';\n\n const grouped: Record<string, typeof items> = {};\n for (const item of items) {\n const key = item.status;\n if (!grouped[key]) grouped[key] = [];\n grouped[key]!.push(item);\n }\n\n const lines: string[] = [];\n\n if (template === 'morning-plan') {\n lines.push('=== CURRENT BOARD ===');\n\n for (const [status, label] of [['backlog', 'BACKLOG (carry-over)'], ['today', 'TODAY'], ['in_progress', 'IN PROGRESS']] as const) {\n const statusItems = grouped[status];\n if (statusItems && statusItems.length > 0) {\n lines.push(`${label}:`);\n statusItems.forEach((item, i) => {\n lines.push(` ${i + 1}. [${priorityLabel(item.priority)}] ${item.title}${timeLabel(item.estimated_minutes)}${deliverableLine(item.deliverable)}`);\n });\n }\n }\n\n lines.push('=====================');\n lines.push('');\n lines.push('Create today\\'s plan. You may:');\n lines.push('- Move backlog items to \"today\"');\n lines.push('- Add new items you\\'ve identified');\n lines.push('- Reprioritise existing items');\n lines.push('');\n } else {\n lines.push('=== YOUR KANBAN BOARD ===');\n\n for (const [status, label] of [['today', 'TODAY'], ['in_progress', 'IN PROGRESS'], ['backlog', 'BACKLOG']] as const) {\n const statusItems = grouped[status];\n if (statusItems && statusItems.length > 0) {\n lines.push(`${label}:`);\n statusItems.forEach((item, i) => {\n lines.push(` ${i + 1}. [${priorityLabel(item.priority)}] ${item.title}${timeLabel(item.estimated_minutes)}${deliverableLine(item.deliverable)}`);\n });\n }\n }\n\n const doneItems = grouped['done'];\n if (doneItems && doneItems.length > 0) {\n lines.push('DONE TODAY:');\n doneItems.forEach((item, i) => {\n lines.push(` ${i + 1}. ${item.title}`);\n });\n }\n\n lines.push('=========================');\n lines.push('');\n lines.push('IMPORTANT: Use kanban MCP tools to update the board IN REAL TIME:');\n lines.push('1. FIRST call kanban.move to move your chosen item to in_progress BEFORE starting work');\n lines.push('2. Do the work');\n lines.push('3. Call kanban.done with a result summary when finished');\n lines.push('4. If blocked, call kanban.update with notes, then pick the next item');\n lines.push('');\n lines.push('SELF-MANAGEMENT: When you receive a request from a channel (Slack, Telegram)');\n lines.push('that takes more than a quick response, create a task first with kanban.add,');\n lines.push('move to in_progress, do the work, then kanban.done with a result summary.');\n lines.push('');\n lines.push('If MCP tools are unavailable, include a KANBAN UPDATE section in your output:');\n lines.push('KANBAN UPDATE:');\n lines.push('- \"item title\": new_status (optional notes)');\n lines.push('- \"item title\": done (result: <what you produced>)');\n lines.push('Statuses: backlog, today, in_progress, done');\n lines.push('');\n }\n\n return lines.join('\\n');\n}\n\nasync function execFilePromise(cmd: string, args: string[]): Promise<{ stdout: string; stderr: string }> {\n const { execFile: ef } = await import('node:child_process');\n return new Promise((resolve, reject) => {\n ef(cmd, args, { timeout: 15_000 }, (err, stdout, stderr) => {\n if (err) reject(err);\n else resolve({ stdout, stderr });\n });\n });\n}\n\nasync function execFilePromiseLong(\n cmd: string,\n args: string[],\n opts?: { cwd?: string; timeout?: number; stdin?: 'ignore' },\n): Promise<{ stdout: string; stderr: string }> {\n const { spawn: sp } = await import('node:child_process');\n return new Promise((resolve, reject) => {\n const child = sp(cmd, args, {\n cwd: opts?.cwd,\n stdio: [opts?.stdin === 'ignore' ? 'ignore' : 'pipe', 'pipe', 'pipe'],\n });\n let stdout = '';\n let stderr = '';\n child.stdout?.on('data', (d: Buffer) => { stdout += d.toString(); });\n child.stderr?.on('data', (d: Buffer) => { stderr += d.toString(); });\n const timer = setTimeout(() => { child.kill(); reject(new Error(`Timed out after ${opts?.timeout ?? 120_000}ms`)); }, opts?.timeout ?? 120_000);\n child.on('close', (code) => { clearTimeout(timer); if (code !== 0) reject(new Error(`Exit code ${code}: ${stderr.slice(0, 500)}`)); else resolve({ stdout, stderr }); });\n child.on('error', (err) => { clearTimeout(timer); reject(err); });\n });\n}\n\n// ---------------------------------------------------------------------------\n// Cron health monitoring — detects late/failed jobs and sends alerts\n// ---------------------------------------------------------------------------\n\nconst LATE_THRESHOLD_MS = 5 * 60 * 1000; // 5 minutes grace period\n\ninterface CronAlert {\n type: 'late_standup' | 'cron_failure';\n agentCodeName: string;\n agentDisplayName: string;\n jobName: string;\n taskName: string;\n schedule: string;\n jobId: string;\n detail: string;\n}\n\nasync function monitorCronHealth(agentStates: AgentState[]): Promise<void> {\n const alerts: CronAlert[] = [];\n const now = Date.now();\n\n for (const agent of agentStates) {\n if (!agent.gatewayRunning || !agent.gatewayPort) continue;\n\n const token = readGatewayToken(agent.codeName);\n const gwArgs = ['--url', `ws://127.0.0.1:${agent.gatewayPort}`, ...(token ? ['--token', token] : [])];\n\n let jobs: Array<{\n id: string;\n name: string;\n enabled: boolean;\n state?: {\n nextRunAtMs?: number;\n lastRunAtMs?: number;\n lastRunStatus?: string;\n lastDelivered?: boolean;\n consecutiveErrors?: number;\n };\n }> = [];\n\n try {\n const cliBin = resolveAgentFramework(agent.codeName).cliBinary ?? 'openclaw';\n const { stdout } = await execFilePromise(cliBin, ['--profile', agent.codeName, 'cron', 'list', '--json', ...gwArgs]);\n const parsed = JSON.parse(stdout);\n jobs = parsed.jobs ?? [];\n } catch {\n continue;\n }\n\n for (const job of jobs) {\n if (!job.enabled || !job.name.startsWith('aug:')) continue;\n const alertKey = `${agent.codeName}:${job.id}`;\n\n // Look up human-readable task info\n const displayInfo = taskDisplayInfo.get(`${agent.codeName}:${job.name}`);\n const taskName = displayInfo?.taskName ?? job.name;\n const schedule = displayInfo?.schedule ?? '';\n const agentDisplayName = displayInfo?.agentDisplayName ?? agent.codeName;\n\n // Check for late jobs — nextRunAtMs is in the past by more than the threshold\n if (job.state?.nextRunAtMs && job.state.nextRunAtMs + LATE_THRESHOLD_MS < now) {\n if (!alertedJobs.has(`late:${alertKey}`)) {\n const minsLate = Math.round((now - job.state.nextRunAtMs) / 60_000);\n alerts.push({\n type: 'late_standup',\n agentCodeName: agent.codeName,\n agentDisplayName,\n jobName: job.name,\n taskName,\n schedule,\n jobId: job.id,\n detail: `Job is ${minsLate}m late (expected at ${new Date(job.state.nextRunAtMs).toISOString()})`,\n });\n alertedJobs.add(`late:${alertKey}`);\n }\n } else {\n // Clear the late alert if the job is no longer late\n alertedJobs.delete(`late:${alertKey}`);\n }\n\n // Check for failed runs\n if (job.state?.lastRunStatus === 'error' || (job.state?.consecutiveErrors && job.state.consecutiveErrors > 0)) {\n if (!alertedJobs.has(`fail:${alertKey}`)) {\n alerts.push({\n type: 'cron_failure',\n agentCodeName: agent.codeName,\n agentDisplayName,\n jobName: job.name,\n taskName,\n schedule,\n jobId: job.id,\n detail: `Last run failed (${job.state.consecutiveErrors ?? 1} consecutive error(s))`,\n });\n alertedJobs.add(`fail:${alertKey}`);\n }\n } else {\n alertedJobs.delete(`fail:${alertKey}`);\n }\n }\n }\n\n if (alerts.length === 0) return;\n\n // Log all alerts\n for (const alert of alerts) {\n log(`ALERT [${alert.type}] ${alert.agentCodeName}/${alert.jobName}: ${alert.detail}`);\n }\n\n // Send to Slack webhook if configured\n if (alertSlackWebhook) {\n await sendSlackAlert(alerts);\n }\n\n // Post to API for dashboard visibility\n try {\n await api.post('/host/cron-alerts', { alerts });\n } catch {\n // Non-fatal — API may not have this endpoint yet\n }\n}\n\n/**\n * Call Telegram Bot API using Node's https module (not fetch).\n * Node's native fetch (undici) can't reach api.telegram.org on some networks.\n */\nfunction telegramApiCall(botToken: string, method: string, body: unknown): Promise<{ ok: boolean; description?: string }> {\n return new Promise((resolve, reject) => {\n const postData = JSON.stringify(body);\n const req = https.request({\n hostname: 'api.telegram.org',\n port: 443,\n path: `/bot${botToken}/${method}`,\n method: 'POST',\n family: 4,\n timeout: 10_000,\n headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(postData) },\n }, (res) => {\n let data = '';\n res.on('data', (d) => { data += d; });\n res.on('end', () => {\n try { resolve(JSON.parse(data)); } catch { reject(new Error('Invalid JSON from Telegram API')); }\n });\n });\n req.on('error', reject);\n req.on('timeout', () => { req.destroy(); reject(new Error('Telegram API timeout')); });\n req.write(postData);\n req.end();\n });\n}\n\nasync function sendSlackWebhookMessage(text: string): Promise<void> {\n if (!alertSlackWebhook) {\n log('sendSlackWebhookMessage: no alertSlackWebhook configured — message dropped');\n return;\n }\n try {\n const response = await fetch(alertSlackWebhook, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ text }),\n });\n if (!response.ok) {\n log(`Slack webhook failed: ${response.status} ${response.statusText}`);\n }\n } catch (err) {\n log(`Slack webhook error: ${(err as Error).message}`);\n }\n}\n\n/**\n * Post a message to a specific Slack channel using the agent's bot token\n * cached from channel_configs during refresh. Returns true if sent successfully.\n */\nasync function sendSlackChannelMessage(agentCodeName: string, channelId: string, text: string): Promise<boolean> {\n const botToken = agentChannelTokens.get(agentCodeName)?.slack;\n if (!botToken) {\n log(`No Slack bot token cached for '${agentCodeName}' — cannot post to ${channelId}`);\n return false;\n }\n\n try {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 5_000);\n try {\n const response = await fetch('https://slack.com/api/chat.postMessage', {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${botToken}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ channel: channelId, text }),\n signal: controller.signal,\n });\n clearTimeout(timeout);\n const data = await response.json() as { ok: boolean; error?: string };\n if (!data.ok) {\n log(`Slack chat.postMessage failed for '${agentCodeName}' to ${channelId}: ${data.error}`);\n return false;\n }\n return true;\n } finally {\n clearTimeout(timeout);\n }\n } catch (err) {\n log(`Slack channel message error for '${agentCodeName}': ${(err as Error).message}`);\n return false;\n }\n}\n\nasync function sendSlackAlert(alerts: CronAlert[]): Promise<void> {\n const blocks = alerts.map((a) => {\n const emoji = a.type === 'late_standup' ? ':warning:' : ':x:';\n const label = a.type === 'late_standup' ? 'Late' : 'Failed';\n const scheduleInfo = a.schedule ? ` (${a.schedule})` : '';\n return `${emoji} *${label}* — *${a.agentDisplayName}* / ${a.taskName}${scheduleInfo}\\n${a.detail}`;\n });\n\n await sendSlackWebhookMessage(`:rotating_light: *Cron Health Alert*\\n\\n${blocks.join('\\n\\n')}`);\n}\n\n/**\n * Send a task notification to a specific channel (Slack or Telegram).\n */\nasync function sendTaskNotification(agentCodeName: string, channel: string, to: string, text: string): Promise<void> {\n const tokens = agentChannelTokens.get(agentCodeName);\n\n if (channel === 'slack') {\n const botToken = tokens?.slack;\n const channelId = to.replace(/^channel:/, '');\n if (botToken) {\n const sent = await sendSlackChannelMessage(agentCodeName, channelId, text);\n if (sent) return;\n }\n log(`No Slack bot token for '${agentCodeName}' — targeted notification dropped`);\n } else if (channel === 'telegram') {\n const botToken = tokens?.telegram;\n const chatId = to.replace(/^chat:/, '');\n if (!botToken) {\n log(`No Telegram bot token for '${agentCodeName}' — notification dropped`);\n return;\n }\n const allowedChats = tokens?.telegramAllowedChats;\n if (allowedChats && allowedChats.length > 0 && !allowedChats.includes(chatId)) {\n log(`Telegram chat ${chatId} not in allowed_chat_ids for '${agentCodeName}'`);\n return;\n }\n try {\n const result = await telegramApiCall(botToken, 'sendMessage', { chat_id: chatId, text });\n if (!result.ok) {\n log(`Telegram sendMessage failed for '${agentCodeName}': ${result.description}`);\n } else {\n log(`Telegram notification sent for '${agentCodeName}' to chat ${chatId}`);\n }\n } catch (err) {\n log(`Telegram API error for '${agentCodeName}': ${(err as Error).message}`);\n }\n } else {\n log(`Unknown notify_channel '${channel}' for '${agentCodeName}'`);\n }\n}\n\n/**\n * Generate provision artifacts without writing to disk.\n * Returns the list of artifacts (relativePath + content) for comparison.\n */\nfunction generateArtifacts(\n agent: { agent_id: string; code_name: string; display_name: string; status: string; environment: string },\n refreshData: {\n agent: Record<string, unknown>;\n charter: { raw_content: string; version: string } | null;\n tools: { raw_content: string; version: string } | null;\n channel_configs: Record<string, { config: unknown; status: string }> | null;\n team_channel_policy: {\n team_id: string;\n allowed_channels: string[];\n denied_channels: string[];\n require_elevated_for_pii: boolean;\n } | null;\n team: { name: string; description: string | null; settings?: Record<string, unknown> } | null;\n scheduled_tasks?: unknown;\n },\n adapter: FrameworkAdapter,\n): { relativePath: string; content: string }[] {\n if (!refreshData.charter || !refreshData.tools) {\n throw new Error('No charter/tools available');\n }\n\n const charterContent = refreshData.charter.raw_content;\n const toolsContent = refreshData.tools.raw_content;\n\n const charterParsed = extractFrontmatter(charterContent);\n if (!charterParsed.frontmatter) {\n throw new Error(`Failed to parse CHARTER.md frontmatter: ${charterParsed.error ?? 'unknown'}`);\n }\n\n const toolsParsed = extractFrontmatter(toolsContent);\n if (!toolsParsed.frontmatter) {\n throw new Error(`Failed to parse TOOLS.md frontmatter: ${toolsParsed.error ?? 'unknown'}`);\n }\n\n const charterFrontmatter = charterParsed.frontmatter as unknown as CharterFrontmatter;\n const toolsFrontmatter = toolsParsed.frontmatter as unknown as ToolsFrontmatter;\n\n const configuredChannels = Object.keys(refreshData.channel_configs ?? {}) as ChannelId[];\n\n const agentChannelPolicy: ChannelPolicy = {\n policy: 'allowlist',\n allowed: configuredChannels,\n denied: [],\n require_approval_to_change: true,\n };\n\n let orgChannelPolicy: OrgChannelPolicy | undefined;\n const policyData = refreshData.team_channel_policy;\n\n if (policyData) {\n orgChannelPolicy = {\n organization_id: policyData.team_id,\n allowed_channels: (policyData.allowed_channels ?? []) as ChannelId[],\n denied_channels: (policyData.denied_channels ?? []) as ChannelId[],\n require_elevated_for_pii: policyData.require_elevated_for_pii ?? false,\n };\n }\n\n const resolvedChannels = resolveChannels(agentChannelPolicy, orgChannelPolicy);\n const effectiveChannels = agent.status === 'paused' ? [] : resolvedChannels;\n\n const provisionInput: ProvisionInput = {\n agent: refreshData.agent as any,\n charterFrontmatter,\n charterContent,\n toolsFrontmatter,\n toolsContent,\n resolvedChannels: effectiveChannels,\n deploymentTarget: 'local_docker' as DeploymentTarget,\n gatewayPort: 9000,\n team: refreshData.team ?? undefined,\n };\n\n const provisionOutput = provision(provisionInput, adapter.id);\n return provisionOutput.artifacts;\n}\n\n// ---------------------------------------------------------------------------\n// Cleanup helper (for revoked agents)\n// ---------------------------------------------------------------------------\n\nasync function cleanupAgentFiles(codeName: string, agentDir: string): Promise<void> {\n // Remove the provision directory\n if (existsSync(agentDir)) {\n try {\n rmSync(agentDir, { recursive: true, force: true });\n log(`Removed provision directory for '${codeName}'`);\n } catch (err) {\n log(`Failed to remove provision dir for '${codeName}': ${(err as Error).message}`);\n }\n }\n\n // Deregister from the framework runtime\n try {\n const adapter = resolveAgentFramework(codeName);\n const registered = await getOrCacheRegisteredAgents(adapter, codeName);\n if (registered.has(codeName)) {\n await adapter.deregisterAgent(codeName);\n registered.delete(codeName);\n log(`Deregistered '${codeName}' from ${adapter.label}`);\n }\n } catch (err) {\n log(`Failed to deregister '${codeName}': ${(err as Error).message}`);\n }\n}\n\n// ---------------------------------------------------------------------------\n// IPC + lifecycle\n// ---------------------------------------------------------------------------\n\nfunction startGatewayPool(): void {\n if (gatewayPool) return;\n\n gatewayPool = new GatewayClientPool();\n\n gatewayPool.on('connected', (codeName: string) => {\n log(`Gateway WebSocket connected for '${codeName}'`);\n });\n\n gatewayPool.on('disconnected', (codeName: string) => {\n log(`Gateway WebSocket disconnected for '${codeName}'`);\n });\n\n gatewayPool.on('error', (err: Error, codeName: string) => {\n log(`Gateway WebSocket error for '${codeName}': ${err.message}`);\n });\n\n gatewayPool.on('event', (evt: PooledGatewayEvent) => {\n // Forward to parent via IPC\n send({ type: 'gateway-event', event: evt.event, payload: evt.payload, agentCodeName: evt.agentCodeName });\n\n // Forward to API (fire and forget)\n getHostId().then((hostId) => {\n if (!hostId) return;\n api.post('/host/events', {\n host_id: hostId,\n agent_code_name: evt.agentCodeName,\n event_type: evt.event,\n payload: evt.payload,\n timestamp: new Date().toISOString(),\n }).catch((err) => {\n log(`Failed to forward gateway event: ${(err as Error).message}`);\n });\n }).catch(() => {\n // Ignore — host ID resolution is best-effort here\n });\n });\n}\n\nfunction stopGatewayPool(): void {\n if (gatewayPool) {\n gatewayPool.disconnectAll();\n gatewayPool = null;\n }\n}\n\nfunction startPolling(): void {\n if (!config || running) return;\n running = true;\n\n log(`Starting poll loop (interval=${config.intervalMs}ms, configDir=${config.configDir})`);\n\n // Run migration, then first poll, then start gateway pool\n void migrateToProfiles().then(() => {\n startGatewayPool();\n return pollCycle();\n }).then(() => {\n scheduleNext();\n });\n}\n\nfunction scheduleNext(): void {\n if (!running || !config) return;\n pollTimer = setTimeout(() => {\n void pollCycle().then(scheduleNext);\n }, config.intervalMs);\n}\n\nasync function stopPolling(): Promise<void> {\n running = false;\n if (pollTimer) {\n clearTimeout(pollTimer);\n pollTimer = null;\n }\n stopRealtimeChat();\n stopGatewayPool();\n\n // Stop all per-agent gateway processes\n await stopAllGateways();\n}\n\n// ---------------------------------------------------------------------------\n// Public API — called directly by the CLI command (no fork/IPC)\n// ---------------------------------------------------------------------------\n\n/**\n * Start the manager poll loop. Call this directly from the CLI command.\n * The process stays alive running the poll loop until stopManager() is called\n * or a signal is received.\n */\nexport function startManager(opts: { intervalMs: number; configDir: string }): void {\n config = opts;\n startPolling();\n}\n\n/**\n * Stop the manager poll loop gracefully.\n */\nexport async function stopManager(): Promise<void> {\n await stopPolling();\n}\n\n// Graceful shutdown on signals\nfor (const sig of ['SIGTERM', 'SIGINT'] as const) {\n process.on(sig, () => {\n log(`Received ${sig}, shutting down`);\n void stopPolling().then(() => {\n process.exit(0);\n });\n });\n}\n\n// If parent disconnects, exit\nprocess.on('disconnect', () => {\n log('Parent disconnected, exiting');\n void stopPolling().then(() => {\n process.exit(0);\n });\n});\n","/**\n * Gateway WebSocket Client — connects to the OpenClaw gateway event stream\n * and emits typed events for consumption by the manager worker.\n */\n\nimport { EventEmitter } from 'node:events';\nimport WebSocket from 'ws';\n\nconst DEFAULT_PORT = 18789;\nconst RECONNECT_INITIAL_MS = 1_000;\nconst RECONNECT_BASE_MS = 5_000;\nconst RECONNECT_MAX_MS = 30_000;\nconst HEARTBEAT_INTERVAL_MS = 30_000;\n\nexport interface GatewayEvent {\n type: 'event';\n event: string;\n payload: unknown;\n seq?: number;\n stateVersion?: number;\n}\n\nexport interface GatewayClientOptions {\n port?: number;\n token?: string;\n}\n\nexport interface PooledGatewayEvent extends GatewayEvent {\n agentCodeName: string;\n}\n\nexport class GatewayClient extends EventEmitter {\n private readonly port: number;\n private readonly token: string | undefined;\n private ws: WebSocket | null = null;\n private _connected = false;\n private _everConnected = false;\n private reconnectAttempts = 0;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private heartbeatTimer: ReturnType<typeof setInterval> | null = null;\n private pongReceived = true;\n private intentionalClose = false;\n private pendingRpc = new Map<string, { resolve: (v: unknown) => void; reject: (e: Error) => void; timer: ReturnType<typeof setTimeout> }>();\n private rpcSeq = 0;\n\n constructor(options: GatewayClientOptions = {}) {\n super();\n this.port = options.port ?? Number(process.env['OPENCLAW_GATEWAY_PORT']) ?? DEFAULT_PORT;\n this.token = options.token ?? process.env['OPENCLAW_GATEWAY_TOKEN'];\n }\n\n get connected(): boolean {\n return this._connected;\n }\n\n connect(): void {\n this.intentionalClose = false;\n this.doConnect();\n }\n\n disconnect(): void {\n this.intentionalClose = true;\n this.clearTimers();\n\n if (this.ws) {\n this.ws.removeAllListeners();\n this.ws.close(1000);\n this.ws = null;\n }\n\n if (this._connected) {\n this._connected = false;\n this.emit('disconnected');\n }\n }\n\n // ── Private ──────────────────────────────────────────────────────────────\n\n private doConnect(): void {\n const url = `ws://127.0.0.1:${this.port}`;\n\n try {\n const headers: Record<string, string> = {};\n if (this.token) {\n headers['Authorization'] = `Bearer ${this.token}`;\n }\n\n this.ws = new WebSocket(url, { headers });\n } catch (err) {\n this.emit('error', err);\n this.scheduleReconnect();\n return;\n }\n\n this.ws.on('open', () => {\n // Wait for challenge message from gateway — connection established, auth pending\n });\n\n this.ws.on('message', (data: WebSocket.Data) => {\n try {\n const msg = JSON.parse(data.toString());\n this.handleMessage(msg);\n } catch {\n // Ignore non-JSON messages\n }\n });\n\n this.ws.on('close', (code: number, reason: Buffer) => {\n this.clearHeartbeat();\n if (this._connected) {\n this._connected = false;\n this.emit('disconnected');\n } else if (!this._everConnected) {\n // Never connected — log the close reason for debugging\n this.emit('error', new Error(`WebSocket closed before auth (code=${code}, reason=${reason?.toString() || 'none'})`));\n }\n if (!this.intentionalClose) {\n this.scheduleReconnect();\n }\n });\n\n this.ws.on('error', (err: Error) => {\n // Suppress ECONNREFUSED before first successful connection — the gateway\n // may still be booting. The reconnect loop will retry with backoff.\n if (!this._everConnected && (err as NodeJS.ErrnoException).code === 'ECONNREFUSED') {\n return;\n }\n this.emit('error', err);\n });\n\n this.ws.on('pong', () => {\n this.pongReceived = true;\n });\n }\n\n private handleMessage(msg: Record<string, unknown>): void {\n switch (msg.type) {\n case 'challenge':\n // Respond to challenge handshake\n this.sendJson({\n type: 'connect',\n nonce: msg.nonce,\n role: 'operator',\n scopes: ['events:read'],\n });\n break;\n\n case 'hello-ok':\n this._connected = true;\n this._everConnected = true;\n this.reconnectAttempts = 0;\n this.startHeartbeat();\n this.emit('connected');\n break;\n\n case 'event':\n this.emit('event', {\n type: 'event',\n event: msg.event,\n payload: msg.payload,\n seq: msg.seq,\n stateVersion: msg.stateVersion,\n } as GatewayEvent);\n break;\n\n case 'heartbeat':\n case 'tick':\n // Gateway-initiated heartbeat — no action needed\n break;\n\n case 'rpc-result':\n case 'rpc-error': {\n const rpcId = msg.id as string;\n const pending = this.pendingRpc.get(rpcId);\n if (pending) {\n this.pendingRpc.delete(rpcId);\n clearTimeout(pending.timer);\n if (msg.type === 'rpc-error') {\n pending.reject(new Error((msg.error as string) ?? 'RPC error'));\n } else {\n pending.resolve(msg.result);\n }\n }\n break;\n }\n\n default:\n // Unknown message type — check if it's an RPC response with a matching id\n if (msg.id && typeof msg.id === 'string') {\n const pending = this.pendingRpc.get(msg.id);\n if (pending) {\n this.pendingRpc.delete(msg.id);\n clearTimeout(pending.timer);\n if (msg.error) {\n pending.reject(new Error(String(msg.error)));\n } else {\n pending.resolve(msg);\n }\n }\n }\n break;\n }\n }\n\n /**\n * Send an RPC call to the gateway and wait for a response.\n * Returns the response payload or throws on timeout/error.\n */\n sendRpc(method: string, params: Record<string, unknown> = {}, timeoutMs = 10_000): Promise<unknown> {\n return new Promise((resolve, reject) => {\n if (!this._connected || this.ws?.readyState !== WebSocket.OPEN) {\n reject(new Error('Gateway not connected'));\n return;\n }\n const id = `rpc-${++this.rpcSeq}-${Date.now()}`;\n const timer = setTimeout(() => {\n this.pendingRpc.delete(id);\n reject(new Error(`RPC ${method} timed out after ${timeoutMs}ms`));\n }, timeoutMs);\n this.pendingRpc.set(id, { resolve, reject, timer });\n this.sendJson({ type: 'rpc', id, method, params });\n });\n }\n\n private sendJson(obj: unknown): void {\n if (this.ws?.readyState === WebSocket.OPEN) {\n this.ws.send(JSON.stringify(obj));\n }\n }\n\n private startHeartbeat(): void {\n this.clearHeartbeat();\n this.pongReceived = true;\n\n this.heartbeatTimer = setInterval(() => {\n if (!this.pongReceived) {\n // Stale connection — force reconnect\n this.ws?.terminate();\n return;\n }\n this.pongReceived = false;\n this.ws?.ping();\n }, HEARTBEAT_INTERVAL_MS);\n }\n\n private clearHeartbeat(): void {\n if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer);\n this.heartbeatTimer = null;\n }\n }\n\n private scheduleReconnect(): void {\n if (this.intentionalClose) return;\n\n // First retry uses a short delay (gateway may still be booting), then exponential backoff\n const delay = this.reconnectAttempts === 0\n ? RECONNECT_INITIAL_MS\n : Math.min(RECONNECT_BASE_MS * Math.pow(2, this.reconnectAttempts - 1), RECONNECT_MAX_MS);\n this.reconnectAttempts++;\n\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null;\n this.doConnect();\n }, delay);\n }\n\n private clearTimers(): void {\n this.clearHeartbeat();\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// GatewayClientPool — manages multiple per-agent gateway connections\n// ---------------------------------------------------------------------------\n\nexport class GatewayClientPool extends EventEmitter {\n private clients = new Map<string, GatewayClient>();\n\n addAgent(codeName: string, port: number, token?: string): void {\n if (this.clients.has(codeName)) {\n this.removeAgent(codeName);\n }\n\n const client = new GatewayClient({ port, token });\n\n client.on('connected', () => {\n this.emit('connected', codeName);\n });\n\n client.on('disconnected', () => {\n this.emit('disconnected', codeName);\n });\n\n client.on('error', (err: Error) => {\n this.emit('error', err, codeName);\n });\n\n client.on('event', (evt: GatewayEvent) => {\n const pooledEvent: PooledGatewayEvent = {\n ...evt,\n agentCodeName: codeName,\n };\n this.emit('event', pooledEvent);\n });\n\n this.clients.set(codeName, client);\n client.connect();\n }\n\n removeAgent(codeName: string): void {\n const client = this.clients.get(codeName);\n if (client) {\n client.disconnect();\n this.clients.delete(codeName);\n }\n }\n\n hasAgent(codeName: string): boolean {\n return this.clients.has(codeName);\n }\n\n isConnected(codeName: string): boolean {\n return this.clients.get(codeName)?.connected ?? false;\n }\n\n /**\n * Send an RPC call to a specific agent's gateway.\n * Returns the response or throws on timeout/error/not connected.\n */\n async sendRpc(codeName: string, method: string, params: Record<string, unknown> = {}, timeoutMs = 10_000): Promise<unknown> {\n const client = this.clients.get(codeName);\n if (!client) throw new Error(`No gateway client for agent '${codeName}'`);\n return client.sendRpc(method, params, timeoutMs);\n }\n\n disconnectAll(): void {\n for (const [, client] of this.clients) {\n client.disconnect();\n }\n this.clients.clear();\n }\n\n get size(): number {\n return this.clients.size;\n }\n}\n","/**\n * Persistent session manager for Claude Code agents.\n *\n * Spawns a long-running `claude --channels` process per agent, monitors\n * health, auto-restarts with backoff, and injects tasks via the webhook\n * channel HTTP endpoint.\n */\n\nimport { spawn, execSync, type ChildProcess } from 'node:child_process';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport { existsSync, readFileSync } from 'node:fs';\n\nexport interface PersistentSessionConfig {\n codeName: string;\n agentId: string;\n projectDir: string;\n mcpConfigPath: string;\n claudeMdPath: string;\n channels: string[]; // e.g. ['plugin:telegram@claude-plugins-official']\n devChannels: string[]; // custom channels needing --dangerously-load-development-channels\n log: (msg: string) => void;\n}\n\nexport interface PersistentSession {\n codeName: string;\n process: ChildProcess | null;\n taskChannelPort: number | null;\n startedAt: number | null;\n restartCount: number;\n status: 'starting' | 'running' | 'stopped' | 'crashed';\n}\n\nconst sessions = new Map<string, PersistentSession>();\n\n// Backoff: 5s, 10s, 20s, 40s, 60s max\nfunction getBackoffMs(restartCount: number): number {\n return Math.min(5000 * Math.pow(2, restartCount), 60_000);\n}\n\n/**\n * Start a persistent Claude Code session for an agent.\n * If already running, returns the existing session.\n */\nexport function startPersistentSession(config: PersistentSessionConfig): PersistentSession {\n const existing = sessions.get(config.codeName);\n if (existing && existing.status === 'running' && existing.process && !existing.process.killed) {\n return existing;\n }\n\n const session: PersistentSession = {\n codeName: config.codeName,\n process: null,\n taskChannelPort: null,\n startedAt: null,\n restartCount: existing?.restartCount ?? 0,\n status: 'starting',\n };\n sessions.set(config.codeName, session);\n\n spawnSession(config, session);\n return session;\n}\n\nfunction spawnSession(config: PersistentSessionConfig, session: PersistentSession): void {\n const { codeName, projectDir, mcpConfigPath, claudeMdPath, channels, devChannels, log } = config;\n\n const args: string[] = [];\n\n // Add official channel plugins\n if (channels.length > 0) {\n args.push('--channels', ...channels);\n }\n\n // Add custom development channels (not on Anthropic's allowlist)\n if (devChannels.length > 0) {\n args.push('--dangerously-load-development-channels', ...devChannels);\n }\n\n // MCP config for augmented tools + task channel\n args.push('--mcp-config', mcpConfigPath);\n\n // Separate channels config (Slack etc.) to avoid duplicate loading\n const channelsConfigPath = join(projectDir, '.mcp-channels.json');\n if (existsSync(channelsConfigPath)) {\n args.push('--mcp-config', channelsConfigPath);\n }\n\n // Agent identity\n if (existsSync(claudeMdPath)) {\n args.push('--system-prompt-file', claudeMdPath);\n }\n\n // Bypass permissions for autonomous operation.\n // --allow-dangerously-skip-permissions enables the option without a confirmation dialog.\n // --dangerously-skip-permissions then activates it.\n args.push('--allow-dangerously-skip-permissions');\n args.push('--dangerously-skip-permissions');\n\n // Session name for identification\n args.push('--name', `agt-${codeName}`);\n\n log(`[persistent-session] Starting session for '${codeName}' with args: ${args.join(' ')}`);\n\n // Channels require a real TTY (interactive mode). Without a TTY, Claude\n // auto-switches to print mode and exits after responding. Use tmux to\n // provide a real terminal. The session stays alive indefinitely.\n const tmuxSession = `agt-${codeName}`;\n\n // Kill any existing tmux session for this agent\n try {\n execSync(`tmux kill-session -t ${tmuxSession} 2>/dev/null`, { stdio: 'ignore' });\n } catch { /* no existing session */ }\n\n // Load .env.integrations into the tmux session environment\n const envIntegrationsPath = join(projectDir, '.env.integrations');\n let envPrefix = '';\n if (existsSync(envIntegrationsPath)) {\n try {\n const envContent = readFileSync(envIntegrationsPath, 'utf-8');\n const envVars = envContent.split('\\n')\n .filter((line: string) => line && !line.startsWith('#') && line.includes('='))\n .map((line: string) => {\n const eqIdx = line.indexOf('=');\n const key = line.slice(0, eqIdx);\n const value = line.slice(eqIdx + 1);\n return `${key}=${JSON.stringify(value)}`;\n })\n .join(' ');\n if (envVars) envPrefix = `env ${envVars} `;\n } catch { /* non-fatal */ }\n }\n\n // Build the full claude command\n const initPrompt = 'You are now online. Wait for messages from your channels (Telegram, Slack) and respond to them. Use your kanban tools to track work.';\n const claudeCmd = `${envPrefix}claude ${JSON.stringify(initPrompt)} ${args.map(a => a.includes(' ') ? JSON.stringify(a) : a).join(' ')}`;\n\n // Start tmux session with claude in it\n const child = spawn('tmux', [\n 'new-session', '-d', '-s', tmuxSession,\n '-c', projectDir,\n claudeCmd,\n ], {\n cwd: projectDir,\n stdio: ['ignore', 'pipe', 'pipe'],\n env: process.env,\n });\n\n session.process = child; // tmux spawner process (exits quickly)\n session.startedAt = Date.now();\n session.status = 'running';\n\n // tmux new-session -d exits immediately. Monitor the tmux session instead.\n child.on('close', (code) => {\n if (code !== 0) {\n log(`[persistent-session] Failed to create tmux session for '${codeName}' (exit ${code})`);\n session.status = 'crashed';\n session.process = null;\n return;\n }\n log(`[persistent-session] tmux session '${tmuxSession}' created for '${codeName}'`);\n\n // Auto-accept startup dialogs by polling the tmux pane content.\n // Only send keystrokes when we detect a specific dialog on screen.\n // Most dialogs persist once approved, but --dangerously-load-development-channels\n // always prompts. We check the screen content to avoid sending keystrokes to the live prompt.\n const acceptDialogs = async () => {\n for (let i = 0; i < 15; i++) { // check every 2s for up to 30s\n await new Promise((r) => setTimeout(r, 2000));\n try {\n const { execSync: es } = await import('node:child_process');\n const screen = es(`tmux capture-pane -t ${tmuxSession} -p 2>/dev/null`, { encoding: 'utf-8' });\n\n if (screen.includes('Yes, I trust this folder')) {\n es(`tmux send-keys -t ${tmuxSession} Enter`, { stdio: 'ignore' });\n log(`[persistent-session] Auto-accepted workspace trust for '${codeName}'`);\n continue;\n }\n if (screen.includes('I am using this for local development')) {\n es(`tmux send-keys -t ${tmuxSession} Enter`, { stdio: 'ignore' });\n log(`[persistent-session] Auto-accepted dev channels for '${codeName}'`);\n continue;\n }\n if (screen.includes('Enter to confirm') && screen.includes('MCP')) {\n es(`tmux send-keys -t ${tmuxSession} Enter`, { stdio: 'ignore' });\n log(`[persistent-session] Auto-accepted MCP servers for '${codeName}'`);\n continue;\n }\n if (screen.includes('Yes, I accept') && screen.includes('Bypass Permissions')) {\n es(`tmux send-keys -t ${tmuxSession} 2`, { stdio: 'ignore' });\n await new Promise((r) => setTimeout(r, 300));\n es(`tmux send-keys -t ${tmuxSession} Enter`, { stdio: 'ignore' });\n log(`[persistent-session] Auto-accepted bypass permissions for '${codeName}'`);\n continue;\n }\n // If we see the prompt (❯), dialogs are done\n if (screen.includes('❯') && !screen.includes('Enter to confirm')) {\n log(`[persistent-session] Session ready for '${codeName}' — no more dialogs`);\n break;\n }\n } catch { /* tmux session may have died */ break; }\n }\n };\n acceptDialogs().catch(() => {});\n });\n\n child.on('error', (err) => {\n log(`[persistent-session] Failed to start tmux for '${codeName}': ${err.message}`);\n session.status = 'crashed';\n });\n}\n\n/**\n * Stop a persistent session gracefully.\n */\nexport function stopPersistentSession(codeName: string, log: (msg: string) => void): void {\n const session = sessions.get(codeName);\n if (!session) return;\n\n log(`[persistent-session] Stopping session for '${codeName}'`);\n session.status = 'stopped';\n\n // Kill the tmux session\n try {\n execSync(`tmux kill-session -t agt-${codeName} 2>/dev/null`, { stdio: 'ignore' });\n } catch { /* session may already be dead */ }\n\n // Legacy: also kill child process if it exists\n if (session.process && !session.process.killed) {\n session.process.kill('SIGTERM');\n }\n\n // Force kill after 10s\n setTimeout(() => {\n if (session.process && !session.process.killed) {\n session.process.kill('SIGKILL');\n }\n }, 10_000);\n\n sessions.delete(codeName);\n}\n\n/**\n * Inject a task/message into a persistent session.\n * Tries the webhook channel first, falls back to stdin stream-json.\n */\nexport async function injectMessage(\n codeName: string,\n type: 'task' | 'chat' | 'system',\n content: string,\n meta?: Record<string, string>,\n): Promise<boolean> {\n const session = sessions.get(codeName);\n if (!session || session.status !== 'running' || !session.process) {\n return false;\n }\n\n // Try webhook channel if available\n if (session.taskChannelPort) {\n try {\n const res = await fetch(`http://127.0.0.1:${session.taskChannelPort}`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ type, content, meta }),\n signal: AbortSignal.timeout(10_000),\n });\n if (res.ok) return true;\n } catch { /* fall through to stdin */ }\n }\n\n // Fallback: inject via tmux send-keys\n try {\n const prefix = meta?.task_name ? `[Task: ${meta.task_name}] ` : '';\n const text = prefix + content;\n // Escape single quotes for shell\n const escaped = text.replace(/'/g, \"'\\\\''\");\n execSync(`tmux send-keys -t agt-${codeName} '${escaped}' Enter`, { stdio: 'ignore' });\n return true;\n } catch {\n return false;\n }\n\n return false;\n}\n\n/**\n * Get the current state of a persistent session.\n */\nexport function getSessionState(codeName: string): PersistentSession | null {\n return sessions.get(codeName) ?? null;\n}\n\n/**\n * Check if a persistent session is healthy (tmux session exists).\n */\nexport function isSessionHealthy(codeName: string): boolean {\n const session = sessions.get(codeName);\n if (!session || session.status !== 'running') return false;\n // Check if tmux session is still alive\n try {\n execSync(`tmux has-session -t agt-${codeName} 2>/dev/null`, { stdio: 'ignore' });\n return true;\n } catch {\n // tmux session died — mark as crashed for restart\n session.status = 'crashed';\n return false;\n }\n}\n\n/**\n * Reset restart counter (call after successful task completion).\n */\nexport function resetRestartCount(codeName: string): void {\n const session = sessions.get(codeName);\n if (session) session.restartCount = 0;\n}\n\n/**\n * Stop all persistent sessions (called on manager shutdown).\n */\nexport function stopAllSessions(log: (msg: string) => void): void {\n for (const codeName of sessions.keys()) {\n stopPersistentSession(codeName, log);\n }\n}\n\n/**\n * Get project dir for a Claude Code agent.\n */\nexport function getProjectDir(codeName: string): string {\n return join(homedir(), '.augmented', codeName, 'project');\n}\n","/**\n * Supabase Realtime subscriptions for the manager.\n *\n * Replaces polling with WebSocket subscriptions:\n * - direct_chat_messages INSERT → instant chat delivery (~100ms vs 2s)\n * - agent_doc_versions INSERT → instant drift detection (~100ms vs 5min)\n * - host_agents INSERT/DELETE → instant agent assignment changes\n *\n * Falls back to polling if the Realtime connection drops.\n */\n\nimport { createClient, type SupabaseClient, type RealtimeChannel } from '@supabase/supabase-js';\n\n// ---------------------------------------------------------------------------\n// Shared client\n// ---------------------------------------------------------------------------\n\nlet client: SupabaseClient | null = null;\nlet chatChannel: RealtimeChannel | null = null;\nlet driftChannel: RealtimeChannel | null = null;\nlet assignChannel: RealtimeChannel | null = null;\nlet configChannel: RealtimeChannel | null = null;\nlet kanbanChannel: RealtimeChannel | null = null;\nlet connected = false;\nlet tearingDown = false; // Guard against re-entrant teardown\n\nexport interface RealtimeConfig {\n supabaseUrl: string;\n supabaseAnonKey: string;\n token: string;\n log: (msg: string) => void;\n}\n\nfunction ensureClient(config: RealtimeConfig): SupabaseClient {\n if (client) return client;\n\n client = createClient(config.supabaseUrl, config.supabaseAnonKey, {\n global: {\n headers: { Authorization: `Bearer ${config.token}` },\n },\n realtime: {\n params: { apikey: config.supabaseAnonKey },\n },\n });\n\n client.realtime.setAuth(config.token);\n return client;\n}\n\n// ---------------------------------------------------------------------------\n// Direct chat subscription\n// ---------------------------------------------------------------------------\n\nexport interface ChatMessagePayload {\n id: string;\n agent_id: string;\n session_id: string;\n content: string;\n status: string;\n created_at: string;\n}\n\nexport function startRealtimeChat(\n config: RealtimeConfig & {\n agentIds: string[];\n onMessage: (msg: ChatMessagePayload) => void;\n onError: (err: Error) => void;\n onStatusChange: (status: 'connected' | 'disconnected' | 'error') => void;\n },\n): void {\n const { agentIds, onMessage, onStatusChange, log } = config;\n if (agentIds.length === 0) return;\n\n const sb = ensureClient(config);\n const filterStr = agentIds.length === 1\n ? `agent_id=eq.${agentIds[0]}`\n : `agent_id=in.(${agentIds.join(',')})`;\n\n chatChannel = sb\n .channel('direct-chat-realtime')\n .on('postgres_changes', {\n event: 'INSERT',\n schema: 'public',\n table: 'direct_chat_messages',\n filter: filterStr,\n }, (payload) => {\n const msg = payload.new as ChatMessagePayload;\n if (msg.status !== 'pending') return;\n log(`[realtime] Chat message for agent ${msg.agent_id}: id=${msg.id}`);\n onMessage(msg);\n })\n .subscribe((status) => {\n if (status === 'SUBSCRIBED') {\n connected = true;\n log('[realtime] Chat channel connected');\n onStatusChange('connected');\n } else if (status === 'CLOSED' || status === 'CHANNEL_ERROR' || status === 'TIMED_OUT') {\n if (tearingDown) return; // Prevent re-entrant teardown from recursive close events\n connected = false;\n log(`[realtime] Chat channel: ${status} — will reconnect next cycle`);\n // Don't call stopRealtimeChat here — it triggers more CLOSED events.\n // Just null out references and let the manager reset flags for fresh reconnect.\n chatChannel = null;\n driftChannel = null;\n assignChannel = null;\n configChannel = null;\n kanbanChannel = null;\n if (client) { try { client.removeAllChannels(); } catch { /* ignore */ } client = null; }\n onStatusChange(status === 'TIMED_OUT' ? 'error' : 'disconnected');\n }\n });\n\n log(`[realtime] Subscribing to direct_chat_messages for ${agentIds.length} agent(s)`);\n}\n\n// ---------------------------------------------------------------------------\n// Drift detection subscription\n// ---------------------------------------------------------------------------\n\nexport interface DriftPayload {\n version_id: string;\n agent_id: string;\n doc_type: string;\n version: string;\n created_at: string;\n}\n\nexport function startRealtimeDrift(\n config: RealtimeConfig & {\n agentIds: string[];\n onDrift: (payload: DriftPayload) => void;\n },\n): void {\n const { agentIds, onDrift, log } = config;\n if (agentIds.length === 0) return;\n\n const sb = ensureClient(config);\n const filterStr = agentIds.length === 1\n ? `agent_id=eq.${agentIds[0]}`\n : `agent_id=in.(${agentIds.join(',')})`;\n\n driftChannel = sb\n .channel('drift-realtime')\n .on('postgres_changes', {\n event: 'INSERT',\n schema: 'public',\n table: 'agent_doc_versions',\n filter: filterStr,\n }, (payload) => {\n const doc = payload.new as DriftPayload;\n log(`[realtime] Doc version change for agent ${doc.agent_id}: ${doc.doc_type} v${doc.version}`);\n onDrift(doc);\n })\n .subscribe((status) => {\n if (status === 'SUBSCRIBED') {\n log('[realtime] Drift channel connected');\n } else if (status === 'CLOSED' || status === 'CHANNEL_ERROR') {\n log(`[realtime] Drift channel: ${status}`);\n }\n });\n\n log(`[realtime] Subscribing to agent_doc_versions for ${agentIds.length} agent(s)`);\n}\n\n// ---------------------------------------------------------------------------\n// Agent assignment subscription\n// ---------------------------------------------------------------------------\n\nexport interface AssignmentPayload {\n host_id: string;\n agent_id: string;\n assigned_by: string;\n}\n\nexport function startRealtimeAssignments(\n config: RealtimeConfig & {\n hostId: string;\n onAssign: (payload: AssignmentPayload) => void;\n onUnassign: (payload: { agent_id: string }) => void;\n },\n): void {\n const { hostId, onAssign, onUnassign, log } = config;\n\n const sb = ensureClient(config);\n\n assignChannel = sb\n .channel('assignment-realtime')\n .on('postgres_changes', {\n event: 'INSERT',\n schema: 'public',\n table: 'host_agents',\n filter: `host_id=eq.${hostId}`,\n }, (payload) => {\n const row = payload.new as AssignmentPayload;\n log(`[realtime] Agent assigned: ${row.agent_id} to host ${row.host_id}`);\n onAssign(row);\n })\n .on('postgres_changes', {\n event: 'DELETE',\n schema: 'public',\n table: 'host_agents',\n }, (payload) => {\n // DELETE events can't be filtered by Supabase Realtime\n // We receive all DELETEs and filter client-side\n const old = payload.old as { host_id?: string; agent_id?: string };\n if (old.host_id === hostId && old.agent_id) {\n log(`[realtime] Agent unassigned: ${old.agent_id} from host ${hostId}`);\n onUnassign({ agent_id: old.agent_id });\n }\n })\n .subscribe((status) => {\n if (status === 'SUBSCRIBED') {\n log('[realtime] Assignment channel connected');\n } else if (status === 'CLOSED' || status === 'CHANNEL_ERROR') {\n log(`[realtime] Assignment channel: ${status}`);\n }\n });\n\n log(`[realtime] Subscribing to host_agents for host ${hostId}`);\n}\n\n// ---------------------------------------------------------------------------\n// Agent config change subscription\n// ---------------------------------------------------------------------------\n\nexport interface AgentConfigPayload {\n agent_id: string;\n code_name: string;\n status: string;\n framework: string;\n session_mode: string;\n primary_model: string | null;\n updated_at: string;\n}\n\nexport function startRealtimeConfig(\n config: RealtimeConfig & {\n agentIds: string[];\n onConfigChange: (payload: AgentConfigPayload) => void;\n },\n): void {\n const { agentIds, onConfigChange, log } = config;\n if (agentIds.length === 0) return;\n\n const sb = ensureClient(config);\n const filterStr = agentIds.length === 1\n ? `agent_id=eq.${agentIds[0]}`\n : `agent_id=in.(${agentIds.join(',')})`;\n\n // Track last known values to filter out timestamp-only updates\n const lastKnown = new Map<string, string>();\n\n configChannel = sb\n .channel('config-realtime')\n .on('postgres_changes', {\n event: 'UPDATE',\n schema: 'public',\n table: 'agents',\n filter: filterStr,\n }, (payload) => {\n const agent = payload.new as AgentConfigPayload;\n\n // Build a fingerprint of meaningful fields (ignore timestamps like updated_at, last_heartbeat_at)\n const fingerprint = `${agent.status}|${agent.framework}|${agent.session_mode}|${agent.primary_model}`;\n const prev = lastKnown.get(agent.agent_id);\n\n if (prev === fingerprint) return; // timestamp-only change, ignore\n lastKnown.set(agent.agent_id, fingerprint);\n\n log(`[realtime] Agent config changed: ${agent.code_name} (status=${agent.status})`);\n onConfigChange(agent);\n })\n .subscribe((status) => {\n if (status === 'SUBSCRIBED') {\n log('[realtime] Config channel connected');\n } else if (status === 'CLOSED' || status === 'CHANNEL_ERROR') {\n log(`[realtime] Config channel: ${status}`);\n }\n });\n\n log(`[realtime] Subscribing to agents table for ${agentIds.length} agent(s)`);\n}\n\n// ---------------------------------------------------------------------------\n// Kanban item subscription — trigger work when items hit 'today'\n// ---------------------------------------------------------------------------\n\nexport interface KanbanItemPayload {\n id: string;\n agent_id: string;\n title: string;\n status: string;\n priority: number;\n}\n\nexport function startRealtimeKanban(\n config: RealtimeConfig & {\n agentIds: string[];\n onTodayItem: (payload: KanbanItemPayload) => void;\n },\n): void {\n const { agentIds, onTodayItem, log } = config;\n if (agentIds.length === 0) return;\n\n const sb = ensureClient(config);\n const filterStr = agentIds.length === 1\n ? `agent_id=eq.${agentIds[0]}`\n : `agent_id=in.(${agentIds.join(',')})`;\n\n kanbanChannel = sb\n .channel('kanban-realtime')\n .on('postgres_changes', {\n event: 'INSERT',\n schema: 'public',\n table: 'agent_kanban_items',\n filter: filterStr,\n }, (payload) => {\n const item = payload.new as KanbanItemPayload;\n if (item.status === 'today') {\n log(`[realtime] New kanban item in 'today': \"${item.title}\" for agent ${item.agent_id}`);\n onTodayItem(item);\n }\n })\n .on('postgres_changes', {\n event: 'UPDATE',\n schema: 'public',\n table: 'agent_kanban_items',\n filter: filterStr,\n }, (payload) => {\n const item = payload.new as KanbanItemPayload;\n const old = payload.old as KanbanItemPayload;\n // Only trigger when status changes TO 'today' (not from today to something else)\n if (item.status === 'today' && old.status !== 'today') {\n log(`[realtime] Kanban item moved to 'today': \"${item.title}\" for agent ${item.agent_id}`);\n onTodayItem(item);\n }\n })\n .subscribe((status) => {\n if (status === 'SUBSCRIBED') {\n log('[realtime] Kanban channel connected');\n } else if (status === 'CLOSED' || status === 'CHANNEL_ERROR') {\n log(`[realtime] Kanban channel: ${status}`);\n }\n });\n\n log(`[realtime] Subscribing to agent_kanban_items for ${agentIds.length} agent(s)`);\n}\n\n// ---------------------------------------------------------------------------\n// Shared utilities\n// ---------------------------------------------------------------------------\n\nexport function updateRealtimeToken(token: string): void {\n if (client) {\n client.realtime.setAuth(token);\n }\n}\n\nexport function isRealtimeConnected(): boolean {\n return connected;\n}\n\nexport function stopRealtimeChat(): void {\n if (tearingDown) return;\n tearingDown = true;\n try {\n if (chatChannel) { try { chatChannel.unsubscribe(); } catch {} chatChannel = null; }\n if (driftChannel) { try { driftChannel.unsubscribe(); } catch {} driftChannel = null; }\n if (assignChannel) { try { assignChannel.unsubscribe(); } catch {} assignChannel = null; }\n if (configChannel) { try { configChannel.unsubscribe(); } catch {} configChannel = null; }\n if (kanbanChannel) { try { kanbanChannel.unsubscribe(); } catch {} kanbanChannel = null; }\n if (client) {\n try { client.removeAllChannels(); } catch {}\n client = null;\n }\n connected = false;\n } finally {\n tearingDown = false;\n }\n}\n"],"mappings":"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","names":["readFileSync","existsSync","join","client","config","log","getProjectDir","config","log","join","readFileSync","existsSync","state","primaryModel","sessionMode","agentDir","getProjectDir"]}
|
|
1
|
+
{"version":3,"sources":["../../src/lib/manager-worker.ts","../../src/lib/gateway-client.ts","../../src/lib/persistent-session.ts","../../src/lib/realtime-chat.ts"],"sourcesContent":["/**\n * Manager Worker — forked child process that polls the API for agent config\n * changes and local file drift. Communicates with the watchdog parent via IPC.\n *\n * This file is a standalone entry point built by tsup so `fork()` can target it.\n */\n\nimport { createHash } from 'node:crypto';\nimport { readFileSync, writeFileSync, mkdirSync, existsSync, rmSync, readdirSync, statSync, unlinkSync } from 'node:fs';\nimport https from 'node:https';\nimport { join } from 'node:path';\nimport {\n extractFrontmatter,\n resolveChannels,\n getFramework,\n type FrameworkAdapter,\n type CharterFrontmatter,\n type ToolsFrontmatter,\n type ChannelId,\n type ChannelPolicy,\n type OrgChannelPolicy,\n type DeploymentTarget,\n type ProvisionInput,\n} from '@augmented/core';\nimport { provision } from '@augmented/core/provisioning/provisioner.js';\n\n// Register framework adapters (side-effect imports)\nimport '@augmented/core/provisioning/frameworks/openclaw/index.js';\nimport '@augmented/core/provisioning/frameworks/nemoclaw/index.js';\nimport '@augmented/core/provisioning/frameworks/claudecode/index.js';\n\nimport { api, getHostId, exchangeApiKey } from './api-client.js';\nimport { getApiKey, requireHost } from './config.js';\nimport { GatewayClientPool, type PooledGatewayEvent } from './gateway-client.js';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ninterface WorkerConfig {\n intervalMs: number;\n configDir: string;\n gatewayPort?: number;\n gatewayToken?: string;\n}\n\ninterface AcpSessionSummary {\n sessionId: string;\n agentCommand: string;\n sessionName?: string;\n queueState: string;\n turnCount: number;\n startedAt: string;\n}\n\ninterface AgentState {\n agentId: string;\n codeName: string;\n status: string;\n charterVersion: string;\n toolsVersion: string;\n secretsHash: string | null;\n lastRefreshAt: string | null;\n lastProvisionAt: string | null;\n lastDriftCheckAt: string | null;\n lastSecretsProvisionAt: string | null;\n gatewayPort: number | null;\n gatewayPid: number | null;\n gatewayRunning: boolean;\n acpSessions: AcpSessionSummary[];\n}\n\ninterface ManagerState {\n pid: number;\n startedAt: string;\n lastPollAt: string | null;\n pollCount: number;\n errorCount: number;\n agents: AgentState[];\n}\n\n// Event types (formerly IPC messages, now just internal events)\ntype ManagerEvent =\n | { type: 'ready' }\n | { type: 'state-update'; state: ManagerState }\n | { type: 'provisioned'; agentId: string; codeName: string }\n | { type: 'drift-detected'; agentId: string; codeName: string; files: string[] }\n | { type: 'gateway-event'; event: string; payload: unknown; agentCodeName?: string }\n | { type: 'error'; message: string }\n | { type: 'shutdown' };\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\n// OpenClaw gateway binds the specified port + a few additional ports above it,\n// so we space allocations 10 apart to avoid collisions.\nconst GATEWAY_PORT_BASE = 18800;\nconst GATEWAY_PORT_STEP = 10;\nconst GATEWAY_PORT_MAX = 18899;\nconst AUGMENTED_DIR = join(process.env['HOME'] ?? '/tmp', '.augmented');\nconst GATEWAY_PORTS_FILE = join(AUGMENTED_DIR, 'gateway-ports.json');\n\n// ---------------------------------------------------------------------------\n// State\n// ---------------------------------------------------------------------------\n\nlet config: WorkerConfig | null = null;\nlet running = false;\nlet pollTimer: ReturnType<typeof setTimeout> | null = null;\n\n// Track last-known versions + hashes per agent to detect changes\nconst knownVersions = new Map<string, { charterVersion: string; toolsVersion: string }>();\nconst knownStatuses = new Map<string, string>();\nconst knownChannels = new Map<string, Set<string>>();\nconst writtenHashes = new Map<string, Map<string, string>>();\nconst knownSecretsHashes = new Map<string, string>();\nconst knownChannelConfigHashes = new Map<string, string>();\nconst knownModels = new Map<string, string>();\nconst knownTasksHashes = new Map<string, string>();\nconst knownIntegrationHashes = new Map<string, string>();\nconst losslessClawInstalled = new Map<string, boolean>();\nconst knownSkillHashes = new Map<string, string>();\n// Track last-seen cron run timestamps per job to avoid re-processing\nconst lastCronRunTs = new Map<string, number>();\n// Track last work_trigger_at per agent to avoid duplicate triggers\nconst lastWorkTriggerAt = new Map<string, number>();\n// Track which in_progress items we've already alerted as stale\nconst alertedStaleItems = new Set<string>();\n// Track agents with known API key errors (avoid spamming the API)\nconst apiKeyStatusCache = new Map<string, boolean>();\nconst STALE_TASK_THRESHOLD_MS = 30 * 60 * 1000; // 30 minutes\n\n// Alert webhook URL — cached from first agent's team settings\nlet alertSlackWebhook: string | null = null;\n// Track alerted job IDs to avoid duplicate alerts within a session\nconst alertedJobs = new Set<string>();\n// Map cron job name (aug:template:uuid) → human-readable task info\nconst taskDisplayInfo = new Map<string, { taskName: string; schedule: string; agentDisplayName: string }>();\n// Map agent code_name → display_name for alerts\nconst agentDisplayNames = new Map<string, string>();\n// Map code_name → agent_id for kanban updates\nconst codeNameToAgentId = new Map<string, string>();\n// Map code_name → channel bot tokens (from channel_configs)\nconst agentChannelTokens = new Map<string, { slack?: string; telegram?: string; telegramAllowedChats?: string[] }>();\n\n// Per-cycle channel tracking — populated by processAgent, reconciled after all agents\nconst activeChannels = new Map<string, Set<string>>(); // channelId -> Set<codeName>\n\n// Gateways started this poll cycle — skip health-check restarts for these\nconst gatewaysStartedThisCycle = new Set<string>();\n\n// Cumulative state for the parent\nlet state: ManagerState = {\n pid: process.pid,\n startedAt: new Date().toISOString(),\n lastPollAt: null,\n pollCount: 0,\n errorCount: 0,\n agents: [],\n};\n\n// Cache registered agents per framework per poll cycle\nconst registeredAgentsCache = new Map<string, Set<string>>();\n\n// Per-agent framework ID cache (populated from API response and refresh data)\nconst agentFrameworkCache = new Map<string, string>();\n\n// Track which framework binaries we've already checked/installed this session\nconst frameworkBinaryChecked = new Set<string>();\n\n// Claude Code auth status — set during ensureFrameworkBinary, checked before launching sessions\nlet agentRuntimeAuthenticated = false;\n\n/** Resolve the framework adapter for a given agent, using the cache or defaulting to 'openclaw'. */\nfunction resolveAgentFramework(codeName: string): FrameworkAdapter {\n const frameworkId = agentFrameworkCache.get(codeName) ?? 'openclaw';\n return getFramework(frameworkId);\n}\n\n// Gateway client pool — replaces single GatewayClient\nlet gatewayPool: GatewayClientPool | null = null;\n\n/**\n * Clear all per-agent caches when an agent is unassigned, revoked, or needs\n * a full reprovision. Keeps the cleanup in one place instead of scattering\n * .delete() calls for every new Map we add.\n */\nfunction clearAgentCaches(agentId: string, codeName: string): void {\n // ID-keyed caches\n knownVersions.delete(agentId);\n knownStatuses.delete(agentId);\n knownChannels.delete(agentId);\n writtenHashes.delete(agentId);\n knownSecretsHashes.delete(agentId);\n knownModels.delete(agentId);\n knownTasksHashes.delete(agentId);\n knownIntegrationHashes.delete(agentId);\n\n // codeName-keyed caches\n losslessClawInstalled.delete(codeName);\n agentDisplayNames.delete(codeName);\n codeNameToAgentId.delete(codeName);\n agentFrameworkCache.delete(codeName);\n kanbanBoardCache.delete(codeName);\n lastHarvestAt.delete(codeName);\n claudeSchedulerStates.delete(codeName);\n claudeTaskConcurrency.delete(codeName);\n\n // Compound-keyed caches (agentId:suffix)\n for (const key of knownChannelConfigHashes.keys()) {\n if (key.startsWith(`${agentId}:`)) knownChannelConfigHashes.delete(key);\n }\n for (const key of knownSkillHashes.keys()) {\n if (key.startsWith(`${agentId}:`)) knownSkillHashes.delete(key);\n }\n for (const key of taskDisplayInfo.keys()) {\n if (key.startsWith(`${codeName}:`)) taskDisplayInfo.delete(key);\n }\n}\n\n// Cached framework version (detected once at startup, refreshed periodically)\nlet cachedFrameworkVersion: string | null = null;\nlet lastVersionCheckAt = 0;\nconst VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1000; // Re-check every 5 minutes\n\n// ---------------------------------------------------------------------------\n// Framework binary install / upgrade\n// ---------------------------------------------------------------------------\n\n/**\n * Ensure a Homebrew formula is installed. Used for framework dependencies\n * like tmux that are required but not part of the framework itself.\n * Returns true if the binary is available after the check.\n */\nasync function ensureBrewDependency(binary: string, formula: string): Promise<boolean> {\n if (frameworkBinaryChecked.has(`dep:${binary}`)) return true;\n\n const { execFileSync } = await import('node:child_process');\n\n try {\n execFileSync('which', [binary], { timeout: 5_000 });\n frameworkBinaryChecked.add(`dep:${binary}`);\n return true;\n } catch {\n // Binary not found — try to install\n }\n\n let brewPath: string;\n try {\n brewPath = execFileSync('which', ['brew'], { timeout: 5_000 }).toString().trim();\n } catch {\n log(`${binary} not found and Homebrew not available — install manually: brew install ${formula}`);\n frameworkBinaryChecked.add(`dep:${binary}`);\n return false;\n }\n\n log(`${binary} not found — installing via Homebrew...`);\n try {\n execFileSync(brewPath, ['install', formula], { timeout: 120_000, stdio: 'pipe' });\n } catch (err) {\n log(`Failed to install ${formula}: ${(err as Error).message}`);\n frameworkBinaryChecked.add(`dep:${binary}`);\n return false;\n }\n\n try {\n execFileSync('which', [binary], { timeout: 5_000 });\n log(`${binary} installed successfully`);\n frameworkBinaryChecked.add(`dep:${binary}`);\n return true;\n } catch {\n log(`${formula} install completed but ${binary} not found on PATH`);\n frameworkBinaryChecked.add(`dep:${binary}`);\n return false;\n }\n}\n\n/**\n * Ensure the CLI binary for a framework is available. Currently only handles\n * `claude-code` via Homebrew. Called once per session when we first see an\n * agent using that framework.\n */\nasync function ensureFrameworkBinary(frameworkId: string): Promise<void> {\n if (frameworkId !== 'claude-code') return;\n if (frameworkBinaryChecked.has(frameworkId)) return;\n frameworkBinaryChecked.add(frameworkId);\n\n // Ensure tmux is available (needed for ACP sessions)\n await ensureBrewDependency('tmux', 'tmux');\n\n const { execFileSync } = await import('node:child_process');\n\n // Check if Homebrew is available\n let brewPath: string;\n try {\n brewPath = execFileSync('which', ['brew'], { timeout: 5_000 }).toString().trim();\n } catch {\n log('Homebrew not found — cannot auto-install/upgrade Claude Code. Install manually: https://claude.ai/download');\n return;\n }\n\n // Check if claude binary exists\n let claudeExists = false;\n try {\n execFileSync('which', ['claude'], { timeout: 5_000 });\n claudeExists = true;\n } catch {\n // Not found\n }\n\n if (!claudeExists) {\n // Install\n log('Claude Code binary not found — installing via Homebrew...');\n try {\n execFileSync(brewPath, ['install', '--cask', 'claude-code'], {\n timeout: 120_000,\n stdio: 'pipe',\n });\n } catch (err) {\n log(`Claude Code install failed: ${(err as Error).message}`);\n return;\n }\n\n // Verify\n try {\n execFileSync('which', ['claude'], { timeout: 5_000 });\n log('Claude Code installed successfully');\n } catch {\n log('Claude Code install completed but binary not found on PATH — you may need to restart your terminal');\n }\n } else {\n // Upgrade\n log('Checking for Claude Code updates...');\n try {\n const output = execFileSync(brewPath, ['upgrade', '--cask', 'claude-code'], {\n timeout: 120_000,\n stdio: 'pipe',\n }).toString();\n\n if (output.includes('already installed') || output.includes('up-to-date')) {\n log('Claude Code is already up to date');\n } else {\n log('Claude Code upgraded successfully');\n }\n } catch (err) {\n const msg = (err as Error).message;\n // brew upgrade exits non-zero when already up to date on some versions\n if (msg.includes('already installed') || msg.includes('up-to-date') || msg.includes('not upgraded')) {\n log('Claude Code is already up to date');\n } else {\n log(`Claude Code upgrade failed: ${msg}`);\n }\n }\n }\n\n // Check if Claude Code is authenticated\n agentRuntimeAuthenticated = checkClaudeAuth(execFileSync);\n}\n\n/** Check Claude Code auth and return true if logged in. */\nfunction checkClaudeAuth(execFileSync: typeof import('node:child_process').execFileSync): boolean {\n try {\n const authOutput = execFileSync('claude', ['auth', 'status'], { timeout: 10_000, stdio: 'pipe' }).toString();\n const authStatus = JSON.parse(authOutput);\n if (authStatus.loggedIn) {\n return true;\n }\n log('⚠️ Claude Code is not authenticated. Run \"claude\" in a terminal to log in, then restart the manager.');\n return false;\n } catch {\n log('⚠️ Could not check Claude Code auth status. Run \"claude\" in a terminal to ensure it is logged in.');\n return false;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Port allocation\n// ---------------------------------------------------------------------------\n\nfunction loadGatewayPorts(): Record<string, number> {\n try {\n return JSON.parse(readFileSync(GATEWAY_PORTS_FILE, 'utf-8'));\n } catch {\n return {};\n }\n}\n\nfunction saveGatewayPorts(ports: Record<string, number>): void {\n mkdirSync(AUGMENTED_DIR, { recursive: true });\n writeFileSync(GATEWAY_PORTS_FILE, JSON.stringify(ports, null, 2));\n}\n\nfunction allocatePort(codeName: string): number {\n const ports = loadGatewayPorts();\n\n // Already allocated\n if (ports[codeName]) return ports[codeName];\n\n // Find next free port (spaced by GATEWAY_PORT_STEP to avoid OpenClaw's extra port binds)\n const usedPorts = new Set(Object.values(ports));\n for (let port = GATEWAY_PORT_BASE; port <= GATEWAY_PORT_MAX; port += GATEWAY_PORT_STEP) {\n if (!usedPorts.has(port)) {\n ports[codeName] = port;\n saveGatewayPorts(ports);\n return port;\n }\n }\n\n throw new Error(`No free gateway ports in range ${GATEWAY_PORT_BASE}-${GATEWAY_PORT_MAX}`);\n}\n\nfunction freePort(codeName: string): void {\n const ports = loadGatewayPorts();\n if (ports[codeName]) {\n delete ports[codeName];\n saveGatewayPorts(ports);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n// State file for external status queries (replaces IPC state-update)\nconst STATE_FILE = join(process.env['HOME'] ?? '/tmp', '.augmented', 'manager-state.json');\n\nfunction send(msg: ManagerEvent): void {\n // Write state updates to file for `agt manager status` to read\n if (msg.type === 'state-update') {\n try {\n writeFileSync(STATE_FILE, JSON.stringify(msg.state, null, 2));\n } catch { /* non-fatal */ }\n }\n // Log notable events\n if (msg.type === 'provisioned') {\n log(`Provisioned ${msg.codeName}`);\n } else if (msg.type === 'drift-detected') {\n log(`Drift detected: ${msg.codeName} (${msg.files?.join(', ')})`);\n } else if (msg.type === 'error') {\n log(`Error: ${msg.message}`);\n }\n}\n\nfunction log(msg: string): void {\n const ts = new Date().toISOString();\n process.stderr.write(`[manager-worker ${ts}] ${msg}\\n`);\n}\n\nfunction sha256(content: string): string {\n return createHash('sha256').update(content, 'utf8').digest('hex');\n}\n\nfunction hashFile(filePath: string): string | null {\n try {\n const content = readFileSync(filePath, 'utf-8');\n return sha256(content);\n } catch {\n return null;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Migration: shared config → per-agent profiles\n// ---------------------------------------------------------------------------\n\nasync function migrateToProfiles(): Promise<void> {\n const homeDir = process.env['HOME'] ?? '/tmp';\n const sharedConfigPath = join(homeDir, '.openclaw', 'openclaw.json');\n\n // Check if shared config exists\n let sharedConfig: Record<string, unknown>;\n try {\n sharedConfig = JSON.parse(readFileSync(sharedConfigPath, 'utf-8'));\n } catch {\n return; // No shared config — nothing to migrate\n }\n\n // Check if there are multiple agents registered in shared config\n const agents = sharedConfig['agents'] as Record<string, unknown> | undefined;\n const agentList = (agents?.['list'] as Array<Record<string, unknown>>) ?? [];\n if (agentList.length === 0) return;\n\n const adapter = getFramework('openclaw');\n let migrated = 0;\n\n for (const agentEntry of agentList) {\n const codeName = agentEntry['id'] as string;\n if (!codeName) continue;\n\n // Skip 'main' — that's the interactive CLI agent, not managed by Augmented\n if (codeName === 'main') continue;\n\n const profileDir = join(homeDir, `.openclaw-${codeName}`);\n\n // Skip agents that already have profile dirs\n if (existsSync(join(profileDir, 'openclaw.json'))) continue;\n\n log(`Migrating agent '${codeName}' to per-agent profile`);\n\n // Seed profile config from shared config\n if (adapter.seedProfileConfig) {\n adapter.seedProfileConfig(codeName);\n }\n\n // Copy auth profiles from shared to profile dir\n const sharedAuthDir = join(homeDir, '.openclaw', 'agents', codeName, 'agent');\n const profileAuthDir = join(profileDir, 'agents', codeName, 'agent');\n const authFile = join(sharedAuthDir, 'auth-profiles.json');\n if (existsSync(authFile)) {\n mkdirSync(profileAuthDir, { recursive: true });\n const authContent = readFileSync(authFile, 'utf-8');\n writeFileSync(join(profileAuthDir, 'auth-profiles.json'), authContent);\n }\n\n // Allocate a gateway port\n allocatePort(codeName);\n\n migrated++;\n }\n\n if (migrated > 0) {\n log(`Migration complete: ${migrated} agent(s) migrated to per-agent profiles`);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Gateway lifecycle\n// ---------------------------------------------------------------------------\n\n/**\n * Resolve model tiers through the inheritance chain:\n * Agent override → Org default → Platform default\n */\nfunction resolveModelChain(refreshData: Record<string, unknown>): { primary?: string; secondary?: string; tertiary?: string } {\n const agent = refreshData.agent as Record<string, unknown> | undefined;\n const modelDefaults = refreshData.model_defaults as { platform?: Record<string, unknown> | null; org?: Record<string, unknown> | null } | undefined;\n const platform = modelDefaults?.platform ?? {};\n const org = modelDefaults?.org ?? {};\n\n function resolve(tier: 'primary' | 'secondary' | 'tertiary'): string | undefined {\n const agentField = `${tier}_model`;\n const platformField = `default_${tier}_model`;\n\n // 1. Agent override\n const agentVal = agent?.[agentField] as string | undefined;\n if (agentVal) return agentVal;\n\n // 2. Org default\n const orgVal = org?.[platformField] as string | undefined;\n if (orgVal) return orgVal;\n\n // 3. Platform default\n const platformVal = platform?.[platformField] as string | undefined;\n if (platformVal) return platformVal;\n\n return undefined;\n }\n\n return {\n primary: resolve('primary'),\n secondary: resolve('secondary'),\n tertiary: resolve('tertiary'),\n };\n}\n\nfunction readGatewayToken(codeName: string): string | undefined {\n const adapter = resolveAgentFramework(codeName);\n if (adapter.readGatewayToken) {\n return adapter.readGatewayToken(codeName);\n }\n // Fallback for adapters without readGatewayToken\n const homeDir = process.env['HOME'] ?? '/tmp';\n try {\n const cfg = JSON.parse(readFileSync(join(homeDir, `.openclaw-${codeName}`, 'openclaw.json'), 'utf-8'));\n return cfg?.gateway?.auth?.token as string | undefined;\n } catch {\n return undefined;\n }\n}\n\nconst GATEWAY_HUNG_TIMEOUT_MS = 5 * 60_000; // 5 minutes\n\n/**\n * Detect if a gateway is hung by checking for cron jobs stuck in \"running\" state.\n * Reads the cron jobs.json directly (no gateway communication needed since the\n * gateway itself may be unresponsive).\n */\nfunction isGatewayHung(codeName: string): boolean {\n const homeDir = process.env['HOME'] ?? '/tmp';\n const jobsPath = join(homeDir, `.openclaw-${codeName}`, 'cron', 'jobs.json');\n if (!existsSync(jobsPath)) return false;\n\n try {\n const data = JSON.parse(readFileSync(jobsPath, 'utf-8')) as Record<string, unknown>;\n const jobs = (data.jobs ?? data) as Array<Record<string, unknown>>;\n if (!Array.isArray(jobs)) return false;\n\n const now = Date.now();\n for (const job of jobs) {\n const state = job.state as Record<string, unknown> | undefined;\n if (!state) continue;\n const runStartedAt = state.runStartedAtMs as number | undefined;\n const isRunning = state.status === 'running' || state.running === true;\n if (isRunning && runStartedAt && (now - runStartedAt) > GATEWAY_HUNG_TIMEOUT_MS) {\n return true;\n }\n }\n } catch { /* non-fatal */ }\n\n return false;\n}\n\nasync function ensureGatewayRunning(codeName: string, adapter: FrameworkAdapter): Promise<{ pid: number | null; port: number | null; running: boolean }> {\n if (!adapter.isGatewayRunning || !adapter.startGateway) {\n return { pid: null, port: null, running: false };\n }\n\n const status = await adapter.isGatewayRunning(codeName);\n if (status.running) {\n // Check if gateway is hung — if a cron has been \"running\" for too long,\n // the gateway is likely stuck and needs a restart\n if (await isGatewayHung(codeName)) {\n log(`Gateway for '${codeName}' appears hung (cron stuck >5min) — restarting`);\n if (adapter.stopGateway) {\n try { await adapter.stopGateway(codeName); } catch { /* force kill below */ }\n }\n // Give it a moment to die\n await new Promise((r) => setTimeout(r, 2000));\n // Clear stale cron state so it doesn't immediately re-hang\n const homeDir = process.env['HOME'] ?? '/tmp';\n const cronJobsPath = join(homeDir, `.openclaw-${codeName}`, 'cron', 'jobs.json');\n clearStaleCronRunState(cronJobsPath);\n // Fall through to start a new gateway below\n } else {\n // Update config port in case it changed (e.g. after manual restart)\n if (status.port) {\n try {\n const homeDir = process.env['HOME'] ?? '/tmp';\n const configPath = join(homeDir, `.openclaw-${codeName}`, 'openclaw.json');\n if (existsSync(configPath)) {\n const cfg = JSON.parse(readFileSync(configPath, 'utf-8'));\n if (cfg.gateway?.port !== status.port) {\n if (!cfg.gateway) cfg.gateway = {};\n cfg.gateway.port = status.port;\n writeFileSync(configPath, JSON.stringify(cfg, null, 2));\n }\n }\n } catch { /* Non-fatal */ }\n }\n // Ensure pool has a connection to this gateway\n if (gatewayPool && status.port && !gatewayPool.hasAgent(codeName)) {\n const token = readGatewayToken(codeName);\n gatewayPool.addAgent(codeName, status.port, token);\n }\n return { pid: status.pid ?? null, port: status.port ?? null, running: true };\n }\n }\n\n // Allocate port and start\n const port = allocatePort(codeName);\n try {\n const result = await adapter.startGateway(codeName, port);\n log(`Gateway started for '${codeName}' on port ${port} (PID ${result.pid})`);\n gatewaysStartedThisCycle.add(codeName);\n\n // Write port to profile config so `openclaw cron run` can find the gateway\n try {\n const homeDir = process.env['HOME'] ?? '/tmp';\n const configPath = join(homeDir, `.openclaw-${codeName}`, 'openclaw.json');\n if (existsSync(configPath)) {\n const cfg = JSON.parse(readFileSync(configPath, 'utf-8'));\n if (!cfg.gateway) cfg.gateway = {};\n cfg.gateway.port = port;\n writeFileSync(configPath, JSON.stringify(cfg, null, 2));\n }\n } catch { /* Non-fatal */ }\n\n // Connect gateway client pool — the client silently handles ECONNREFUSED\n // on first attempt and retries with backoff while the gateway boots.\n if (gatewayPool) {\n const token = readGatewayToken(codeName);\n gatewayPool.addAgent(codeName, port, token);\n }\n\n return { pid: result.pid, port, running: true };\n } catch (err) {\n log(`Failed to start gateway for '${codeName}': ${(err as Error).message}`);\n return { pid: null, port, running: false };\n }\n}\n\nasync function stopGatewayIfRunning(codeName: string, adapter: FrameworkAdapter): Promise<void> {\n if (!adapter.stopGateway) return;\n\n try {\n const stopped = await adapter.stopGateway(codeName);\n if (stopped) {\n log(`Gateway stopped for '${codeName}'`);\n }\n } catch (err) {\n log(`Failed to stop gateway for '${codeName}': ${(err as Error).message}`);\n }\n\n // Disconnect from pool\n if (gatewayPool) {\n gatewayPool.removeAgent(codeName);\n }\n}\n\nasync function stopAllGateways(): Promise<void> {\n const ports = loadGatewayPorts();\n\n for (const codeName of Object.keys(ports)) {\n const adapter = resolveAgentFramework(codeName);\n await stopGatewayIfRunning(codeName, adapter);\n }\n\n if (gatewayPool) {\n gatewayPool.disconnectAll();\n }\n}\n\nasync function healthCheckGateways(agentStates: AgentState[]): Promise<void> {\n for (const agentState of agentStates) {\n if (agentState.status !== 'active' || !agentState.gatewayPort) continue;\n\n const adapter = resolveAgentFramework(agentState.codeName);\n if (!adapter.isGatewayRunning || !adapter.startGateway) continue;\n\n // Skip gateways that were just started this cycle — they may still be booting\n if (gatewaysStartedThisCycle.has(agentState.codeName)) continue;\n\n const status = await adapter.isGatewayRunning(agentState.codeName);\n if (!status.running && agentState.gatewayRunning) {\n // Gateway crashed — alert and restart\n const displayName = agentDisplayNames.get(agentState.codeName) ?? agentState.codeName;\n log(`Gateway for '${agentState.codeName}' crashed, restarting...`);\n sendSlackWebhookMessage(\n `:red_circle: *Host Down* — *${displayName}* (\\`${agentState.codeName}\\`)\\nOpenClaw gateway crashed. Attempting automatic restart...`,\n ).catch(() => {});\n\n try {\n const result = await adapter.startGateway(agentState.codeName, agentState.gatewayPort);\n agentState.gatewayPid = result.pid;\n agentState.gatewayRunning = true;\n log(`Gateway restarted for '${agentState.codeName}' (PID ${result.pid})`);\n\n // Give the gateway process time to bind the port before connecting WebSocket\n await new Promise((resolve) => setTimeout(resolve, 2000));\n\n // Reconnect pool client\n if (gatewayPool) {\n const token = readGatewayToken(agentState.codeName);\n gatewayPool.addAgent(agentState.codeName, agentState.gatewayPort, token);\n }\n\n sendSlackWebhookMessage(\n `:large_green_circle: *Host Recovered* — *${displayName}* (\\`${agentState.codeName}\\`)\\nGateway restarted successfully (PID ${result.pid}).`,\n ).catch(() => {});\n } catch (err) {\n agentState.gatewayRunning = false;\n log(`Failed to restart gateway for '${agentState.codeName}': ${(err as Error).message}`);\n sendSlackWebhookMessage(\n `:x: *Host Restart Failed* — *${displayName}* (\\`${agentState.codeName}\\`)\\nAutomatic restart failed: ${(err as Error).message}`,\n ).catch(() => {});\n }\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Poll cycle\n// ---------------------------------------------------------------------------\n\nasync function pollCycle(): Promise<void> {\n if (!config) return;\n\n try {\n // Clear per-cycle caches\n registeredAgentsCache.clear();\n gatewaysStartedThisCycle.clear();\n\n // 1. Discover assigned agents\n const hostId = await getHostId();\n if (!hostId) {\n send({ type: 'error', message: 'Could not resolve host ID from API key' });\n return;\n }\n\n // 1b. Detect framework version (cached, refreshed every 5 min)\n const now = Date.now();\n if (now - lastVersionCheckAt > VERSION_CHECK_INTERVAL_MS) {\n try {\n // Use the first known agent's framework, or default to openclaw\n const firstAgent = state.agents[0];\n const versionAdapter = firstAgent ? resolveAgentFramework(firstAgent.codeName) : getFramework('openclaw');\n if (versionAdapter.getVersion) {\n cachedFrameworkVersion = await versionAdapter.getVersion();\n }\n } catch {\n // Non-fatal — version detection is supplementary\n }\n lastVersionCheckAt = now;\n }\n\n // 1c. Heartbeat — update last_seen_at, framework_version, and host security\n try {\n const { detectHostSecurity } = await import('./host-security.js');\n await api.post('/host/heartbeat', {\n host_id: hostId,\n framework_version: cachedFrameworkVersion ?? undefined,\n host_security: detectHostSecurity() ?? undefined,\n agent_runtime_authenticated: agentRuntimeAuthenticated,\n });\n } catch (err) {\n log(`Heartbeat failed: ${(err as Error).message}`);\n }\n\n const data = await api.post<{\n agents: Array<{\n agent_id: string;\n code_name: string;\n display_name: string;\n status: string;\n environment: string;\n framework?: string;\n }>;\n }>('/host/agents', { host_id: hostId });\n\n const agents = data.agents ?? [];\n\n // Ensure framework binaries are installed/upgraded for any new frameworks\n const frameworksThisCycle = new Set(agents.map((a) => a.framework).filter(Boolean));\n for (const fw of frameworksThisCycle) {\n await ensureFrameworkBinary(fw!);\n }\n\n // Track which channels have at least one active agent per profile\n activeChannels.clear();\n\n // Update state agents list\n const agentStates: AgentState[] = [];\n\n for (const agent of agents) {\n try {\n await processAgent(agent, agentStates);\n } catch (err) {\n log(`Error processing agent '${agent.code_name}': ${(err as Error).message}`);\n // Preserve existing state for this agent on error\n const existing = state.agents.find((a) => a.agentId === agent.agent_id);\n if (existing) {\n agentStates.push(existing);\n } else {\n agentStates.push({\n agentId: agent.agent_id,\n codeName: agent.code_name,\n status: agent.status,\n charterVersion: '',\n toolsVersion: '',\n secretsHash: null,\n lastRefreshAt: null,\n lastProvisionAt: null,\n lastDriftCheckAt: null,\n lastSecretsProvisionAt: null,\n gatewayPort: null,\n gatewayPid: null,\n gatewayRunning: false,\n acpSessions: [],\n });\n }\n }\n }\n\n // Reconcile channel enabled state per profile.\n // Each agent has its own profile config, so enable/disable within that profile.\n try {\n for (const [channelId, codeNames] of activeChannels) {\n for (const codeName of codeNames) {\n const adapter = resolveAgentFramework(codeName);\n if (adapter.setChannelEnabled) {\n adapter.setChannelEnabled(channelId, true, codeName);\n }\n }\n }\n } catch { /* non-fatal */ }\n\n // Detect unassigned agents (were in state but not in current list)\n const currentIds = new Set(agents.map((a) => a.agent_id));\n for (const prev of state.agents) {\n if (!currentIds.has(prev.agentId)) {\n log(`Agent '${prev.codeName}' unassigned from host`);\n // Stop gateway for unassigned agent (resolve before clearing caches)\n const adapter = resolveAgentFramework(prev.codeName);\n clearAgentCaches(prev.agentId, prev.codeName);\n await stopGatewayIfRunning(prev.codeName, adapter);\n }\n }\n\n // Health check: restart crashed gateways\n await healthCheckGateways(agentStates);\n\n // Monitor cron health — detect late/failed jobs and alert (throttled)\n const lastHealthCheck = lastHarvestAt.get('__cron_health__') ?? 0;\n if (Date.now() - lastHealthCheck >= HARVEST_INTERVAL_MS) {\n lastHarvestAt.set('__cron_health__', Date.now());\n monitorCronHealth(agentStates).catch((err) => {\n log(`Cron health monitor error: ${(err as Error).message}`);\n });\n }\n\n // Direct chat: use Realtime if connected, fall back to polling\n if (!isRealtimeConnected()) {\n pollDirectChatMessages(agentStates).catch((err) => {\n log(`Direct chat poll error: ${(err as Error).message}`);\n });\n }\n\n // Start Realtime subscription if not yet started and we have Supabase config\n ensureRealtimeStarted(agentStates);\n ensureRealtimeDriftStarted(agentStates);\n ensureRealtimeAssignStarted(agentStates);\n ensureRealtimeConfigStarted(agentStates);\n ensureRealtimeKanbanStarted(agentStates);\n\n // Spawn due recurring kanban templates\n try {\n const spawnData = await api.post<{ spawned: number }>('/host/kanban/recurring/spawn');\n if (spawnData.spawned > 0) {\n log(`Spawned ${spawnData.spawned} recurring kanban item(s)`);\n }\n } catch { /* non-fatal */ }\n\n state = {\n ...state,\n lastPollAt: new Date().toISOString(),\n pollCount: state.pollCount + 1,\n agents: agentStates,\n };\n\n send({ type: 'state-update', state });\n } catch (err) {\n state.errorCount++;\n const message = (err as Error).message;\n log(`Poll error: ${message}`);\n send({ type: 'error', message });\n\n // Fatal auth error — exit so watchdog can restart with backoff\n if (message.includes('exchange failed') || message.includes('401')) {\n log('Fatal auth error, exiting for watchdog restart');\n send({ type: 'shutdown' });\n process.exit(1);\n }\n }\n}\n\nasync function getOrCacheRegisteredAgents(adapter: FrameworkAdapter, profile?: string): Promise<Set<string>> {\n const cacheKey = profile ? `${adapter.id}:${profile}` : adapter.id;\n let cached = registeredAgentsCache.get(cacheKey);\n if (!cached) {\n cached = await adapter.getRegisteredAgents(profile);\n registeredAgentsCache.set(cacheKey, cached);\n }\n return cached;\n}\n\nasync function processAgent(\n agent: { agent_id: string; code_name: string; display_name: string; status: string; environment: string; framework?: string },\n agentStates: AgentState[],\n): Promise<void> {\n if (!config) return;\n\n log(`==================== ${agent.display_name} (${agent.code_name}) ====================`);\n agentDisplayNames.set(agent.code_name, agent.display_name);\n codeNameToAgentId.set(agent.code_name, agent.agent_id);\n\n // Cache the framework from the agent list response (refreshAgentConfig may override with more specific data)\n if (agent.framework) {\n agentFrameworkCache.set(agent.code_name, agent.framework);\n }\n\n const now = new Date().toISOString();\n const agentDir = join(config.configDir, agent.code_name, 'provision');\n const adapter = resolveAgentFramework(agent.code_name);\n\n // 1a. Status-aware branching\n if (agent.status === 'draft' || agent.status === 'paused') {\n log(`Agent '${agent.code_name}' is ${agent.status}, skipping provisioning`);\n await stopGatewayIfRunning(agent.code_name, adapter);\n // Kill persistent tmux session if it exists (prevents paused agents responding on channels)\n // Must use tmux kill-session directly — the sessions Map doesn't track sessions from previous manager runs\n stopPersistentSession(agent.code_name, log);\n try {\n const { execSync: es } = await import('node:child_process');\n es(`tmux kill-session -t agt-${agent.code_name} 2>/dev/null`, { stdio: 'ignore' });\n log(`Killed tmux session for paused agent '${agent.code_name}'`);\n } catch { /* no session to kill */ }\n agentStates.push({\n agentId: agent.agent_id,\n codeName: agent.code_name,\n status: agent.status,\n charterVersion: '',\n toolsVersion: '',\n secretsHash: null,\n lastRefreshAt: now,\n lastProvisionAt: null,\n lastDriftCheckAt: null,\n lastSecretsProvisionAt: null,\n gatewayPort: null,\n gatewayPid: null,\n gatewayRunning: false,\n acpSessions: [],\n });\n return;\n }\n\n if (agent.status === 'revoked') {\n log(`Agent '${agent.code_name}' is revoked, cleaning up`);\n await stopGatewayIfRunning(agent.code_name, adapter);\n stopPersistentSession(agent.code_name, log);\n try { const { execSync: es } = await import('node:child_process'); es(`tmux kill-session -t agt-${agent.code_name} 2>/dev/null`, { stdio: 'ignore' }); } catch { /* no session */ }\n freePort(agent.code_name);\n await cleanupAgentFiles(agent.code_name, agentDir);\n clearAgentCaches(agent.agent_id, agent.code_name);\n knownStatuses.set(agent.agent_id, agent.status);\n agentStates.push({\n agentId: agent.agent_id,\n codeName: agent.code_name,\n status: agent.status,\n charterVersion: '',\n toolsVersion: '',\n secretsHash: null,\n lastRefreshAt: now,\n lastProvisionAt: null,\n lastDriftCheckAt: null,\n lastSecretsProvisionAt: null,\n gatewayPort: null,\n gatewayPid: null,\n gatewayRunning: false,\n acpSessions: [],\n });\n return;\n }\n\n // 1b. Detect status change → force reprovision and channel re-evaluation\n const previousStatus = knownStatuses.get(agent.agent_id);\n if (previousStatus && previousStatus !== agent.status) {\n log(`Agent '${agent.code_name}' status changed: ${previousStatus} → ${agent.status}`);\n knownVersions.delete(agent.agent_id); // Force reprovision\n // Invalidate channel config hashes so credentials/bindings/enabled state get rewritten\n for (const key of knownChannelConfigHashes.keys()) {\n if (key.startsWith(`${agent.agent_id}:`)) knownChannelConfigHashes.delete(key);\n }\n }\n knownStatuses.set(agent.agent_id, agent.status);\n\n // 2. Refresh — get latest charter/tools from API\n let refreshData: {\n agent: Record<string, unknown>;\n charter: { raw_content: string; version: string } | null;\n tools: { raw_content: string; version: string } | null;\n channel_configs: Record<string, { config: unknown; status: string }> | null;\n team_channel_policy: {\n team_id: string;\n allowed_channels: string[];\n denied_channels: string[];\n require_elevated_for_pii: boolean;\n } | null;\n team: { name: string; description: string | null; settings?: Record<string, unknown> } | null;\n scheduled_tasks: Array<{\n id: string;\n template_id: string;\n name: string;\n schedule_kind: string;\n schedule_expr: string | null;\n schedule_every: string | null;\n schedule_at: string | null;\n timezone: string;\n prompt: string;\n session_target: string;\n delivery_mode: string;\n delivery_channel: string;\n delivery_to: string | null;\n enabled: boolean;\n }> | null;\n };\n\n try {\n refreshData = await api.post<typeof refreshData>('/host/refresh', {\n agent_id: agent.agent_id,\n });\n } catch (err) {\n log(`Refresh failed for '${agent.code_name}': ${(err as Error).message}`);\n const existing = state.agents.find((a) => a.agentId === agent.agent_id);\n agentStates.push(existing ?? {\n agentId: agent.agent_id,\n codeName: agent.code_name,\n status: agent.status,\n charterVersion: '',\n toolsVersion: '',\n secretsHash: null,\n lastRefreshAt: null,\n lastProvisionAt: null,\n lastDriftCheckAt: null,\n lastSecretsProvisionAt: null,\n gatewayPort: null,\n gatewayPid: null,\n gatewayRunning: false,\n acpSessions: [],\n });\n return;\n }\n\n // Cache alert webhook from team settings (first agent wins)\n if (!alertSlackWebhook && refreshData.team?.settings) {\n const webhook = refreshData.team.settings['alert_slack_webhook'];\n if (typeof webhook === 'string' && webhook.startsWith('https://')) {\n alertSlackWebhook = webhook;\n }\n }\n\n if (!refreshData.charter || !refreshData.tools) {\n log(`No charter/tools for '${agent.code_name}', skipping`);\n agentStates.push({\n agentId: agent.agent_id,\n codeName: agent.code_name,\n status: agent.status,\n charterVersion: '',\n toolsVersion: '',\n secretsHash: null,\n lastRefreshAt: now,\n lastProvisionAt: null,\n lastDriftCheckAt: null,\n lastSecretsProvisionAt: null,\n gatewayPort: null,\n gatewayPid: null,\n gatewayRunning: false,\n acpSessions: [],\n });\n return;\n }\n\n // Resolve framework adapter from agent data and update cache\n const frameworkId = (refreshData.agent.framework as string) ?? 'openclaw';\n agentFrameworkCache.set(agent.code_name, frameworkId);\n const frameworkAdapter = getFramework(frameworkId);\n\n // Ensure per-agent profile config exists\n if (frameworkAdapter.seedProfileConfig) {\n frameworkAdapter.seedProfileConfig(agent.code_name);\n }\n\n const charterVersion = refreshData.charter.version;\n const toolsVersion = refreshData.tools.version;\n const known = knownVersions.get(agent.agent_id);\n\n let lastProvisionAt = state.agents.find((a) => a.agentId === agent.agent_id)?.lastProvisionAt ?? null;\n\n // Detect channel changes\n const currentChannelIds = new Set(Object.keys(refreshData.channel_configs ?? {}));\n const previousChannelIds = knownChannels.get(agent.agent_id);\n const channelsChanged = !previousChannelIds ||\n currentChannelIds.size !== previousChannelIds.size ||\n [...currentChannelIds].some((ch) => !previousChannelIds.has(ch)) ||\n [...previousChannelIds].some((ch) => !currentChannelIds.has(ch));\n\n // Remove credentials for channels that were unbound\n if (previousChannelIds && channelsChanged && frameworkAdapter.removeChannelCredentials) {\n for (const ch of previousChannelIds) {\n if (!currentChannelIds.has(ch)) {\n try {\n frameworkAdapter.removeChannelCredentials(agent.code_name, ch);\n log(`Removed ${ch} credentials for '${agent.code_name}'`);\n } catch (err) {\n log(`Failed to remove ${ch} credentials for '${agent.code_name}': ${(err as Error).message}`);\n }\n }\n }\n }\n\n knownChannels.set(agent.agent_id, currentChannelIds);\n\n // 3. Content-based re-provisioning: always generate artifacts, compare against\n // what's on disk, and only write files that actually changed. This catches\n // template code changes, DB data changes (role, description), and version bumps.\n try {\n const artifacts = generateArtifacts(agent, refreshData, frameworkAdapter);\n const changedFiles: { relativePath: string; content: string }[] = [];\n\n mkdirSync(agentDir, { recursive: true });\n for (const artifact of artifacts) {\n const filePath = join(agentDir, artifact.relativePath);\n const newHash = sha256(artifact.content);\n const existingHash = hashFile(filePath);\n\n if (newHash !== existingHash) {\n changedFiles.push(artifact);\n }\n }\n\n if (changedFiles.length > 0) {\n const isFirst = !existsSync(join(agentDir, 'CHARTER.md'));\n const verb = isFirst ? 'Provisioning' : 'Updating';\n const fileNames = changedFiles.map((f) => f.relativePath).join(', ');\n log(`${verb} '${agent.code_name}': ${fileNames}`);\n\n for (const file of changedFiles) {\n writeFileSync(join(agentDir, file.relativePath), file.content);\n }\n lastProvisionAt = new Date().toISOString();\n\n knownVersions.set(agent.agent_id, { charterVersion, toolsVersion });\n\n // Update written hashes for drift detection\n const trackedFiles = frameworkAdapter.driftTrackedFiles();\n const hashes = new Map<string, string>();\n for (const file of trackedFiles) {\n const h = hashFile(join(agentDir, file));\n if (h) hashes.set(file, h);\n }\n writtenHashes.set(agent.agent_id, hashes);\n\n // Register in framework runtime if not already present\n const resolvedModelsForRegistration = resolveModelChain(refreshData);\n const primaryModel = resolvedModelsForRegistration.primary ?? (refreshData.agent.primary_model as string | null | undefined);\n const registeredAgents = await getOrCacheRegisteredAgents(frameworkAdapter, agent.code_name);\n if (!registeredAgents.has(agent.code_name)) {\n const registered = await frameworkAdapter.registerAgent(agent.code_name, agentDir, primaryModel);\n if (registered) {\n registeredAgents.add(agent.code_name);\n log(`Registered '${agent.code_name}' in ${frameworkAdapter.label}`);\n }\n }\n\n send({ type: 'provisioned', agentId: agent.agent_id, codeName: agent.code_name });\n }\n\n // Always deploy artifacts to project dir — the provision dir is the source\n // of truth, and channel MCP servers are merged from a separate path.\n // This must run outside changedFiles so the merge always produces a\n // complete .mcp.json (base servers + channel servers).\n if (frameworkAdapter.deployArtifactsToProject) {\n frameworkAdapter.deployArtifactsToProject(agent.code_name, agentDir);\n }\n } catch (err) {\n log(`Provision failed for '${agent.code_name}': ${(err as Error).message}`);\n }\n\n // 3b. Ensure model is set correctly in per-agent profile (on first run and on change)\n const resolvedForModel = resolveModelChain(refreshData);\n const primaryModel = resolvedForModel.primary ?? (refreshData.agent.primary_model as string | null | undefined);\n if (primaryModel && frameworkAdapter.updateAgentModel) {\n const previousModel = knownModels.get(agent.agent_id);\n if (previousModel !== primaryModel) {\n try {\n const updated = await frameworkAdapter.updateAgentModel(agent.code_name, primaryModel);\n if (updated) {\n if (previousModel) {\n log(`Model updated for '${agent.code_name}': ${previousModel} → ${primaryModel}`);\n } else {\n log(`Model set for '${agent.code_name}': ${primaryModel}`);\n }\n }\n } catch (err) {\n log(`Failed to update model for '${agent.code_name}': ${(err as Error).message}`);\n }\n }\n knownModels.set(agent.agent_id, primaryModel);\n }\n\n // 4. Drift check — hash local files and compare\n let lastDriftCheckAt = now;\n const written = writtenHashes.get(agent.agent_id);\n\n if (written && existsSync(agentDir)) {\n const driftedFiles: string[] = [];\n\n for (const [file, expectedHash] of written) {\n const localHash = hashFile(join(agentDir, file));\n if (localHash && localHash !== expectedHash) {\n driftedFiles.push(file);\n }\n }\n\n if (driftedFiles.length > 0) {\n log(`Drift detected for '${agent.code_name}': ${driftedFiles.join(', ')}`);\n send({ type: 'drift-detected', agentId: agent.agent_id, codeName: agent.code_name, files: driftedFiles });\n\n // Report drift to API\n try {\n const localHashes: Record<string, string | null> = {};\n for (const file of driftedFiles) {\n localHashes[file] = hashFile(join(agentDir, file));\n }\n await api.post('/host/drift', {\n agent_id: agent.agent_id,\n drifted_files: driftedFiles,\n local_hashes: localHashes,\n });\n } catch (err) {\n log(`Failed to report drift for '${agent.code_name}': ${(err as Error).message}`);\n }\n }\n }\n\n // Cache bot tokens from channel_configs for notification delivery\n if (refreshData.channel_configs) {\n const tokens: { slack?: string; telegram?: string; telegramAllowedChats?: string[] } = {};\n const slackCfg = refreshData.channel_configs['slack'];\n if (slackCfg?.config) {\n const bt = (slackCfg.config as Record<string, unknown>).bot_token;\n if (typeof bt === 'string' && bt) tokens.slack = bt;\n }\n const tgCfg = refreshData.channel_configs['telegram'];\n if (tgCfg?.config) {\n const tgConfig = tgCfg.config as Record<string, unknown>;\n const bt = tgConfig.bot_token;\n if (typeof bt === 'string' && bt) tokens.telegram = bt;\n const allowedChats = tgConfig.allowed_chat_ids;\n if (Array.isArray(allowedChats)) tokens.telegramAllowedChats = allowedChats as string[];\n }\n if (tokens.slack || tokens.telegram) {\n agentChannelTokens.set(agent.code_name, tokens);\n } else {\n agentChannelTokens.delete(agent.code_name);\n }\n }\n\n let needsGatewayRestart = false;\n\n // 5. Write channel credentials to per-agent profile config (only if changed)\n const hasChannelConfigs = refreshData.channel_configs && Object.keys(refreshData.channel_configs).length > 0;\n\n if (refreshData.channel_configs && frameworkAdapter.writeChannelCredentials) {\n if (agent.status === 'active') {\n for (const [channelId, entry] of Object.entries(refreshData.channel_configs)) {\n if ((entry.status === 'active' || entry.status === 'pending') && entry.config) {\n // Track that this channel is active for this agent's profile\n if (!activeChannels.has(channelId)) {\n activeChannels.set(channelId, new Set());\n }\n activeChannels.get(channelId)!.add(agent.code_name);\n\n // Hash the config to detect changes — skip credential write if identical to last poll\n const configHash = createHash('sha256').update(JSON.stringify(entry.config)).digest('hex');\n const cacheKey = `${agent.agent_id}:${channelId}`;\n if (knownChannelConfigHashes.get(cacheKey) === configHash) {\n continue;\n }\n try {\n const sessionMode = (refreshData.agent as Record<string, unknown>).session_mode as string | undefined;\n frameworkAdapter.writeChannelCredentials(agent.code_name, channelId, entry.config as Record<string, unknown>, { sessionMode });\n knownChannelConfigHashes.set(cacheKey, configHash);\n log(`Channel credentials written for '${agent.code_name}/${channelId}'`);\n } catch (err) {\n log(`Failed to write channel credentials for '${agent.code_name}/${channelId}': ${(err as Error).message}`);\n }\n }\n }\n } else if (agent.status === 'paused') {\n // Paused agents: disable channels in their profile\n if (frameworkAdapter.setChannelEnabled) {\n for (const channelId of Object.keys(refreshData.channel_configs)) {\n frameworkAdapter.setChannelEnabled(channelId, false, agent.code_name);\n }\n }\n }\n }\n\n // 6. Fetch and write auth profiles (secrets)\n let lastSecretsProvisionAt = state.agents.find((a) => a.agentId === agent.agent_id)?.lastSecretsProvisionAt ?? null;\n let secretsHash = knownSecretsHashes.get(agent.agent_id) ?? null;\n\n try {\n const secretsData = await api.post<{\n profiles: Array<{\n provider: string;\n profile_name: string;\n auth_type: string;\n api_key?: string;\n metadata: Record<string, unknown>;\n }>;\n secrets_hash: string | null;\n }>('/host/secrets', { agent_id: agent.agent_id });\n\n const newHash = secretsData.secrets_hash;\n const hashChanged = newHash !== secretsHash;\n\n if (hashChanged && secretsData.profiles.length > 0) {\n frameworkAdapter.writeAuthProfiles(agent.code_name, secretsData.profiles);\n lastSecretsProvisionAt = new Date().toISOString();\n log(`Secrets updated for '${agent.code_name}'`);\n }\n\n if (newHash) {\n knownSecretsHashes.set(agent.agent_id, newHash);\n secretsHash = newHash;\n } else {\n knownSecretsHashes.delete(agent.agent_id);\n secretsHash = null;\n }\n } catch (err) {\n // Non-fatal — secrets are supplementary to provisioning\n log(`Secrets fetch failed for '${agent.code_name}': ${(err as Error).message}`);\n }\n\n // 6b. Integration provisioning — fetch integrations, resolve satisfied capabilities,\n // install skills + CLI tools\n try {\n const integrationsData = await api.post<{\n integrations: Array<{\n id: string;\n definition_id: string;\n credentials: Record<string, unknown>;\n config: Record<string, unknown>;\n capabilities: Array<{ id: string; name: string; description: string; access: string }>;\n auth_type: string;\n display_name: string;\n scope: string;\n }>;\n }>('/host/agent-integrations', { agent_id: agent.agent_id });\n\n const integrations = integrationsData.integrations ?? [];\n\n // 6b-i. Refresh OAuth tokens nearing expiry (< 10 min remaining)\n for (const integration of integrations) {\n if (integration.auth_type !== 'oauth2') continue;\n const expiresAt = integration.credentials?.token_expires_at as string | undefined;\n const refreshToken = integration.credentials?.refresh_token as string | undefined;\n if (!expiresAt || !refreshToken) continue;\n\n const msRemaining = new Date(expiresAt).getTime() - Date.now();\n if (msRemaining > 10 * 60 * 1000) continue; // Still valid for > 10 min\n\n try {\n const integrationId = integration.id;\n if (!integrationId) continue;\n const refreshResult = await api.post<{ ok: boolean; expires_at?: string; access_token?: string }>(\n `/integrations/oauth/${integrationId}/refresh`,\n {},\n );\n if (refreshResult.ok) {\n // Update in-memory credentials so writeIntegrations() uses the new token\n integration.credentials.token_expires_at = refreshResult.expires_at;\n if (refreshResult.access_token) {\n integration.credentials.access_token = refreshResult.access_token;\n }\n log(`OAuth token refreshed for '${agent.code_name}/${integration.definition_id}'`);\n\n // Write live token file as fallback for agents not yet using the\n // token_refresh MCP tool. Agents with the plugin can call token.refresh\n // on demand instead of relying on this file-based handoff.\n if (frameworkAdapter.writeTokenFile) {\n frameworkAdapter.writeTokenFile(agent.code_name, integrations as Parameters<typeof frameworkAdapter.writeTokenFile>[1]);\n }\n }\n } catch (err) {\n log(`OAuth token refresh failed for '${agent.code_name}/${integration.definition_id}': ${(err as Error).message}`);\n }\n }\n\n if (integrations.length > 0) {\n // Hash integration credentials to detect credential changes\n const intHash = createHash('sha256')\n .update(JSON.stringify(integrations.map((i) => `${i.definition_id}:${JSON.stringify(i.credentials)}`)))\n .digest('hex')\n .slice(0, 16);\n const prevIntHash = knownIntegrationHashes.get(agent.agent_id);\n\n if (intHash !== prevIntHash) {\n // Write integration credentials via framework adapter\n if (frameworkAdapter.writeIntegrations) {\n frameworkAdapter.writeIntegrations(agent.code_name, integrations as Parameters<typeof frameworkAdapter.writeIntegrations>[1]);\n }\n knownIntegrationHashes.set(agent.agent_id, intHash);\n log(`Integrations provisioned for '${agent.code_name}' (${integrations.length} integration(s))`);\n\n // Flag: restart gateway later (step 8) so new env vars take effect\n needsGatewayRestart = true;\n\n // Auto-install lossless-claw plugin if integration is present\n const hasLcm = integrations.some((i) => i.definition_id === 'lossless-claw');\n if (hasLcm && !losslessClawInstalled.get(agent.code_name)) {\n try {\n const { execFileSync } = await import('node:child_process');\n // Check if plugin is already installed\n let pluginList: string;\n try {\n pluginList = execFileSync(\n 'openclaw',\n ['--profile', agent.code_name, 'plugins', 'list', '--json'],\n { timeout: 15_000 },\n ).toString();\n } catch {\n pluginList = '[]';\n }\n const installed = JSON.parse(pluginList) as Array<{ name: string }>;\n const alreadyInstalled = installed.some(\n (p) => p.name === 'lossless-claw' || p.name === '@martian-engineering/lossless-claw',\n );\n if (!alreadyInstalled) {\n log(`Installing lossless-claw plugin for '${agent.code_name}'...`);\n execFileSync(\n 'openclaw',\n ['--profile', agent.code_name, 'plugins', 'install', '@martian-engineering/lossless-claw'],\n { stdio: 'ignore', timeout: 60_000 },\n );\n log(`lossless-claw plugin installed for '${agent.code_name}'`);\n }\n losslessClawInstalled.set(agent.code_name, true);\n } catch (pluginErr) {\n log(`lossless-claw plugin install failed for '${agent.code_name}': ${(pluginErr as Error).message}`);\n }\n }\n }\n\n // Sync capability skill files — hashed separately so skill content\n // updates get deployed even when credentials haven't changed.\n const resolvedDefIds = new Set(integrations.map((i) => i.definition_id));\n\n for (const capId of resolvedDefIds) {\n try {\n const capData = await api.post<{\n capability_id: string;\n requiredIntegrations: string[];\n skills: Array<{\n id: string;\n name: string;\n allowedTools: string[];\n files: Array<{ relativePath: string; content: string }>;\n }>;\n cliTools: Array<{ package: string; binary: string; envKey: string; fromIntegration: string }>;\n }>('/host/capability-skill', { definition_id: capId });\n\n // Check all required integrations are satisfied\n const allSatisfied = capData.requiredIntegrations.every((reqId) => resolvedDefIds.has(reqId));\n if (!allSatisfied) {\n const missing = capData.requiredIntegrations.filter((reqId) => !resolvedDefIds.has(reqId));\n log(`Capability '${capId}' skipped — missing integration(s): ${missing.join(', ')}`);\n continue;\n }\n\n // Hash skill file content to detect changes\n const skillContent = JSON.stringify(capData.skills.map((s) => s.files.map((f) => `${f.relativePath}:${f.content}`)));\n const skillHash = createHash('sha256').update(skillContent).digest('hex').slice(0, 16);\n const skillKey = `${agent.agent_id}:${capId}`;\n const prevSkillHash = knownSkillHashes.get(skillKey);\n\n if (skillHash !== prevSkillHash) {\n // Install skill files via framework adapter\n if (frameworkAdapter.installSkillFiles && capData.skills) {\n for (const skill of capData.skills) {\n if (skill.files.length > 0) {\n frameworkAdapter.installSkillFiles(agent.code_name, skill.id, skill.files);\n log(`Installed skill '${skill.id}' for '${agent.code_name}' (${skill.files.length} file(s))`);\n }\n }\n }\n knownSkillHashes.set(skillKey, skillHash);\n }\n\n // Install CLI tools — each tool declares which integration provides its credential\n // Only packages on the explicit allowlist may be auto-installed (deny-by-default)\n const ALLOWED_CLI_PACKAGES = new Set([\n 'xero-cli',\n '@openapitools/openapi-generator-cli',\n 'gh',\n '@schpet/linear-cli',\n '@googleworkspace/cli',\n '@tobilu/qmd',\n ]);\n\n if (intHash !== prevIntHash) {\n const { execFileSync } = await import('node:child_process');\n for (const tool of capData.cliTools) {\n if (!ALLOWED_CLI_PACKAGES.has(tool.package)) {\n log(`Skipping CLI tool '${tool.package}' for '${agent.code_name}' — not on the allowed packages list`);\n continue;\n }\n // Check if binary is already on PATH, install if not\n try {\n execFileSync('which', [tool.binary], { stdio: 'ignore' });\n } catch {\n log(`Installing CLI tool '${tool.package}' for '${agent.code_name}'...`);\n try {\n execFileSync('npm', ['install', '-g', tool.package], { stdio: 'ignore', timeout: 60_000 });\n log(`CLI tool '${tool.binary}' installed successfully`);\n } catch (installErr) {\n log(`Failed to install CLI tool '${tool.package}': ${(installErr as Error).message}`);\n }\n }\n\n // Post-install setup hooks (run whether freshly installed or already present)\n if (tool.binary === 'qmd') {\n try {\n // qmd collection add uses CWD-relative paths — run from the agent's\n // parent dir with 'project' as relative path for correct resolution\n const agentDir = join(process.env['HOME'] ?? '/tmp', '.augmented', agent.code_name);\n execFileSync('qmd', ['collection', 'add', agent.code_name, 'project'], {\n stdio: 'ignore', timeout: 30_000, cwd: agentDir,\n });\n log(`QMD collection '${agent.code_name}' configured`);\n } catch { /* collection may already exist — non-fatal */ }\n }\n }\n }\n } catch (skillErr) {\n // Non-fatal — capability may not have a package yet (e.g. github, xero)\n const msg = (skillErr as Error).message ?? '';\n if (!msg.includes('404') && !msg.includes('Unknown capability')) {\n log(`Capability fetch failed for '${capId}': ${msg}`);\n }\n }\n }\n }\n } catch (err) {\n // Non-fatal — integration provisioning is supplementary\n log(`Integration provisioning failed for '${agent.code_name}': ${(err as Error).message}`);\n }\n\n // 7. Gateway lifecycle — ensure running for active agents with channels\n let gatewayPort: number | null = null;\n let gatewayPid: number | null = null;\n let gatewayRunning = false;\n\n if (agent.status === 'active' && hasChannelConfigs) {\n const gwStatus = await ensureGatewayRunning(agent.code_name, frameworkAdapter);\n gatewayPort = gwStatus.port;\n gatewayPid = gwStatus.pid;\n gatewayRunning = gwStatus.running;\n } else if (agent.status === 'paused') {\n // Stop gateway for paused agents\n await stopGatewayIfRunning(agent.code_name, frameworkAdapter);\n }\n\n // Note: gateway restart after integration changes removed — was killing gateways.\n // New env vars take effect on next gateway restart (manual or via manager cycle).\n\n // 7b. Auto-provision org/team default schedules\n let tasks = refreshData.scheduled_tasks ?? [];\n const existingTemplateIds = new Set(tasks.map((t) => t.template_id));\n\n try {\n const defaultsData = await api.post<{\n schedules: Array<{\n template_id: string;\n name: string;\n schedule_expr: string;\n prompt: string;\n session_target?: string;\n enabled?: boolean;\n }>;\n team_id: string;\n timezone: string;\n }>('/host/resolve-default-schedules', { agent_id: agent.agent_id });\n\n const missing = (defaultsData.schedules ?? []).filter(\n (s) => !existingTemplateIds.has(s.template_id),\n );\n\n // Always call ensure-default-schedules to insert missing tasks and\n // fix delivery_mode on existing tasks that don't match the template default.\n const allSchedules = defaultsData.schedules ?? [];\n if (allSchedules.length > 0) {\n await api.post('/host/ensure-default-schedules', {\n agent_id: agent.agent_id,\n team_id: defaultsData.team_id,\n timezone: defaultsData.timezone,\n schedules: allSchedules,\n });\n if (missing.length > 0) {\n log(`Auto-provisioned ${missing.length} default schedule(s) for '${agent.code_name}': ${missing.map((s) => s.template_id).join(', ')}`);\n }\n\n // Re-fetch tasks since schedules may have changed\n const freshData = await api.post<{ scheduled_tasks?: typeof tasks }>('/host/refresh', { agent_id: agent.agent_id });\n tasks = freshData.scheduled_tasks ?? tasks;\n }\n } catch (err) {\n log(`Default schedule provisioning failed for '${agent.code_name}': ${(err as Error).message}`);\n }\n\n // 7c. Auto-provision Augmented plugin and kanban skill for all active agents\n if (agent.status === 'active') {\n // Augmented OpenClaw plugin — provides kanban_list, kanban_add, kanban_move,\n // kanban_update, kanban_done, status_standup, status_update tools natively\n if (frameworkAdapter.installPlugin) {\n try {\n const pluginPath = join(process.cwd(), 'packages', 'openclaw-plugin-augmented', 'src', 'index.ts');\n if (existsSync(pluginPath)) {\n frameworkAdapter.installPlugin(agent.code_name, 'augmented', pluginPath, {\n agtHost: requireHost(),\n agtApiKey: getApiKey() ?? undefined,\n agentId: agent.agent_id,\n });\n }\n } catch (err) {\n log(`Augmented plugin install failed for '${agent.code_name}': ${(err as Error).message}`);\n }\n }\n\n // Kanban skill files\n if (frameworkAdapter.installSkillFiles) {\n try {\n const skillContent = getBuiltInSkillContent('kanban');\n if (skillContent) {\n frameworkAdapter.installSkillFiles(agent.code_name, 'kanban', skillContent);\n }\n } catch (err) {\n log(`Kanban skill install failed for '${agent.code_name}': ${(err as Error).message}`);\n }\n }\n }\n\n // 7d. Fetch kanban board for prompt injection into board-aware templates\n let boardItems: BoardItem[] = [];\n const hasBoardTemplates = tasks.some((t) => BOARD_INJECT_TEMPLATES.has(t.template_id));\n if (hasBoardTemplates) {\n try {\n const boardData = await api.post<{ items?: BoardItem[] }>('/host/my-kanban', { agent_id: agent.agent_id });\n boardItems = (boardData.items ?? []).map(sanitizeBoardItem);\n kanbanBoardCache.set(agent.code_name, boardItems);\n } catch {\n // Non-fatal — board may not exist yet\n boardItems = kanbanBoardCache.get(agent.code_name) ?? [];\n }\n }\n\n // Resolve framework once for sections 8-11\n const agentFw = agentFrameworkCache.get(agent.code_name) ?? 'openclaw';\n\n // 8. Sync scheduled tasks\n const sessionMode = (refreshData.agent as Record<string, unknown>).session_mode as string ?? 'oneshot';\n\n if (agentFw === 'claude-code' && sessionMode === 'persistent') {\n // Claude Code persistent mode: manage long-running session with channels\n await ensurePersistentSession(agent, tasks, boardItems, refreshData);\n } else if (agentFw === 'claude-code' && tasks.length > 0) {\n // Claude Code oneshot mode: fire-and-forget via claude -p\n await syncAndCheckClaudeScheduler(agent, tasks, boardItems, refreshData);\n } else if (frameworkAdapter.syncScheduledTasks && gatewayRunning && gatewayPort) {\n // Hash ONLY stable task fields (without board-injected prompts) to decide\n // whether a re-sync is needed. Board context changes every poll cycle as\n // kanban items move around — hashing it caused syncScheduledTasks to fire\n // on every cycle, spawning duplicate openclaw-cron processes.\n const stableTasksHash = createHash('sha256')\n .update(JSON.stringify(tasks))\n .digest('hex')\n .slice(0, 16);\n\n // Board context hash — triggers a re-sync when the board meaningfully changes\n // (items added/removed, moved between columns, reprioritised, or renamed)\n const boardHash = boardItems.length > 0\n ? createHash('sha256')\n .update(JSON.stringify(boardItems.map((b) => ({ id: b.id, title: b.title, status: b.status, priority: b.priority, deliverable: b.deliverable }))))\n .digest('hex')\n .slice(0, 16)\n : 'empty';\n\n // Include resolved models in the hash so default changes trigger resync\n const resolvedModels = resolveModelChain(refreshData);\n const modelsHash = createHash('sha256')\n .update(JSON.stringify(resolvedModels))\n .digest('hex')\n .slice(0, 16);\n\n const combinedHash = `${stableTasksHash}:${boardHash}:${modelsHash}`;\n const prevTasksHash = knownTasksHashes.get(agent.agent_id);\n\n if (combinedHash !== prevTasksHash) {\n // Inject board context into prompts for board-aware templates\n const enrichedTasks = tasks.map((t) => {\n if (BOARD_INJECT_TEMPLATES.has(t.template_id) && boardItems.length > 0) {\n const template = PLAN_TEMPLATES.has(t.template_id) ? 'morning-plan' : 'follow-up';\n const boardPrefix = formatBoardForPrompt(boardItems, template);\n return { ...t, prompt: boardPrefix + t.prompt };\n }\n return t;\n });\n\n try {\n const token = readGatewayToken(agent.code_name);\n await frameworkAdapter.syncScheduledTasks(\n agent.code_name,\n enrichedTasks.map((t) => ({\n id: t.id,\n template_id: t.template_id,\n name: t.name,\n schedule_kind: t.schedule_kind as 'cron' | 'every' | 'at',\n schedule_expr: t.schedule_expr,\n schedule_every: t.schedule_every,\n schedule_at: t.schedule_at,\n timezone: t.timezone,\n prompt: t.prompt,\n session_target: t.session_target as 'main' | 'isolated',\n delivery_mode: t.delivery_mode as 'announce' | 'none',\n delivery_channel: t.delivery_channel,\n delivery_to: t.delivery_to,\n enabled: t.enabled,\n model_tier: ((t as Record<string, unknown>).model_tier as 'primary' | 'secondary' | 'tertiary' | undefined) ?? 'primary',\n })),\n gatewayPort,\n token,\n {\n models: resolvedModels,\n },\n );\n knownTasksHashes.set(agent.agent_id, combinedHash);\n log(`Scheduled tasks synced for '${agent.code_name}' (${enrichedTasks.length} task(s))`);\n } catch (err) {\n log(`Failed to sync scheduled tasks for '${agent.code_name}': ${(err as Error).message}`);\n }\n }\n }\n\n // Update task display info map for cron health alerts\n for (const t of tasks) {\n const jobName = `aug:${t.template_id}:${t.id ?? t.name.toLowerCase().replace(/\\s+/g, '-')}`;\n taskDisplayInfo.set(`${agent.code_name}:${jobName}`, {\n taskName: t.name,\n schedule: t.schedule_expr ?? t.schedule_every ?? '',\n agentDisplayName: agent.display_name,\n });\n }\n\n // 9. Harvest cron run results for standup/task updates (throttled to reduce process spawning)\n const ccInFlight = agentFw === 'claude-code' ? (claudeTaskConcurrency.get(agent.code_name) ?? 0) : null;\n log(`[${agent.code_name}] Harvest gate: gatewayRunning=${gatewayRunning} gatewayPort=${gatewayPort} tasks=${tasks.length} fw=${agentFw}${ccInFlight !== null ? ` claude-p=${ccInFlight}/${MAX_CLAUDE_CONCURRENCY}` : ''}`);\n if (agentFw === 'openclaw' && gatewayRunning && gatewayPort && tasks.length > 0) {\n const lastHarvest = lastHarvestAt.get(agent.code_name) ?? 0;\n if (Date.now() - lastHarvest >= HARVEST_INTERVAL_MS) {\n lastHarvestAt.set(agent.code_name, Date.now());\n harvestCronResults(agent.code_name, tasks, gatewayPort).catch((err) => {\n log(`Cron result harvest failed for '${agent.code_name}': ${(err as Error).message}`);\n });\n }\n }\n\n // 10. Immediate work trigger — if webapp signalled a new task, fire kanban-work now\n {\n const triggerAt = (refreshData.agent as Record<string, unknown>).work_trigger_at as string | null;\n if (triggerAt) {\n const triggerTs = new Date(triggerAt).getTime();\n const lastTrigger = lastWorkTriggerAt.get(agent.code_name) ?? 0;\n if (triggerTs > lastTrigger) {\n lastWorkTriggerAt.set(agent.code_name, triggerTs);\n\n if (agentFw === 'openclaw' && gatewayRunning && gatewayPort) {\n // OpenClaw: find kanban-work job ID from cron jobs file\n const homeDir = process.env['HOME'] ?? '/tmp';\n const jobsPath = join(homeDir, `.openclaw-${agent.code_name}`, 'cron', 'jobs.json');\n if (existsSync(jobsPath)) {\n try {\n const jobsData = JSON.parse(readFileSync(jobsPath, 'utf-8'));\n const kanbanJob = (jobsData.jobs ?? []).find((j: Record<string, unknown>) =>\n typeof j.name === 'string' && j.name.includes('kanban-work'),\n );\n if (kanbanJob?.id) {\n const cliBin = resolveAgentFramework(agent.code_name).cliBinary ?? 'openclaw';\n log(`Work trigger: firing kanban-work for '${agent.code_name}'`);\n execFilePromise(cliBin, ['--profile', agent.code_name, 'cron', 'run', kanbanJob.id])\n .then(() => log(`Work trigger succeeded for '${agent.code_name}'`))\n .catch((err) => log(`Work trigger failed for '${agent.code_name}': ${(err as Error).message}`));\n }\n } catch { /* jobs.json read failed — non-fatal */ }\n }\n } else if (agentFw === 'claude-code') {\n // Claude Code: find kanban-work task in scheduler state and fire immediately\n fireClaudeWorkTrigger(agent.code_name, agent.agent_id, boardItems);\n }\n }\n }\n }\n\n // 11. Clean up stale cron session files to prevent context overflow (OpenClaw only)\n if (agentFw === 'openclaw') {\n cleanupStaleSessions(agent.code_name);\n }\n\n // 12. Detect newly-done kanban items and send notifications (runs every cycle)\n {\n const agentId = codeNameToAgentId.get(agent.code_name);\n if (agentId) {\n try {\n const boardData = await api.post<{ items?: BoardItem[] }>('/host/my-kanban', { agent_id: agentId });\n const freshBoard = (boardData.items ?? []).map(sanitizeBoardItem);\n const freshDoneIds = new Set(freshBoard.filter((b) => b.status === 'done' || b.status === 'failed').map((b) => b.id));\n\n const previousDoneIds = notifyBoardCache.get(agent.code_name);\n notifyBoardCache.set(agent.code_name, freshDoneIds);\n\n // Skip first cycle — no previous state to compare against\n if (!previousDoneIds) {\n log(`[${agent.code_name}] Board diff: initial cache (${freshDoneIds.size} done items)`);\n } else {\n const newlyDone = freshBoard.filter(\n (b) => (b.status === 'done' || b.status === 'failed') && !previousDoneIds.has(b.id),\n );\n\n log(`[${agent.code_name}] Board diff: ${previousDoneIds.size} prev done → ${freshDoneIds.size} now, ${newlyDone.length} newly done`);\n\n if (newlyDone.length > 0) {\n const displayName = agentDisplayNames.get(agent.code_name) ?? agent.code_name;\n for (const item of newlyDone) {\n log(`Newly done: '${item.title}' notify_channel=${item.notify_channel ?? 'none'} notify_to=${item.notify_to ?? 'none'}`);\n if (item.notify_channel && item.notify_to) {\n const isFailed = item.status === 'failed';\n const resultLine = item.result ? `\\n${isFailed ? 'Reason' : 'Result'}: ${item.result}` : '';\n const emoji = isFailed ? '❌' : '✅';\n const message = `${emoji} ${isFailed ? 'Task Failed' : 'Task Complete'} — ${displayName}\\n${item.title}${resultLine}`;\n sendTaskNotification(agent.code_name, item.notify_channel, item.notify_to, message).catch((err) => {\n log(`sendTaskNotification failed for '${agent.code_name}': ${(err as Error).message}`);\n });\n }\n }\n }\n }\n // Check for stale in_progress items\n const staleItems = freshBoard.filter((b) => {\n if (b.status !== 'in_progress' || !b.updated_at) return false;\n const age = Date.now() - new Date(b.updated_at).getTime();\n return age > STALE_TASK_THRESHOLD_MS && !alertedStaleItems.has(`${agent.code_name}:${b.id}`);\n });\n\n if (staleItems.length > 0) {\n const displayName = agentDisplayNames.get(agent.code_name) ?? agent.code_name;\n for (const item of staleItems) {\n const age = Math.round((Date.now() - new Date(item.updated_at!).getTime()) / 60_000);\n log(`Stale task: '${item.title}' (id=${item.id}) in_progress for ${age}m — auto-failing for '${agent.code_name}'`);\n alertedStaleItems.add(`${agent.code_name}:${item.id}`);\n\n // Auto-fail the task via API (try ID first, fallback to title)\n try {\n const failResult = await api.post<{ ok?: boolean; updated?: number; error?: string }>('/host/kanban', {\n agent_id: agentId,\n update: [{ id: item.id, title: item.title, status: 'failed', result: `Timed out — in progress for ${age} minutes with no update` }],\n });\n log(`Auto-fail result for '${item.title}': updated=${failResult.updated}`);\n // Mark as done only when mutation actually succeeded,\n // so we don't suppress legitimate later notifications.\n if ((failResult.updated ?? 0) > 0 || failResult.ok === true) {\n freshDoneIds.add(item.id);\n }\n } catch (err) {\n log(`Auto-fail API error for '${item.title}': ${(err as Error).message}`);\n }\n\n // Notify\n const message = `⏳ Task Timed Out — ${displayName}\\n${item.title}\\nIn progress for ${age} minutes with no update — auto-failed`;\n if (item.notify_channel && item.notify_to) {\n sendTaskNotification(agent.code_name, item.notify_channel, item.notify_to, message).catch(() => {});\n }\n sendSlackWebhookMessage(`⏳ *Task Timed Out* — *${displayName}*\\n*${item.title}*\\nIn progress for ${age} minutes — auto-failed`).catch(() => {});\n }\n }\n\n // Clear stale alerts for items no longer in_progress (scoped to this agent)\n const prefix = `${agent.code_name}:`;\n for (const key of alertedStaleItems) {\n if (key.startsWith(prefix)) {\n const itemId = key.slice(prefix.length);\n if (!freshBoard.some((b) => b.id === itemId && b.status === 'in_progress')) {\n alertedStaleItems.delete(key);\n }\n }\n }\n } catch (err) {\n log(`Board diff failed for '${agent.code_name}': ${(err as Error).message}`);\n }\n }\n }\n\n agentStates.push({\n agentId: agent.agent_id,\n codeName: agent.code_name,\n status: agent.status,\n charterVersion,\n toolsVersion,\n secretsHash,\n lastRefreshAt: now,\n lastProvisionAt,\n lastDriftCheckAt,\n lastSecretsProvisionAt,\n gatewayPort,\n gatewayPid,\n gatewayRunning,\n acpSessions: [],\n });\n}\n\n// ---------------------------------------------------------------------------\n// Session cleanup — prevent context overflow from accumulated cron sessions\n// ---------------------------------------------------------------------------\n\nconst CRON_SESSION_KEEP_COUNT = 10;\nconst CRON_RUN_RETENTION_DAYS = 7;\nconst lastCleanupAt = new Map<string, number>();\nconst CLEANUP_INTERVAL_MS = 60_000; // Run cleanup every 1 minute per agent\n\nfunction cleanupStaleSessions(codeName: string): void {\n // Run immediately on first poll (lastRun defaults to 0), then throttle\n const lastRun = lastCleanupAt.get(codeName) ?? 0;\n if (lastRun > 0 && Date.now() - lastRun < CLEANUP_INTERVAL_MS) return;\n lastCleanupAt.set(codeName, Date.now());\n\n const homeDir = process.env['HOME'] ?? '/tmp';\n\n // 1. Clean CRON session files only (preserve chat/Slack/Telegram sessions)\n for (const agentDir of ['main', codeName]) {\n const sessionsDir = join(homeDir, `.openclaw-${codeName}`, 'agents', agentDir, 'sessions');\n cleanupCronSessions(sessionsDir, CRON_SESSION_KEEP_COUNT);\n }\n\n // 2. Clean cron run logs older than 7 days\n const cronRunsDir = join(homeDir, `.openclaw-${codeName}`, 'cron', 'runs');\n cleanupOldFiles(cronRunsDir, CRON_RUN_RETENTION_DAYS, '.jsonl');\n\n // 3. Clear stale \"running\" state from cron jobs.json.\n // If a cron run was in progress when the gateway crashed, the state persists\n // as \"running\" and blocks all future runs with \"already-running\". Reset any\n // run that's been \"running\" for more than 5 minutes.\n const cronJobsPath = join(homeDir, `.openclaw-${codeName}`, 'cron', 'jobs.json');\n clearStaleCronRunState(cronJobsPath);\n}\n\n/**\n * Clean up cron session entries from sessions.json and their corresponding\n * .jsonl files. Preserves chat, Slack, Telegram, and other non-cron sessions.\n *\n * Cron sessions have keys matching `agent:*:cron:*:run:*` in sessions.json.\n */\nfunction cleanupCronSessions(sessionsDir: string, keepCount: number): void {\n const indexPath = join(sessionsDir, 'sessions.json');\n if (!existsSync(indexPath)) return;\n\n try {\n const raw = readFileSync(indexPath, 'utf-8');\n const index = JSON.parse(raw) as Record<string, { sessionId?: string; updatedAt?: number }>;\n\n // Find cron run entries (pattern: agent:*:cron:*:run:*)\n const cronRunKeys = Object.keys(index)\n .filter((k) => k.includes(':cron:') && k.includes(':run:'))\n .map((k) => ({\n key: k,\n sessionId: index[k]?.sessionId,\n updatedAt: index[k]?.updatedAt ?? 0,\n }))\n .sort((a, b) => b.updatedAt - a.updatedAt); // newest first\n\n if (cronRunKeys.length <= keepCount) return;\n\n // Keep the most recent N, delete the rest\n const toDelete = cronRunKeys.slice(keepCount);\n let deletedFiles = 0;\n\n for (const entry of toDelete) {\n // Remove from index\n delete index[entry.key];\n\n // Delete the session .jsonl file\n if (entry.sessionId) {\n const sessionFile = join(sessionsDir, `${entry.sessionId}.jsonl`);\n try {\n if (existsSync(sessionFile)) {\n unlinkSync(sessionFile);\n deletedFiles++;\n }\n } catch { /* ignore */ }\n }\n }\n\n // Also clean up parent cron session keys that have no remaining runs\n const cronParentKeys = Object.keys(index).filter(\n (k) => k.includes(':cron:') && !k.includes(':run:') && k !== 'agent:main:main',\n );\n for (const parentKey of cronParentKeys) {\n const hasRuns = Object.keys(index).some(\n (k) => k.startsWith(parentKey + ':run:'),\n );\n if (!hasRuns) {\n const parentSessionId = index[parentKey]?.sessionId;\n delete index[parentKey];\n if (parentSessionId) {\n try {\n const f = join(sessionsDir, `${parentSessionId}.jsonl`);\n if (existsSync(f)) { unlinkSync(f); deletedFiles++; }\n } catch { /* ignore */ }\n }\n }\n }\n\n // Write updated index\n writeFileSync(indexPath, JSON.stringify(index));\n\n if (toDelete.length > 0) {\n log(`Cleaned ${toDelete.length} cron session(s) and ${deletedFiles} file(s) from ${sessionsDir}`);\n }\n } catch { /* non-fatal */ }\n}\n\nconst STALE_RUN_TIMEOUT_MS = 5 * 60_000; // 5 minutes\n\nfunction clearStaleCronRunState(jobsPath: string): void {\n if (!existsSync(jobsPath)) return;\n\n try {\n const raw = readFileSync(jobsPath, 'utf-8');\n const data = JSON.parse(raw) as Record<string, unknown>;\n const jobs = (data.jobs ?? data) as Array<Record<string, unknown>>;\n if (!Array.isArray(jobs)) return;\n\n let changed = false;\n const now = Date.now();\n\n for (const job of jobs) {\n const state = job.state as Record<string, unknown> | undefined;\n if (!state) continue;\n\n // Check if a run is stuck in \"running\" state\n // OpenClaw uses `running: true` + `runningAtMs` (not `runStartedAtMs`)\n const runStartedAt = (state.runningAtMs ?? state.runStartedAtMs) as number | undefined;\n const isRunning = state.running === true || state.status === 'running';\n\n if (isRunning && runStartedAt && (now - runStartedAt) > STALE_RUN_TIMEOUT_MS) {\n state.running = false;\n delete state.status;\n delete state.runStartedAtMs;\n delete state.currentRunId;\n changed = true;\n log(`Cleared stale running state for cron job '${job.name}' (stuck for ${Math.round((now - runStartedAt) / 60_000)}min)`);\n } else if (isRunning && !runStartedAt) {\n // running=true but no timestamp — clear it\n state.running = false;\n changed = true;\n log(`Cleared stale running state for cron job '${job.name}' (no start timestamp)`);\n }\n }\n\n if (changed) {\n writeFileSync(jobsPath, JSON.stringify(data, null, 2));\n }\n } catch { /* non-fatal */ }\n}\n\nfunction cleanupOldFiles(dir: string, maxAgeDays: number, ext: string): void {\n if (!existsSync(dir)) return;\n\n const cutoff = Date.now() - maxAgeDays * 24 * 60 * 60 * 1000;\n let removed = 0;\n\n try {\n for (const f of readdirSync(dir)) {\n if (!f.endsWith(ext)) continue;\n const fullPath = join(dir, f);\n try {\n const st = statSync(fullPath);\n if (st.mtimeMs < cutoff) {\n unlinkSync(fullPath);\n removed++;\n }\n } catch { /* ignore */ }\n }\n\n if (removed > 0) {\n log(`Cleaned ${removed} old cron run log(s) from ${dir}`);\n }\n } catch { /* non-fatal */ }\n}\n\n// ---------------------------------------------------------------------------\n// Claude Code in-process scheduler\n// ---------------------------------------------------------------------------\n\nimport {\n syncTasksToScheduler,\n getReadyTasks,\n markTaskFired,\n loadSchedulerState,\n findTaskByTemplate,\n getProjectDir as ccGetProjectDir,\n type SchedulerTaskInput,\n type SchedulerTaskState,\n} from './claude-scheduler.js';\n\n// Track in-flight Claude scheduled tasks and concurrency per agent\nconst inFlightClaudeTasks = new Set<string>();\nconst claudeTaskConcurrency = new Map<string, number>();\nconst MAX_CLAUDE_CONCURRENCY = 2;\n\n// In-memory scheduler states (loaded from disk on first access)\nconst claudeSchedulerStates = new Map<string, ReturnType<typeof loadSchedulerState>>();\n\nasync function syncAndCheckClaudeScheduler(\n agent: { agent_id: string; code_name: string; display_name: string },\n tasks: Array<Record<string, unknown>>,\n boardItems: Array<{ id: string; title: string; status: string; priority: number; estimated_minutes?: number; deliverable?: string; result?: string; notify_channel?: string; notify_to?: string }>,\n refreshData: Record<string, unknown>,\n): Promise<void> {\n const codeName = agent.code_name;\n\n // Hash-based change detection (same as OpenClaw path)\n const stableTasksHash = createHash('sha256')\n .update(JSON.stringify(tasks))\n .digest('hex')\n .slice(0, 16);\n\n const boardHash = boardItems.length > 0\n ? createHash('sha256')\n .update(JSON.stringify(boardItems.map((b) => ({ id: b.id, title: b.title, status: b.status, priority: b.priority, deliverable: b.deliverable }))))\n .digest('hex')\n .slice(0, 16)\n : 'empty';\n\n const resolvedModels = resolveModelChain(refreshData);\n const modelsHash = createHash('sha256')\n .update(JSON.stringify(resolvedModels))\n .digest('hex')\n .slice(0, 16);\n\n const combinedHash = `${stableTasksHash}:${boardHash}:${modelsHash}`;\n const prevHash = knownTasksHashes.get(agent.agent_id);\n\n if (combinedHash !== prevHash) {\n // Sync tasks to scheduler state\n const taskInputs: SchedulerTaskInput[] = tasks.map((t) => ({\n id: t.id as string,\n template_id: t.template_id as string,\n name: t.name as string,\n schedule_kind: t.schedule_kind as 'cron' | 'every' | 'at',\n schedule_expr: (t.schedule_expr as string) ?? null,\n schedule_every: (t.schedule_every as string) ?? null,\n schedule_at: (t.schedule_at as string) ?? null,\n timezone: (t.timezone as string) ?? 'UTC',\n prompt: (t.prompt as string) ?? '',\n session_target: (t.session_target as string) ?? 'isolated',\n delivery_mode: (t.delivery_mode as string) ?? 'none',\n delivery_channel: (t.delivery_channel as string) ?? null,\n delivery_to: (t.delivery_to as string) ?? null,\n enabled: (t.enabled as boolean) ?? true,\n }));\n\n const state = syncTasksToScheduler(codeName, agent.agent_id, taskInputs);\n claudeSchedulerStates.set(codeName, state);\n knownTasksHashes.set(agent.agent_id, combinedHash);\n log(`[claude-scheduler] Tasks synced for '${codeName}' (${taskInputs.length} task(s))`);\n }\n\n // Load state if not cached\n if (!claudeSchedulerStates.has(codeName)) {\n claudeSchedulerStates.set(codeName, loadSchedulerState(codeName));\n }\n\n const state = claudeSchedulerStates.get(codeName)!;\n const ready = getReadyTasks(state);\n if (ready.length === 0) return;\n\n for (const task of ready) {\n if (inFlightClaudeTasks.has(task.taskId)) continue;\n if ((claudeTaskConcurrency.get(codeName) ?? 0) >= MAX_CLAUDE_CONCURRENCY) break;\n\n // Enrich prompt with board context\n let prompt = task.prompt;\n if (BOARD_INJECT_TEMPLATES.has(task.templateId) && boardItems.length > 0) {\n const template = PLAN_TEMPLATES.has(task.templateId) ? 'morning-plan' : 'follow-up';\n const boardPrefix = formatBoardForPrompt(boardItems, template);\n prompt = boardPrefix + prompt;\n }\n\n // For kanban-work: move the top \"today\" item to in_progress before starting\n if (KANBAN_WORK_TEMPLATES.has(task.templateId)) {\n const todayItem = boardItems.find((b) => b.status === 'today');\n if (todayItem) {\n try {\n await api.post('/host/kanban', {\n agent_id: agent.agent_id,\n update: [{ id: todayItem.id, title: todayItem.title, status: 'in_progress' }],\n });\n log(`[claude-scheduler] Moved '${todayItem.title}' to in_progress for '${codeName}'`);\n } catch (err) {\n log(`[claude-scheduler] Failed to move item to in_progress: ${(err as Error).message}`);\n }\n }\n }\n\n inFlightClaudeTasks.add(task.taskId);\n claudeTaskConcurrency.set(codeName, (claudeTaskConcurrency.get(codeName) ?? 0) + 1);\n\n log(`[claude-scheduler] Firing '${task.name}' for '${codeName}'`);\n\n executeAndProcessClaudeTask(codeName, agent.agent_id, task, prompt)\n .finally(() => {\n inFlightClaudeTasks.delete(task.taskId);\n claudeTaskConcurrency.set(codeName, Math.max(0, (claudeTaskConcurrency.get(codeName) ?? 1) - 1));\n });\n }\n}\n\nasync function executeAndProcessClaudeTask(\n codeName: string,\n agentId: string,\n task: SchedulerTaskState,\n prompt: string,\n): Promise<void> {\n const projectDir = ccGetProjectDir(codeName);\n const mcpConfigPath = join(projectDir, '.mcp.json');\n try {\n const claudeMdPath = join(projectDir, 'CLAUDE.md');\n const claudeArgs = [\n '-p', prompt,\n '--output-format', 'text',\n '--mcp-config', mcpConfigPath,\n '--allowedTools', 'mcp__augmented__*,Bash,Read,Write,Edit,Grep,Glob',\n ];\n // Inject agent identity as system prompt so personality is always present\n if (existsSync(claudeMdPath)) {\n claudeArgs.push('--system-prompt-file', claudeMdPath);\n }\n const { stdout, stderr } = await execFilePromiseLong('claude', claudeArgs, {\n cwd: projectDir, timeout: 300_000, stdin: 'ignore',\n });\n\n if (stderr) {\n log(`[claude-scheduler] Task '${task.name}' stderr for '${codeName}': ${stderr.slice(0, 500)}`);\n }\n\n const output = stdout.trim();\n log(`[claude-scheduler] Task '${task.name}' completed for '${codeName}' (${output.length} chars): ${output.slice(0, 300)}`);\n\n // Route result based on template\n await processClaudeTaskResult(codeName, agentId, task.templateId, output);\n\n // Update scheduler state\n const updated = markTaskFired(codeName, task.taskId, 'ok');\n claudeSchedulerStates.set(codeName, updated);\n } catch (err) {\n const errMsg = err instanceof Error ? err.message : String(err);\n log(`[claude-scheduler] Task '${task.name}' failed for '${codeName}': ${errMsg}`);\n const updated = markTaskFired(codeName, task.taskId, 'error');\n claudeSchedulerStates.set(codeName, updated);\n }\n}\n\nasync function processClaudeTaskResult(\n codeName: string,\n agentId: string,\n templateId: string,\n output: string,\n): Promise<void> {\n try {\n if (STANDUP_TEMPLATES.has(templateId)) {\n const standup = parseStandupSummary(output);\n await api.post('/host/agent-status', {\n agent_id: agentId,\n standup,\n current_status: 'idle',\n });\n log(`[claude-scheduler] Standup posted for '${codeName}'`);\n } else if (TASK_UPDATE_TEMPLATES.has(templateId)) {\n await api.post('/host/agent-status', {\n agent_id: agentId,\n current_tasks: output.slice(0, 2000),\n });\n log(`[claude-scheduler] Task update posted for '${codeName}'`);\n } else if (PLAN_TEMPLATES.has(templateId)) {\n const planItems = parsePlanItems(output);\n if (planItems.length > 0) {\n await api.post('/host/kanban', {\n agent_id: agentId,\n add: planItems,\n });\n log(`[claude-scheduler] Plan items posted for '${codeName}' (${planItems.length} items)`);\n }\n } else if (KANBAN_WORK_TEMPLATES.has(templateId)) {\n const kanbanUpdates = parseKanbanUpdates(output);\n if (kanbanUpdates.length > 0) {\n await api.post('/host/kanban', {\n agent_id: agentId,\n update: kanbanUpdates,\n });\n log(`[claude-scheduler] Kanban updates posted for '${codeName}' (${kanbanUpdates.length} updates)`);\n }\n }\n } catch (err) {\n log(`[claude-scheduler] Failed to post result for '${codeName}': ${(err as Error).message}`);\n }\n}\n\nfunction fireClaudeWorkTrigger(\n codeName: string,\n agentId: string,\n boardItems: Array<{ id: string; title: string; status: string; priority: number; estimated_minutes?: number; deliverable?: string; result?: string }>,\n): void {\n const state = claudeSchedulerStates.get(codeName) ?? loadSchedulerState(codeName);\n const kanbanTask = findTaskByTemplate(state, 'kanban-work');\n if (!kanbanTask) {\n log(`[claude-scheduler] Work trigger: no kanban-work task found for '${codeName}'`);\n return;\n }\n if (inFlightClaudeTasks.has(kanbanTask.taskId)) {\n log(`[claude-scheduler] Work trigger: kanban-work already in-flight for '${codeName}'`);\n return;\n }\n\n let prompt = kanbanTask.prompt;\n if (boardItems.length > 0) {\n const boardPrefix = formatBoardForPrompt(boardItems, 'follow-up');\n prompt = boardPrefix + prompt;\n }\n\n inFlightClaudeTasks.add(kanbanTask.taskId);\n claudeTaskConcurrency.set(codeName, (claudeTaskConcurrency.get(codeName) ?? 0) + 1);\n log(`[claude-scheduler] Work trigger: firing kanban-work for '${codeName}'`);\n\n executeAndProcessClaudeTask(codeName, agentId, kanbanTask, prompt)\n .finally(() => {\n inFlightClaudeTasks.delete(kanbanTask.taskId);\n claudeTaskConcurrency.set(codeName, Math.max(0, (claudeTaskConcurrency.get(codeName) ?? 1) - 1));\n });\n}\n\n// ---------------------------------------------------------------------------\n// Persistent session management (session_mode = 'persistent')\n// ---------------------------------------------------------------------------\n\nimport {\n startPersistentSession,\n stopPersistentSession,\n injectMessage,\n isSessionHealthy,\n getSessionState,\n resetRestartCount,\n stopAllSessions,\n getProjectDir as psGetProjectDir,\n} from './persistent-session.js';\n\n// Track which agents have persistent sessions started\nconst persistentSessionAgents = new Set<string>();\n\nasync function ensurePersistentSession(\n agent: { agent_id: string; code_name: string; display_name: string },\n tasks: Array<Record<string, unknown>>,\n boardItems: Array<{ id: string; title: string; status: string; priority: number; estimated_minutes?: number; deliverable?: string; result?: string }>,\n refreshData: Record<string, unknown>,\n): Promise<void> {\n const codeName = agent.code_name;\n const projectDir = psGetProjectDir(codeName);\n const mcpConfigPath = join(projectDir, '.mcp.json');\n const claudeMdPath = join(projectDir, 'CLAUDE.md');\n\n // Resolve channel plugins from agent's channel configs\n const channelConfigs = refreshData.channel_configs as Record<string, { config: unknown; status: string }> | null;\n const channels: string[] = [];\n\n // Map known channel types to their Claude Code channel plugins\n const devChannels: string[] = []; // custom channels needing --dangerously-load-development-channels\n if (channelConfigs) {\n if ('telegram' in channelConfigs) {\n channels.push('plugin:telegram@claude-plugins-official');\n }\n if ('discord' in channelConfigs) {\n channels.push('plugin:discord@claude-plugins-official');\n }\n // Slack uses our custom channel server loaded from .mcp-channels.json\n // (separate from .mcp.json to avoid duplicate loading)\n if ('slack' in channelConfigs) {\n devChannels.push('server:slack');\n }\n }\n\n // Block session launch if Claude Code is not authenticated\n if (!agentRuntimeAuthenticated) {\n // Re-check in case user logged in since last check\n const { execFileSync } = await import('node:child_process');\n agentRuntimeAuthenticated = checkClaudeAuth(execFileSync);\n if (!agentRuntimeAuthenticated) {\n log(`[persistent-session] Skipping '${codeName}' — Claude Code not authenticated`);\n return;\n }\n }\n\n // Start or maintain the persistent session\n if (!isSessionHealthy(codeName)) {\n if (persistentSessionAgents.has(codeName)) {\n log(`[persistent-session] Session for '${codeName}' is unhealthy, will restart`);\n }\n\n startPersistentSession({\n codeName,\n agentId: agent.agent_id,\n projectDir,\n mcpConfigPath,\n claudeMdPath,\n channels,\n devChannels,\n log,\n });\n persistentSessionAgents.add(codeName);\n return; // Wait for next cycle to inject tasks (session needs time to boot)\n }\n\n // Session is healthy — reset restart counter\n resetRestartCount(codeName);\n\n // Inject scheduled tasks that are due\n const state = claudeSchedulerStates.get(codeName);\n if (state) {\n const ready = getReadyTasks(state);\n if (ready.length > 0) {\n log(`[persistent-session] ${ready.length} ready task(s) for '${codeName}': ${ready.map(t => `${t.name}(next=${t.nextFireAt ? new Date(t.nextFireAt).toISOString() : 'null'})`).join(', ')}`);\n }\n for (const task of ready) {\n\n // Enrich prompt with board context\n let prompt = task.prompt;\n if (BOARD_INJECT_TEMPLATES.has(task.templateId) && boardItems.length > 0) {\n const template = PLAN_TEMPLATES.has(task.templateId) ? 'morning-plan' : 'follow-up';\n const boardPrefix = formatBoardForPrompt(boardItems, template);\n prompt = boardPrefix + prompt;\n }\n\n // For kanban-work: move top today item to in_progress\n if (KANBAN_WORK_TEMPLATES.has(task.templateId)) {\n const todayItem = boardItems.find((b) => b.status === 'today');\n if (todayItem) {\n try {\n await api.post('/host/kanban', {\n agent_id: agent.agent_id,\n update: [{ id: todayItem.id, title: todayItem.title, status: 'in_progress' }],\n });\n log(`[persistent-session] Moved '${todayItem.title}' to in_progress for '${codeName}'`);\n } catch { /* non-fatal */ }\n }\n }\n\n log(`[persistent-session] Injecting task '${task.name}' into '${codeName}'`);\n\n const injected = await injectMessage(codeName, 'task', prompt, {\n task_id: task.taskId,\n template_id: task.templateId,\n task_name: task.name,\n });\n\n if (injected) {\n // Mark as fired — this advances nextFireAt to the next scheduled time\n const updated = markTaskFired(codeName, task.taskId, 'ok');\n claudeSchedulerStates.set(codeName, updated);\n log(`[persistent-session] Task '${task.name}' injected, next fire at ${new Date(updated.tasks[task.taskId]?.nextFireAt ?? 0).toISOString()}`);\n }\n\n // Only inject one task per cycle in persistent mode\n break;\n }\n }\n\n // Sync scheduler state (same hash-based detection as oneshot)\n const stableTasksHash = createHash('sha256')\n .update(JSON.stringify(tasks))\n .digest('hex')\n .slice(0, 16);\n const prevHash = knownTasksHashes.get(agent.agent_id);\n if (stableTasksHash !== prevHash) {\n const taskInputs: SchedulerTaskInput[] = tasks.map((t) => ({\n id: t.id as string,\n template_id: t.template_id as string,\n name: t.name as string,\n schedule_kind: t.schedule_kind as 'cron' | 'every' | 'at',\n schedule_expr: (t.schedule_expr as string) ?? null,\n schedule_every: (t.schedule_every as string) ?? null,\n schedule_at: (t.schedule_at as string) ?? null,\n timezone: (t.timezone as string) ?? 'UTC',\n prompt: (t.prompt as string) ?? '',\n session_target: (t.session_target as string) ?? 'isolated',\n delivery_mode: (t.delivery_mode as string) ?? 'none',\n delivery_channel: (t.delivery_channel as string) ?? null,\n delivery_to: (t.delivery_to as string) ?? null,\n enabled: (t.enabled as boolean) ?? true,\n }));\n const schedulerState = syncTasksToScheduler(codeName, agent.agent_id, taskInputs);\n claudeSchedulerStates.set(codeName, schedulerState);\n knownTasksHashes.set(agent.agent_id, stableTasksHash);\n log(`[persistent-session] Tasks synced for '${codeName}' (${taskInputs.length} task(s))`);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Supabase Realtime for direct chat (replaces 2s polling)\n// ---------------------------------------------------------------------------\n\nimport {\n startRealtimeChat,\n startRealtimeDrift,\n startRealtimeAssignments,\n startRealtimeConfig,\n startRealtimeKanban,\n stopRealtimeChat,\n isRealtimeConnected,\n updateRealtimeToken,\n} from './realtime-chat.js';\n\nlet realtimeStarted = false;\nlet realtimeDriftStarted = false;\nlet realtimeKanbanStarted = false;\nlet realtimeAssignStarted = false;\nlet realtimeConfigStarted = false;\n\nfunction ensureRealtimeStarted(agentStates: AgentState[]): void {\n if (realtimeStarted) return;\n\n const activeAgentIds = agentStates\n .filter((a) => a.status === 'active')\n .map((a) => a.agentId);\n\n if (activeAgentIds.length === 0) return;\n\n const apiKey = process.env['AGT_API_KEY'];\n if (!apiKey) return;\n\n // Get Supabase config + token from the cached exchange result\n void exchangeApiKey(apiKey).then((exchange) => {\n if (!exchange.supabaseUrl || !exchange.supabaseAnonKey) {\n log('[realtime-chat] No Supabase URL/key from exchange — staying on polling');\n return;\n }\n\n startRealtimeChat({\n supabaseUrl: exchange.supabaseUrl,\n supabaseAnonKey: exchange.supabaseAnonKey,\n token: exchange.token,\n agentIds: activeAgentIds,\n onMessage: (msg) => {\n const agent = agentStates.find((a) => a.agentId === msg.agent_id);\n if (!agent) return;\n\n if (directChatInFlight.has(msg.id)) return;\n directChatInFlight.add(msg.id);\n\n processDirectChatMessage(agent, {\n id: msg.id,\n session_id: msg.session_id,\n content: msg.content,\n }).finally(() => {\n directChatInFlight.delete(msg.id);\n });\n },\n onError: (err) => {\n log(`[realtime-chat] Error: ${err.message}`);\n },\n onStatusChange: (status) => {\n if (status === 'disconnected' || status === 'error') {\n log('[realtime] Disconnected — falling back to polling, will reconnect next cycle');\n // Reset all subscription flags so they reconnect with a fresh client\n realtimeStarted = false;\n realtimeDriftStarted = false;\n realtimeAssignStarted = false;\n realtimeConfigStarted = false;\n realtimeKanbanStarted = false;\n }\n },\n log,\n });\n\n realtimeStarted = true;\n log(`[realtime-chat] Started for ${activeAgentIds.length} agent(s)`);\n }).catch((err) => {\n log(`[realtime-chat] Failed to start: ${(err as Error).message}`);\n });\n}\n\nfunction ensureRealtimeDriftStarted(agentStates: AgentState[]): void {\n if (realtimeDriftStarted) return;\n\n const activeAgentIds = agentStates.filter((a) => a.status === 'active').map((a) => a.agentId);\n if (activeAgentIds.length === 0) return;\n\n const apiKey = process.env['AGT_API_KEY'];\n if (!apiKey) return;\n\n void exchangeApiKey(apiKey).then((exchange) => {\n if (!exchange.supabaseUrl || !exchange.supabaseAnonKey) return;\n\n startRealtimeDrift({\n supabaseUrl: exchange.supabaseUrl,\n supabaseAnonKey: exchange.supabaseAnonKey,\n token: exchange.token,\n agentIds: activeAgentIds,\n onDrift: (doc) => {\n // Invalidate the known version so next poll cycle re-provisions\n const agentState = agentStates.find((a) => a.agentId === doc.agent_id);\n if (agentState) {\n knownVersions.delete(doc.agent_id);\n log(`[realtime] Drift invalidated for '${agentState.codeName}' — will re-provision next cycle`);\n }\n },\n log,\n });\n\n realtimeDriftStarted = true;\n log(`[realtime] Drift subscription started for ${activeAgentIds.length} agent(s)`);\n }).catch((err) => {\n log(`[realtime] Drift subscription failed: ${(err as Error).message}`);\n });\n}\n\nfunction ensureRealtimeAssignStarted(agentStates: AgentState[]): void {\n if (realtimeAssignStarted) return;\n\n const apiKey = process.env['AGT_API_KEY'];\n if (!apiKey) return;\n\n void exchangeApiKey(apiKey).then((exchange) => {\n if (!exchange.supabaseUrl || !exchange.supabaseAnonKey || !exchange.hostId) return;\n\n startRealtimeAssignments({\n supabaseUrl: exchange.supabaseUrl,\n supabaseAnonKey: exchange.supabaseAnonKey,\n token: exchange.token,\n hostId: exchange.hostId,\n onAssign: (payload) => {\n log(`[realtime] Agent ${payload.agent_id} assigned — will pick up next cycle`);\n // No cache invalidation needed — the next poll cycle will discover the new agent\n },\n onUnassign: (payload) => {\n log(`[realtime] Agent ${payload.agent_id} unassigned`);\n clearAgentCaches(payload.agent_id, '');\n },\n log,\n });\n\n realtimeAssignStarted = true;\n log(`[realtime] Assignment subscription started for host ${exchange.hostId}`);\n }).catch((err) => {\n log(`[realtime] Assignment subscription failed: ${(err as Error).message}`);\n });\n}\n\nfunction ensureRealtimeConfigStarted(agentStates: AgentState[]): void {\n if (realtimeConfigStarted) return;\n\n const activeAgentIds = agentStates.filter((a) => a.status === 'active').map((a) => a.agentId);\n if (activeAgentIds.length === 0) return;\n\n const apiKey = process.env['AGT_API_KEY'];\n if (!apiKey) return;\n\n void exchangeApiKey(apiKey).then((exchange) => {\n if (!exchange.supabaseUrl || !exchange.supabaseAnonKey) return;\n\n startRealtimeConfig({\n supabaseUrl: exchange.supabaseUrl,\n supabaseAnonKey: exchange.supabaseAnonKey,\n token: exchange.token,\n agentIds: activeAgentIds,\n onConfigChange: (agent) => {\n // Only invalidate status cache — version/provision caches are handled by drift subscription.\n // Don't invalidate knownVersions here as that triggers re-provision which updates\n // updated_at, creating a feedback loop with this Realtime subscription.\n knownStatuses.delete(agent.agent_id);\n },\n log,\n });\n\n realtimeConfigStarted = true;\n log(`[realtime] Config subscription started for ${activeAgentIds.length} agent(s)`);\n }).catch((err) => {\n log(`[realtime] Config subscription failed: ${(err as Error).message}`);\n });\n}\n\nfunction ensureRealtimeKanbanStarted(agentStates: AgentState[]): void {\n if (realtimeKanbanStarted) return;\n\n const activeAgentIds = agentStates.filter((a) => a.status === 'active').map((a) => a.agentId);\n if (activeAgentIds.length === 0) return;\n\n const apiKey = process.env['AGT_API_KEY'];\n if (!apiKey) return;\n\n void exchangeApiKey(apiKey).then((exchange) => {\n if (!exchange.supabaseUrl || !exchange.supabaseAnonKey) return;\n\n startRealtimeKanban({\n supabaseUrl: exchange.supabaseUrl,\n supabaseAnonKey: exchange.supabaseAnonKey,\n token: exchange.token,\n agentIds: activeAgentIds,\n onTodayItem: (item) => {\n // Trigger kanban-work immediately for this agent\n const agent = agentStates.find((a) => a.agentId === item.agent_id);\n if (!agent) return;\n\n const agentFw = agentFrameworkCache.get(agent.codeName) ?? 'openclaw';\n\n if (agentFw === 'claude-code') {\n // For persistent sessions, inject via tmux; for oneshot, fire claude -p\n const boardItems = kanbanBoardCache.get(agent.codeName) ?? [];\n if (isSessionHealthy(agent.codeName)) {\n injectMessage(agent.codeName, 'task', `New task added to your board: \"${item.title}\" (priority ${item.priority}). Pick it up — move to in_progress and start working.`, {\n task_name: 'kanban-work-trigger',\n });\n log(`[realtime] Injected kanban-work trigger for '${agent.codeName}': \"${item.title}\"`);\n } else {\n fireClaudeWorkTrigger(agent.codeName, agent.agentId, boardItems);\n log(`[realtime] Fired kanban-work for '${agent.codeName}': \"${item.title}\"`);\n }\n }\n },\n log,\n });\n\n realtimeKanbanStarted = true;\n log(`[realtime] Kanban subscription started for ${activeAgentIds.length} agent(s)`);\n }).catch((err) => {\n log(`[realtime] Kanban subscription failed: ${(err as Error).message}`);\n });\n}\n\n// ---------------------------------------------------------------------------\n// Direct chat — poll for pending messages (fallback when Realtime is down)\n// ---------------------------------------------------------------------------\n\n// Track in-flight direct chat messages to avoid double-processing\nconst directChatInFlight = new Set<string>();\n\nasync function pollDirectChatMessages(agentStates: AgentState[]): Promise<void> {\n for (const agent of agentStates) {\n if (agent.status !== 'active') continue;\n const fw = agentFrameworkCache.get(agent.codeName) ?? 'openclaw';\n // OpenClaw requires a running gateway; Claude Code does not\n if (fw === 'openclaw' && (!agent.gatewayRunning || !agent.gatewayPort)) continue;\n\n try {\n const data = await api.post<{\n messages: Array<{\n id: string;\n session_id: string;\n content: string;\n created_at: string;\n }>;\n }>('/host/direct-chat/poll', { agent_id: agent.agentId });\n\n for (const msg of data.messages) {\n if (directChatInFlight.has(msg.id)) continue;\n directChatInFlight.add(msg.id);\n\n // Process async so we don't block the poll cycle\n processDirectChatMessage(agent, msg).finally(() => {\n directChatInFlight.delete(msg.id);\n });\n }\n } catch (err) {\n log(`Direct chat poll failed for '${agent.codeName}': ${(err as Error).message}`);\n }\n }\n}\n\nasync function processDirectChatMessage(\n agent: AgentState,\n msg: { id: string; session_id: string; content: string },\n): Promise<void> {\n const fw = agentFrameworkCache.get(agent.codeName) ?? 'openclaw';\n log(`[direct-chat] Processing message for '${agent.codeName}' (fw=${fw}): id=${msg.id} len=${msg.content.length}`);\n\n try {\n let reply: string;\n\n if (fw === 'claude-code') {\n // Always use claude -p for webapp direct chat so the reply comes back\n // through the API. The persistent session handles Slack/Telegram channels.\n const { getProjectDir: ccProjectDir } = await import('./claude-scheduler.js');\n const projDir = ccProjectDir(agent.codeName);\n const chatArgs = [\n '-p', msg.content,\n '--output-format', 'text',\n '--mcp-config', join(projDir, '.mcp.json'),\n '--allowedTools', 'mcp__augmented__*,Bash,Read,Write,Edit,Grep,Glob',\n ];\n const chatClaudeMd = join(projDir, 'CLAUDE.md');\n if (existsSync(chatClaudeMd)) {\n chatArgs.push('--system-prompt-file', chatClaudeMd);\n }\n const { stdout } = await execFilePromiseLong('claude', chatArgs, { cwd: projDir, stdin: 'ignore' });\n reply = stdout.trim() || '[No response from agent]';\n } else {\n // OpenClaw: use profile-based agent invocation\n const { stdout } = await execFilePromiseLong('openclaw', [\n '--profile', agent.codeName,\n 'agent',\n '--local',\n '--agent', agent.codeName,\n '--message', msg.content,\n '--session-id', msg.session_id,\n '--json',\n ]);\n\n // OpenClaw agent --json returns either:\n // { payloads: [{ text }], meta: {...} } (success)\n // { result: { payloads: [{ text }] }, meta: {...} } (some versions)\n try {\n const parsed = JSON.parse(stdout);\n const payloads = (parsed?.payloads ?? parsed?.result?.payloads) as Array<{ text?: string }> | undefined;\n reply = payloads?.[0]?.text ?? parsed?.reply ?? parsed?.text ?? parsed?.message ?? stdout;\n } catch {\n reply = stdout.trim() || '[No response from agent]';\n }\n }\n\n // Post the reply back\n await api.post('/host/direct-chat/reply', {\n agent_id: agent.agentId,\n session_id: msg.session_id,\n content: reply,\n });\n\n log(`[direct-chat] Reply sent for '${agent.codeName}'`);\n } catch (err) {\n const errMsg = err instanceof Error ? err.message : String(err);\n const errorId = createHash('sha256').update(errMsg).digest('hex').slice(0, 12);\n log(`[direct-chat] Failed to process message for '${agent.codeName}': error_id=${errorId}`);\n\n // Post an error reply so the webapp doesn't poll forever\n try {\n await api.post('/host/direct-chat/reply', {\n agent_id: agent.agentId,\n session_id: msg.session_id,\n content: `[Error] Failed to process message (ref: ${errorId}). Please retry.`,\n });\n } catch {\n // Last resort — nothing more we can do\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Cron result harvesting — polls cron run history and updates agent status\n// ---------------------------------------------------------------------------\n\n// Template IDs that map to agent field updates\nconst STANDUP_TEMPLATES = new Set(['daily-standup', 'end-of-day-summary']);\nconst TASK_UPDATE_TEMPLATES = new Set(['hourly-status', 'task-update']);\nconst PLAN_TEMPLATES = new Set(['morning-plan']);\nconst KANBAN_WORK_TEMPLATES = new Set(['kanban-work']);\nconst BOARD_INJECT_TEMPLATES = new Set(['morning-plan', 'task-update', 'hourly-status', 'end-of-day-summary', 'kanban-work']);\n\n// Throttle harvest — no need to check cron results every 30s cycle\nconst lastHarvestAt = new Map<string, number>();\nconst HARVEST_INTERVAL_MS = 3 * 60 * 1000; // 3 minutes\n\n// Cache kanban board per agent per poll cycle\ntype BoardItem = { id: string; title: string; status: string; priority: number; estimated_minutes?: number; deliverable?: string; result?: string; notify_channel?: string; notify_to?: string; updated_at?: string };\nconst kanbanBoardCache = new Map<string, BoardItem[]>();\n// Separate cache for notification board diff — not pre-populated by step 7d\nconst notifyBoardCache = new Map<string, Set<string>>();\n\ninterface CronRunEntry {\n ts: number;\n jobId: string;\n action: string;\n status: string;\n summary?: string;\n}\n\nasync function harvestCronResults(\n codeName: string,\n tasks: Array<{ id: string; template_id: string; name: string }>,\n gatewayPort: number,\n): Promise<void> {\n const token = readGatewayToken(codeName);\n const gwArgs = ['--url', `ws://127.0.0.1:${gatewayPort}`, ...(token ? ['--token', token] : [])];\n\n // List current jobs to map job IDs to template IDs\n let gatewayJobs: Array<{ id: string; name: string }> = [];\n try {\n const cliBin = resolveAgentFramework(codeName).cliBinary ?? 'openclaw';\n const { stdout } = await execFilePromise(cliBin, ['--profile', codeName, 'cron', 'list', '--json', ...gwArgs]);\n const parsed = JSON.parse(stdout);\n gatewayJobs = (parsed.jobs ?? []) as Array<{ id: string; name: string }>;\n } catch {\n return; // Gateway not ready\n }\n\n // Build a map from gateway job ID → DB task template_id\n const jobTemplateMap = new Map<string, string>();\n for (const job of gatewayJobs) {\n if (!job.name.startsWith('aug:')) continue;\n // Name format: aug:{template_id}:{task_uuid}\n const parts = job.name.split(':');\n if (parts.length >= 3) {\n jobTemplateMap.set(job.id, parts[1]!);\n }\n }\n\n // Check each relevant job for new completed runs\n for (const [jobId, templateId] of jobTemplateMap) {\n if (!STANDUP_TEMPLATES.has(templateId) && !TASK_UPDATE_TEMPLATES.has(templateId) && !PLAN_TEMPLATES.has(templateId) && !KANBAN_WORK_TEMPLATES.has(templateId)) continue;\n\n let runs: CronRunEntry[] = [];\n try {\n const cliBin2 = resolveAgentFramework(codeName).cliBinary ?? 'openclaw';\n const { stdout } = await execFilePromise(cliBin2, ['--profile', codeName, 'cron', 'runs', '--id', jobId, ...gwArgs]);\n const parsed = JSON.parse(stdout);\n runs = (parsed.entries ?? []) as CronRunEntry[];\n } catch {\n continue;\n }\n\n // Detect API key errors from failed runs\n const latestRun = runs.filter((r) => r.action === 'finished').sort((a, b) => b.ts - a.ts)[0];\n if (latestRun) {\n const agentId = codeNameToAgentId.get(codeName);\n const summary = latestRun.summary ?? '';\n const isKeyError = summary.includes('Key limit exceeded') || summary.includes('key limit') ||\n summary.includes('rate limit') || summary.includes('insufficient_quota') ||\n summary.includes('billing') || summary.includes('402');\n if (agentId) {\n if (latestRun.status === 'error' && isKeyError) {\n const errorMsg = summary.slice(0, 200);\n if (!apiKeyStatusCache.get(codeName)) {\n apiKeyStatusCache.set(codeName, true);\n api.post('/host/agent-api-key-status', { agent_id: agentId, status: 'rate_limited', error: errorMsg }).catch(() => {});\n log(`API key error detected for '${codeName}': ${errorMsg}`);\n }\n } else if (latestRun.status === 'ok' && apiKeyStatusCache.get(codeName)) {\n apiKeyStatusCache.delete(codeName);\n api.post('/host/agent-api-key-status', { agent_id: agentId, status: null, error: null }).catch(() => {});\n log(`API key status cleared for '${codeName}' — run succeeded`);\n }\n }\n }\n\n // Find the latest successful run\n const completed = runs\n .filter((r) => r.action === 'finished' && r.status === 'ok' && r.summary)\n .sort((a, b) => b.ts - a.ts);\n\n if (completed.length === 0) continue;\n\n const latest = completed[0]!;\n const lastSeen = lastCronRunTs.get(jobId) ?? 0;\n if (latest.ts <= lastSeen) continue; // Already processed\n\n lastCronRunTs.set(jobId, latest.ts);\n\n // POST result to API\n const statusUpdate: Record<string, unknown> = { agent_code_name: codeName };\n\n if (STANDUP_TEMPLATES.has(templateId)) {\n // Parse standup summary into structured fields\n const summary = latest.summary ?? '';\n statusUpdate.standup = parseStandupSummary(summary);\n }\n\n if (TASK_UPDATE_TEMPLATES.has(templateId)) {\n statusUpdate.current_tasks = latest.summary ?? '';\n }\n\n // Only POST agent-status if we have something to update (standup or current_tasks)\n if (statusUpdate.standup || statusUpdate.current_tasks !== undefined) {\n try {\n await api.post('/host/agent-status', statusUpdate);\n log(`Updated ${templateId} for '${codeName}' from cron result`);\n } catch (err) {\n log(`Failed to update ${templateId} for '${codeName}': ${(err as Error).message}`);\n }\n }\n\n // Kanban: Parse plan items from morning-plan template\n if (PLAN_TEMPLATES.has(templateId)) {\n const summary = latest.summary ?? '';\n const planItems = parsePlanItems(summary);\n if (planItems.length > 0) {\n // Look up agent_id from code_name\n try {\n const agentId = codeNameToAgentId.get(codeName);\n if (agentId) {\n await api.post('/host/kanban', {\n agent_id: agentId,\n add: planItems,\n archive_days: 7,\n });\n log(`Added ${planItems.length} kanban items for '${codeName}' from morning-plan`);\n }\n } catch (err) {\n log(`Failed to update kanban for '${codeName}': ${(err as Error).message}`);\n }\n }\n }\n\n // Kanban: Parse status updates from task-update/hourly/kanban-work templates\n if (TASK_UPDATE_TEMPLATES.has(templateId) || KANBAN_WORK_TEMPLATES.has(templateId)) {\n const summary = latest.summary ?? '';\n const kanbanUpdates = parseKanbanUpdates(summary);\n if (kanbanUpdates.length > 0) {\n try {\n const agentId = codeNameToAgentId.get(codeName);\n if (agentId) {\n await api.post('/host/kanban', {\n agent_id: agentId,\n update: kanbanUpdates,\n });\n log(`Updated ${kanbanUpdates.length} kanban items for '${codeName}'`);\n }\n } catch (err) {\n log(`Failed to update kanban for '${codeName}': ${(err as Error).message}`);\n }\n }\n\n // Board diff notification detection moved to step 12 in processAgent\n // (runs every poll cycle, not just on cron harvest)\n }\n }\n}\n\nfunction parseStandupSummary(summary: string): { yesterday: string; today: string; blockers: string } {\n // Try to extract sections from the standup text\n const lines = summary.split('\\n');\n let yesterday = '';\n let today = '';\n let blockers = '';\n let currentSection: 'yesterday' | 'today' | 'blockers' | null = null;\n\n for (const line of lines) {\n const lower = line.toLowerCase();\n if (lower.includes('yesterday') || lower.includes('accomplished')) {\n currentSection = 'yesterday';\n continue;\n } else if (lower.includes('today') || lower.includes('working on')) {\n currentSection = 'today';\n continue;\n } else if (lower.includes('blocker')) {\n currentSection = 'blockers';\n continue;\n }\n\n const trimmed = line.replace(/^[-*•]\\s*/, '').trim();\n if (!trimmed) continue;\n\n switch (currentSection) {\n case 'yesterday': yesterday += (yesterday ? '\\n' : '') + trimmed; break;\n case 'today': today += (today ? '\\n' : '') + trimmed; break;\n case 'blockers': blockers += (blockers ? '\\n' : '') + trimmed; break;\n }\n }\n\n // Fallback: if parsing didn't find sections, use full summary\n if (!yesterday && !today && !blockers) {\n today = summary;\n }\n\n return { yesterday, today, blockers };\n}\n\nfunction parsePlanItems(summary: string): Array<{\n title: string;\n description?: string;\n priority: number;\n estimated_minutes?: number;\n status: string;\n}> {\n const items: Array<{\n title: string;\n description?: string;\n priority: number;\n estimated_minutes?: number;\n status: string;\n }> = [];\n\n const lines = summary.split('\\n');\n let currentItem: (typeof items)[0] | null = null;\n\n for (const line of lines) {\n const trimmed = line.trim();\n\n // Match numbered/bulleted items: \"1. [HIGH] Task title (~30min)\" or \"- [MEDIUM] Task (~2hr)\"\n const itemMatch = trimmed.match(/^(?:\\d+[\\.\\)]\\s*|[-*•]\\s*)\\[?(HIGH|MEDIUM|LOW|MED)\\]?\\s*(.+)/i);\n\n if (itemMatch) {\n // Push previous item\n if (currentItem) items.push(currentItem);\n\n const priorityStr = itemMatch[1]!.toUpperCase();\n const rest = itemMatch[2]!;\n\n // Extract time estimate\n let estimatedMinutes: number | undefined;\n const timeMatch = rest.match(/\\(~?(\\d+)\\s*(min(?:utes?)?|hr?(?:ours?)?|h)\\)/i);\n if (timeMatch) {\n const val = parseInt(timeMatch[1]!, 10);\n const unit = timeMatch[2]!.toLowerCase();\n estimatedMinutes = unit.startsWith('h') ? val * 60 : val;\n }\n\n // Title is everything except the time estimate — sanitize LLM output\n const title = sanitizeKanbanString(\n rest.replace(/\\(~?\\d+\\s*(?:min(?:utes?)?|hr?(?:ours?)?|h)\\)/i, ''),\n MAX_KANBAN_TITLE_LENGTH,\n );\n if (!title) continue;\n\n const priorityMap: Record<string, number> = { HIGH: 1, MEDIUM: 2, MED: 2, LOW: 3 };\n const priority = priorityMap[priorityStr] ?? 2;\n if (![1, 2, 3].includes(priority)) continue;\n\n currentItem = {\n title,\n priority,\n estimated_minutes: estimatedMinutes,\n status: 'today',\n };\n } else if (currentItem && trimmed && !trimmed.match(/^(?:PLAN|---)/i)) {\n // Non-numbered line after a plan item = description (length-limited)\n const descLine = sanitizeKanbanString(trimmed, MAX_KANBAN_NOTES_LENGTH);\n currentItem.description = currentItem.description\n ? sanitizeKanbanString(currentItem.description + '\\n' + descLine, MAX_KANBAN_NOTES_LENGTH)\n : descLine;\n }\n }\n\n if (currentItem) items.push(currentItem);\n return items;\n}\n\nconst VALID_KANBAN_STATUSES = new Set(['backlog', 'today', 'in_progress', 'done']);\nconst MAX_KANBAN_TITLE_LENGTH = 500;\nconst MAX_KANBAN_NOTES_LENGTH = 2000;\n\n/** Sanitize a string from LLM output: trim + length limit */\nfunction sanitizeKanbanString(value: string, maxLen: number): string {\n if (!value) return '';\n return value\n .replace(/[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F\\x7F]/g, '') // strip control chars (keep \\n, \\r, \\t)\n .replace(/\\{\\{.*?\\}\\}/g, '') // strip template injection markers\n .replace(/^(System|Assistant|Human):\\s*/gmi, '') // strip prompt-role prefixes\n .replace(/#{2,}/g, '') // strip markdown heading markers\n .replace(/\\s+/g, ' ') // collapse whitespace\n .trim()\n .slice(0, maxLen);\n}\n\n/** Sanitize all external fields on a board item before caching / prompt injection */\nfunction sanitizeBoardItem<T extends { title: string; status: string; deliverable?: string }>(item: T): T {\n return {\n ...item,\n title: sanitizeKanbanString(item.title, 200),\n status: sanitizeKanbanString(item.status, 50),\n ...(item.deliverable ? { deliverable: sanitizeKanbanString(item.deliverable, 500) } : {}),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Built-in skill files — bundled for auto-deployment to all agents\n// ---------------------------------------------------------------------------\n\nconst builtInSkillCache = new Map<string, Array<{ relativePath: string; content: string }> | null>();\n\nfunction getBuiltInSkillContent(skillId: string): Array<{ relativePath: string; content: string }> | null {\n if (builtInSkillCache.has(skillId)) return builtInSkillCache.get(skillId)!;\n\n try {\n // Resolve skill directory relative to the CLI package root\n // In dev: skills/<skillId>/SKILL.md is in the monorepo root\n // When bundled: skills are embedded at build time or read from cwd\n const candidates = [\n join(process.cwd(), 'skills', skillId, 'SKILL.md'),\n join(new URL('.', import.meta.url).pathname, '..', '..', '..', '..', 'skills', skillId, 'SKILL.md'),\n ];\n\n for (const candidate of candidates) {\n if (existsSync(candidate)) {\n const content = readFileSync(candidate, 'utf-8');\n const files = [{ relativePath: 'SKILL.md', content }];\n builtInSkillCache.set(skillId, files);\n return files;\n }\n }\n\n builtInSkillCache.set(skillId, null);\n return null;\n } catch {\n builtInSkillCache.set(skillId, null);\n return null;\n }\n}\n\n// ---------------------------------------------------------------------------\n\nfunction parseKanbanUpdates(summary: string): Array<{\n title: string;\n status: string;\n notes?: string;\n result?: string;\n}> {\n const updates: Array<{ title: string; status: string; notes?: string; result?: string }> = [];\n\n // Look for \"KANBAN UPDATE:\" section\n const kanbanIdx = summary.indexOf('KANBAN UPDATE:');\n if (kanbanIdx === -1) return updates;\n\n const kanbanSection = summary.slice(kanbanIdx + 'KANBAN UPDATE:'.length);\n const lines = kanbanSection.split('\\n');\n\n for (const line of lines) {\n const trimmed = line.trim();\n // Match: - \"item title\": status (optional notes/result)\n const match = trimmed.match(/^[-*•]\\s*\"([^\"]+)\":\\s*(backlog|today|in_progress|done)(?:\\s*\\((.+)\\))?/i);\n if (match) {\n const status = match[2]!.toLowerCase();\n // Validate status is in the allowed set\n if (!VALID_KANBAN_STATUSES.has(status)) continue;\n\n const title = sanitizeKanbanString(match[1]!, MAX_KANBAN_TITLE_LENGTH);\n if (!title) continue;\n\n const parenthetical = match[3] ?? undefined;\n\n // Extract result from parenthetical when status is done\n // Pattern: \"result: <value>\" or just the whole parenthetical as notes\n let notes: string | undefined;\n let result: string | undefined;\n\n if (parenthetical && status === 'done') {\n const resultMatch = parenthetical.match(/^result:\\s*(.+)/i);\n if (resultMatch) {\n result = sanitizeKanbanString(resultMatch[1]!, MAX_KANBAN_NOTES_LENGTH);\n } else {\n notes = sanitizeKanbanString(parenthetical, MAX_KANBAN_NOTES_LENGTH);\n }\n } else if (parenthetical) {\n notes = sanitizeKanbanString(parenthetical, MAX_KANBAN_NOTES_LENGTH);\n }\n\n updates.push({\n title,\n status,\n notes,\n result,\n });\n }\n }\n\n return updates;\n}\n\nfunction formatBoardForPrompt(\n items: Array<{ title: string; status: string; priority: number; estimated_minutes?: number; deliverable?: string }>,\n template: 'morning-plan' | 'follow-up',\n): string {\n if (items.length === 0) return '';\n\n const priorityLabel = (p: number) => p === 1 ? 'HIGH' : p === 3 ? 'LOW' : 'MED';\n const timeLabel = (m?: number) => m ? ` (~${m >= 60 ? `${Math.round(m / 60)}hr` : `${m}min`})` : '';\n const deliverableLine = (d?: string) => d ? `\\n Deliverable: ${d}` : '';\n\n const grouped: Record<string, typeof items> = {};\n for (const item of items) {\n const key = item.status;\n if (!grouped[key]) grouped[key] = [];\n grouped[key]!.push(item);\n }\n\n const lines: string[] = [];\n\n if (template === 'morning-plan') {\n lines.push('=== CURRENT BOARD ===');\n\n for (const [status, label] of [['backlog', 'BACKLOG (carry-over)'], ['today', 'TODAY'], ['in_progress', 'IN PROGRESS']] as const) {\n const statusItems = grouped[status];\n if (statusItems && statusItems.length > 0) {\n lines.push(`${label}:`);\n statusItems.forEach((item, i) => {\n lines.push(` ${i + 1}. [${priorityLabel(item.priority)}] ${item.title}${timeLabel(item.estimated_minutes)}${deliverableLine(item.deliverable)}`);\n });\n }\n }\n\n lines.push('=====================');\n lines.push('');\n lines.push('Create today\\'s plan. You may:');\n lines.push('- Move backlog items to \"today\"');\n lines.push('- Add new items you\\'ve identified');\n lines.push('- Reprioritise existing items');\n lines.push('');\n } else {\n lines.push('=== YOUR KANBAN BOARD ===');\n\n for (const [status, label] of [['today', 'TODAY'], ['in_progress', 'IN PROGRESS'], ['backlog', 'BACKLOG']] as const) {\n const statusItems = grouped[status];\n if (statusItems && statusItems.length > 0) {\n lines.push(`${label}:`);\n statusItems.forEach((item, i) => {\n lines.push(` ${i + 1}. [${priorityLabel(item.priority)}] ${item.title}${timeLabel(item.estimated_minutes)}${deliverableLine(item.deliverable)}`);\n });\n }\n }\n\n const doneItems = grouped['done'];\n if (doneItems && doneItems.length > 0) {\n lines.push('DONE TODAY:');\n doneItems.forEach((item, i) => {\n lines.push(` ${i + 1}. ${item.title}`);\n });\n }\n\n lines.push('=========================');\n lines.push('');\n lines.push('IMPORTANT: Use kanban MCP tools to update the board IN REAL TIME:');\n lines.push('1. FIRST call kanban.move to move your chosen item to in_progress BEFORE starting work');\n lines.push('2. Do the work');\n lines.push('3. Call kanban.done with a result summary when finished');\n lines.push('4. If blocked, call kanban.update with notes, then pick the next item');\n lines.push('');\n lines.push('SELF-MANAGEMENT: When you receive a request from a channel (Slack, Telegram)');\n lines.push('that takes more than a quick response, create a task first with kanban.add,');\n lines.push('move to in_progress, do the work, then kanban.done with a result summary.');\n lines.push('');\n lines.push('If MCP tools are unavailable, include a KANBAN UPDATE section in your output:');\n lines.push('KANBAN UPDATE:');\n lines.push('- \"item title\": new_status (optional notes)');\n lines.push('- \"item title\": done (result: <what you produced>)');\n lines.push('Statuses: backlog, today, in_progress, done');\n lines.push('');\n }\n\n return lines.join('\\n');\n}\n\nasync function execFilePromise(cmd: string, args: string[]): Promise<{ stdout: string; stderr: string }> {\n const { execFile: ef } = await import('node:child_process');\n return new Promise((resolve, reject) => {\n ef(cmd, args, { timeout: 15_000 }, (err, stdout, stderr) => {\n if (err) reject(err);\n else resolve({ stdout, stderr });\n });\n });\n}\n\nasync function execFilePromiseLong(\n cmd: string,\n args: string[],\n opts?: { cwd?: string; timeout?: number; stdin?: 'ignore' },\n): Promise<{ stdout: string; stderr: string }> {\n const { spawn: sp } = await import('node:child_process');\n return new Promise((resolve, reject) => {\n const child = sp(cmd, args, {\n cwd: opts?.cwd,\n stdio: [opts?.stdin === 'ignore' ? 'ignore' : 'pipe', 'pipe', 'pipe'],\n });\n let stdout = '';\n let stderr = '';\n child.stdout?.on('data', (d: Buffer) => { stdout += d.toString(); });\n child.stderr?.on('data', (d: Buffer) => { stderr += d.toString(); });\n const timer = setTimeout(() => { child.kill(); reject(new Error(`Timed out after ${opts?.timeout ?? 120_000}ms`)); }, opts?.timeout ?? 120_000);\n child.on('close', (code) => { clearTimeout(timer); if (code !== 0) reject(new Error(`Exit code ${code}: ${stderr.slice(0, 500)}`)); else resolve({ stdout, stderr }); });\n child.on('error', (err) => { clearTimeout(timer); reject(err); });\n });\n}\n\n// ---------------------------------------------------------------------------\n// Cron health monitoring — detects late/failed jobs and sends alerts\n// ---------------------------------------------------------------------------\n\nconst LATE_THRESHOLD_MS = 5 * 60 * 1000; // 5 minutes grace period\n\ninterface CronAlert {\n type: 'late_standup' | 'cron_failure';\n agentCodeName: string;\n agentDisplayName: string;\n jobName: string;\n taskName: string;\n schedule: string;\n jobId: string;\n detail: string;\n}\n\nasync function monitorCronHealth(agentStates: AgentState[]): Promise<void> {\n const alerts: CronAlert[] = [];\n const now = Date.now();\n\n for (const agent of agentStates) {\n if (!agent.gatewayRunning || !agent.gatewayPort) continue;\n\n const token = readGatewayToken(agent.codeName);\n const gwArgs = ['--url', `ws://127.0.0.1:${agent.gatewayPort}`, ...(token ? ['--token', token] : [])];\n\n let jobs: Array<{\n id: string;\n name: string;\n enabled: boolean;\n state?: {\n nextRunAtMs?: number;\n lastRunAtMs?: number;\n lastRunStatus?: string;\n lastDelivered?: boolean;\n consecutiveErrors?: number;\n };\n }> = [];\n\n try {\n const cliBin = resolveAgentFramework(agent.codeName).cliBinary ?? 'openclaw';\n const { stdout } = await execFilePromise(cliBin, ['--profile', agent.codeName, 'cron', 'list', '--json', ...gwArgs]);\n const parsed = JSON.parse(stdout);\n jobs = parsed.jobs ?? [];\n } catch {\n continue;\n }\n\n for (const job of jobs) {\n if (!job.enabled || !job.name.startsWith('aug:')) continue;\n const alertKey = `${agent.codeName}:${job.id}`;\n\n // Look up human-readable task info\n const displayInfo = taskDisplayInfo.get(`${agent.codeName}:${job.name}`);\n const taskName = displayInfo?.taskName ?? job.name;\n const schedule = displayInfo?.schedule ?? '';\n const agentDisplayName = displayInfo?.agentDisplayName ?? agent.codeName;\n\n // Check for late jobs — nextRunAtMs is in the past by more than the threshold\n if (job.state?.nextRunAtMs && job.state.nextRunAtMs + LATE_THRESHOLD_MS < now) {\n if (!alertedJobs.has(`late:${alertKey}`)) {\n const minsLate = Math.round((now - job.state.nextRunAtMs) / 60_000);\n alerts.push({\n type: 'late_standup',\n agentCodeName: agent.codeName,\n agentDisplayName,\n jobName: job.name,\n taskName,\n schedule,\n jobId: job.id,\n detail: `Job is ${minsLate}m late (expected at ${new Date(job.state.nextRunAtMs).toISOString()})`,\n });\n alertedJobs.add(`late:${alertKey}`);\n }\n } else {\n // Clear the late alert if the job is no longer late\n alertedJobs.delete(`late:${alertKey}`);\n }\n\n // Check for failed runs\n if (job.state?.lastRunStatus === 'error' || (job.state?.consecutiveErrors && job.state.consecutiveErrors > 0)) {\n if (!alertedJobs.has(`fail:${alertKey}`)) {\n alerts.push({\n type: 'cron_failure',\n agentCodeName: agent.codeName,\n agentDisplayName,\n jobName: job.name,\n taskName,\n schedule,\n jobId: job.id,\n detail: `Last run failed (${job.state.consecutiveErrors ?? 1} consecutive error(s))`,\n });\n alertedJobs.add(`fail:${alertKey}`);\n }\n } else {\n alertedJobs.delete(`fail:${alertKey}`);\n }\n }\n }\n\n if (alerts.length === 0) return;\n\n // Log all alerts\n for (const alert of alerts) {\n log(`ALERT [${alert.type}] ${alert.agentCodeName}/${alert.jobName}: ${alert.detail}`);\n }\n\n // Send to Slack webhook if configured\n if (alertSlackWebhook) {\n await sendSlackAlert(alerts);\n }\n\n // Post to API for dashboard visibility\n try {\n await api.post('/host/cron-alerts', { alerts });\n } catch {\n // Non-fatal — API may not have this endpoint yet\n }\n}\n\n/**\n * Call Telegram Bot API using Node's https module (not fetch).\n * Node's native fetch (undici) can't reach api.telegram.org on some networks.\n */\nfunction telegramApiCall(botToken: string, method: string, body: unknown): Promise<{ ok: boolean; description?: string }> {\n return new Promise((resolve, reject) => {\n const postData = JSON.stringify(body);\n const req = https.request({\n hostname: 'api.telegram.org',\n port: 443,\n path: `/bot${botToken}/${method}`,\n method: 'POST',\n family: 4,\n timeout: 10_000,\n headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(postData) },\n }, (res) => {\n let data = '';\n res.on('data', (d) => { data += d; });\n res.on('end', () => {\n try { resolve(JSON.parse(data)); } catch { reject(new Error('Invalid JSON from Telegram API')); }\n });\n });\n req.on('error', reject);\n req.on('timeout', () => { req.destroy(); reject(new Error('Telegram API timeout')); });\n req.write(postData);\n req.end();\n });\n}\n\nasync function sendSlackWebhookMessage(text: string): Promise<void> {\n if (!alertSlackWebhook) {\n log('sendSlackWebhookMessage: no alertSlackWebhook configured — message dropped');\n return;\n }\n try {\n const response = await fetch(alertSlackWebhook, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ text }),\n });\n if (!response.ok) {\n log(`Slack webhook failed: ${response.status} ${response.statusText}`);\n }\n } catch (err) {\n log(`Slack webhook error: ${(err as Error).message}`);\n }\n}\n\n/**\n * Post a message to a specific Slack channel using the agent's bot token\n * cached from channel_configs during refresh. Returns true if sent successfully.\n */\nasync function sendSlackChannelMessage(agentCodeName: string, channelId: string, text: string): Promise<boolean> {\n const botToken = agentChannelTokens.get(agentCodeName)?.slack;\n if (!botToken) {\n log(`No Slack bot token cached for '${agentCodeName}' — cannot post to ${channelId}`);\n return false;\n }\n\n try {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 5_000);\n try {\n const response = await fetch('https://slack.com/api/chat.postMessage', {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${botToken}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ channel: channelId, text }),\n signal: controller.signal,\n });\n clearTimeout(timeout);\n const data = await response.json() as { ok: boolean; error?: string };\n if (!data.ok) {\n log(`Slack chat.postMessage failed for '${agentCodeName}' to ${channelId}: ${data.error}`);\n return false;\n }\n return true;\n } finally {\n clearTimeout(timeout);\n }\n } catch (err) {\n log(`Slack channel message error for '${agentCodeName}': ${(err as Error).message}`);\n return false;\n }\n}\n\nasync function sendSlackAlert(alerts: CronAlert[]): Promise<void> {\n const blocks = alerts.map((a) => {\n const emoji = a.type === 'late_standup' ? ':warning:' : ':x:';\n const label = a.type === 'late_standup' ? 'Late' : 'Failed';\n const scheduleInfo = a.schedule ? ` (${a.schedule})` : '';\n return `${emoji} *${label}* — *${a.agentDisplayName}* / ${a.taskName}${scheduleInfo}\\n${a.detail}`;\n });\n\n await sendSlackWebhookMessage(`:rotating_light: *Cron Health Alert*\\n\\n${blocks.join('\\n\\n')}`);\n}\n\n/**\n * Send a task notification to a specific channel (Slack or Telegram).\n */\nasync function sendTaskNotification(agentCodeName: string, channel: string, to: string, text: string): Promise<void> {\n const tokens = agentChannelTokens.get(agentCodeName);\n\n if (channel === 'slack') {\n const botToken = tokens?.slack;\n const channelId = to.replace(/^channel:/, '');\n if (botToken) {\n const sent = await sendSlackChannelMessage(agentCodeName, channelId, text);\n if (sent) return;\n }\n log(`No Slack bot token for '${agentCodeName}' — targeted notification dropped`);\n } else if (channel === 'telegram') {\n const botToken = tokens?.telegram;\n const chatId = to.replace(/^chat:/, '');\n if (!botToken) {\n log(`No Telegram bot token for '${agentCodeName}' — notification dropped`);\n return;\n }\n const allowedChats = tokens?.telegramAllowedChats;\n if (allowedChats && allowedChats.length > 0 && !allowedChats.includes(chatId)) {\n log(`Telegram chat ${chatId} not in allowed_chat_ids for '${agentCodeName}'`);\n return;\n }\n try {\n const result = await telegramApiCall(botToken, 'sendMessage', { chat_id: chatId, text });\n if (!result.ok) {\n log(`Telegram sendMessage failed for '${agentCodeName}': ${result.description}`);\n } else {\n log(`Telegram notification sent for '${agentCodeName}' to chat ${chatId}`);\n }\n } catch (err) {\n log(`Telegram API error for '${agentCodeName}': ${(err as Error).message}`);\n }\n } else {\n log(`Unknown notify_channel '${channel}' for '${agentCodeName}'`);\n }\n}\n\n/**\n * Generate provision artifacts without writing to disk.\n * Returns the list of artifacts (relativePath + content) for comparison.\n */\nfunction generateArtifacts(\n agent: { agent_id: string; code_name: string; display_name: string; status: string; environment: string },\n refreshData: {\n agent: Record<string, unknown>;\n charter: { raw_content: string; version: string } | null;\n tools: { raw_content: string; version: string } | null;\n channel_configs: Record<string, { config: unknown; status: string }> | null;\n team_channel_policy: {\n team_id: string;\n allowed_channels: string[];\n denied_channels: string[];\n require_elevated_for_pii: boolean;\n } | null;\n team: { name: string; description: string | null; settings?: Record<string, unknown> } | null;\n scheduled_tasks?: unknown;\n },\n adapter: FrameworkAdapter,\n): { relativePath: string; content: string }[] {\n if (!refreshData.charter || !refreshData.tools) {\n throw new Error('No charter/tools available');\n }\n\n const charterContent = refreshData.charter.raw_content;\n const toolsContent = refreshData.tools.raw_content;\n\n const charterParsed = extractFrontmatter(charterContent);\n if (!charterParsed.frontmatter) {\n throw new Error(`Failed to parse CHARTER.md frontmatter: ${charterParsed.error ?? 'unknown'}`);\n }\n\n const toolsParsed = extractFrontmatter(toolsContent);\n if (!toolsParsed.frontmatter) {\n throw new Error(`Failed to parse TOOLS.md frontmatter: ${toolsParsed.error ?? 'unknown'}`);\n }\n\n const charterFrontmatter = charterParsed.frontmatter as unknown as CharterFrontmatter;\n const toolsFrontmatter = toolsParsed.frontmatter as unknown as ToolsFrontmatter;\n\n const configuredChannels = Object.keys(refreshData.channel_configs ?? {}) as ChannelId[];\n\n const agentChannelPolicy: ChannelPolicy = {\n policy: 'allowlist',\n allowed: configuredChannels,\n denied: [],\n require_approval_to_change: true,\n };\n\n let orgChannelPolicy: OrgChannelPolicy | undefined;\n const policyData = refreshData.team_channel_policy;\n\n if (policyData) {\n orgChannelPolicy = {\n organization_id: policyData.team_id,\n allowed_channels: (policyData.allowed_channels ?? []) as ChannelId[],\n denied_channels: (policyData.denied_channels ?? []) as ChannelId[],\n require_elevated_for_pii: policyData.require_elevated_for_pii ?? false,\n };\n }\n\n const resolvedChannels = resolveChannels(agentChannelPolicy, orgChannelPolicy);\n const effectiveChannels = agent.status === 'paused' ? [] : resolvedChannels;\n\n const provisionInput: ProvisionInput = {\n agent: refreshData.agent as any,\n charterFrontmatter,\n charterContent,\n toolsFrontmatter,\n toolsContent,\n resolvedChannels: effectiveChannels,\n deploymentTarget: 'local_docker' as DeploymentTarget,\n gatewayPort: 9000,\n team: refreshData.team ?? undefined,\n };\n\n const provisionOutput = provision(provisionInput, adapter.id);\n return provisionOutput.artifacts;\n}\n\n// ---------------------------------------------------------------------------\n// Cleanup helper (for revoked agents)\n// ---------------------------------------------------------------------------\n\nasync function cleanupAgentFiles(codeName: string, agentDir: string): Promise<void> {\n // Remove the provision directory\n if (existsSync(agentDir)) {\n try {\n rmSync(agentDir, { recursive: true, force: true });\n log(`Removed provision directory for '${codeName}'`);\n } catch (err) {\n log(`Failed to remove provision dir for '${codeName}': ${(err as Error).message}`);\n }\n }\n\n // Deregister from the framework runtime\n try {\n const adapter = resolveAgentFramework(codeName);\n const registered = await getOrCacheRegisteredAgents(adapter, codeName);\n if (registered.has(codeName)) {\n await adapter.deregisterAgent(codeName);\n registered.delete(codeName);\n log(`Deregistered '${codeName}' from ${adapter.label}`);\n }\n } catch (err) {\n log(`Failed to deregister '${codeName}': ${(err as Error).message}`);\n }\n}\n\n// ---------------------------------------------------------------------------\n// IPC + lifecycle\n// ---------------------------------------------------------------------------\n\nfunction startGatewayPool(): void {\n if (gatewayPool) return;\n\n gatewayPool = new GatewayClientPool();\n\n gatewayPool.on('connected', (codeName: string) => {\n log(`Gateway WebSocket connected for '${codeName}'`);\n });\n\n gatewayPool.on('disconnected', (codeName: string) => {\n log(`Gateway WebSocket disconnected for '${codeName}'`);\n });\n\n gatewayPool.on('error', (err: Error, codeName: string) => {\n log(`Gateway WebSocket error for '${codeName}': ${err.message}`);\n });\n\n gatewayPool.on('event', (evt: PooledGatewayEvent) => {\n // Forward to parent via IPC\n send({ type: 'gateway-event', event: evt.event, payload: evt.payload, agentCodeName: evt.agentCodeName });\n\n // Forward to API (fire and forget)\n getHostId().then((hostId) => {\n if (!hostId) return;\n api.post('/host/events', {\n host_id: hostId,\n agent_code_name: evt.agentCodeName,\n event_type: evt.event,\n payload: evt.payload,\n timestamp: new Date().toISOString(),\n }).catch((err) => {\n log(`Failed to forward gateway event: ${(err as Error).message}`);\n });\n }).catch(() => {\n // Ignore — host ID resolution is best-effort here\n });\n });\n}\n\nfunction stopGatewayPool(): void {\n if (gatewayPool) {\n gatewayPool.disconnectAll();\n gatewayPool = null;\n }\n}\n\nfunction startPolling(): void {\n if (!config || running) return;\n running = true;\n\n log(`Starting poll loop (interval=${config.intervalMs}ms, configDir=${config.configDir})`);\n\n // Run migration, then first poll, then start gateway pool\n void migrateToProfiles().then(() => {\n startGatewayPool();\n return pollCycle();\n }).then(() => {\n scheduleNext();\n });\n}\n\nfunction scheduleNext(): void {\n if (!running || !config) return;\n pollTimer = setTimeout(() => {\n void pollCycle().then(scheduleNext);\n }, config.intervalMs);\n}\n\nasync function stopPolling(): Promise<void> {\n running = false;\n if (pollTimer) {\n clearTimeout(pollTimer);\n pollTimer = null;\n }\n stopRealtimeChat();\n stopGatewayPool();\n\n // Stop all per-agent gateway processes\n await stopAllGateways();\n}\n\n// ---------------------------------------------------------------------------\n// Public API — called directly by the CLI command (no fork/IPC)\n// ---------------------------------------------------------------------------\n\n/**\n * Start the manager poll loop. Call this directly from the CLI command.\n * The process stays alive running the poll loop until stopManager() is called\n * or a signal is received.\n */\nexport function startManager(opts: { intervalMs: number; configDir: string }): void {\n config = opts;\n startPolling();\n}\n\n/**\n * Stop the manager poll loop gracefully.\n */\nexport async function stopManager(): Promise<void> {\n await stopPolling();\n}\n\n// Graceful shutdown on signals\nfor (const sig of ['SIGTERM', 'SIGINT'] as const) {\n process.on(sig, () => {\n log(`Received ${sig}, shutting down`);\n void stopPolling().then(() => {\n process.exit(0);\n });\n });\n}\n\n// If parent disconnects, exit\nprocess.on('disconnect', () => {\n log('Parent disconnected, exiting');\n void stopPolling().then(() => {\n process.exit(0);\n });\n});\n","/**\n * Gateway WebSocket Client — connects to the OpenClaw gateway event stream\n * and emits typed events for consumption by the manager worker.\n */\n\nimport { EventEmitter } from 'node:events';\nimport WebSocket from 'ws';\n\nconst DEFAULT_PORT = 18789;\nconst RECONNECT_INITIAL_MS = 1_000;\nconst RECONNECT_BASE_MS = 5_000;\nconst RECONNECT_MAX_MS = 30_000;\nconst HEARTBEAT_INTERVAL_MS = 30_000;\n\nexport interface GatewayEvent {\n type: 'event';\n event: string;\n payload: unknown;\n seq?: number;\n stateVersion?: number;\n}\n\nexport interface GatewayClientOptions {\n port?: number;\n token?: string;\n}\n\nexport interface PooledGatewayEvent extends GatewayEvent {\n agentCodeName: string;\n}\n\nexport class GatewayClient extends EventEmitter {\n private readonly port: number;\n private readonly token: string | undefined;\n private ws: WebSocket | null = null;\n private _connected = false;\n private _everConnected = false;\n private reconnectAttempts = 0;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private heartbeatTimer: ReturnType<typeof setInterval> | null = null;\n private pongReceived = true;\n private intentionalClose = false;\n private pendingRpc = new Map<string, { resolve: (v: unknown) => void; reject: (e: Error) => void; timer: ReturnType<typeof setTimeout> }>();\n private rpcSeq = 0;\n\n constructor(options: GatewayClientOptions = {}) {\n super();\n this.port = options.port ?? Number(process.env['OPENCLAW_GATEWAY_PORT']) ?? DEFAULT_PORT;\n this.token = options.token ?? process.env['OPENCLAW_GATEWAY_TOKEN'];\n }\n\n get connected(): boolean {\n return this._connected;\n }\n\n connect(): void {\n this.intentionalClose = false;\n this.doConnect();\n }\n\n disconnect(): void {\n this.intentionalClose = true;\n this.clearTimers();\n\n if (this.ws) {\n this.ws.removeAllListeners();\n this.ws.close(1000);\n this.ws = null;\n }\n\n if (this._connected) {\n this._connected = false;\n this.emit('disconnected');\n }\n }\n\n // ── Private ──────────────────────────────────────────────────────────────\n\n private doConnect(): void {\n const url = `ws://127.0.0.1:${this.port}`;\n\n try {\n const headers: Record<string, string> = {};\n if (this.token) {\n headers['Authorization'] = `Bearer ${this.token}`;\n }\n\n this.ws = new WebSocket(url, { headers });\n } catch (err) {\n this.emit('error', err);\n this.scheduleReconnect();\n return;\n }\n\n this.ws.on('open', () => {\n // Wait for challenge message from gateway — connection established, auth pending\n });\n\n this.ws.on('message', (data: WebSocket.Data) => {\n try {\n const msg = JSON.parse(data.toString());\n this.handleMessage(msg);\n } catch {\n // Ignore non-JSON messages\n }\n });\n\n this.ws.on('close', (code: number, reason: Buffer) => {\n this.clearHeartbeat();\n if (this._connected) {\n this._connected = false;\n this.emit('disconnected');\n } else if (!this._everConnected) {\n // Never connected — log the close reason for debugging\n this.emit('error', new Error(`WebSocket closed before auth (code=${code}, reason=${reason?.toString() || 'none'})`));\n }\n if (!this.intentionalClose) {\n this.scheduleReconnect();\n }\n });\n\n this.ws.on('error', (err: Error) => {\n // Suppress ECONNREFUSED before first successful connection — the gateway\n // may still be booting. The reconnect loop will retry with backoff.\n if (!this._everConnected && (err as NodeJS.ErrnoException).code === 'ECONNREFUSED') {\n return;\n }\n this.emit('error', err);\n });\n\n this.ws.on('pong', () => {\n this.pongReceived = true;\n });\n }\n\n private handleMessage(msg: Record<string, unknown>): void {\n switch (msg.type) {\n case 'challenge':\n // Respond to challenge handshake\n this.sendJson({\n type: 'connect',\n nonce: msg.nonce,\n role: 'operator',\n scopes: ['events:read'],\n });\n break;\n\n case 'hello-ok':\n this._connected = true;\n this._everConnected = true;\n this.reconnectAttempts = 0;\n this.startHeartbeat();\n this.emit('connected');\n break;\n\n case 'event':\n this.emit('event', {\n type: 'event',\n event: msg.event,\n payload: msg.payload,\n seq: msg.seq,\n stateVersion: msg.stateVersion,\n } as GatewayEvent);\n break;\n\n case 'heartbeat':\n case 'tick':\n // Gateway-initiated heartbeat — no action needed\n break;\n\n case 'rpc-result':\n case 'rpc-error': {\n const rpcId = msg.id as string;\n const pending = this.pendingRpc.get(rpcId);\n if (pending) {\n this.pendingRpc.delete(rpcId);\n clearTimeout(pending.timer);\n if (msg.type === 'rpc-error') {\n pending.reject(new Error((msg.error as string) ?? 'RPC error'));\n } else {\n pending.resolve(msg.result);\n }\n }\n break;\n }\n\n default:\n // Unknown message type — check if it's an RPC response with a matching id\n if (msg.id && typeof msg.id === 'string') {\n const pending = this.pendingRpc.get(msg.id);\n if (pending) {\n this.pendingRpc.delete(msg.id);\n clearTimeout(pending.timer);\n if (msg.error) {\n pending.reject(new Error(String(msg.error)));\n } else {\n pending.resolve(msg);\n }\n }\n }\n break;\n }\n }\n\n /**\n * Send an RPC call to the gateway and wait for a response.\n * Returns the response payload or throws on timeout/error.\n */\n sendRpc(method: string, params: Record<string, unknown> = {}, timeoutMs = 10_000): Promise<unknown> {\n return new Promise((resolve, reject) => {\n if (!this._connected || this.ws?.readyState !== WebSocket.OPEN) {\n reject(new Error('Gateway not connected'));\n return;\n }\n const id = `rpc-${++this.rpcSeq}-${Date.now()}`;\n const timer = setTimeout(() => {\n this.pendingRpc.delete(id);\n reject(new Error(`RPC ${method} timed out after ${timeoutMs}ms`));\n }, timeoutMs);\n this.pendingRpc.set(id, { resolve, reject, timer });\n this.sendJson({ type: 'rpc', id, method, params });\n });\n }\n\n private sendJson(obj: unknown): void {\n if (this.ws?.readyState === WebSocket.OPEN) {\n this.ws.send(JSON.stringify(obj));\n }\n }\n\n private startHeartbeat(): void {\n this.clearHeartbeat();\n this.pongReceived = true;\n\n this.heartbeatTimer = setInterval(() => {\n if (!this.pongReceived) {\n // Stale connection — force reconnect\n this.ws?.terminate();\n return;\n }\n this.pongReceived = false;\n this.ws?.ping();\n }, HEARTBEAT_INTERVAL_MS);\n }\n\n private clearHeartbeat(): void {\n if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer);\n this.heartbeatTimer = null;\n }\n }\n\n private scheduleReconnect(): void {\n if (this.intentionalClose) return;\n\n // First retry uses a short delay (gateway may still be booting), then exponential backoff\n const delay = this.reconnectAttempts === 0\n ? RECONNECT_INITIAL_MS\n : Math.min(RECONNECT_BASE_MS * Math.pow(2, this.reconnectAttempts - 1), RECONNECT_MAX_MS);\n this.reconnectAttempts++;\n\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null;\n this.doConnect();\n }, delay);\n }\n\n private clearTimers(): void {\n this.clearHeartbeat();\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// GatewayClientPool — manages multiple per-agent gateway connections\n// ---------------------------------------------------------------------------\n\nexport class GatewayClientPool extends EventEmitter {\n private clients = new Map<string, GatewayClient>();\n\n addAgent(codeName: string, port: number, token?: string): void {\n if (this.clients.has(codeName)) {\n this.removeAgent(codeName);\n }\n\n const client = new GatewayClient({ port, token });\n\n client.on('connected', () => {\n this.emit('connected', codeName);\n });\n\n client.on('disconnected', () => {\n this.emit('disconnected', codeName);\n });\n\n client.on('error', (err: Error) => {\n this.emit('error', err, codeName);\n });\n\n client.on('event', (evt: GatewayEvent) => {\n const pooledEvent: PooledGatewayEvent = {\n ...evt,\n agentCodeName: codeName,\n };\n this.emit('event', pooledEvent);\n });\n\n this.clients.set(codeName, client);\n client.connect();\n }\n\n removeAgent(codeName: string): void {\n const client = this.clients.get(codeName);\n if (client) {\n client.disconnect();\n this.clients.delete(codeName);\n }\n }\n\n hasAgent(codeName: string): boolean {\n return this.clients.has(codeName);\n }\n\n isConnected(codeName: string): boolean {\n return this.clients.get(codeName)?.connected ?? false;\n }\n\n /**\n * Send an RPC call to a specific agent's gateway.\n * Returns the response or throws on timeout/error/not connected.\n */\n async sendRpc(codeName: string, method: string, params: Record<string, unknown> = {}, timeoutMs = 10_000): Promise<unknown> {\n const client = this.clients.get(codeName);\n if (!client) throw new Error(`No gateway client for agent '${codeName}'`);\n return client.sendRpc(method, params, timeoutMs);\n }\n\n disconnectAll(): void {\n for (const [, client] of this.clients) {\n client.disconnect();\n }\n this.clients.clear();\n }\n\n get size(): number {\n return this.clients.size;\n }\n}\n","/**\n * Persistent session manager for Claude Code agents.\n *\n * Spawns a long-running `claude --channels` process per agent, monitors\n * health, auto-restarts with backoff, and injects tasks via the webhook\n * channel HTTP endpoint.\n */\n\nimport { spawn, execSync, type ChildProcess } from 'node:child_process';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport { existsSync, readFileSync } from 'node:fs';\n\nexport interface PersistentSessionConfig {\n codeName: string;\n agentId: string;\n projectDir: string;\n mcpConfigPath: string;\n claudeMdPath: string;\n channels: string[]; // e.g. ['plugin:telegram@claude-plugins-official']\n devChannels: string[]; // custom channels needing --dangerously-load-development-channels\n log: (msg: string) => void;\n}\n\nexport interface PersistentSession {\n codeName: string;\n process: ChildProcess | null;\n taskChannelPort: number | null;\n startedAt: number | null;\n restartCount: number;\n status: 'starting' | 'running' | 'stopped' | 'crashed';\n}\n\nconst sessions = new Map<string, PersistentSession>();\n\n// Backoff: 5s, 10s, 20s, 40s, 60s max\nfunction getBackoffMs(restartCount: number): number {\n return Math.min(5000 * Math.pow(2, restartCount), 60_000);\n}\n\n/**\n * Start a persistent Claude Code session for an agent.\n * If already running, returns the existing session.\n */\nexport function startPersistentSession(config: PersistentSessionConfig): PersistentSession {\n const existing = sessions.get(config.codeName);\n if (existing && existing.status === 'running' && existing.process && !existing.process.killed) {\n return existing;\n }\n\n const session: PersistentSession = {\n codeName: config.codeName,\n process: null,\n taskChannelPort: null,\n startedAt: null,\n restartCount: existing?.restartCount ?? 0,\n status: 'starting',\n };\n sessions.set(config.codeName, session);\n\n spawnSession(config, session);\n return session;\n}\n\nfunction spawnSession(config: PersistentSessionConfig, session: PersistentSession): void {\n const { codeName, projectDir, mcpConfigPath, claudeMdPath, channels, devChannels, log } = config;\n\n const args: string[] = [];\n\n // Add official channel plugins\n if (channels.length > 0) {\n args.push('--channels', ...channels);\n }\n\n // Add custom development channels (not on Anthropic's allowlist)\n if (devChannels.length > 0) {\n args.push('--dangerously-load-development-channels', ...devChannels);\n }\n\n // MCP config for augmented tools + task channel\n args.push('--mcp-config', mcpConfigPath);\n\n // Separate channels config (Slack etc.) to avoid duplicate loading\n const channelsConfigPath = join(projectDir, '.mcp-channels.json');\n if (existsSync(channelsConfigPath)) {\n args.push('--mcp-config', channelsConfigPath);\n }\n\n // Agent identity\n if (existsSync(claudeMdPath)) {\n args.push('--system-prompt-file', claudeMdPath);\n }\n\n // Bypass permissions for autonomous operation.\n // --allow-dangerously-skip-permissions enables the option without a confirmation dialog.\n // --dangerously-skip-permissions then activates it.\n args.push('--allow-dangerously-skip-permissions');\n args.push('--dangerously-skip-permissions');\n\n // Session name for identification\n args.push('--name', `agt-${codeName}`);\n\n log(`[persistent-session] Starting session for '${codeName}' with args: ${args.join(' ')}`);\n\n // Channels require a real TTY (interactive mode). Without a TTY, Claude\n // auto-switches to print mode and exits after responding. Use tmux to\n // provide a real terminal. The session stays alive indefinitely.\n const tmuxSession = `agt-${codeName}`;\n\n // Kill any existing tmux session for this agent\n try {\n execSync(`tmux kill-session -t ${tmuxSession} 2>/dev/null`, { stdio: 'ignore' });\n } catch { /* no existing session */ }\n\n // Load .env.integrations into the tmux session environment\n const envIntegrationsPath = join(projectDir, '.env.integrations');\n let envPrefix = '';\n if (existsSync(envIntegrationsPath)) {\n try {\n const envContent = readFileSync(envIntegrationsPath, 'utf-8');\n const envVars = envContent.split('\\n')\n .filter((line: string) => line && !line.startsWith('#') && line.includes('='))\n .map((line: string) => {\n const eqIdx = line.indexOf('=');\n const key = line.slice(0, eqIdx);\n const value = line.slice(eqIdx + 1);\n return `${key}=${JSON.stringify(value)}`;\n })\n .join(' ');\n if (envVars) envPrefix = `env ${envVars} `;\n } catch { /* non-fatal */ }\n }\n\n // Build the full claude command\n const initPrompt = 'You are now online. Wait for messages from your channels (Telegram, Slack) and respond to them. Use your kanban tools to track work.';\n const claudeCmd = `${envPrefix}claude ${JSON.stringify(initPrompt)} ${args.map(a => a.includes(' ') ? JSON.stringify(a) : a).join(' ')}`;\n\n // Start tmux session with claude in it\n const child = spawn('tmux', [\n 'new-session', '-d', '-s', tmuxSession,\n '-c', projectDir,\n claudeCmd,\n ], {\n cwd: projectDir,\n stdio: ['ignore', 'pipe', 'pipe'],\n env: process.env,\n });\n\n session.process = child; // tmux spawner process (exits quickly)\n session.startedAt = Date.now();\n session.status = 'running';\n\n // tmux new-session -d exits immediately. Monitor the tmux session instead.\n child.on('close', (code) => {\n if (code !== 0) {\n log(`[persistent-session] Failed to create tmux session for '${codeName}' (exit ${code})`);\n session.status = 'crashed';\n session.process = null;\n return;\n }\n log(`[persistent-session] tmux session '${tmuxSession}' created for '${codeName}'`);\n\n // Auto-accept startup dialogs by polling the tmux pane content.\n // Only send keystrokes when we detect a specific dialog on screen.\n // Most dialogs persist once approved, but --dangerously-load-development-channels\n // always prompts. We check the screen content to avoid sending keystrokes to the live prompt.\n const acceptDialogs = async () => {\n for (let i = 0; i < 15; i++) { // check every 2s for up to 30s\n await new Promise((r) => setTimeout(r, 2000));\n try {\n const { execSync: es } = await import('node:child_process');\n const screen = es(`tmux capture-pane -t ${tmuxSession} -p 2>/dev/null`, { encoding: 'utf-8' });\n\n if (screen.includes('Yes, I trust this folder')) {\n es(`tmux send-keys -t ${tmuxSession} Enter`, { stdio: 'ignore' });\n log(`[persistent-session] Auto-accepted workspace trust for '${codeName}'`);\n continue;\n }\n if (screen.includes('I am using this for local development')) {\n es(`tmux send-keys -t ${tmuxSession} Enter`, { stdio: 'ignore' });\n log(`[persistent-session] Auto-accepted dev channels for '${codeName}'`);\n continue;\n }\n if (screen.includes('Enter to confirm') && screen.includes('MCP')) {\n es(`tmux send-keys -t ${tmuxSession} Enter`, { stdio: 'ignore' });\n log(`[persistent-session] Auto-accepted MCP servers for '${codeName}'`);\n continue;\n }\n if (screen.includes('Yes, I accept') && screen.includes('Bypass Permissions')) {\n es(`tmux send-keys -t ${tmuxSession} 2`, { stdio: 'ignore' });\n await new Promise((r) => setTimeout(r, 300));\n es(`tmux send-keys -t ${tmuxSession} Enter`, { stdio: 'ignore' });\n log(`[persistent-session] Auto-accepted bypass permissions for '${codeName}'`);\n continue;\n }\n // If we see the prompt (❯), dialogs are done\n if (screen.includes('❯') && !screen.includes('Enter to confirm')) {\n log(`[persistent-session] Session ready for '${codeName}' — no more dialogs`);\n break;\n }\n } catch { /* tmux session may have died */ break; }\n }\n };\n acceptDialogs().catch(() => {});\n });\n\n child.on('error', (err) => {\n log(`[persistent-session] Failed to start tmux for '${codeName}': ${err.message}`);\n session.status = 'crashed';\n });\n}\n\n/**\n * Stop a persistent session gracefully.\n */\nexport function stopPersistentSession(codeName: string, log: (msg: string) => void): void {\n const session = sessions.get(codeName);\n if (!session) return;\n\n log(`[persistent-session] Stopping session for '${codeName}'`);\n session.status = 'stopped';\n\n // Kill the tmux session\n try {\n execSync(`tmux kill-session -t agt-${codeName} 2>/dev/null`, { stdio: 'ignore' });\n } catch { /* session may already be dead */ }\n\n // Legacy: also kill child process if it exists\n if (session.process && !session.process.killed) {\n session.process.kill('SIGTERM');\n }\n\n // Force kill after 10s\n setTimeout(() => {\n if (session.process && !session.process.killed) {\n session.process.kill('SIGKILL');\n }\n }, 10_000);\n\n sessions.delete(codeName);\n}\n\n/**\n * Inject a task/message into a persistent session.\n * Tries the webhook channel first, falls back to stdin stream-json.\n */\nexport async function injectMessage(\n codeName: string,\n type: 'task' | 'chat' | 'system',\n content: string,\n meta?: Record<string, string>,\n): Promise<boolean> {\n const session = sessions.get(codeName);\n if (!session || session.status !== 'running' || !session.process) {\n return false;\n }\n\n // Try webhook channel if available\n if (session.taskChannelPort) {\n try {\n const res = await fetch(`http://127.0.0.1:${session.taskChannelPort}`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ type, content, meta }),\n signal: AbortSignal.timeout(10_000),\n });\n if (res.ok) return true;\n } catch { /* fall through to stdin */ }\n }\n\n // Fallback: inject via tmux send-keys\n try {\n const prefix = meta?.task_name ? `[Task: ${meta.task_name}] ` : '';\n const text = prefix + content;\n // Escape single quotes for shell\n const escaped = text.replace(/'/g, \"'\\\\''\");\n execSync(`tmux send-keys -t agt-${codeName} '${escaped}' Enter`, { stdio: 'ignore' });\n return true;\n } catch {\n return false;\n }\n\n return false;\n}\n\n/**\n * Get the current state of a persistent session.\n */\nexport function getSessionState(codeName: string): PersistentSession | null {\n return sessions.get(codeName) ?? null;\n}\n\n/**\n * Check if a persistent session is healthy (tmux session exists).\n */\nexport function isSessionHealthy(codeName: string): boolean {\n const session = sessions.get(codeName);\n if (!session || session.status !== 'running') return false;\n // Check if tmux session is still alive\n try {\n execSync(`tmux has-session -t agt-${codeName} 2>/dev/null`, { stdio: 'ignore' });\n return true;\n } catch {\n // tmux session died — mark as crashed for restart\n session.status = 'crashed';\n return false;\n }\n}\n\n/**\n * Reset restart counter (call after successful task completion).\n */\nexport function resetRestartCount(codeName: string): void {\n const session = sessions.get(codeName);\n if (session) session.restartCount = 0;\n}\n\n/**\n * Stop all persistent sessions (called on manager shutdown).\n */\nexport function stopAllSessions(log: (msg: string) => void): void {\n for (const codeName of sessions.keys()) {\n stopPersistentSession(codeName, log);\n }\n}\n\n/**\n * Get project dir for a Claude Code agent.\n */\nexport function getProjectDir(codeName: string): string {\n return join(homedir(), '.augmented', codeName, 'project');\n}\n","/**\n * Supabase Realtime subscriptions for the manager.\n *\n * Replaces polling with WebSocket subscriptions:\n * - direct_chat_messages INSERT → instant chat delivery (~100ms vs 2s)\n * - agent_doc_versions INSERT → instant drift detection (~100ms vs 5min)\n * - host_agents INSERT/DELETE → instant agent assignment changes\n *\n * Falls back to polling if the Realtime connection drops.\n */\n\nimport { createClient, type SupabaseClient, type RealtimeChannel } from '@supabase/supabase-js';\n\n// ---------------------------------------------------------------------------\n// Shared client\n// ---------------------------------------------------------------------------\n\nlet client: SupabaseClient | null = null;\nlet chatChannel: RealtimeChannel | null = null;\nlet driftChannel: RealtimeChannel | null = null;\nlet assignChannel: RealtimeChannel | null = null;\nlet configChannel: RealtimeChannel | null = null;\nlet kanbanChannel: RealtimeChannel | null = null;\nlet connected = false;\nlet tearingDown = false; // Guard against re-entrant teardown\n\nexport interface RealtimeConfig {\n supabaseUrl: string;\n supabaseAnonKey: string;\n token: string;\n log: (msg: string) => void;\n}\n\nfunction ensureClient(config: RealtimeConfig): SupabaseClient {\n if (client) return client;\n\n client = createClient(config.supabaseUrl, config.supabaseAnonKey, {\n global: {\n headers: { Authorization: `Bearer ${config.token}` },\n },\n realtime: {\n params: { apikey: config.supabaseAnonKey },\n },\n });\n\n client.realtime.setAuth(config.token);\n return client;\n}\n\n// ---------------------------------------------------------------------------\n// Direct chat subscription\n// ---------------------------------------------------------------------------\n\nexport interface ChatMessagePayload {\n id: string;\n agent_id: string;\n session_id: string;\n content: string;\n status: string;\n created_at: string;\n}\n\nexport function startRealtimeChat(\n config: RealtimeConfig & {\n agentIds: string[];\n onMessage: (msg: ChatMessagePayload) => void;\n onError: (err: Error) => void;\n onStatusChange: (status: 'connected' | 'disconnected' | 'error') => void;\n },\n): void {\n const { agentIds, onMessage, onStatusChange, log } = config;\n if (agentIds.length === 0) return;\n\n const sb = ensureClient(config);\n const filterStr = agentIds.length === 1\n ? `agent_id=eq.${agentIds[0]}`\n : `agent_id=in.(${agentIds.join(',')})`;\n\n chatChannel = sb\n .channel('direct-chat-realtime')\n .on('postgres_changes', {\n event: 'INSERT',\n schema: 'public',\n table: 'direct_chat_messages',\n filter: filterStr,\n }, (payload) => {\n const msg = payload.new as ChatMessagePayload;\n if (msg.status !== 'pending') return;\n log(`[realtime] Chat message for agent ${msg.agent_id}: id=${msg.id}`);\n onMessage(msg);\n })\n .subscribe((status) => {\n if (status === 'SUBSCRIBED') {\n connected = true;\n log('[realtime] Chat channel connected');\n onStatusChange('connected');\n } else if (status === 'CLOSED' || status === 'CHANNEL_ERROR' || status === 'TIMED_OUT') {\n if (tearingDown) return; // Prevent re-entrant teardown from recursive close events\n connected = false;\n log(`[realtime] Chat channel: ${status} — will reconnect next cycle`);\n // Don't call stopRealtimeChat here — it triggers more CLOSED events.\n // Just null out references and let the manager reset flags for fresh reconnect.\n chatChannel = null;\n driftChannel = null;\n assignChannel = null;\n configChannel = null;\n kanbanChannel = null;\n if (client) { try { client.removeAllChannels(); } catch { /* ignore */ } client = null; }\n onStatusChange(status === 'TIMED_OUT' ? 'error' : 'disconnected');\n }\n });\n\n log(`[realtime] Subscribing to direct_chat_messages for ${agentIds.length} agent(s)`);\n}\n\n// ---------------------------------------------------------------------------\n// Drift detection subscription\n// ---------------------------------------------------------------------------\n\nexport interface DriftPayload {\n version_id: string;\n agent_id: string;\n doc_type: string;\n version: string;\n created_at: string;\n}\n\nexport function startRealtimeDrift(\n config: RealtimeConfig & {\n agentIds: string[];\n onDrift: (payload: DriftPayload) => void;\n },\n): void {\n const { agentIds, onDrift, log } = config;\n if (agentIds.length === 0) return;\n\n const sb = ensureClient(config);\n const filterStr = agentIds.length === 1\n ? `agent_id=eq.${agentIds[0]}`\n : `agent_id=in.(${agentIds.join(',')})`;\n\n driftChannel = sb\n .channel('drift-realtime')\n .on('postgres_changes', {\n event: 'INSERT',\n schema: 'public',\n table: 'agent_doc_versions',\n filter: filterStr,\n }, (payload) => {\n const doc = payload.new as DriftPayload;\n log(`[realtime] Doc version change for agent ${doc.agent_id}: ${doc.doc_type} v${doc.version}`);\n onDrift(doc);\n })\n .subscribe((status) => {\n if (status === 'SUBSCRIBED') {\n log('[realtime] Drift channel connected');\n } else if (status === 'CLOSED' || status === 'CHANNEL_ERROR') {\n log(`[realtime] Drift channel: ${status}`);\n }\n });\n\n log(`[realtime] Subscribing to agent_doc_versions for ${agentIds.length} agent(s)`);\n}\n\n// ---------------------------------------------------------------------------\n// Agent assignment subscription\n// ---------------------------------------------------------------------------\n\nexport interface AssignmentPayload {\n host_id: string;\n agent_id: string;\n assigned_by: string;\n}\n\nexport function startRealtimeAssignments(\n config: RealtimeConfig & {\n hostId: string;\n onAssign: (payload: AssignmentPayload) => void;\n onUnassign: (payload: { agent_id: string }) => void;\n },\n): void {\n const { hostId, onAssign, onUnassign, log } = config;\n\n const sb = ensureClient(config);\n\n assignChannel = sb\n .channel('assignment-realtime')\n .on('postgres_changes', {\n event: 'INSERT',\n schema: 'public',\n table: 'host_agents',\n filter: `host_id=eq.${hostId}`,\n }, (payload) => {\n const row = payload.new as AssignmentPayload;\n log(`[realtime] Agent assigned: ${row.agent_id} to host ${row.host_id}`);\n onAssign(row);\n })\n .on('postgres_changes', {\n event: 'DELETE',\n schema: 'public',\n table: 'host_agents',\n }, (payload) => {\n // DELETE events can't be filtered by Supabase Realtime\n // We receive all DELETEs and filter client-side\n const old = payload.old as { host_id?: string; agent_id?: string };\n if (old.host_id === hostId && old.agent_id) {\n log(`[realtime] Agent unassigned: ${old.agent_id} from host ${hostId}`);\n onUnassign({ agent_id: old.agent_id });\n }\n })\n .subscribe((status) => {\n if (status === 'SUBSCRIBED') {\n log('[realtime] Assignment channel connected');\n } else if (status === 'CLOSED' || status === 'CHANNEL_ERROR') {\n log(`[realtime] Assignment channel: ${status}`);\n }\n });\n\n log(`[realtime] Subscribing to host_agents for host ${hostId}`);\n}\n\n// ---------------------------------------------------------------------------\n// Agent config change subscription\n// ---------------------------------------------------------------------------\n\nexport interface AgentConfigPayload {\n agent_id: string;\n code_name: string;\n status: string;\n framework: string;\n session_mode: string;\n primary_model: string | null;\n updated_at: string;\n}\n\nexport function startRealtimeConfig(\n config: RealtimeConfig & {\n agentIds: string[];\n onConfigChange: (payload: AgentConfigPayload) => void;\n },\n): void {\n const { agentIds, onConfigChange, log } = config;\n if (agentIds.length === 0) return;\n\n const sb = ensureClient(config);\n const filterStr = agentIds.length === 1\n ? `agent_id=eq.${agentIds[0]}`\n : `agent_id=in.(${agentIds.join(',')})`;\n\n // Track last known values to filter out timestamp-only updates\n const lastKnown = new Map<string, string>();\n\n configChannel = sb\n .channel('config-realtime')\n .on('postgres_changes', {\n event: 'UPDATE',\n schema: 'public',\n table: 'agents',\n filter: filterStr,\n }, (payload) => {\n const agent = payload.new as AgentConfigPayload;\n\n // Build a fingerprint of meaningful fields (ignore timestamps like updated_at, last_heartbeat_at)\n const fingerprint = `${agent.status}|${agent.framework}|${agent.session_mode}|${agent.primary_model}`;\n const prev = lastKnown.get(agent.agent_id);\n\n if (prev === fingerprint) return; // timestamp-only change, ignore\n lastKnown.set(agent.agent_id, fingerprint);\n\n log(`[realtime] Agent config changed: ${agent.code_name} (status=${agent.status})`);\n onConfigChange(agent);\n })\n .subscribe((status) => {\n if (status === 'SUBSCRIBED') {\n log('[realtime] Config channel connected');\n } else if (status === 'CLOSED' || status === 'CHANNEL_ERROR') {\n log(`[realtime] Config channel: ${status}`);\n }\n });\n\n log(`[realtime] Subscribing to agents table for ${agentIds.length} agent(s)`);\n}\n\n// ---------------------------------------------------------------------------\n// Kanban item subscription — trigger work when items hit 'today'\n// ---------------------------------------------------------------------------\n\nexport interface KanbanItemPayload {\n id: string;\n agent_id: string;\n title: string;\n status: string;\n priority: number;\n}\n\nexport function startRealtimeKanban(\n config: RealtimeConfig & {\n agentIds: string[];\n onTodayItem: (payload: KanbanItemPayload) => void;\n },\n): void {\n const { agentIds, onTodayItem, log } = config;\n if (agentIds.length === 0) return;\n\n const sb = ensureClient(config);\n const filterStr = agentIds.length === 1\n ? `agent_id=eq.${agentIds[0]}`\n : `agent_id=in.(${agentIds.join(',')})`;\n\n kanbanChannel = sb\n .channel('kanban-realtime')\n .on('postgres_changes', {\n event: 'INSERT',\n schema: 'public',\n table: 'agent_kanban_items',\n filter: filterStr,\n }, (payload) => {\n const item = payload.new as KanbanItemPayload;\n if (item.status === 'today') {\n log(`[realtime] New kanban item in 'today': \"${item.title}\" for agent ${item.agent_id}`);\n onTodayItem(item);\n }\n })\n .on('postgres_changes', {\n event: 'UPDATE',\n schema: 'public',\n table: 'agent_kanban_items',\n filter: filterStr,\n }, (payload) => {\n const item = payload.new as KanbanItemPayload;\n const old = payload.old as KanbanItemPayload;\n // Only trigger when status changes TO 'today' (not from today to something else)\n if (item.status === 'today' && old.status !== 'today') {\n log(`[realtime] Kanban item moved to 'today': \"${item.title}\" for agent ${item.agent_id}`);\n onTodayItem(item);\n }\n })\n .subscribe((status) => {\n if (status === 'SUBSCRIBED') {\n log('[realtime] Kanban channel connected');\n } else if (status === 'CLOSED' || status === 'CHANNEL_ERROR') {\n log(`[realtime] Kanban channel: ${status}`);\n }\n });\n\n log(`[realtime] Subscribing to agent_kanban_items for ${agentIds.length} agent(s)`);\n}\n\n// ---------------------------------------------------------------------------\n// Shared utilities\n// ---------------------------------------------------------------------------\n\nexport function updateRealtimeToken(token: string): void {\n if (client) {\n client.realtime.setAuth(token);\n }\n}\n\nexport function isRealtimeConnected(): boolean {\n return connected;\n}\n\nexport function stopRealtimeChat(): void {\n if (tearingDown) return;\n tearingDown = true;\n try {\n if (chatChannel) { try { chatChannel.unsubscribe(); } catch {} chatChannel = null; }\n if (driftChannel) { try { driftChannel.unsubscribe(); } catch {} driftChannel = null; }\n if (assignChannel) { try { assignChannel.unsubscribe(); } catch {} assignChannel = null; }\n if (configChannel) { try { configChannel.unsubscribe(); } catch {} configChannel = null; }\n if (kanbanChannel) { try { kanbanChannel.unsubscribe(); } catch {} kanbanChannel = null; }\n if (client) {\n try { client.removeAllChannels(); } catch {}\n client = null;\n }\n connected = false;\n } finally {\n tearingDown = false;\n }\n}\n"],"mappings":"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","names":["readFileSync","existsSync","join","client","config","log","getProjectDir","config","log","join","readFileSync","existsSync","state","primaryModel","sessionMode","agentDir","getProjectDir"]}
|