agenttop 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +351 -0
- package/dist/chunk-4I4UZNKS.js +1019 -0
- package/dist/chunk-4I4UZNKS.js.map +1 -0
- package/dist/index.js +1390 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-server.js +14 -0
- package/dist/mcp-server.js.map +1 -0
- package/hooks/agenttop-guard.py +120 -0
- package/package.json +62 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.tsx","../src/ui/App.tsx","../src/hooks/installer.ts","../src/install-mcp.ts","../src/updates.ts","../src/ui/components/StatusBar.tsx","../src/ui/theme.ts","../src/ui/components/SessionList.tsx","../src/ui/components/ActivityFeed.tsx","../src/ui/components/AlertBar.tsx","../src/ui/components/SessionDetail.tsx","../src/ui/components/SetupModal.tsx","../src/ui/components/FooterBar.tsx","../src/ui/hooks/useSessions.ts","../src/ui/hooks/useActivityStream.ts","../src/ui/hooks/useAlerts.ts","../src/notifications.ts","../src/alerts/logger.ts","../src/ui/hooks/useTextInput.ts","../src/stream.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport { join, dirname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport React from 'react';\nimport { render } from 'ink';\n\nimport type { AlertSeverity, CLIOptions } from './discovery/types.js';\nimport { App } from './ui/App.js';\nimport { installHooks, uninstallHooks } from './hooks/installer.js';\nimport { loadConfig, saveConfig, isFirstRun } from './config/store.js';\nimport { startMcpServer } from './mcp/server.js';\nimport { runStreamMode } from './stream.js';\nimport { installMcpConfig } from './install-mcp.js';\n\nconst getVersion = (): string => {\n try {\n const thisFile = fileURLToPath(import.meta.url);\n const pkgPath = join(dirname(thisFile), '..', 'package.json');\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));\n return pkg.version || '0.0.0';\n } catch {\n return '0.0.0';\n }\n};\n\nconst VERSION = getVersion();\n\nconst HELP = `agenttop v${VERSION} -- Real-time dashboard for AI coding agent sessions\n\nUsage: agenttop [options]\n\nOptions:\n --all-users Monitor all users (root only)\n --no-security Disable security analysis\n --json Stream events as JSON lines (no TUI)\n --plain Stream events as plain text (no TUI)\n --alert-level <l> Minimum: info|warn|high|critical (default: warn)\n --no-notify Disable all notifications\n --no-alert-log Disable alert file logging\n --no-updates Disable update checks\n --poll-interval <ms> Session discovery interval (default: 10000)\n --mcp Start as MCP server (for Claude Code integration)\n --install-mcp Register agenttop as MCP server in Claude Code\n --install-hooks Install Claude Code PostToolUse hook for active protection\n --uninstall-hooks Remove agenttop hooks from Claude Code\n --version Show version\n --help Show this help\n\nStreaming modes (--json / --plain):\n Stream session events to stdout for piping into other tools.\n --json outputs one JSON object per line (JSONL format).\n --plain outputs human-readable lines.\n\n Examples:\n agenttop --json | jq 'select(.type == \"alert\")'\n agenttop --plain | grep ALERT\n agenttop --json --no-security # stream tool calls only\n`;\n\nconst write = (msg: string): void => {\n process.stdout.write(msg + '\\n');\n};\n\nconst parseArgs = (argv: string[]): CLIOptions => {\n const args = argv.slice(2);\n const options: CLIOptions = {\n allUsers: false,\n noSecurity: false,\n json: false,\n plain: false,\n alertLevel: 'warn',\n installHooks: false,\n uninstallHooks: false,\n help: false,\n version: false,\n noNotify: false,\n noAlertLog: false,\n noUpdates: false,\n pollInterval: 10000,\n mcp: false,\n installMcp: false,\n };\n\n for (let i = 0; i < args.length; i++) {\n switch (args[i]) {\n case '--all-users':\n options.allUsers = true;\n break;\n case '--no-security':\n options.noSecurity = true;\n break;\n case '--json':\n options.json = true;\n break;\n case '--plain':\n options.plain = true;\n break;\n case '--alert-level':\n i++;\n if (['info', 'warn', 'high', 'critical'].includes(args[i])) {\n options.alertLevel = args[i] as AlertSeverity;\n }\n break;\n case '--no-notify':\n options.noNotify = true;\n break;\n case '--no-alert-log':\n options.noAlertLog = true;\n break;\n case '--no-updates':\n options.noUpdates = true;\n break;\n case '--poll-interval':\n i++;\n {\n const n = parseInt(args[i], 10);\n if (n > 0) options.pollInterval = n;\n }\n break;\n case '--mcp':\n options.mcp = true;\n break;\n case '--install-mcp':\n options.installMcp = true;\n break;\n case '--install-hooks':\n options.installHooks = true;\n break;\n case '--uninstall-hooks':\n options.uninstallHooks = true;\n break;\n case '--version':\n options.version = true;\n break;\n case '--help':\n options.help = true;\n break;\n }\n }\n\n return options;\n};\n\nconst main = () => {\n const options = parseArgs(process.argv);\n\n if (options.version) {\n write(`agenttop v${VERSION}`);\n process.exit(0);\n }\n if (options.help) {\n write(HELP);\n process.exit(0);\n }\n if (options.installHooks) {\n installHooks();\n process.exit(0);\n }\n if (options.uninstallHooks) {\n uninstallHooks();\n process.exit(0);\n }\n if (options.installMcp) {\n installMcpConfig();\n process.exit(0);\n }\n\n if (options.mcp) {\n startMcpServer(options.allUsers, options.noSecurity).catch((err) => {\n process.stderr.write(`mcp server error: ${err}\\n`);\n process.exit(1);\n });\n return;\n }\n\n if (options.json || options.plain) {\n runStreamMode(options, options.json);\n return;\n }\n\n const config = loadConfig();\n const firstRun = isFirstRun();\n\n if (options.noNotify) {\n config.notifications.bell = false;\n config.notifications.desktop = false;\n }\n if (options.noAlertLog) config.alerts.enabled = false;\n if (options.noUpdates) config.updates.checkOnLaunch = false;\n if (options.noSecurity) config.security.enabled = false;\n\n if (firstRun) saveConfig(config);\n\n render(React.createElement(App, { options, config, version: VERSION, firstRun }));\n};\n\nmain();\n","import React, { useState, useEffect, useCallback } from 'react';\nimport { Box, Text, useApp, useInput, useStdout } from 'ink';\n\nimport type { CLIOptions } from '../discovery/types.js';\nimport type { Config } from '../config/store.js';\nimport { setNickname, clearNickname, saveConfig } from '../config/store.js';\nimport { installHooks } from '../hooks/installer.js';\nimport { installMcpConfig } from '../install-mcp.js';\nimport { checkForUpdate, installUpdate } from '../updates.js';\nimport type { UpdateInfo } from '../updates.js';\nimport { StatusBar } from './components/StatusBar.js';\nimport { SessionList } from './components/SessionList.js';\nimport { ActivityFeed } from './components/ActivityFeed.js';\nimport { AlertBar } from './components/AlertBar.js';\nimport { SessionDetail } from './components/SessionDetail.js';\nimport { SetupModal } from './components/SetupModal.js';\nimport { FooterBar } from './components/FooterBar.js';\nimport { useSessions } from './hooks/useSessions.js';\nimport { useActivityStream } from './hooks/useActivityStream.js';\nimport { useAlerts } from './hooks/useAlerts.js';\nimport { useTextInput } from './hooks/useTextInput.js';\nimport { colors } from './theme.js';\n\ntype Panel = 'sessions' | 'activity';\ntype InputMode = 'normal' | 'nickname' | 'filter';\n\ninterface AppProps {\n options: CLIOptions;\n config: Config;\n version: string;\n firstRun: boolean;\n}\n\nconst matchKey = (binding: string, input: string, key: Record<string, unknown>): boolean => {\n if (binding === 'tab') return Boolean(key.tab);\n if (binding === 'shift+tab') return Boolean(key.shift && key.tab);\n if (binding === 'enter') return Boolean(key.return);\n return input === binding;\n};\n\nexport const App: React.FC<AppProps> = ({ options, config, version, firstRun }) => {\n const { exit } = useApp();\n const { stdout } = useStdout();\n const termHeight = stdout?.rows ?? 40;\n const kb = config.keybindings;\n\n const [activePanel, setActivePanel] = useState<Panel>('sessions');\n const [activityScroll, setActivityScroll] = useState(0);\n const [inputMode, setInputMode] = useState<InputMode>('normal');\n const [showSetup, setShowSetup] = useState(firstRun);\n const [filter, setFilter] = useState('');\n const [updateInfo, setUpdateInfo] = useState<UpdateInfo | null>(null);\n const [updateStatus, setUpdateStatus] = useState('');\n const [showDetail, setShowDetail] = useState(false);\n\n const { sessions, selectedSession, selectedIndex, selectNext, selectPrev } = useSessions(\n options.allUsers,\n filter || undefined,\n );\n const events = useActivityStream(selectedSession, options.allUsers);\n const { alerts } = useAlerts(!options.noSecurity, options.alertLevel, options.allUsers, config);\n\n const nicknameInput = useTextInput((value) => {\n if (selectedSession && value.trim()) setNickname(selectedSession.sessionId, value.trim());\n setInputMode('normal');\n });\n const filterInput = useTextInput((value) => {\n setFilter(value);\n setInputMode('normal');\n });\n\n useEffect(() => {\n if (options.noUpdates || !config.updates.checkOnLaunch) return;\n try {\n const i = checkForUpdate();\n if (i.available) setUpdateInfo(i);\n } catch {\n /* */\n }\n const iv = setInterval(() => {\n try {\n const i = checkForUpdate();\n if (i.available) setUpdateInfo(i);\n } catch {\n /* */\n }\n }, config.updates.checkInterval);\n return () => clearInterval(iv);\n }, []);\n\n const alertHeight = options.noSecurity ? 0 : 6;\n const mainHeight = termHeight - 3 - alertHeight - 1 - (inputMode !== 'normal' ? 1 : 0);\n const viewportRows = mainHeight - 2;\n const maxScroll = Math.max(0, events.length - viewportRows);\n\n useEffect(() => {\n setActivityScroll(0);\n }, [selectedSession?.sessionId]);\n\n const handleSetupComplete = useCallback(\n (results: Array<'yes' | 'not_now' | 'dismiss'>) => {\n const nc = { ...config };\n const [hc, mc] = results;\n if (hc === 'yes') {\n try {\n installHooks();\n } catch {\n /**/\n }\n nc.prompts.hook = 'installed';\n } else if (hc === 'dismiss') nc.prompts.hook = 'dismissed';\n if (mc === 'yes') {\n try {\n installMcpConfig();\n } catch {\n /**/\n }\n nc.prompts.mcp = 'installed';\n } else if (mc === 'dismiss') nc.prompts.mcp = 'dismissed';\n saveConfig(nc);\n setShowSetup(false);\n },\n [config],\n );\n\n const switchPanel = useCallback((_dir: 'next' | 'prev') => {\n setActivePanel((p) => (p === 'sessions' ? 'activity' : 'sessions'));\n }, []);\n\n useInput((input, key) => {\n if (showSetup) return;\n\n if (inputMode === 'nickname') {\n nicknameInput.handleInput(input, key);\n return;\n }\n if (inputMode === 'filter') {\n if (key.escape) {\n setFilter('');\n setInputMode('normal');\n filterInput.cancel();\n return;\n }\n filterInput.handleInput(input, key);\n return;\n }\n\n if (matchKey(kb.quit, input, key)) {\n exit();\n return;\n }\n\n if (showDetail) {\n if (key.escape || key.return || key.leftArrow) {\n setShowDetail(false);\n }\n return;\n }\n\n if (matchKey(kb.detail, input, key) && selectedSession && activePanel === 'sessions') {\n setShowDetail(true);\n return;\n }\n\n if (matchKey(kb.panelNext, input, key) || key.rightArrow) {\n switchPanel('next');\n return;\n }\n if (matchKey(kb.panelPrev, input, key) || key.leftArrow) {\n switchPanel('prev');\n return;\n }\n\n if (matchKey(kb.nickname, input, key) && selectedSession) {\n setInputMode('nickname');\n nicknameInput.start(selectedSession.nickname || '');\n return;\n }\n if (matchKey(kb.clearNickname, input, key) && selectedSession) {\n clearNickname(selectedSession.sessionId);\n return;\n }\n if (matchKey(kb.filter, input, key)) {\n setInputMode('filter');\n filterInput.start(filter);\n return;\n }\n if (key.escape && filter) {\n setFilter('');\n return;\n }\n if (matchKey(kb.update, input, key) && updateInfo?.available) {\n setUpdateStatus('updating...');\n installUpdate()\n .then(() => setUpdateStatus(`updated to v${updateInfo.latest} — restart to apply`))\n .catch(() => setUpdateStatus('update failed'));\n return;\n }\n\n if (activePanel === 'sessions') {\n if (matchKey(kb.navDown, input, key) || key.downArrow) selectNext();\n if (matchKey(kb.navUp, input, key) || key.upArrow) selectPrev();\n }\n if (activePanel === 'activity') {\n if (matchKey(kb.navUp, input, key) || key.upArrow) setActivityScroll((s) => Math.min(s + 1, maxScroll));\n if (matchKey(kb.navDown, input, key) || key.downArrow) setActivityScroll((s) => Math.max(s - 1, 0));\n if (matchKey(kb.scrollBottom, input, key) || key.end) setActivityScroll(0);\n if (matchKey(kb.scrollTop, input, key) || key.home) setActivityScroll(maxScroll);\n }\n });\n\n if (showSetup) {\n const steps = [];\n if (config.prompts.hook === 'pending')\n steps.push({\n title: 'Install Claude Code hook?',\n description: 'Adds a PostToolUse hook that blocks prompt injection attempts in real-time.',\n });\n if (config.prompts.mcp === 'pending')\n steps.push({\n title: 'Install MCP server?',\n description: 'Registers agenttop as an MCP server so Claude Code can query session status and alerts.',\n });\n if (steps.length === 0) {\n setShowSetup(false);\n return null;\n }\n return <SetupModal steps={steps} onComplete={handleSetupComplete} />;\n }\n\n const rightPanel =\n showDetail && selectedSession ? (\n <SessionDetail session={selectedSession} focused={activePanel === 'activity'} height={mainHeight} />\n ) : (\n <ActivityFeed\n events={events}\n sessionSlug={selectedSession?.slug ?? null}\n focused={activePanel === 'activity'}\n height={mainHeight}\n scrollOffset={activityScroll}\n />\n );\n\n return (\n <Box flexDirection=\"column\" height={termHeight}>\n <StatusBar sessionCount={sessions.length} alertCount={alerts.length} version={version} updateInfo={updateInfo} />\n <Box flexGrow={1} height={mainHeight}>\n <SessionList\n sessions={sessions}\n selectedIndex={selectedIndex}\n focused={activePanel === 'sessions'}\n filter={filter || undefined}\n />\n {rightPanel}\n </Box>\n {!options.noSecurity && <AlertBar alerts={alerts} />}\n {inputMode === 'nickname' && (\n <Box paddingX={1}>\n <Text color={colors.primary}>nickname: </Text>\n <Text color={colors.bright}>{nicknameInput.value}</Text>\n <Text color={colors.muted}>_</Text>\n </Box>\n )}\n {inputMode === 'filter' && (\n <Box paddingX={1}>\n <Text color={colors.primary}>/</Text>\n <Text color={colors.bright}>{filterInput.value}</Text>\n <Text color={colors.muted}>_</Text>\n </Box>\n )}\n {inputMode === 'normal' && <FooterBar keybindings={kb} updateStatus={updateStatus} />}\n </Box>\n );\n};\n","import { existsSync, readFileSync, writeFileSync, copyFileSync, mkdirSync, chmodSync } from 'node:fs';\nimport { join, dirname } from 'node:path';\nimport { homedir } from 'node:os';\nimport { fileURLToPath } from 'node:url';\n\nconst HOOK_FILENAME = 'agenttop-guard.py';\nconst SETTINGS_PATH = join(homedir(), '.claude', 'settings.json');\n\nconst getHookSource = (): string => {\n const thisFile = fileURLToPath(import.meta.url);\n const srcHooksDir = join(dirname(thisFile), '..', 'src', 'hooks');\n const distHooksDir = join(dirname(thisFile), 'hooks');\n\n for (const dir of [distHooksDir, srcHooksDir]) {\n const path = join(dir, HOOK_FILENAME);\n if (existsSync(path)) return path;\n }\n\n const npmGlobalPath = join(dirname(thisFile), '..', 'hooks', HOOK_FILENAME);\n if (existsSync(npmGlobalPath)) return npmGlobalPath;\n\n throw new Error(`cannot find ${HOOK_FILENAME} — is agenttop installed correctly?`);\n};\n\nconst getHookTarget = (): string => {\n const claudeHooksDir = join(homedir(), '.claude', 'hooks');\n mkdirSync(claudeHooksDir, { recursive: true });\n return join(claudeHooksDir, HOOK_FILENAME);\n};\n\ninterface HookEntry {\n type: string;\n command: string;\n}\n\ninterface MatcherEntry {\n matcher: string;\n hooks: HookEntry[];\n}\n\nconst readSettings = (): Record<string, unknown> => {\n if (!existsSync(SETTINGS_PATH)) {\n return {};\n }\n try {\n return JSON.parse(readFileSync(SETTINGS_PATH, 'utf-8'));\n } catch {\n return {};\n }\n};\n\nconst writeSettings = (settings: Record<string, unknown>): void => {\n mkdirSync(dirname(SETTINGS_PATH), { recursive: true });\n writeFileSync(SETTINGS_PATH, JSON.stringify(settings, null, 2) + '\\n');\n};\n\nexport const installHooks = (): void => {\n const source = getHookSource();\n const target = getHookTarget();\n\n copyFileSync(source, target);\n chmodSync(target, 0o755);\n\n const settings = readSettings();\n const hooks = (settings.hooks ?? {}) as Record<string, MatcherEntry[]>;\n\n const postToolUse = hooks.PostToolUse ?? [];\n const hookCommand = target;\n\n const allToolsMatcher = postToolUse.find(\n (entry: MatcherEntry) => entry.matcher === 'Bash|Read|Grep|Glob|WebFetch|WebSearch',\n );\n\n if (allToolsMatcher) {\n const alreadyInstalled = allToolsMatcher.hooks.some((h: HookEntry) => h.command.includes('agenttop-guard'));\n if (alreadyInstalled) {\n process.stdout.write('agenttop hooks already installed\\n');\n return;\n }\n allToolsMatcher.hooks.push({ type: 'command', command: hookCommand });\n } else {\n postToolUse.push({\n matcher: 'Bash|Read|Grep|Glob|WebFetch|WebSearch',\n hooks: [{ type: 'command', command: hookCommand }],\n });\n }\n\n hooks.PostToolUse = postToolUse;\n settings.hooks = hooks;\n writeSettings(settings);\n\n process.stdout.write(`agenttop hooks installed:\\n`);\n process.stdout.write(` hook: ${target}\\n`);\n process.stdout.write(` settings: ${SETTINGS_PATH}\\n`);\n process.stdout.write(` matcher: PostToolUse (Bash|Read|Grep|Glob|WebFetch|WebSearch)\\n`);\n};\n\nexport const uninstallHooks = (): void => {\n const settings = readSettings();\n const hooks = (settings.hooks ?? {}) as Record<string, MatcherEntry[]>;\n const postToolUse = hooks.PostToolUse ?? [];\n\n let removed = false;\n for (const entry of postToolUse) {\n const before = entry.hooks.length;\n entry.hooks = entry.hooks.filter((h: HookEntry) => !h.command.includes('agenttop-guard'));\n if (entry.hooks.length < before) removed = true;\n }\n\n hooks.PostToolUse = postToolUse.filter((e: MatcherEntry) => e.hooks.length > 0);\n settings.hooks = hooks;\n writeSettings(settings);\n\n if (removed) {\n process.stdout.write('agenttop hooks removed from Claude Code settings\\n');\n } else {\n process.stdout.write('agenttop hooks were not installed\\n');\n }\n};\n","import { readFileSync, writeFileSync, mkdirSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\n\nexport const installMcpConfig = (): void => {\n const settingsPath = join(homedir(), '.claude', 'settings.json');\n let settings: Record<string, unknown> = {};\n try {\n settings = JSON.parse(readFileSync(settingsPath, 'utf-8'));\n } catch {\n /* empty */\n }\n const mcpServers = (settings.mcpServers ?? {}) as Record<string, unknown>;\n mcpServers.agenttop = { command: 'agenttop', args: ['--mcp'] };\n settings.mcpServers = mcpServers;\n mkdirSync(join(homedir(), '.claude'), { recursive: true });\n writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\\n');\n process.stdout.write('agenttop MCP server registered in Claude Code settings\\n');\n process.stdout.write(` settings: ${settingsPath}\\n`);\n};\n","import { execSync, exec } from 'node:child_process';\nimport { readFileSync } from 'node:fs';\nimport { join, dirname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nconst getPackageVersion = (): string => {\n try {\n const thisFile = fileURLToPath(import.meta.url);\n const pkgPath = join(dirname(thisFile), '..', 'package.json');\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));\n return pkg.version || '0.0.0';\n } catch {\n return '0.0.0';\n }\n};\n\nexport interface UpdateInfo {\n current: string;\n latest: string;\n available: boolean;\n}\n\nexport const checkForUpdate = (): UpdateInfo => {\n const current = getPackageVersion();\n try {\n const latest = execSync('npm view agenttop version', { encoding: 'utf-8', timeout: 5000 }).trim();\n return {\n current,\n latest,\n available: latest !== current && compareVersions(latest, current) > 0,\n };\n } catch {\n return { current, latest: current, available: false };\n }\n};\n\nexport const installUpdate = (): Promise<string> => {\n return new Promise((resolve, reject) => {\n exec('npm install -g agenttop@latest', { timeout: 60000 }, (err, stdout) => {\n if (err) {\n reject(err);\n } else {\n resolve(stdout.trim());\n }\n });\n });\n};\n\nconst compareVersions = (a: string, b: string): number => {\n const pa = a.split('.').map(Number);\n const pb = b.split('.').map(Number);\n for (let i = 0; i < 3; i++) {\n const da = pa[i] ?? 0;\n const db = pb[i] ?? 0;\n if (da > db) return 1;\n if (da < db) return -1;\n }\n return 0;\n};\n","import React, { useState, useEffect } from 'react';\nimport { Box, Text } from 'ink';\n\nimport { colors } from '../theme.js';\nimport type { UpdateInfo } from '../../updates.js';\n\ninterface StatusBarProps {\n sessionCount: number;\n alertCount: number;\n version: string;\n updateInfo?: UpdateInfo | null;\n}\n\nexport const StatusBar: React.FC<StatusBarProps> = React.memo(({ sessionCount, alertCount, version, updateInfo }) => {\n const [time, setTime] = useState(new Date());\n\n useEffect(() => {\n const interval = setInterval(() => setTime(new Date()), 1000);\n return () => clearInterval(interval);\n }, []);\n\n const timeStr = time.toLocaleTimeString('en-GB', { hour12: false });\n\n return (\n <Box borderStyle=\"single\" borderColor={colors.border} paddingX={1} justifyContent=\"space-between\">\n <Text color={colors.header} bold>\n agenttop v{version}\n </Text>\n <Text color={colors.text}>\n {sessionCount} session{sessionCount !== 1 ? 's' : ''}\n </Text>\n {alertCount > 0 && (\n <Text color={colors.error} bold>\n {alertCount} alert{alertCount !== 1 ? 's' : ''}\n </Text>\n )}\n {updateInfo?.available && <Text color={colors.secondary}>v{updateInfo.latest} available (u)</Text>}\n <Text color={colors.muted}>{timeStr}</Text>\n </Box>\n );\n});\n","export const colors = {\n primary: '#61AFEF',\n secondary: '#98C379',\n accent: '#C678DD',\n warning: '#E5C07B',\n error: '#E06C75',\n critical: '#FF0000',\n muted: '#5C6370',\n text: '#ABB2BF',\n bright: '#FFFFFF',\n border: '#3E4451',\n selected: '#2C313A',\n header: '#61AFEF',\n};\n\nexport const severityColors: Record<string, string> = {\n info: colors.muted,\n warn: colors.warning,\n high: colors.error,\n critical: colors.critical,\n};\n\nexport const toolColors: Record<string, string> = {\n Bash: colors.error,\n Read: colors.secondary,\n Write: colors.accent,\n Edit: colors.accent,\n Grep: colors.primary,\n Glob: colors.primary,\n Task: colors.warning,\n WebFetch: colors.warning,\n WebSearch: colors.warning,\n};\n\nexport const getToolColor = (toolName: string): string => toolColors[toolName] || colors.text;\n","import React from 'react';\nimport { Box, Text } from 'ink';\n\nimport type { Session } from '../../discovery/types.js';\nimport { colors } from '../theme.js';\n\ninterface SessionListProps {\n sessions: Session[];\n selectedIndex: number;\n focused: boolean;\n filter?: string;\n}\n\nconst formatModel = (model: string): string => {\n if (model.includes('opus')) return 'opus';\n if (model.includes('sonnet')) return 'sonnet';\n if (model.includes('haiku')) return 'haiku';\n return model.slice(0, 8);\n};\n\nconst formatProject = (project: string): string => {\n const parts = project.split('/');\n const last = parts[parts.length - 1] || project;\n return last.length > 18 ? last.slice(0, 17) + '\\u2026' : last;\n};\n\nconst formatTokens = (n: number): string => {\n if (n >= 1_000_000) return (n / 1_000_000).toFixed(1) + 'M';\n if (n >= 1_000) return (n / 1_000).toFixed(1) + 'k';\n return String(n);\n};\n\nexport const SessionList: React.FC<SessionListProps> = React.memo(({ sessions, selectedIndex, focused, filter }) => {\n return (\n <Box flexDirection=\"column\" width={28} borderStyle=\"single\" borderColor={focused ? colors.primary : colors.border}>\n <Box paddingX={1}>\n <Text color={colors.header} bold>\n SESSIONS\n </Text>\n {filter && <Text color={colors.muted}> [{filter}]</Text>}\n </Box>\n\n {sessions.length === 0 && (\n <Box paddingX={1} paddingY={1}>\n <Text color={colors.muted} italic>\n {filter ? 'No matching sessions' : 'No active sessions'}\n </Text>\n </Box>\n )}\n\n {sessions.map((session, i) => {\n const isSelected = i === selectedIndex;\n const indicator = isSelected ? '>' : ' ';\n const displayName = session.nickname || session.slug;\n const totalIn = session.usage.inputTokens + session.usage.cacheReadTokens;\n\n return (\n <Box key={session.sessionId} flexDirection=\"column\" paddingX={1} paddingY={0}>\n <Text\n color={isSelected ? colors.bright : colors.text}\n bold={isSelected}\n backgroundColor={isSelected ? colors.selected : undefined}\n >\n {indicator} {displayName}\n </Text>\n {session.nickname && (\n <Text color={colors.muted}>\n {' '}\n {session.slug}\n </Text>\n )}\n <Text color={colors.muted}>\n {' '}\n {formatProject(session.project)} | {formatModel(session.model)}\n </Text>\n <Text color={colors.muted}>\n {' '}CPU {session.cpu}% | {session.memMB}MB | {session.agentCount} ag\n </Text>\n <Text color={colors.muted}>\n {' '}\n {formatTokens(totalIn)} in | {formatTokens(session.usage.outputTokens)} out\n </Text>\n </Box>\n );\n })}\n </Box>\n );\n});\n","import React from 'react';\nimport { Box, Text } from 'ink';\n\nimport type { ToolCall } from '../../discovery/types.js';\nimport { colors, getToolColor } from '../theme.js';\n\ninterface ActivityFeedProps {\n events: ToolCall[];\n sessionSlug: string | null;\n focused: boolean;\n height: number;\n scrollOffset: number;\n}\n\nconst formatTime = (ts: number): string => {\n const d = new Date(ts);\n return d.toLocaleTimeString('en-GB', { hour12: false });\n};\n\nconst summarizeInput = (call: ToolCall): string => {\n const input = call.toolInput;\n\n switch (call.toolName) {\n case 'Bash':\n return String(input.command || '').slice(0, 50);\n case 'Read':\n case 'Write':\n case 'Edit':\n return String(input.file_path || '')\n .split('/')\n .slice(-2)\n .join('/');\n case 'Grep':\n return `pattern=\"${String(input.pattern || '').slice(0, 30)}\"`;\n case 'Glob':\n return String(input.pattern || '').slice(0, 40);\n case 'Task':\n return String(input.description || '').slice(0, 40);\n case 'WebFetch':\n case 'WebSearch':\n return String(input.url || input.query || '').slice(0, 40);\n default:\n return JSON.stringify(input).slice(0, 40);\n }\n};\n\nexport const ActivityFeed: React.FC<ActivityFeedProps> = React.memo(\n ({ events, sessionSlug, focused, height, scrollOffset }) => {\n const viewportRows = height - 2;\n const totalEvents = events.length;\n const start = Math.max(0, totalEvents - viewportRows - scrollOffset);\n const end = start + viewportRows;\n const visible = events.slice(start, end);\n\n const isAtBottom = scrollOffset === 0;\n const isAtTop = start === 0;\n const canScroll = totalEvents > viewportRows;\n\n return (\n <Box\n flexDirection=\"column\"\n flexGrow={1}\n borderStyle=\"single\"\n borderColor={focused ? colors.primary : colors.border}\n >\n <Box paddingX={1} justifyContent=\"space-between\">\n <Box>\n <Text color={colors.header} bold>\n ACTIVITY\n </Text>\n {sessionSlug && <Text color={colors.muted}> ({sessionSlug})</Text>}\n </Box>\n {focused && canScroll && !isAtBottom && (\n <Text color={colors.muted}>\n [{totalEvents - end + viewportRows}/{totalEvents}]\n </Text>\n )}\n </Box>\n\n {visible.length === 0 && (\n <Box paddingX={1} paddingY={1}>\n <Text color={colors.muted} italic>\n {sessionSlug ? 'Waiting for activity...' : 'Select a session'}\n </Text>\n </Box>\n )}\n\n {visible.map((event, i) => (\n <Box key={`${event.timestamp}-${i}`} paddingX={1}>\n <Text color={colors.muted}>{formatTime(event.timestamp)} </Text>\n <Text color={getToolColor(event.toolName)} bold>\n {event.toolName.padEnd(8)}\n </Text>\n <Text color={colors.text}> {summarizeInput(event)}</Text>\n </Box>\n ))}\n\n {focused && canScroll && !isAtTop && visible.length > 0 && (\n <Box paddingX={1} justifyContent=\"flex-end\">\n <Text color={colors.muted}>{isAtBottom ? '' : 'G:bottom '}</Text>\n </Box>\n )}\n </Box>\n );\n },\n);\n","import React from 'react';\nimport { Box, Text } from 'ink';\n\nimport type { Alert } from '../../discovery/types.js';\nimport { colors, severityColors } from '../theme.js';\n\ninterface AlertBarProps {\n alerts: Alert[];\n maxVisible?: number;\n}\n\nconst formatTime = (ts: number): string => {\n const d = new Date(ts);\n return d.toLocaleTimeString('en-GB', { hour12: false });\n};\n\nconst severityIcon: Record<string, string> = {\n info: 'i',\n warn: '!',\n high: '!!',\n critical: '!!!',\n};\n\nexport const AlertBar: React.FC<AlertBarProps> = React.memo(({ alerts, maxVisible = 4 }) => {\n const visible = alerts.slice(-maxVisible);\n\n return (\n <Box flexDirection=\"column\" borderStyle=\"single\" borderColor={alerts.length > 0 ? colors.error : colors.border}>\n <Box paddingX={1}>\n <Text color={colors.error} bold>\n ALERTS\n </Text>\n {alerts.length === 0 && <Text color={colors.muted}> (none)</Text>}\n </Box>\n\n {visible.map((alert, i) => (\n <Box key={alert.id || i} paddingX={1}>\n <Text color={severityColors[alert.severity] || colors.text}>[{severityIcon[alert.severity] || '?'}]</Text>\n <Text color={colors.muted}> {formatTime(alert.timestamp)} </Text>\n <Text color={colors.warning}>{alert.sessionSlug}: </Text>\n <Text color={colors.text}>{alert.message.slice(0, 60)}</Text>\n </Box>\n ))}\n </Box>\n );\n});\n","import React from 'react';\nimport { Box, Text } from 'ink';\n\nimport type { Session } from '../../discovery/types.js';\nimport { colors } from '../theme.js';\n\ninterface SessionDetailProps {\n session: Session;\n focused: boolean;\n height: number;\n}\n\nconst formatTokens = (n: number): string => {\n if (n >= 1_000_000) return (n / 1_000_000).toFixed(1) + 'M';\n if (n >= 1_000) return (n / 1_000).toFixed(1) + 'k';\n return String(n);\n};\n\nconst formatUptime = (startTime: number): string => {\n const ms = Date.now() - startTime;\n const secs = Math.floor(ms / 1000);\n const mins = Math.floor(secs / 60);\n const hours = Math.floor(mins / 60);\n if (hours > 0) return `${hours}h ${mins % 60}m`;\n if (mins > 0) return `${mins}m ${secs % 60}s`;\n return `${secs}s`;\n};\n\nconst formatModel = (model: string): string => {\n if (model.includes('opus')) return 'opus';\n if (model.includes('sonnet')) return 'sonnet';\n if (model.includes('haiku')) return 'haiku';\n return model.slice(0, 20);\n};\n\nexport const SessionDetail: React.FC<SessionDetailProps> = React.memo(({ session, focused }) => {\n const totalInput = session.usage.inputTokens + session.usage.cacheCreationTokens + session.usage.cacheReadTokens;\n const totalTokens = totalInput + session.usage.outputTokens;\n const cacheHitRate = totalInput > 0 ? ((session.usage.cacheReadTokens / totalInput) * 100).toFixed(0) : '0';\n\n return (\n <Box\n flexDirection=\"column\"\n flexGrow={1}\n borderStyle=\"single\"\n borderColor={focused ? colors.primary : colors.border}\n >\n <Box paddingX={1}>\n <Text color={colors.header} bold>\n SESSION DETAIL\n </Text>\n <Text color={colors.muted}> (Esc to return)</Text>\n </Box>\n\n <Box flexDirection=\"column\" paddingX={2} paddingY={1}>\n <Box>\n <Text color={colors.muted}>{'slug: '}</Text>\n <Text color={colors.bright} bold>\n {session.slug}\n </Text>\n </Box>\n {session.nickname && (\n <Box>\n <Text color={colors.muted}>{'nickname: '}</Text>\n <Text color={colors.secondary}>{session.nickname}</Text>\n </Box>\n )}\n <Box>\n <Text color={colors.muted}>{'model: '}</Text>\n <Text color={colors.text}>{formatModel(session.model)}</Text>\n </Box>\n <Box>\n <Text color={colors.muted}>{'cwd: '}</Text>\n <Text color={colors.text}>{session.cwd}</Text>\n </Box>\n {session.gitBranch && (\n <Box>\n <Text color={colors.muted}>{'branch: '}</Text>\n <Text color={colors.secondary}>{session.gitBranch}</Text>\n </Box>\n )}\n <Box>\n <Text color={colors.muted}>{'version: '}</Text>\n <Text color={colors.text}>{session.version || 'unknown'}</Text>\n </Box>\n <Box>\n <Text color={colors.muted}>{'pid: '}</Text>\n <Text color={colors.text}>{session.pid ?? 'not running'}</Text>\n </Box>\n <Box>\n <Text color={colors.muted}>{'cpu: '}</Text>\n <Text color={colors.text}>{session.cpu}%</Text>\n </Box>\n <Box>\n <Text color={colors.muted}>{'memory: '}</Text>\n <Text color={colors.text}>{session.memMB}MB</Text>\n </Box>\n <Box>\n <Text color={colors.muted}>{'uptime: '}</Text>\n <Text color={colors.text}>{formatUptime(session.startTime)}</Text>\n </Box>\n <Box>\n <Text color={colors.muted}>{'agents: '}</Text>\n <Text color={colors.text}>{session.agentCount}</Text>\n </Box>\n\n <Box marginTop={1}>\n <Text color={colors.header} bold>\n Token usage\n </Text>\n </Box>\n <Box>\n <Text color={colors.muted}>{' input: '}</Text>\n <Text color={colors.text}>{formatTokens(session.usage.inputTokens)}</Text>\n </Box>\n <Box>\n <Text color={colors.muted}>{' output: '}</Text>\n <Text color={colors.text}>{formatTokens(session.usage.outputTokens)}</Text>\n </Box>\n <Box>\n <Text color={colors.muted}>{' cache write: '}</Text>\n <Text color={colors.text}>{formatTokens(session.usage.cacheCreationTokens)}</Text>\n </Box>\n <Box>\n <Text color={colors.muted}>{' cache read: '}</Text>\n <Text color={colors.text}>{formatTokens(session.usage.cacheReadTokens)}</Text>\n </Box>\n <Box>\n <Text color={colors.muted}>{' cache hit: '}</Text>\n <Text color={session.usage.cacheReadTokens > 0 ? colors.secondary : colors.text}>{cacheHitRate}%</Text>\n </Box>\n <Box>\n <Text color={colors.muted}>{' total: '}</Text>\n <Text color={colors.bright} bold>\n {formatTokens(totalTokens)}\n </Text>\n </Box>\n </Box>\n </Box>\n );\n});\n","import React, { useState } from 'react';\nimport { Box, Text, useInput } from 'ink';\n\nimport { colors } from '../theme.js';\n\ntype PromptChoice = 'yes' | 'not_now' | 'dismiss';\n\ninterface SetupStep {\n title: string;\n description: string;\n}\n\ninterface SetupModalProps {\n steps: SetupStep[];\n onComplete: (results: PromptChoice[]) => void;\n}\n\nconst OPTIONS: Array<{ label: string; value: PromptChoice }> = [\n { label: 'Yes', value: 'yes' },\n { label: 'Not now', value: 'not_now' },\n { label: \"Don't ask again\", value: 'dismiss' },\n];\n\nexport const SetupModal: React.FC<SetupModalProps> = React.memo(({ steps, onComplete }) => {\n const [stepIndex, setStepIndex] = useState(0);\n const [selectedOption, setSelectedOption] = useState(0);\n const [results, setResults] = useState<PromptChoice[]>([]);\n\n const step = steps[stepIndex];\n\n useInput((_input, key) => {\n if (key.upArrow) {\n setSelectedOption((i) => Math.max(0, i - 1));\n }\n if (key.downArrow) {\n setSelectedOption((i) => Math.min(OPTIONS.length - 1, i + 1));\n }\n if (key.return) {\n const choice = OPTIONS[selectedOption].value;\n const newResults = [...results, choice];\n if (stepIndex + 1 >= steps.length) {\n onComplete(newResults);\n } else {\n setResults(newResults);\n setStepIndex(stepIndex + 1);\n setSelectedOption(0);\n }\n }\n });\n\n if (!step) return null;\n\n return (\n <Box flexDirection=\"column\" paddingX={4} paddingY={2}>\n <Box borderStyle=\"round\" borderColor={colors.primary} flexDirection=\"column\" paddingX={3} paddingY={1}>\n <Box marginBottom={1}>\n <Text color={colors.header} bold>\n agenttop setup ({stepIndex + 1}/{steps.length})\n </Text>\n </Box>\n\n <Box marginBottom={1}>\n <Text color={colors.bright} bold>\n {step.title}\n </Text>\n </Box>\n <Box marginBottom={1}>\n <Text color={colors.text}>{step.description}</Text>\n </Box>\n\n {OPTIONS.map((opt, i) => (\n <Box key={opt.value}>\n <Text color={i === selectedOption ? colors.primary : colors.muted}>\n {i === selectedOption ? '> ' : ' '}\n {opt.label}\n </Text>\n </Box>\n ))}\n\n <Box marginTop={1}>\n <Text color={colors.muted}>Use arrow keys + Enter to select</Text>\n </Box>\n </Box>\n </Box>\n );\n});\n","import React from 'react';\nimport { Box, Text } from 'ink';\n\nimport type { KeybindingsConfig } from '../../config/store.js';\nimport { colors } from '../theme.js';\n\ninterface FooterBarProps {\n keybindings: KeybindingsConfig;\n updateStatus?: string;\n}\n\nconst label = (key: string): string => {\n if (key === 'tab') return 'tab';\n if (key === 'shift+tab') return 'S-tab';\n if (key === 'enter') return 'enter';\n return key;\n};\n\nexport const FooterBar: React.FC<FooterBarProps> = React.memo(({ keybindings, updateStatus }) => (\n <Box paddingX={1}>\n <Box marginRight={2}>\n <Text color=\"#5C6370\">{label(keybindings.quit)}:quit</Text>\n </Box>\n <Box marginRight={2}>\n <Text color=\"#5C6370\">\n {label(keybindings.navDown)}/{label(keybindings.navUp)}:nav\n </Text>\n </Box>\n <Box marginRight={2}>\n <Text color=\"#5C6370\">{label(keybindings.panelNext)}:panel</Text>\n </Box>\n <Box marginRight={2}>\n <Text color=\"#5C6370\">{label(keybindings.filter)}:filter</Text>\n </Box>\n <Box marginRight={2}>\n <Text color=\"#5C6370\">{label(keybindings.nickname)}:name</Text>\n </Box>\n <Box marginRight={2}>\n <Text color=\"#5C6370\">{label(keybindings.detail)}:detail</Text>\n </Box>\n {updateStatus && (\n <Box marginRight={2}>\n <Text color={colors.secondary}>{updateStatus}</Text>\n </Box>\n )}\n </Box>\n));\n","import { useState, useEffect, useCallback, useRef } from 'react';\n\nimport { discoverSessions } from '../../discovery/sessions.js';\nimport type { Session, TokenUsage } from '../../discovery/types.js';\nimport { getNicknames } from '../../config/store.js';\n\nconst ACTIVE_POLL_MS = 10_000;\nconst IDLE_POLL_MS = 30_000;\n\nexport const useSessions = (allUsers: boolean, filter?: string) => {\n const [sessions, setSessions] = useState<Session[]>([]);\n const [selectedIndex, setSelectedIndex] = useState(0);\n const usageOverrides = useRef(new Map<string, TokenUsage>());\n\n const refresh = useCallback(() => {\n const found = discoverSessions(allUsers);\n const nicknames = getNicknames();\n\n const enriched = found.map((s) => {\n const override = usageOverrides.current.get(s.sessionId);\n return {\n ...s,\n nickname: nicknames[s.sessionId],\n usage: override\n ? {\n inputTokens: s.usage.inputTokens + override.inputTokens,\n cacheCreationTokens: s.usage.cacheCreationTokens + override.cacheCreationTokens,\n cacheReadTokens: s.usage.cacheReadTokens + override.cacheReadTokens,\n outputTokens: s.usage.outputTokens + override.outputTokens,\n }\n : s.usage,\n };\n });\n\n let filtered = enriched;\n if (filter) {\n const lower = filter.toLowerCase();\n filtered = enriched.filter(\n (s) =>\n s.slug.toLowerCase().includes(lower) ||\n s.nickname?.toLowerCase().includes(lower) ||\n s.project.toLowerCase().includes(lower) ||\n s.model.toLowerCase().includes(lower),\n );\n }\n\n setSessions(filtered);\n }, [allUsers, filter]);\n\n useEffect(() => {\n refresh();\n const pollMs = sessions.length > 0 ? ACTIVE_POLL_MS : IDLE_POLL_MS;\n const interval = setInterval(refresh, pollMs);\n return () => clearInterval(interval);\n }, [refresh, sessions.length > 0]);\n\n const selectedSession = sessions[selectedIndex] ?? null;\n\n const selectNext = useCallback(() => {\n setSelectedIndex((i) => Math.min(i + 1, Math.max(0, sessions.length - 1)));\n }, [sessions.length]);\n\n const selectPrev = useCallback(() => {\n setSelectedIndex((i) => Math.max(i - 1, 0));\n }, []);\n\n const selectIndex = useCallback((i: number) => {\n setSelectedIndex(i);\n }, []);\n\n const addUsage = useCallback((sessionId: string, usage: TokenUsage) => {\n const existing = usageOverrides.current.get(sessionId);\n if (existing) {\n usageOverrides.current.set(sessionId, {\n inputTokens: existing.inputTokens + usage.inputTokens,\n cacheCreationTokens: existing.cacheCreationTokens + usage.cacheCreationTokens,\n cacheReadTokens: existing.cacheReadTokens + usage.cacheReadTokens,\n outputTokens: existing.outputTokens + usage.outputTokens,\n });\n } else {\n usageOverrides.current.set(sessionId, usage);\n }\n }, []);\n\n return { sessions, selectedSession, selectedIndex, selectNext, selectPrev, selectIndex, refresh, addUsage };\n};\n","import { useState, useEffect, useRef } from 'react';\n\nimport type { Session, ToolCall } from '../../discovery/types.js';\nimport { Watcher } from '../../ingestion/watcher.js';\n\nconst MAX_EVENTS = 200;\n\nexport const useActivityStream = (session: Session | null, allUsers: boolean) => {\n const [events, setEvents] = useState<ToolCall[]>([]);\n const watcherRef = useRef<Watcher | null>(null);\n\n useEffect(() => {\n setEvents([]);\n\n if (!session) return;\n\n const existingCalls: ToolCall[] = [];\n const tempWatcher = new Watcher(() => {}, allUsers);\n for (const file of session.outputFiles) {\n existingCalls.push(...tempWatcher.readExisting(file));\n }\n setEvents(existingCalls.slice(-MAX_EVENTS));\n\n const handler = (calls: ToolCall[]) => {\n const sessionCalls = calls.filter((c) => c.sessionId === session.sessionId);\n if (sessionCalls.length === 0) return;\n setEvents((prev) => [...prev, ...sessionCalls].slice(-MAX_EVENTS));\n };\n\n const watcher = new Watcher(handler, allUsers);\n watcherRef.current = watcher;\n watcher.start();\n\n return () => {\n watcher.stop();\n watcherRef.current = null;\n };\n }, [session?.sessionId, allUsers]);\n\n return events;\n};\n","import { useState, useEffect, useRef } from 'react';\n\nimport type { Alert, AlertSeverity, SecurityEvent } from '../../discovery/types.js';\nimport { SecurityEngine } from '../../analysis/security.js';\nimport { Watcher } from '../../ingestion/watcher.js';\nimport { notify } from '../../notifications.js';\nimport { AlertLogger } from '../../alerts/logger.js';\nimport type { Config } from '../../config/store.js';\n\nconst MAX_ALERTS = 100;\n\nexport const useAlerts = (enabled: boolean, alertLevel: AlertSeverity, allUsers: boolean, config?: Config) => {\n const [alerts, setAlerts] = useState<Alert[]>([]);\n const engineRef = useRef(new SecurityEngine(alertLevel));\n const watcherRef = useRef<Watcher | null>(null);\n const loggerRef = useRef<AlertLogger | null>(null);\n\n useEffect(() => {\n if (!enabled) return;\n\n engineRef.current = new SecurityEngine(alertLevel);\n\n if (config?.alerts.enabled) {\n loggerRef.current = new AlertLogger(config);\n }\n\n const securityHandler = (events: SecurityEvent[]) => {\n const newAlerts: Alert[] = [];\n for (const event of events) {\n newAlerts.push(...engineRef.current.analyzeEvent(event));\n }\n if (newAlerts.length > 0) {\n for (const alert of newAlerts) {\n if (config) {\n notify(alert, config.notifications);\n }\n loggerRef.current?.log(alert);\n }\n setAlerts((prev) => [...prev, ...newAlerts].slice(-MAX_ALERTS));\n }\n };\n\n const watcher = new Watcher(() => {}, allUsers, securityHandler);\n watcherRef.current = watcher;\n watcher.start();\n\n return () => {\n watcher.stop();\n watcherRef.current = null;\n loggerRef.current = null;\n };\n }, [enabled, alertLevel, allUsers]);\n\n const clearAlerts = () => setAlerts([]);\n\n return { alerts, clearAlerts };\n};\n","import { exec } from 'node:child_process';\nimport { platform } from 'node:os';\n\nimport type { Alert, AlertSeverity } from './discovery/types.js';\nimport type { NotificationsConfig } from './config/store.js';\n\nconst SEVERITY_ORDER: Record<AlertSeverity, number> = {\n info: 0,\n warn: 1,\n high: 2,\n critical: 3,\n};\n\nconst RATE_LIMIT_MS = 30_000;\nlet lastDesktopNotification = 0;\n\nexport const notify = (alert: Alert, config: NotificationsConfig): void => {\n if (SEVERITY_ORDER[alert.severity] < SEVERITY_ORDER[config.minSeverity]) return;\n\n if (config.bell) {\n process.stdout.write('\\x07');\n }\n\n if (config.desktop) {\n const now = Date.now();\n if (now - lastDesktopNotification < RATE_LIMIT_MS) return;\n lastDesktopNotification = now;\n\n const title = `agenttop: ${alert.severity} alert`;\n const body = `${alert.sessionSlug}: ${alert.message.slice(0, 100)}`;\n\n const os = platform();\n if (os === 'linux') {\n exec(`notify-send ${JSON.stringify(title)} ${JSON.stringify(body)}`, { timeout: 3000 });\n } else if (os === 'darwin') {\n exec(`osascript -e 'display notification ${JSON.stringify(body)} with title ${JSON.stringify(title)}'`, {\n timeout: 3000,\n });\n }\n }\n};\n","import { appendFileSync, mkdirSync } from 'node:fs';\nimport { dirname } from 'node:path';\n\nimport type { Alert } from '../discovery/types.js';\nimport { resolveAlertLogPath, rotateLogFile } from '../config/store.js';\nimport type { Config } from '../config/store.js';\n\nexport class AlertLogger {\n private logPath: string;\n private writeCount = 0;\n\n constructor(config: Config) {\n this.logPath = resolveAlertLogPath(config);\n mkdirSync(dirname(this.logPath), { recursive: true });\n }\n\n log(alert: Alert): void {\n const entry = {\n timestamp: new Date(alert.timestamp).toISOString(),\n severity: alert.severity,\n rule: alert.rule,\n message: alert.message,\n sessionSlug: alert.sessionSlug,\n sessionId: alert.sessionId,\n };\n\n try {\n appendFileSync(this.logPath, JSON.stringify(entry) + '\\n');\n this.writeCount++;\n if (this.writeCount % 100 === 0) {\n rotateLogFile(this.logPath);\n }\n } catch {\n // silently ignore write errors\n }\n }\n}\n","import { useState, useCallback } from 'react';\n\nexport interface TextInputState {\n value: string;\n isActive: boolean;\n start: (initial?: string) => void;\n cancel: () => void;\n confirm: () => string;\n handleInput: (\n input: string,\n key: { return?: boolean; escape?: boolean; backspace?: boolean; delete?: boolean },\n ) => boolean;\n}\n\nexport const useTextInput = (onConfirm?: (value: string) => void): TextInputState => {\n const [value, setValue] = useState('');\n const [isActive, setIsActive] = useState(false);\n\n const start = useCallback((initial = '') => {\n setValue(initial);\n setIsActive(true);\n }, []);\n\n const cancel = useCallback(() => {\n setValue('');\n setIsActive(false);\n }, []);\n\n const confirm = useCallback(() => {\n const result = value;\n setIsActive(false);\n setValue('');\n onConfirm?.(result);\n return result;\n }, [value, onConfirm]);\n\n const handleInput = useCallback(\n (input: string, key: { return?: boolean; escape?: boolean; backspace?: boolean; delete?: boolean }): boolean => {\n if (!isActive) return false;\n\n if (key.escape) {\n cancel();\n return true;\n }\n\n if (key.return) {\n confirm();\n return true;\n }\n\n if (key.backspace || key.delete) {\n setValue((v) => v.slice(0, -1));\n return true;\n }\n\n if (input && input.length === 1 && input >= ' ') {\n setValue((v) => v + input);\n return true;\n }\n\n return true;\n },\n [isActive, cancel, confirm],\n );\n\n return { value, isActive, start, cancel, confirm, handleInput };\n};\n","import type { CLIOptions, ToolCall, SecurityEvent, TokenUsage } from './discovery/types.js';\nimport { discoverSessions } from './discovery/sessions.js';\nimport { Watcher } from './ingestion/watcher.js';\nimport { SecurityEngine } from './analysis/security.js';\n\nconst write = (msg: string): void => {\n process.stdout.write(msg + '\\n');\n};\n\nconst formatTokens = (n: number): string => {\n if (n >= 1_000_000) return (n / 1_000_000).toFixed(1) + 'M';\n if (n >= 1_000) return (n / 1_000).toFixed(1) + 'k';\n return String(n);\n};\n\nexport const runStreamMode = (options: CLIOptions, isJson: boolean): void => {\n const engine = options.noSecurity ? null : new SecurityEngine(options.alertLevel);\n\n const sessions = discoverSessions(options.allUsers);\n if (isJson) {\n write(JSON.stringify({ type: 'sessions', data: sessions }));\n } else {\n for (const s of sessions) {\n write(\n `SESSION ${s.slug} | ${s.model} | ${s.cwd} | CPU ${s.cpu}% | ${s.memMB}MB | ${formatTokens(s.usage.inputTokens)} in / ${formatTokens(s.usage.outputTokens)} out`,\n );\n }\n }\n\n const handler = (calls: ToolCall[]) => {\n for (const call of calls) {\n if (isJson) {\n write(JSON.stringify({ type: 'tool_call', data: call }));\n } else {\n const ts = new Date(call.timestamp).toLocaleTimeString('en-GB', { hour12: false });\n const input =\n call.toolName === 'Bash'\n ? String(call.toolInput.command || '').slice(0, 80)\n : JSON.stringify(call.toolInput).slice(0, 80);\n write(`${ts} ${call.slug} ${call.toolName.padEnd(8)} ${input}`);\n }\n }\n };\n\n const securityHandler = engine\n ? (events: SecurityEvent[]) => {\n for (const event of events) {\n const alerts = engine.analyzeEvent(event);\n for (const alert of alerts) {\n if (isJson) {\n write(JSON.stringify({ type: 'alert', data: alert }));\n } else {\n const ts = new Date(alert.timestamp).toLocaleTimeString('en-GB', { hour12: false });\n write(`ALERT ${ts} [${alert.severity}] ${alert.sessionSlug}: ${alert.message}`);\n }\n }\n }\n }\n : undefined;\n\n const usageHandler = (sessionId: string, usage: TokenUsage) => {\n if (isJson) {\n write(JSON.stringify({ type: 'usage', data: { sessionId, usage } }));\n } else {\n write(\n `USAGE ${sessionId.slice(0, 12)} +${formatTokens(usage.inputTokens)} in / +${formatTokens(usage.outputTokens)} out`,\n );\n }\n };\n\n const watcher = new Watcher(handler, options.allUsers, securityHandler, usageHandler);\n watcher.start();\n\n process.on('SIGINT', () => {\n watcher.stop();\n process.exit(0);\n });\n process.on('SIGTERM', () => {\n watcher.stop();\n process.exit(0);\n });\n};\n"],"mappings":"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","names":["readFileSync","join","dirname","fileURLToPath","React","useState","useEffect","useCallback","Box","Text","useInput","readFileSync","writeFileSync","mkdirSync","join","homedir","readFileSync","join","dirname","fileURLToPath","React","Box","Text","jsx","jsxs","React","Box","Text","React","Box","Text","jsx","jsxs","React","Box","Text","React","Box","Text","jsx","jsxs","formatTime","React","Box","Text","React","Box","Text","jsx","jsxs","formatTokens","formatModel","React","Box","Text","React","useState","Box","Text","jsx","jsxs","React","useState","Box","Text","React","Box","Text","jsx","jsxs","React","Box","Text","useState","useEffect","useState","useEffect","useState","useEffect","useRef","useState","useRef","useEffect","useState","useEffect","useRef","exec","mkdirSync","dirname","mkdirSync","dirname","useState","useRef","useEffect","useState","useCallback","jsx","jsxs","useState","useEffect","useCallback","useInput","Box","Text","formatTokens","fileURLToPath","join","dirname","readFileSync","write","React"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
startMcpServer
|
|
4
|
+
} from "./chunk-4I4UZNKS.js";
|
|
5
|
+
|
|
6
|
+
// src/mcp-server.ts
|
|
7
|
+
var allUsers = process.argv.includes("--all-users");
|
|
8
|
+
var noSecurity = process.argv.includes("--no-security");
|
|
9
|
+
startMcpServer(allUsers, noSecurity).catch((err) => {
|
|
10
|
+
process.stderr.write(`agenttop mcp server error: ${err}
|
|
11
|
+
`);
|
|
12
|
+
process.exit(1);
|
|
13
|
+
});
|
|
14
|
+
//# sourceMappingURL=mcp-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/mcp-server.ts"],"sourcesContent":["import { startMcpServer } from './mcp/server.js';\n\nconst allUsers = process.argv.includes('--all-users');\nconst noSecurity = process.argv.includes('--no-security');\n\nstartMcpServer(allUsers, noSecurity).catch((err) => {\n process.stderr.write(`agenttop mcp server error: ${err}\\n`);\n process.exit(1);\n});\n"],"mappings":";;;;;;AAEA,IAAM,WAAW,QAAQ,KAAK,SAAS,aAAa;AACpD,IAAM,aAAa,QAAQ,KAAK,SAAS,eAAe;AAExD,eAAe,UAAU,UAAU,EAAE,MAAM,CAAC,QAAQ;AAClD,UAAQ,OAAO,MAAM,8BAA8B,GAAG;AAAA,CAAI;AAC1D,UAAQ,KAAK,CAAC;AAChB,CAAC;","names":[]}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
agenttop Claude Code hook — active prompt injection protection.
|
|
4
|
+
|
|
5
|
+
install as a PostToolUse hook to scan all tool results for prompt
|
|
6
|
+
injection attempts before Claude processes them. blocks on critical
|
|
7
|
+
severity, warns on lower.
|
|
8
|
+
|
|
9
|
+
hook type: PostToolUse (runs after tool executes, before result
|
|
10
|
+
reaches Claude — stderr output with exit code 2 blocks the result)
|
|
11
|
+
|
|
12
|
+
input (stdin): json with tool_name, tool_input, tool_result
|
|
13
|
+
output: exit 0 = pass, exit 2 = block (stderr = reason)
|
|
14
|
+
|
|
15
|
+
install:
|
|
16
|
+
agenttop --install-hooks
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
import json
|
|
20
|
+
import re
|
|
21
|
+
import sys
|
|
22
|
+
|
|
23
|
+
INJECTION_PATTERNS = [
|
|
24
|
+
(r'ignore\s+(all\s+)?previous\s+instructions', 'ignore previous instructions'),
|
|
25
|
+
(r'ignore\s+(all\s+)?prior\s+instructions', 'ignore prior instructions'),
|
|
26
|
+
(r'disregard\s+(all\s+)?previous', 'disregard previous'),
|
|
27
|
+
(r'you\s+are\s+now\s+', 'role reassignment attempt'),
|
|
28
|
+
(r'new\s+instructions?\s*:', 'new instructions injection'),
|
|
29
|
+
(r'system\s*:\s*you', 'fake system prompt'),
|
|
30
|
+
(r'\bdo\s+not\s+follow\s+(your|the)\s+(original|previous)', 'instruction override'),
|
|
31
|
+
(r'override\s+(your\s+)?(instructions|rules|guidelines)', 'instruction override'),
|
|
32
|
+
(r'forget\s+(your\s+)?(instructions|rules|guidelines)', 'instruction override'),
|
|
33
|
+
(r'act\s+as\s+(if\s+)?(you\s+are|a)\s+', 'role reassignment attempt'),
|
|
34
|
+
(r'pretend\s+(you\s+are|to\s+be)\s+', 'role reassignment attempt'),
|
|
35
|
+
(r'\bAI\s+assistant\b.*\bmust\b', 'directive injection'),
|
|
36
|
+
(r'<\s*system\s*>', 'fake system tag'),
|
|
37
|
+
(r'\[\s*INST\s*\]', 'fake instruction tag'),
|
|
38
|
+
(r'BEGIN\s+HIDDEN\s+INSTRUCTIONS', 'hidden instructions'),
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
ENCODED_PATTERNS = [
|
|
42
|
+
(r'aWdub3JlIHByZXZpb3Vz', 'base64 encoded injection'),
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
EXFIL_PATTERNS = [
|
|
46
|
+
(r'base64.*\|\s*(curl|wget|nc)', 'data exfiltration via encoding + network'),
|
|
47
|
+
(r'cat\s+.*\|\s*(curl|wget|nc)', 'data exfiltration via pipe to network'),
|
|
48
|
+
(r'>\s*/dev/tcp/', 'data exfiltration via /dev/tcp'),
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
TOOLS_WITH_EXTERNAL_CONTENT = [
|
|
52
|
+
'Bash', 'Read', 'Grep', 'Glob', 'WebFetch', 'WebSearch',
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def scan_text(text: str) -> list[tuple[str, str]]:
|
|
57
|
+
"""scan text for injection patterns. returns list of (matched_text, description)."""
|
|
58
|
+
if not text or len(text) < 10:
|
|
59
|
+
return []
|
|
60
|
+
|
|
61
|
+
findings = []
|
|
62
|
+
for pattern, desc in INJECTION_PATTERNS + ENCODED_PATTERNS:
|
|
63
|
+
match = re.search(pattern, text, re.IGNORECASE)
|
|
64
|
+
if match:
|
|
65
|
+
findings.append((match.group(0)[:60], desc))
|
|
66
|
+
|
|
67
|
+
return findings
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def scan_for_exfil(text: str) -> list[tuple[str, str]]:
|
|
71
|
+
"""scan for data exfiltration patterns in tool results."""
|
|
72
|
+
if not text:
|
|
73
|
+
return []
|
|
74
|
+
|
|
75
|
+
findings = []
|
|
76
|
+
for pattern, desc in EXFIL_PATTERNS:
|
|
77
|
+
match = re.search(pattern, text, re.IGNORECASE)
|
|
78
|
+
if match:
|
|
79
|
+
findings.append((match.group(0)[:60], desc))
|
|
80
|
+
|
|
81
|
+
return findings
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def main():
|
|
85
|
+
try:
|
|
86
|
+
input_data = json.load(sys.stdin)
|
|
87
|
+
except json.JSONDecodeError:
|
|
88
|
+
sys.exit(0)
|
|
89
|
+
|
|
90
|
+
tool_name = input_data.get('tool_name', '')
|
|
91
|
+
tool_result = input_data.get('tool_result', '')
|
|
92
|
+
|
|
93
|
+
if tool_name not in TOOLS_WITH_EXTERNAL_CONTENT:
|
|
94
|
+
sys.exit(0)
|
|
95
|
+
|
|
96
|
+
if not tool_result:
|
|
97
|
+
sys.exit(0)
|
|
98
|
+
|
|
99
|
+
result_text = str(tool_result) if not isinstance(tool_result, str) else tool_result
|
|
100
|
+
|
|
101
|
+
injection_findings = scan_text(result_text)
|
|
102
|
+
exfil_findings = scan_for_exfil(result_text)
|
|
103
|
+
|
|
104
|
+
all_findings = injection_findings + exfil_findings
|
|
105
|
+
|
|
106
|
+
if not all_findings:
|
|
107
|
+
sys.exit(0)
|
|
108
|
+
|
|
109
|
+
print("[agenttop] BLOCKED: potential prompt injection in tool result", file=sys.stderr)
|
|
110
|
+
print("", file=sys.stderr)
|
|
111
|
+
for matched, desc in all_findings[:3]:
|
|
112
|
+
print(f" [{desc}]: \"{matched}\"", file=sys.stderr)
|
|
113
|
+
print("", file=sys.stderr)
|
|
114
|
+
print(f" tool: {tool_name}", file=sys.stderr)
|
|
115
|
+
print(" review the tool output carefully before proceeding", file=sys.stderr)
|
|
116
|
+
sys.exit(2)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
if __name__ == '__main__':
|
|
120
|
+
main()
|
package/package.json
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "agenttop",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Real-time terminal dashboard for monitoring AI coding agent sessions — like htop for agents",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"agenttop": "dist/index.js",
|
|
8
|
+
"agenttop-mcp": "dist/mcp-server.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"hooks"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsup && chmod +x dist/index.js dist/mcp-server.js && mkdir -p hooks && cp src/hooks/agenttop-guard.py hooks/",
|
|
16
|
+
"dev": "tsup --watch",
|
|
17
|
+
"start": "node dist/index.js",
|
|
18
|
+
"test": "vitest run",
|
|
19
|
+
"lint": "eslint src tests",
|
|
20
|
+
"format": "prettier --write 'src/**/*.{ts,tsx}' 'tests/**/*.ts'",
|
|
21
|
+
"format:check": "prettier --check 'src/**/*.{ts,tsx}' 'tests/**/*.ts'"
|
|
22
|
+
},
|
|
23
|
+
"keywords": [
|
|
24
|
+
"agenttop",
|
|
25
|
+
"ai-agent",
|
|
26
|
+
"claude-code",
|
|
27
|
+
"monitor",
|
|
28
|
+
"dashboard",
|
|
29
|
+
"tui",
|
|
30
|
+
"security",
|
|
31
|
+
"htop",
|
|
32
|
+
"mcp"
|
|
33
|
+
],
|
|
34
|
+
"repository": {
|
|
35
|
+
"type": "git",
|
|
36
|
+
"url": "https://github.com/wrxck/agenttop.git"
|
|
37
|
+
},
|
|
38
|
+
"homepage": "https://github.com/wrxck/agenttop#readme",
|
|
39
|
+
"bugs": {
|
|
40
|
+
"url": "https://github.com/wrxck/agenttop/issues"
|
|
41
|
+
},
|
|
42
|
+
"author": "Matt Hesketh <matt@heskethwebdesign.co.uk>",
|
|
43
|
+
"license": "MIT",
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"@modelcontextprotocol/sdk": "1.27.1",
|
|
46
|
+
"chokidar": "4.0.3",
|
|
47
|
+
"ink": "6.0.0",
|
|
48
|
+
"react": "19.1.0"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@eslint/js": "10.0.1",
|
|
52
|
+
"@types/node": "22.15.3",
|
|
53
|
+
"@types/react": "19.1.2",
|
|
54
|
+
"eslint": "10.1.0",
|
|
55
|
+
"eslint-config-prettier": "10.1.8",
|
|
56
|
+
"prettier": "3.8.1",
|
|
57
|
+
"tsup": "8.5.0",
|
|
58
|
+
"typescript": "5.8.3",
|
|
59
|
+
"typescript-eslint": "8.57.1",
|
|
60
|
+
"vitest": "4.1.0"
|
|
61
|
+
}
|
|
62
|
+
}
|