squads-cli 0.6.2 → 0.7.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/README.md +196 -1152
- package/dist/auth-YW3UPFSB.js +23 -0
- package/dist/autonomy-BWTVDEAT.js +102 -0
- package/dist/autonomy-BWTVDEAT.js.map +1 -0
- package/dist/chunk-3KCWNZWW.js +401 -0
- package/dist/chunk-3KCWNZWW.js.map +1 -0
- package/dist/chunk-67RO2HKR.js +174 -0
- package/dist/chunk-67RO2HKR.js.map +1 -0
- package/dist/chunk-7JVD7RD4.js +275 -0
- package/dist/chunk-7JVD7RD4.js.map +1 -0
- package/dist/chunk-BODLDQY7.js +452 -0
- package/dist/chunk-BODLDQY7.js.map +1 -0
- package/dist/chunk-FFFCFZ6A.js +121 -0
- package/dist/chunk-FFFCFZ6A.js.map +1 -0
- package/dist/chunk-FIWT2NMM.js +165 -0
- package/dist/chunk-FIWT2NMM.js.map +1 -0
- package/dist/chunk-L6GQCHDF.js +222 -0
- package/dist/chunk-L6GQCHDF.js.map +1 -0
- package/dist/{chunk-O7UV3FWI.js → chunk-LDM62TIX.js} +2 -2
- package/dist/chunk-LDM62TIX.js.map +1 -0
- package/dist/chunk-LOA3KWYJ.js +294 -0
- package/dist/chunk-LOA3KWYJ.js.map +1 -0
- package/dist/chunk-NA45DFXY.js +616 -0
- package/dist/chunk-NA45DFXY.js.map +1 -0
- package/dist/{chunk-4CMAEQQY.js → chunk-NQN6JPI7.js} +4 -3
- package/dist/chunk-NQN6JPI7.js.map +1 -0
- package/dist/chunk-OQJHPULO.js +103 -0
- package/dist/chunk-OQJHPULO.js.map +1 -0
- package/dist/chunk-QHNUMM4V.js +87 -0
- package/dist/chunk-QHNUMM4V.js.map +1 -0
- package/dist/chunk-RM6BWILN.js +74 -0
- package/dist/chunk-RM6BWILN.js.map +1 -0
- package/dist/chunk-WBR5J7EX.js +90 -0
- package/dist/chunk-WBR5J7EX.js.map +1 -0
- package/dist/chunk-Z2UKDBNL.js +162 -0
- package/dist/chunk-Z2UKDBNL.js.map +1 -0
- package/dist/cli.js +2136 -12600
- package/dist/cli.js.map +1 -1
- package/dist/context-M2A2DOFV.js +291 -0
- package/dist/context-M2A2DOFV.js.map +1 -0
- package/dist/context-feed-JMNW4GAM.js +391 -0
- package/dist/context-feed-JMNW4GAM.js.map +1 -0
- package/dist/cost-N37I4UTA.js +274 -0
- package/dist/cost-N37I4UTA.js.map +1 -0
- package/dist/create-554W5HNU.js +286 -0
- package/dist/create-554W5HNU.js.map +1 -0
- package/dist/daemon-XWPQPPPN.js +546 -0
- package/dist/daemon-XWPQPPPN.js.map +1 -0
- package/dist/dashboard-L7YKVQEB.js +945 -0
- package/dist/dashboard-L7YKVQEB.js.map +1 -0
- package/dist/dashboard-MFNRLCEE.js +794 -0
- package/dist/dashboard-MFNRLCEE.js.map +1 -0
- package/dist/doctor-RG75M5RO.js +346 -0
- package/dist/doctor-RG75M5RO.js.map +1 -0
- package/dist/env-config-KCLDBKYX.js +21 -0
- package/dist/exec-JQKBF7BL.js +197 -0
- package/dist/exec-JQKBF7BL.js.map +1 -0
- package/dist/feedback-KA2UYBZG.js +229 -0
- package/dist/feedback-KA2UYBZG.js.map +1 -0
- package/dist/github-UQTM5KMS.js +23 -0
- package/dist/goal-EOPC5ZCD.js +168 -0
- package/dist/goal-EOPC5ZCD.js.map +1 -0
- package/dist/health-3FZDOSR5.js +209 -0
- package/dist/health-3FZDOSR5.js.map +1 -0
- package/dist/history-TFVXJEDH.js +229 -0
- package/dist/history-TFVXJEDH.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/init-UOWTNMIE.js +747 -0
- package/dist/init-UOWTNMIE.js.map +1 -0
- package/dist/kpi-2SQ2WCVT.js +413 -0
- package/dist/kpi-2SQ2WCVT.js.map +1 -0
- package/dist/learn-6ERTERAO.js +269 -0
- package/dist/learn-6ERTERAO.js.map +1 -0
- package/dist/list-KSOMUBMB.js +92 -0
- package/dist/list-KSOMUBMB.js.map +1 -0
- package/dist/login-ST6PAXYE.js +155 -0
- package/dist/login-ST6PAXYE.js.map +1 -0
- package/dist/memory-3CSNKXIL.js +562 -0
- package/dist/memory-3CSNKXIL.js.map +1 -0
- package/dist/progress-FKG4V2VH.js +202 -0
- package/dist/progress-FKG4V2VH.js.map +1 -0
- package/dist/providers-66PDCORB.js +65 -0
- package/dist/providers-66PDCORB.js.map +1 -0
- package/dist/results-2MJFLWEO.js +224 -0
- package/dist/results-2MJFLWEO.js.map +1 -0
- package/dist/run-72OQLH5A.js +2685 -0
- package/dist/run-72OQLH5A.js.map +1 -0
- package/dist/session-6H67XPAQ.js +64 -0
- package/dist/session-6H67XPAQ.js.map +1 -0
- package/dist/{chunk-NHGLXN2F.js → sessions-GVQIMN4W.js} +23 -459
- package/dist/sessions-GVQIMN4W.js.map +1 -0
- package/dist/{squad-parser-4BI3G4RS.js → squad-parser-CM3HOIWM.js} +2 -2
- package/dist/squad-parser-CM3HOIWM.js.map +1 -0
- package/dist/stats-ONZI557Q.js +335 -0
- package/dist/stats-ONZI557Q.js.map +1 -0
- package/dist/status-FYH42FTB.js +346 -0
- package/dist/status-FYH42FTB.js.map +1 -0
- package/dist/sync-HJZJNXHW.js +800 -0
- package/dist/sync-HJZJNXHW.js.map +1 -0
- package/dist/update-B4WMUOPO.js +83 -0
- package/dist/update-B4WMUOPO.js.map +1 -0
- package/dist/{update-ALJKFFM7.js → update-L7FGHN6W.js} +2 -2
- package/dist/update-L7FGHN6W.js.map +1 -0
- package/package.json +18 -10
- package/dist/chunk-4CMAEQQY.js.map +0 -1
- package/dist/chunk-NHGLXN2F.js.map +0 -1
- package/dist/chunk-O7UV3FWI.js.map +0 -1
- package/dist/sessions-6PB7ALCE.js +0 -16
- /package/dist/{sessions-6PB7ALCE.js.map → auth-YW3UPFSB.js.map} +0 -0
- /package/dist/{squad-parser-4BI3G4RS.js.map → env-config-KCLDBKYX.js.map} +0 -0
- /package/dist/{update-ALJKFFM7.js.map → github-UQTM5KMS.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/dashboard/loader.ts","../src/lib/dashboard/sources/postgres.ts","../src/lib/dashboard/renderers/base.ts","../src/lib/dashboard/renderers/summary.ts","../src/lib/dashboard/renderers/table.ts","../src/lib/dashboard/renderers/trend.ts","../src/lib/dashboard/renderers/bar.ts","../src/lib/dashboard/renderers/list.ts","../src/lib/dashboard/renderers/index.ts","../src/lib/dashboard/engine.ts"],"sourcesContent":["/**\n * Dashboard Loader\n * Loads and parses dashboard YAML definitions\n */\n\nimport { readFileSync, readdirSync, existsSync } from 'fs';\nimport { join, basename } from 'path';\nimport { createRequire } from 'module';\nimport type { DashboardDefinition } from './types.js';\n\nconst require = createRequire(import.meta.url);\nconst yaml = require('js-yaml');\n\n// Cache loaded dashboards\nconst dashboardCache = new Map<string, DashboardDefinition>();\n\n/**\n * Find the dashboards directory\n */\nexport function findDashboardsDir(): string | null {\n // Start from cwd and walk up\n let dir = process.cwd();\n for (let i = 0; i < 10; i++) {\n const dashDir = join(dir, '.agents', 'dashboards');\n if (existsSync(dashDir)) {\n return dashDir;\n }\n const parent = join(dir, '..');\n if (parent === dir) break;\n dir = parent;\n }\n return null;\n}\n\n/**\n * List all available dashboards\n */\nexport function listDashboards(): string[] {\n const dir = findDashboardsDir();\n if (!dir) return [];\n\n try {\n return readdirSync(dir)\n .filter(f => f.endsWith('.yaml') && !f.startsWith('_'))\n .map(f => basename(f, '.yaml'));\n } catch {\n return [];\n }\n}\n\n/**\n * Load a dashboard definition by name\n */\nexport function loadDashboard(name: string): DashboardDefinition | null {\n // Check cache\n if (dashboardCache.has(name)) {\n return dashboardCache.get(name)!;\n }\n\n const dir = findDashboardsDir();\n if (!dir) return null;\n\n const filePath = join(dir, `${name}.yaml`);\n if (!existsSync(filePath)) return null;\n\n try {\n const content = readFileSync(filePath, 'utf-8');\n const def = yaml.load(content) as DashboardDefinition;\n\n // Validate required fields\n if (!def.name || !def.title || !def.source || !def.metrics || !def.views) {\n console.error(`Invalid dashboard definition: ${name}`);\n return null;\n }\n\n // Cache and return\n dashboardCache.set(name, def);\n return def;\n } catch (err) {\n console.error(`Error loading dashboard ${name}:`, err);\n return null;\n }\n}\n\n/**\n * Load all dashboards\n */\nexport function loadAllDashboards(): DashboardDefinition[] {\n const names = listDashboards();\n return names\n .map(name => loadDashboard(name))\n .filter((d): d is DashboardDefinition => d !== null);\n}\n\n/**\n * Clear the dashboard cache (useful for hot-reload)\n */\nexport function clearDashboardCache(): void {\n dashboardCache.clear();\n}\n\n/**\n * Get dashboard by partial match (fuzzy find)\n */\nexport function findDashboard(query: string): DashboardDefinition | null {\n // Exact match first\n const exact = loadDashboard(query);\n if (exact) return exact;\n\n // Partial match\n const all = listDashboards();\n const match = all.find(name =>\n name.toLowerCase().includes(query.toLowerCase())\n );\n if (match) return loadDashboard(match);\n\n return null;\n}\n","/**\n * PostgreSQL Data Source — stub implementation\n *\n * Database queries are a platform feature (Layer 3).\n * The CLI dashboard uses local data sources only.\n * The pure utility functions (buildQuery, buildWhereClause, parseDateRange) are kept\n * as they don't depend on pg and may be used by other data sources.\n */\n\nimport type { DataSource, QueryResult } from '../types.js';\n\nexport const postgresSource: DataSource = {\n name: 'postgres',\n\n async query(_sql: string, _params: unknown[] = []): Promise<QueryResult> {\n return { rows: [], columns: [] };\n },\n\n async isAvailable(): Promise<boolean> {\n return false;\n },\n\n async close(): Promise<void> {\n // No-op\n },\n};\n\n/**\n * Build a SELECT query from dashboard definition\n */\nexport function buildQuery(\n table: string,\n metrics: { name: string; sql: string }[],\n groupBy?: string[],\n where?: string,\n orderBy?: string,\n limit?: number\n): string {\n const selectParts: string[] = [];\n\n if (groupBy && groupBy.length > 0) {\n for (const col of groupBy) {\n selectParts.push(col);\n }\n }\n\n for (const metric of metrics) {\n selectParts.push(`${metric.sql} AS ${metric.name}`);\n }\n\n let sql = `SELECT ${selectParts.join(', ')} FROM ${table}`;\n\n if (where) {\n sql += ` WHERE ${where}`;\n }\n\n if (groupBy && groupBy.length > 0) {\n sql += ` GROUP BY ${groupBy.join(', ')}`;\n }\n\n if (orderBy) {\n sql += ` ORDER BY ${orderBy}`;\n }\n\n if (limit) {\n sql += ` LIMIT ${limit}`;\n }\n\n return sql;\n}\n\n/**\n * Build WHERE clause from filters\n */\nexport function buildWhereClause(\n filters: Record<string, unknown>,\n filterDefs: { name: string; field?: string; type: string }[]\n): string | null {\n const conditions: string[] = [];\n\n for (const [name, value] of Object.entries(filters)) {\n if (value === undefined || value === null) continue;\n\n const def = filterDefs.find(f => f.name === name);\n if (!def) continue;\n\n const field = def.field || name;\n\n if (def.type === 'date_range' && typeof value === 'object') {\n const range = value as { start?: Date; end?: Date };\n if (range.start) {\n conditions.push(`${field} >= '${range.start.toISOString()}'`);\n }\n if (range.end) {\n conditions.push(`${field} <= '${range.end.toISOString()}'`);\n }\n } else if (def.type === 'select' && Array.isArray(value)) {\n if (value.length > 0) {\n const escaped = value.map(v => `'${String(v).replace(/'/g, \"''\")}'`);\n conditions.push(`${field} IN (${escaped.join(', ')})`);\n }\n } else if (def.type === 'boolean') {\n conditions.push(`${field} = ${value ? 'true' : 'false'}`);\n } else if (def.type === 'text') {\n conditions.push(`${field} ILIKE '%${String(value).replace(/'/g, \"''\")}%'`);\n }\n }\n\n return conditions.length > 0 ? conditions.join(' AND ') : null;\n}\n\n/**\n * Parse date range presets\n */\nexport function parseDateRange(preset: string): { start: Date; end: Date } {\n const now = new Date();\n const end = new Date(now);\n end.setHours(23, 59, 59, 999);\n\n const start = new Date(now);\n start.setHours(0, 0, 0, 0);\n\n switch (preset) {\n case 'today':\n return { start, end };\n\n case 'yesterday':\n start.setDate(start.getDate() - 1);\n end.setDate(end.getDate() - 1);\n return { start, end };\n\n case 'last_7d':\n start.setDate(start.getDate() - 7);\n return { start, end };\n\n case 'last_30d':\n start.setDate(start.getDate() - 30);\n return { start, end };\n\n case 'this_month':\n start.setDate(1);\n return { start, end };\n\n case 'last_month':\n start.setMonth(start.getMonth() - 1);\n start.setDate(1);\n end.setDate(0);\n return { start, end };\n\n case 'this_quarter': {\n const q = Math.floor(now.getMonth() / 3);\n start.setMonth(q * 3);\n start.setDate(1);\n return { start, end };\n }\n\n default:\n start.setDate(start.getDate() - 7);\n return { start, end };\n }\n}\n","/**\n * Base Renderer Utilities\n * Shared formatting and rendering functions\n */\n\nimport {\n colors,\n bold,\n RESET,\n box,\n padEnd,\n truncate,\n writeLine,\n progressBar,\n sparkline,\n barChart,\n gradient,\n} from '../../terminal.js';\n\nexport { colors, bold, RESET, box, padEnd, truncate, writeLine, progressBar, sparkline, barChart, gradient };\n\n/**\n * Format a value based on format type\n */\nexport function formatValue(\n value: unknown,\n format: string,\n truncateLen?: number\n): string {\n if (value === null || value === undefined) {\n return `${colors.dim}—${RESET}`;\n }\n\n const strValue = String(value);\n\n switch (format) {\n case 'number': {\n const num = typeof value === 'number' ? value : parseFloat(strValue);\n if (isNaN(num)) return strValue;\n if (num >= 1_000_000) return `${(num / 1_000_000).toFixed(1)}M`;\n if (num >= 1_000) return `${(num / 1_000).toFixed(1)}k`;\n return num.toLocaleString();\n }\n\n case 'currency': {\n const amount = typeof value === 'number' ? value : parseFloat(strValue);\n if (isNaN(amount)) return strValue;\n return `$${amount.toFixed(2)}`;\n }\n\n case 'percent': {\n const pct = typeof value === 'number' ? value : parseFloat(strValue);\n if (isNaN(pct)) return strValue;\n return `${pct.toFixed(1)}%`;\n }\n\n case 'duration': {\n const secs = typeof value === 'number' ? value : parseFloat(strValue);\n if (isNaN(secs)) return strValue;\n if (secs < 60) return `${secs.toFixed(1)}s`;\n if (secs < 3600) return `${Math.floor(secs / 60)}m ${Math.round(secs % 60)}s`;\n return `${Math.floor(secs / 3600)}h ${Math.floor((secs % 3600) / 60)}m`;\n }\n\n case 'tokens': {\n const tokens = typeof value === 'number' ? value : parseInt(strValue, 10);\n if (isNaN(tokens)) return strValue;\n if (tokens >= 1_000_000) return `${(tokens / 1_000_000).toFixed(1)}M`;\n if (tokens >= 1_000) return `${(tokens / 1_000).toFixed(0)}k`;\n return tokens.toLocaleString();\n }\n\n case 'relative_time':\n return formatRelativeTime(value);\n\n case 'relative_date':\n return formatRelativeDate(value);\n\n case 'status_badge':\n return formatStatusBadge(strValue);\n\n case 'progress_bar': {\n const progress = typeof value === 'number' ? value : parseFloat(strValue);\n if (isNaN(progress)) return strValue;\n return progressBar(progress, 8);\n }\n\n default:\n if (truncateLen && strValue.length > truncateLen) {\n return truncate(strValue, truncateLen);\n }\n return strValue;\n }\n}\n\n/**\n * Format relative time (e.g., \"5 minutes ago\")\n */\nfunction formatRelativeTime(value: unknown): string {\n const date = value instanceof Date ? value : new Date(String(value));\n if (isNaN(date.getTime())) return String(value);\n\n const now = new Date();\n const diffMs = now.getTime() - date.getTime();\n const diffSecs = Math.floor(diffMs / 1000);\n const diffMins = Math.floor(diffSecs / 60);\n const diffHours = Math.floor(diffMins / 60);\n const diffDays = Math.floor(diffHours / 24);\n\n if (diffSecs < 60) return `${diffSecs}s ago`;\n if (diffMins < 60) return `${diffMins}m ago`;\n if (diffHours < 24) return `${diffHours}h ago`;\n if (diffDays < 7) return `${diffDays}d ago`;\n return date.toLocaleDateString();\n}\n\n/**\n * Format relative date (e.g., \"today\", \"yesterday\", \"5 days ago\")\n */\nfunction formatRelativeDate(value: unknown): string {\n const date = value instanceof Date ? value : new Date(String(value));\n if (isNaN(date.getTime())) return String(value);\n\n const now = new Date();\n const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());\n const target = new Date(date.getFullYear(), date.getMonth(), date.getDate());\n const diffDays = Math.floor((today.getTime() - target.getTime()) / (1000 * 60 * 60 * 24));\n\n if (diffDays === 0) return 'today';\n if (diffDays === 1) return 'yesterday';\n if (diffDays < 7) return `${diffDays}d ago`;\n if (diffDays < 30) return `${Math.floor(diffDays / 7)}w ago`;\n return date.toLocaleDateString();\n}\n\n/**\n * Format status badge with color\n */\nfunction formatStatusBadge(status: string): string {\n const lower = status.toLowerCase();\n\n switch (lower) {\n case 'success':\n case 'completed':\n case 'active':\n return `${colors.green}${status}${RESET}`;\n\n case 'failed':\n case 'error':\n return `${colors.red}${status}${RESET}`;\n\n case 'running':\n case 'pending':\n case 'in_progress':\n return `${colors.yellow}${status}${RESET}`;\n\n case 'timeout':\n case 'cancelled':\n return `${colors.dim}${status}${RESET}`;\n\n default:\n return status;\n }\n}\n\n/**\n * Get color based on value threshold\n */\nexport function getThresholdColor(\n value: number,\n thresholds: { good?: number; warning?: number; direction?: 'up' | 'down' }\n): string {\n const { good = 80, warning = 50, direction = 'up' } = thresholds;\n\n if (direction === 'up') {\n if (value >= good) return colors.green;\n if (value >= warning) return colors.yellow;\n return colors.red;\n } else {\n if (value <= good) return colors.green;\n if (value <= warning) return colors.yellow;\n return colors.red;\n }\n}\n\n/**\n * Render a horizontal divider\n */\nexport function renderDivider(width: number = 50): void {\n writeLine(` ${colors.dim}${box.horizontal.repeat(width)}${RESET}`);\n}\n\n/**\n * Render section header\n */\nexport function renderSectionHeader(title: string): void {\n writeLine();\n writeLine(` ${bold}${title}${RESET}`);\n writeLine();\n}\n\n/**\n * Calculate column widths for table rendering\n */\nexport function calculateColumnWidths(\n rows: Record<string, unknown>[],\n columns: { field: string; label?: string }[],\n maxWidth: number = 80\n): number[] {\n const widths = columns.map(col => {\n const headerLen = (col.label || col.field).length;\n const maxValueLen = rows.reduce((max, row) => {\n const val = String(row[col.field] ?? '');\n return Math.max(max, val.length);\n }, 0);\n return Math.min(Math.max(headerLen, maxValueLen) + 2, 30);\n });\n\n // Scale down if total exceeds maxWidth\n const totalWidth = widths.reduce((sum, w) => sum + w, 0);\n if (totalWidth > maxWidth) {\n const scale = maxWidth / totalWidth;\n return widths.map(w => Math.max(Math.floor(w * scale), 5));\n }\n\n return widths;\n}\n","/**\n * Summary Renderer\n * Renders key metrics in a horizontal row\n */\n\nimport type { ViewDefinition, MetricDefinition, QueryResult } from '../types.js';\nimport { colors, bold, RESET, formatValue } from './base.js';\n\nexport function renderSummary(\n view: ViewDefinition,\n data: QueryResult,\n metricDefs: MetricDefinition[]\n): string[] {\n const lines: string[] = [];\n const row = data.rows[0] || {};\n\n // Build metric display parts\n const parts: string[] = [];\n\n for (const metricName of view.metrics || []) {\n const def = metricDefs.find(m => m.name === metricName);\n if (!def) continue;\n\n const value = row[metricName];\n const formatted = formatValue(value, def.format);\n const label = def.label || metricName;\n\n // Color based on format\n const valueColor = def.format === 'currency' ? colors.green :\n def.format === 'percent' ? colors.purple :\n colors.cyan;\n\n parts.push(`${valueColor}${formatted}${RESET} ${colors.dim}${label}${RESET}`);\n }\n\n // Join with dividers\n const line = parts.join(` ${colors.dim}|${RESET} `);\n lines.push(` ${line}`);\n\n return lines;\n}\n\n/**\n * Render summary as a boxed card\n */\nexport function renderSummaryBox(\n view: ViewDefinition,\n data: QueryResult,\n metricDefs: MetricDefinition[]\n): string[] {\n const lines: string[] = [];\n const row = data.rows[0] || {};\n\n if (view.title) {\n lines.push(` ${bold}${view.title}${RESET}`);\n lines.push('');\n }\n\n // Render each metric on its own line\n for (const metricName of view.metrics || []) {\n const def = metricDefs.find(m => m.name === metricName);\n if (!def) continue;\n\n const value = row[metricName];\n const formatted = formatValue(value, def.format);\n const label = def.label || metricName;\n\n const valueColor = def.format === 'currency' ? colors.green :\n def.format === 'percent' ? colors.purple :\n colors.cyan;\n\n lines.push(` ${colors.dim}${label.padEnd(16)}${RESET} ${valueColor}${formatted}${RESET}`);\n }\n\n return lines;\n}\n","/**\n * Table Renderer\n * Renders data in a tabular format with borders\n */\n\nimport type { ViewDefinition, MetricDefinition, DimensionDefinition, QueryResult } from '../types.js';\nimport { colors, bold, RESET, box, padEnd, formatValue, calculateColumnWidths } from './base.js';\n\nexport function renderTable(\n view: ViewDefinition,\n data: QueryResult,\n metricDefs: MetricDefinition[],\n dimensionDefs: DimensionDefinition[]\n): string[] {\n const lines: string[] = [];\n\n if (data.rows.length === 0) {\n lines.push(` ${colors.dim}No data${RESET}`);\n return lines;\n }\n\n // Build column definitions\n const columns: { field: string; label: string; format?: string; width: number }[] = [];\n\n // Add group by columns first (dimensions)\n if (view.group_by) {\n for (const dimName of view.group_by) {\n const def = dimensionDefs.find(d => d.name === dimName);\n columns.push({\n field: dimName,\n label: def?.label || dimName,\n format: undefined,\n width: 0, // Will calculate\n });\n }\n }\n\n // Add metric columns\n if (view.metrics) {\n for (const metricName of view.metrics) {\n const def = metricDefs.find(m => m.name === metricName);\n columns.push({\n field: metricName,\n label: def?.label || metricName,\n format: def?.format,\n width: 0,\n });\n }\n }\n\n // Use explicit columns if provided\n if (view.columns && view.columns.length > 0) {\n columns.length = 0;\n for (const col of view.columns) {\n columns.push({\n field: col.field,\n label: col.label || col.field,\n format: col.format,\n width: 0,\n });\n }\n }\n\n // Calculate widths\n const widths = calculateColumnWidths(data.rows, columns, 70);\n columns.forEach((col, i) => col.width = widths[i]);\n\n // Calculate table width\n const tableWidth = columns.reduce((sum, col) => sum + col.width, 0) + columns.length + 1;\n\n // Title\n if (view.title) {\n lines.push(` ${bold}${view.title}${RESET}`);\n lines.push('');\n }\n\n // Top border\n lines.push(` ${colors.purple}${box.topLeft}${colors.dim}${box.horizontal.repeat(tableWidth)}${colors.purple}${box.topRight}${RESET}`);\n\n // Header row\n let headerRow = ` ${colors.purple}${box.vertical}${RESET}`;\n for (const col of columns) {\n headerRow += ` ${bold}${padEnd(col.label.toUpperCase(), col.width - 1)}${RESET}`;\n }\n headerRow += `${colors.purple}${box.vertical}${RESET}`;\n lines.push(headerRow);\n\n // Header divider\n lines.push(` ${colors.purple}${box.teeRight}${colors.dim}${box.horizontal.repeat(tableWidth)}${colors.purple}${box.teeLeft}${RESET}`);\n\n // Data rows\n for (const row of data.rows) {\n let rowStr = ` ${colors.purple}${box.vertical}${RESET}`;\n for (const col of columns) {\n const value = row[col.field];\n const formatted = formatValue(value, col.format || 'string', col.width - 3);\n\n // Strip ANSI for padding calculation\n const visibleLen = formatted.replace(/\\x1b\\[[0-9;]*m/g, '').length;\n const padding = Math.max(0, col.width - 1 - visibleLen);\n\n rowStr += ` ${formatted}${' '.repeat(padding)}`;\n }\n rowStr += `${colors.purple}${box.vertical}${RESET}`;\n lines.push(rowStr);\n }\n\n // Bottom border\n lines.push(` ${colors.purple}${box.bottomLeft}${colors.dim}${box.horizontal.repeat(tableWidth)}${colors.purple}${box.bottomRight}${RESET}`);\n\n return lines;\n}\n\n/**\n * Render a simple table without borders\n */\nexport function renderSimpleTable(\n view: ViewDefinition,\n data: QueryResult,\n metricDefs: MetricDefinition[],\n dimensionDefs: DimensionDefinition[]\n): string[] {\n const lines: string[] = [];\n\n if (data.rows.length === 0) {\n lines.push(` ${colors.dim}No data${RESET}`);\n return lines;\n }\n\n // Build columns\n const columns: { field: string; label: string; format?: string }[] = [];\n\n if (view.group_by) {\n for (const dimName of view.group_by) {\n const def = dimensionDefs.find(d => d.name === dimName);\n columns.push({ field: dimName, label: def?.label || dimName });\n }\n }\n\n if (view.metrics) {\n for (const metricName of view.metrics) {\n const def = metricDefs.find(m => m.name === metricName);\n columns.push({ field: metricName, label: def?.label || metricName, format: def?.format });\n }\n }\n\n // Calculate widths\n const widths = calculateColumnWidths(data.rows, columns, 70);\n\n // Title\n if (view.title) {\n lines.push(` ${bold}${view.title}${RESET}`);\n lines.push('');\n }\n\n // Header\n let header = ' ';\n for (let i = 0; i < columns.length; i++) {\n header += `${colors.dim}${padEnd(columns[i].label.toUpperCase(), widths[i])}${RESET}`;\n }\n lines.push(header);\n\n // Data rows\n for (const row of data.rows) {\n let rowStr = ' ';\n for (let i = 0; i < columns.length; i++) {\n const col = columns[i];\n const value = row[col.field];\n const formatted = formatValue(value, col.format || 'string', widths[i] - 2);\n\n const visibleLen = formatted.replace(/\\x1b\\[[0-9;]*m/g, '').length;\n const padding = Math.max(0, widths[i] - visibleLen);\n\n rowStr += `${formatted}${' '.repeat(padding)}`;\n }\n lines.push(rowStr);\n }\n\n return lines;\n}\n","/**\n * Trend Renderer\n * Renders time-series data as sparklines\n */\n\nimport type { ViewDefinition, MetricDefinition, QueryResult } from '../types.js';\nimport { colors, bold, RESET, formatValue, sparkline } from './base.js';\n\nexport function renderTrend(\n view: ViewDefinition,\n data: QueryResult,\n metricDefs: MetricDefinition[]\n): string[] {\n const lines: string[] = [];\n\n if (data.rows.length === 0) {\n lines.push(` ${colors.dim}No data${RESET}`);\n return lines;\n }\n\n // Title\n if (view.title) {\n lines.push(` ${bold}${view.title}${RESET}`);\n lines.push('');\n }\n\n // Render each metric as a sparkline\n for (const metricName of view.metrics || []) {\n const def = metricDefs.find(m => m.name === metricName);\n if (!def) continue;\n\n // Extract values for sparkline (reversed if data is desc order)\n const values = data.rows.map(row => {\n const val = row[metricName];\n return typeof val === 'number' ? val : parseFloat(String(val)) || 0;\n });\n\n // Reverse if needed (assume data comes newest first)\n const orderedValues = [...values].reverse();\n\n // Calculate summary stats\n const total = orderedValues.reduce((sum, v) => sum + v, 0);\n const avg = orderedValues.length > 0 ? total / orderedValues.length : 0;\n const latest = orderedValues[orderedValues.length - 1] || 0;\n const previous = orderedValues[orderedValues.length - 2] || 0;\n const change = previous > 0 ? ((latest - previous) / previous) * 100 : 0;\n\n // Render sparkline\n const spark = sparkline(orderedValues);\n\n // Format the summary\n const label = def.label || metricName;\n const totalFormatted = formatValue(total, def.format);\n const avgFormatted = formatValue(avg, def.format);\n\n // Change indicator\n const changeColor = change > 0 ? colors.green : change < 0 ? colors.red : colors.dim;\n const changeSign = change > 0 ? '+' : '';\n const changeStr = `${changeColor}${changeSign}${change.toFixed(0)}%${RESET}`;\n\n lines.push(` ${colors.dim}${label}:${RESET} ${spark} ${colors.cyan}${totalFormatted}${RESET} total ${colors.dim}(avg ${avgFormatted})${RESET} ${changeStr}`);\n }\n\n return lines;\n}\n\n/**\n * Render stacked trend (multiple metrics on same chart)\n */\nexport function renderStackedTrend(\n view: ViewDefinition,\n data: QueryResult,\n metricDefs: MetricDefinition[]\n): string[] {\n const lines: string[] = [];\n\n if (data.rows.length === 0) {\n lines.push(` ${colors.dim}No data${RESET}`);\n return lines;\n }\n\n // Title\n if (view.title) {\n lines.push(` ${bold}${view.title}${RESET}`);\n lines.push('');\n }\n\n // Build combined sparkline (showing first metric for the visual)\n const primaryMetric = view.metrics?.[0];\n if (primaryMetric) {\n const values = data.rows.map(row => {\n const val = row[primaryMetric];\n return typeof val === 'number' ? val : parseFloat(String(val)) || 0;\n }).reverse();\n\n const spark = sparkline(values);\n lines.push(` ${spark}`);\n lines.push('');\n }\n\n // Show legend with totals\n const legendParts: string[] = [];\n for (const metricName of view.metrics || []) {\n const def = metricDefs.find(m => m.name === metricName);\n if (!def) continue;\n\n const total = data.rows.reduce((sum, row) => {\n const val = row[metricName];\n return sum + (typeof val === 'number' ? val : parseFloat(String(val)) || 0);\n }, 0);\n\n const label = def.label || metricName;\n const formatted = formatValue(total, def.format);\n\n // Color code by metric position\n const metricColor = metricName === view.metrics?.[0] ? colors.green :\n metricName === view.metrics?.[1] ? colors.yellow :\n colors.red;\n\n legendParts.push(`${metricColor}${formatted}${RESET} ${colors.dim}${label}${RESET}`);\n }\n\n lines.push(` ${legendParts.join(' ')}`);\n\n return lines;\n}\n","/**\n * Bar Chart Renderer\n * Renders horizontal bar charts\n */\n\nimport type { ViewDefinition, MetricDefinition, DimensionDefinition, QueryResult } from '../types.js';\nimport { colors, bold, RESET, padEnd, formatValue, barChart } from './base.js';\n\nexport function renderBar(\n view: ViewDefinition,\n data: QueryResult,\n metricDefs: MetricDefinition[],\n _dimensionDefs: DimensionDefinition[]\n): string[] {\n const lines: string[] = [];\n\n if (data.rows.length === 0) {\n lines.push(` ${colors.dim}No data${RESET}`);\n return lines;\n }\n\n // Title\n if (view.title) {\n lines.push(` ${bold}${view.title}${RESET}`);\n lines.push('');\n }\n\n // Get the primary dimension and metric\n const dimName = view.group_by?.[0];\n const metricName = view.metrics?.[0];\n\n if (!dimName || !metricName) {\n lines.push(` ${colors.dim}Bar chart requires group_by and metrics${RESET}`);\n return lines;\n }\n\n const metricDef = metricDefs.find(m => m.name === metricName);\n\n // Find max value for scaling\n const values = data.rows.map(row => {\n const val = row[metricName];\n return typeof val === 'number' ? val : parseFloat(String(val)) || 0;\n });\n const maxValue = Math.max(...values, 1);\n\n // Calculate label width\n const labels = data.rows.map(row => String(row[dimName] || 'Unknown'));\n const maxLabelWidth = Math.min(Math.max(...labels.map(l => l.length)), 20);\n\n // Render bars\n for (const row of data.rows) {\n const label = String(row[dimName] || 'Unknown');\n const value = row[metricName];\n const numValue = typeof value === 'number' ? value : parseFloat(String(value)) || 0;\n\n const bar = barChart(numValue, maxValue, 20);\n const formatted = formatValue(value, metricDef?.format || 'number');\n\n lines.push(` ${colors.cyan}${padEnd(label.slice(0, maxLabelWidth), maxLabelWidth + 1)}${RESET}${bar} ${colors.dim}${formatted}${RESET}`);\n }\n\n return lines;\n}\n\n/**\n * Render a pie chart as a horizontal distribution\n */\nexport function renderPie(\n view: ViewDefinition,\n data: QueryResult,\n _metricDefs: MetricDefinition[],\n _dimensionDefs: DimensionDefinition[]\n): string[] {\n const lines: string[] = [];\n\n if (data.rows.length === 0) {\n lines.push(` ${colors.dim}No data${RESET}`);\n return lines;\n }\n\n // Title\n if (view.title) {\n lines.push(` ${bold}${view.title}${RESET}`);\n lines.push('');\n }\n\n // Get dimension and metric\n const dimName = view.group_by?.[0];\n const metricName = view.metrics?.[0];\n\n if (!dimName || !metricName) {\n lines.push(` ${colors.dim}Pie chart requires group_by and metrics${RESET}`);\n return lines;\n }\n\n // Calculate total and percentages\n const values = data.rows.map(row => {\n const val = row[metricName];\n return {\n label: String(row[dimName] || 'Unknown'),\n value: typeof val === 'number' ? val : parseFloat(String(val)) || 0,\n };\n });\n\n const total = values.reduce((sum, v) => sum + v.value, 0);\n if (total === 0) {\n lines.push(` ${colors.dim}No data${RESET}`);\n return lines;\n }\n\n // Color palette\n const colorPalette = [colors.cyan, colors.green, colors.yellow, colors.purple, colors.red];\n\n // Render horizontal bar showing distribution\n const barWidth = 40;\n let barStr = '';\n let pos = 0;\n\n for (let i = 0; i < values.length; i++) {\n const pct = values[i].value / total;\n const width = Math.max(1, Math.round(pct * barWidth));\n const color = colorPalette[i % colorPalette.length];\n barStr += `${color}${'█'.repeat(width)}${RESET}`;\n pos += width;\n }\n\n // Pad to full width if needed\n if (pos < barWidth) {\n barStr += `${colors.dim}${'░'.repeat(barWidth - pos)}${RESET}`;\n }\n\n lines.push(` ${barStr}`);\n lines.push('');\n\n // Legend\n for (let i = 0; i < values.length; i++) {\n const v = values[i];\n const pct = (v.value / total) * 100;\n const color = colorPalette[i % colorPalette.length];\n\n lines.push(` ${color}■${RESET} ${padEnd(v.label.slice(0, 15), 16)} ${color}${pct.toFixed(1)}%${RESET} ${colors.dim}(${v.value.toLocaleString()})${RESET}`);\n }\n\n return lines;\n}\n","/**\n * List Renderer\n * Renders data as a list of items\n */\n\nimport type { ViewDefinition, QueryResult, ColumnDefinition } from '../types.js';\nimport { colors, bold, RESET, formatValue } from './base.js';\n\nexport function renderList(\n view: ViewDefinition,\n data: QueryResult\n): string[] {\n const lines: string[] = [];\n\n if (data.rows.length === 0) {\n lines.push(` ${colors.dim}No data${RESET}`);\n return lines;\n }\n\n // Title\n if (view.title) {\n lines.push(` ${bold}${view.title}${RESET}`);\n lines.push('');\n }\n\n // Get columns from view definition or infer from data\n const columns: ColumnDefinition[] = view.columns || data.columns.map(c => ({ field: c }));\n\n // Render each row\n for (const row of data.rows) {\n const parts: string[] = [];\n\n for (const col of columns) {\n const value = row[col.field];\n let formatted = formatValue(value, col.format || 'string', col.truncate);\n\n // Apply label if this is the first column and we have a label defined\n if (col.label) {\n formatted = `${colors.dim}${col.label}:${RESET} ${formatted}`;\n }\n\n parts.push(formatted);\n }\n\n // Join with spacing\n lines.push(` ${parts.join(' ')}`);\n }\n\n return lines;\n}\n\n/**\n * Render list with detailed multi-line items\n */\nexport function renderDetailedList(\n view: ViewDefinition,\n data: QueryResult\n): string[] {\n const lines: string[] = [];\n\n if (data.rows.length === 0) {\n lines.push(` ${colors.dim}No data${RESET}`);\n return lines;\n }\n\n // Title\n if (view.title) {\n lines.push(` ${bold}${view.title}${RESET}`);\n lines.push('');\n }\n\n const columns: ColumnDefinition[] = view.columns || data.columns.map(c => ({ field: c }));\n\n // Render each row as a multi-line block\n for (let i = 0; i < data.rows.length; i++) {\n const row = data.rows[i];\n\n // First column as header\n if (columns.length > 0) {\n const mainCol = columns[0];\n const mainValue = formatValue(row[mainCol.field], mainCol.format || 'string');\n lines.push(` ${colors.cyan}${mainValue}${RESET}`);\n }\n\n // Remaining columns as details\n for (let j = 1; j < columns.length; j++) {\n const col = columns[j];\n const value = formatValue(row[col.field], col.format || 'string', col.truncate || 50);\n const label = col.label || col.field;\n lines.push(` ${colors.dim}${label}:${RESET} ${value}`);\n }\n\n // Add spacing between items\n if (i < data.rows.length - 1) {\n lines.push('');\n }\n }\n\n return lines;\n}\n\n/**\n * Render recent items with time-based header\n */\nexport function renderRecentList(\n view: ViewDefinition,\n data: QueryResult\n): string[] {\n const lines: string[] = [];\n\n if (data.rows.length === 0) {\n lines.push(` ${colors.dim}No recent items${RESET}`);\n return lines;\n }\n\n // Title\n if (view.title) {\n lines.push(` ${bold}${view.title}${RESET}`);\n lines.push('');\n }\n\n const columns = view.columns || [];\n\n // Find time column\n const timeCol = columns.find(c => c.format === 'relative_time' || c.field.includes('_at'));\n\n // Render each row\n for (const row of data.rows) {\n const parts: string[] = [];\n\n // Time first if present\n if (timeCol) {\n const timeVal = formatValue(row[timeCol.field], 'relative_time');\n parts.push(`${colors.dim}${timeVal}${RESET}`);\n }\n\n // Other columns\n for (const col of columns) {\n if (col === timeCol) continue;\n\n const value = row[col.field];\n const formatted = formatValue(value, col.format || 'string', col.truncate);\n parts.push(formatted);\n }\n\n lines.push(` ${parts.join(' ')}`);\n }\n\n return lines;\n}\n","/**\n * Renderer Index\n * Exports all renderers and provides a unified render function\n */\n\nimport type { ViewDefinition, MetricDefinition, DimensionDefinition, QueryResult } from '../types.js';\nimport { renderSummary } from './summary.js';\nimport { renderTable } from './table.js';\nimport { renderTrend, renderStackedTrend } from './trend.js';\nimport { renderBar, renderPie } from './bar.js';\nimport { renderList, renderRecentList } from './list.js';\nimport { colors, RESET } from './base.js';\n\nexport * from './base.js';\n\n/**\n * Render a view based on its type\n */\nexport function renderView(\n view: ViewDefinition,\n data: QueryResult,\n metricDefs: MetricDefinition[],\n dimensionDefs: DimensionDefinition[]\n): string[] {\n switch (view.type) {\n case 'summary':\n return renderSummary(view, data, metricDefs);\n\n case 'table':\n return renderTable(view, data, metricDefs, dimensionDefs);\n\n case 'trend':\n if (view.stacked) {\n return renderStackedTrend(view, data, metricDefs);\n }\n return renderTrend(view, data, metricDefs);\n\n case 'bar':\n return renderBar(view, data, metricDefs, dimensionDefs);\n\n case 'pie':\n return renderPie(view, data, metricDefs, dimensionDefs);\n\n case 'list': {\n // Detect if this looks like a recent items list\n const hasTimeCol = view.columns?.some(c =>\n c.format === 'relative_time' || c.field.includes('_at')\n );\n if (hasTimeCol) {\n return renderRecentList(view, data);\n }\n return renderList(view, data);\n }\n\n case 'histogram':\n // TODO: Implement histogram\n return [` ${colors.dim}Histogram not yet implemented${RESET}`];\n\n case 'heatmap':\n // TODO: Implement heatmap\n return [` ${colors.dim}Heatmap not yet implemented${RESET}`];\n\n default:\n return [` ${colors.dim}Unknown view type: ${view.type}${RESET}`];\n }\n}\n","/**\n * Dashboard Engine\n * Orchestrates loading definitions, fetching data, and rendering views\n */\n\nimport type {\n DashboardDefinition,\n ViewDefinition,\n QueryResult,\n AppliedFilters,\n DataSource,\n} from './types.js';\nimport { loadDashboard, listDashboards, findDashboard } from './loader.js';\nimport { postgresSource, buildQuery, buildWhereClause, parseDateRange } from './sources/postgres.js';\nimport { renderView, writeLine, colors, RESET, gradient } from './renderers/index.js';\n\nexport { loadDashboard, listDashboards, findDashboard } from './loader.js';\nexport * from './types.js';\n\n/**\n * Get the appropriate data source for a dashboard\n */\nfunction getDataSource(sourceName: string): DataSource | null {\n switch (sourceName) {\n case 'postgres':\n return postgresSource;\n // TODO: Add other sources\n case 'sessions':\n case 'langfuse':\n case 'api':\n return null;\n default:\n return null;\n }\n}\n\n/**\n * Execute a dashboard and return rendered output\n */\nexport async function executeDashboard(\n name: string,\n options: {\n filters?: AppliedFilters;\n views?: string[]; // Specific views to render (default: all)\n verbose?: boolean;\n } = {}\n): Promise<{ success: boolean; lines: string[] }> {\n const lines: string[] = [];\n\n // Load definition\n const def = findDashboard(name);\n if (!def) {\n return {\n success: false,\n lines: [`${colors.red}Dashboard not found: ${name}${RESET}`],\n };\n }\n\n // Get data source\n const source = getDataSource(def.source);\n if (!source) {\n return {\n success: false,\n lines: [`${colors.red}Data source not available: ${def.source}${RESET}`],\n };\n }\n\n // Check availability\n const available = await source.isAvailable();\n if (!available) {\n return {\n success: false,\n lines: [`${colors.red}Cannot connect to ${def.source}${RESET}`],\n };\n }\n\n // Apply default filters\n const filters = { ...options.filters };\n for (const filterDef of def.filters || []) {\n if (filters[filterDef.name] === undefined && filterDef.default) {\n if (filterDef.type === 'date_range') {\n filters[filterDef.name] = parseDateRange(filterDef.default as string);\n } else {\n filters[filterDef.name] = filterDef.default;\n }\n }\n }\n\n // Header\n lines.push('');\n lines.push(` ${gradient('squads')} ${colors.dim}${def.title}${RESET}`);\n if (def.description && options.verbose) {\n lines.push(` ${colors.dim}${def.description}${RESET}`);\n }\n lines.push('');\n\n // Determine which views to render\n const viewsToRender = options.views\n ? def.views.filter(v => options.views!.includes(v.id))\n : def.views;\n\n // Execute each view\n for (const view of viewsToRender) {\n try {\n const data = await fetchViewData(def, view, filters, source);\n const viewLines = renderView(view, data, def.metrics, def.dimensions || []);\n lines.push(...viewLines);\n lines.push('');\n } catch (err) {\n if (options.verbose) {\n lines.push(` ${colors.red}Error rendering ${view.id}: ${err}${RESET}`);\n }\n }\n }\n\n // Cleanup\n await source.close();\n\n return { success: true, lines };\n}\n\n/**\n * Fetch data for a specific view\n */\nasync function fetchViewData(\n def: DashboardDefinition,\n view: ViewDefinition,\n filters: AppliedFilters,\n source: DataSource\n): Promise<QueryResult> {\n // If view has custom source SQL, use it directly\n if (view.source) {\n return source.query(view.source);\n }\n\n // Build query from definition\n if (!def.table) {\n throw new Error('Dashboard requires table or view.source');\n }\n\n // Get metrics for this view\n const metrics = (view.metrics || []).map(name => {\n const m = def.metrics.find(m => m.name === name);\n if (!m) throw new Error(`Unknown metric: ${name}`);\n return m;\n });\n\n // Build WHERE clause\n const filterDefs = def.filters || [];\n let where = buildWhereClause(filters, filterDefs);\n\n // Add view-specific filter\n if (view.filter) {\n where = where ? `(${where}) AND (${view.filter})` : view.filter;\n }\n\n // Build and execute query\n const sql = buildQuery(\n def.table,\n metrics,\n view.group_by,\n where ?? undefined,\n view.sort,\n view.limit\n );\n\n return source.query(sql);\n}\n\n/**\n * Render a dashboard to the terminal\n */\nexport async function renderDashboard(\n name: string,\n options: {\n filters?: AppliedFilters;\n views?: string[];\n verbose?: boolean;\n } = {}\n): Promise<boolean> {\n const result = await executeDashboard(name, options);\n\n for (const line of result.lines) {\n writeLine(line);\n }\n\n return result.success;\n}\n\n/**\n * List all available dashboards with descriptions\n */\nexport function showAvailableDashboards(): void {\n const names = listDashboards();\n\n writeLine();\n writeLine(` ${gradient('squads')} ${colors.dim}dashboards${RESET}`);\n writeLine();\n\n if (names.length === 0) {\n writeLine(` ${colors.dim}No dashboards found${RESET}`);\n writeLine(` ${colors.dim}Create dashboards in .agents/dashboards/*.yaml${RESET}`);\n writeLine();\n return;\n }\n\n for (const name of names) {\n const def = loadDashboard(name);\n if (def) {\n writeLine(` ${colors.cyan}${name.padEnd(16)}${RESET} ${colors.dim}${def.title}${RESET}`);\n }\n }\n\n writeLine();\n writeLine(` ${colors.dim}Usage:${RESET} squads dash ${colors.cyan}<dashboard>${RESET}`);\n writeLine(` ${colors.dim} squads dash ${colors.cyan}<dashboard>${RESET} ${colors.dim}--view=<view-id>${RESET}`);\n writeLine();\n}\n\n/**\n * Interactive dashboard with filter support\n */\nexport async function interactiveDashboard(\n name: string,\n initialFilters?: AppliedFilters\n): Promise<void> {\n // For now, just render the dashboard\n // TODO: Add interactive filter selection\n await renderDashboard(name, { filters: initialFilters });\n}\n"],"mappings":"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","names":["require","m"]}
|
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
findProjectRoot
|
|
4
|
+
} from "./chunk-LDM62TIX.js";
|
|
5
|
+
import {
|
|
6
|
+
RESET,
|
|
7
|
+
colors,
|
|
8
|
+
gradient,
|
|
9
|
+
padEnd,
|
|
10
|
+
writeLine
|
|
11
|
+
} from "./chunk-N7KDWU4W.js";
|
|
12
|
+
import "./chunk-7OCVIDC7.js";
|
|
13
|
+
|
|
14
|
+
// src/commands/doctor.ts
|
|
15
|
+
import { execSync } from "child_process";
|
|
16
|
+
import { existsSync } from "fs";
|
|
17
|
+
import { join } from "path";
|
|
18
|
+
var TOOLS = [
|
|
19
|
+
// Core — squads won't work well without these
|
|
20
|
+
{
|
|
21
|
+
name: "claude",
|
|
22
|
+
command: "claude",
|
|
23
|
+
versionFlag: "--version",
|
|
24
|
+
category: "core",
|
|
25
|
+
purpose: "AI agent execution engine",
|
|
26
|
+
installHint: "npm install -g @anthropic-ai/claude-code",
|
|
27
|
+
unlocks: "Agent execution (required)"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
name: "git",
|
|
31
|
+
command: "git",
|
|
32
|
+
versionFlag: "--version",
|
|
33
|
+
category: "core",
|
|
34
|
+
purpose: "Version control and state management",
|
|
35
|
+
installHint: "xcode-select --install (macOS) or apt install git",
|
|
36
|
+
unlocks: "Squad memory, conversation transcripts, PR workflows"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: "node",
|
|
40
|
+
command: "node",
|
|
41
|
+
versionFlag: "--version",
|
|
42
|
+
category: "core",
|
|
43
|
+
purpose: "JavaScript runtime",
|
|
44
|
+
installHint: "https://nodejs.org or nvm install --lts",
|
|
45
|
+
unlocks: "CLI execution, build tools"
|
|
46
|
+
},
|
|
47
|
+
// Recommended — significantly better experience
|
|
48
|
+
{
|
|
49
|
+
name: "gh",
|
|
50
|
+
command: "gh",
|
|
51
|
+
versionFlag: "--version",
|
|
52
|
+
category: "recommended",
|
|
53
|
+
purpose: "GitHub CLI for issues, PRs, and repos",
|
|
54
|
+
installHint: "brew install gh && gh auth login",
|
|
55
|
+
unlocks: "Issue tracking, PR workflows, cross-repo coordination"
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
name: "python3",
|
|
59
|
+
command: "python3",
|
|
60
|
+
versionFlag: "--version",
|
|
61
|
+
category: "recommended",
|
|
62
|
+
purpose: "Python runtime for data and API agents",
|
|
63
|
+
installHint: "brew install python3 or https://python.org",
|
|
64
|
+
unlocks: "Data analysis, API integrations, ML workflows"
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
name: "jq",
|
|
68
|
+
command: "jq",
|
|
69
|
+
versionFlag: "--version",
|
|
70
|
+
category: "recommended",
|
|
71
|
+
purpose: "JSON processor for API responses",
|
|
72
|
+
installHint: "brew install jq or apt install jq",
|
|
73
|
+
unlocks: "API response parsing, data extraction"
|
|
74
|
+
},
|
|
75
|
+
// Optional — enhance specific agent capabilities
|
|
76
|
+
{
|
|
77
|
+
name: "curl",
|
|
78
|
+
command: "curl",
|
|
79
|
+
versionFlag: "--version",
|
|
80
|
+
category: "optional",
|
|
81
|
+
purpose: "HTTP requests for API integrations",
|
|
82
|
+
installHint: "Usually pre-installed on macOS/Linux",
|
|
83
|
+
unlocks: "Slack notifications, webhook integrations, API calls"
|
|
84
|
+
}
|
|
85
|
+
];
|
|
86
|
+
function checkTool(tool) {
|
|
87
|
+
try {
|
|
88
|
+
const output = execSync(`${tool.command} ${tool.versionFlag} 2>&1`, {
|
|
89
|
+
encoding: "utf-8",
|
|
90
|
+
timeout: 5e3,
|
|
91
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
92
|
+
});
|
|
93
|
+
const version = output.trim().split("\n")[0].replace(/^[^0-9]*/, "").trim();
|
|
94
|
+
return { tool, installed: true, version: version.slice(0, 30) };
|
|
95
|
+
} catch {
|
|
96
|
+
return { tool, installed: false };
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function checkAuth() {
|
|
100
|
+
const results = [];
|
|
101
|
+
try {
|
|
102
|
+
const hasApiKey = !!process.env.ANTHROPIC_API_KEY;
|
|
103
|
+
if (hasApiKey) {
|
|
104
|
+
results.push({ name: "Claude", authenticated: true, detail: "API key" });
|
|
105
|
+
} else {
|
|
106
|
+
try {
|
|
107
|
+
const whoami = execSync("claude whoami 2>&1", { encoding: "utf-8", timeout: 5e3 });
|
|
108
|
+
const emailMatch = whoami.match(/[\w.+-]+@[\w.-]+/);
|
|
109
|
+
const email = emailMatch ? emailMatch[0] : "OAuth";
|
|
110
|
+
results.push({ name: "Claude", authenticated: true, detail: email });
|
|
111
|
+
} catch {
|
|
112
|
+
results.push({ name: "Claude", authenticated: true, detail: "OAuth" });
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
} catch {
|
|
116
|
+
results.push({ name: "Claude", authenticated: false });
|
|
117
|
+
}
|
|
118
|
+
try {
|
|
119
|
+
execSync("gh auth status 2>&1", { encoding: "utf-8", timeout: 5e3 });
|
|
120
|
+
results.push({ name: "GitHub", authenticated: true });
|
|
121
|
+
} catch (err) {
|
|
122
|
+
const output = err.stderr || "";
|
|
123
|
+
if (output.includes("Logged in")) {
|
|
124
|
+
results.push({ name: "GitHub", authenticated: true });
|
|
125
|
+
} else {
|
|
126
|
+
results.push({ name: "GitHub", authenticated: false, detail: "Run: gh auth login" });
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
try {
|
|
130
|
+
const output = execSync("gcloud config get-value account 2>/dev/null", {
|
|
131
|
+
encoding: "utf-8",
|
|
132
|
+
timeout: 5e3
|
|
133
|
+
});
|
|
134
|
+
const account = output.trim();
|
|
135
|
+
if (account && account !== "(unset)") {
|
|
136
|
+
results.push({ name: "GCP", authenticated: true, detail: account });
|
|
137
|
+
} else {
|
|
138
|
+
results.push({ name: "GCP", authenticated: false, detail: "gcloud auth login" });
|
|
139
|
+
}
|
|
140
|
+
} catch {
|
|
141
|
+
}
|
|
142
|
+
return results;
|
|
143
|
+
}
|
|
144
|
+
function checkProject() {
|
|
145
|
+
const root = findProjectRoot();
|
|
146
|
+
if (!root) {
|
|
147
|
+
return { hasProject: false };
|
|
148
|
+
}
|
|
149
|
+
const squadsDir = join(root, ".agents", "squads");
|
|
150
|
+
let squadCount = 0;
|
|
151
|
+
let agentCount = 0;
|
|
152
|
+
if (existsSync(squadsDir)) {
|
|
153
|
+
try {
|
|
154
|
+
const entries = execSync(`ls -d ${squadsDir}/*/SQUAD.md 2>/dev/null | wc -l`, {
|
|
155
|
+
encoding: "utf-8",
|
|
156
|
+
timeout: 3e3
|
|
157
|
+
});
|
|
158
|
+
squadCount = parseInt(entries.trim()) || 0;
|
|
159
|
+
const agents = execSync(`find ${squadsDir} -name "*.md" ! -name "SQUAD.md" 2>/dev/null | wc -l`, {
|
|
160
|
+
encoding: "utf-8",
|
|
161
|
+
timeout: 3e3
|
|
162
|
+
});
|
|
163
|
+
agentCount = parseInt(agents.trim()) || 0;
|
|
164
|
+
} catch {
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
const memoryDir = join(root, ".agents", "memory");
|
|
168
|
+
const convDir = join(root, ".agents", "conversations");
|
|
169
|
+
return {
|
|
170
|
+
hasProject: true,
|
|
171
|
+
squadsDir: root,
|
|
172
|
+
squadCount,
|
|
173
|
+
agentCount,
|
|
174
|
+
hasMemory: existsSync(memoryDir),
|
|
175
|
+
hasConversations: existsSync(convDir)
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
function checkRunningSquads() {
|
|
179
|
+
try {
|
|
180
|
+
const output = execSync("ps aux 2>/dev/null", { encoding: "utf-8", timeout: 3e3 });
|
|
181
|
+
const results = [];
|
|
182
|
+
for (const line of output.split("\n")) {
|
|
183
|
+
if (!line.includes("squads run") || line.includes("grep")) continue;
|
|
184
|
+
const parts = line.trim().split(/\s+/);
|
|
185
|
+
const pid = parts[1];
|
|
186
|
+
const fullCmd = parts.slice(10).join(" ");
|
|
187
|
+
const squadMatch = fullCmd.match(/squads\s+run\s+(\S+)/);
|
|
188
|
+
if (!squadMatch) continue;
|
|
189
|
+
const squad = squadMatch[1];
|
|
190
|
+
const taskMatch = fullCmd.match(/--task\s+(.+?)(?:\s+--|$)/);
|
|
191
|
+
const task = taskMatch ? taskMatch[1].replace(/^["']|["']$/g, "") : void 0;
|
|
192
|
+
const timeCol = parts[9];
|
|
193
|
+
let elapsed;
|
|
194
|
+
if (timeCol && timeCol.includes(":")) {
|
|
195
|
+
const timeParts = timeCol.split(":").map(Number);
|
|
196
|
+
if (timeParts.length === 2 && timeParts.every((n) => !isNaN(n))) {
|
|
197
|
+
const totalMins = timeParts[0];
|
|
198
|
+
elapsed = totalMins < 60 ? `${totalMins}m` : `${Math.floor(totalMins / 60)}h${totalMins % 60}m`;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
results.push({ squad, pid, elapsed, task });
|
|
202
|
+
}
|
|
203
|
+
return results;
|
|
204
|
+
} catch {
|
|
205
|
+
return [];
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
function checkDaemon() {
|
|
209
|
+
try {
|
|
210
|
+
const output = execSync("ps aux 2>/dev/null", { encoding: "utf-8", timeout: 3e3 });
|
|
211
|
+
for (const line of output.split("\n")) {
|
|
212
|
+
if (line.includes("squads autonomous") && !line.includes("grep")) {
|
|
213
|
+
const pid = line.trim().split(/\s+/)[1];
|
|
214
|
+
let routines = 0;
|
|
215
|
+
try {
|
|
216
|
+
const root = findProjectRoot();
|
|
217
|
+
if (root) {
|
|
218
|
+
const count = execSync(
|
|
219
|
+
`grep -r "schedule:" ${join(root, ".agents", "squads")}/*/SQUAD.md 2>/dev/null | wc -l`,
|
|
220
|
+
{ encoding: "utf-8", timeout: 3e3 }
|
|
221
|
+
);
|
|
222
|
+
routines = parseInt(count.trim()) || 0;
|
|
223
|
+
}
|
|
224
|
+
} catch {
|
|
225
|
+
}
|
|
226
|
+
return { running: true, pid, routines };
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return { running: false };
|
|
230
|
+
} catch {
|
|
231
|
+
return { running: false };
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
function getRecentTranscripts(projectRoot) {
|
|
235
|
+
try {
|
|
236
|
+
const convDir = join(projectRoot, ".agents", "conversations");
|
|
237
|
+
if (!existsSync(convDir)) return [];
|
|
238
|
+
const output = execSync(
|
|
239
|
+
`find ${convDir} -name "*.md" -mmin -1440 -exec stat -f "%m %N" {} + 2>/dev/null | sort -rn | head -10`,
|
|
240
|
+
{ encoding: "utf-8", timeout: 5e3 }
|
|
241
|
+
);
|
|
242
|
+
const results = [];
|
|
243
|
+
for (const line of output.trim().split("\n")) {
|
|
244
|
+
if (!line.trim()) continue;
|
|
245
|
+
const [timestamp, filePath] = line.trim().split(" ", 2);
|
|
246
|
+
if (!filePath) continue;
|
|
247
|
+
const pathParts = filePath.split("/");
|
|
248
|
+
const squad = pathParts[pathParts.length - 2];
|
|
249
|
+
const file = pathParts[pathParts.length - 1];
|
|
250
|
+
let turns = "?";
|
|
251
|
+
let cost = "?";
|
|
252
|
+
try {
|
|
253
|
+
const head = execSync(`head -5 "${filePath}" 2>/dev/null`, { encoding: "utf-8", timeout: 2e3 });
|
|
254
|
+
const turnsMatch = head.match(/Turns:\s*(\d+)/);
|
|
255
|
+
const costMatch = head.match(/cost:\s*\$?([\d.]+)/);
|
|
256
|
+
if (turnsMatch) turns = turnsMatch[1];
|
|
257
|
+
if (costMatch) cost = costMatch[1];
|
|
258
|
+
} catch {
|
|
259
|
+
}
|
|
260
|
+
const secs = Math.floor(Date.now() / 1e3 - parseInt(timestamp));
|
|
261
|
+
let ago;
|
|
262
|
+
if (secs < 60) ago = "just now";
|
|
263
|
+
else if (secs < 3600) ago = `${Math.floor(secs / 60)}m ago`;
|
|
264
|
+
else if (secs < 86400) ago = `${Math.floor(secs / 3600)}h ago`;
|
|
265
|
+
else ago = `${Math.floor(secs / 86400)}d ago`;
|
|
266
|
+
results.push({ squad, file, ago, turns, cost });
|
|
267
|
+
}
|
|
268
|
+
return results;
|
|
269
|
+
} catch {
|
|
270
|
+
return [];
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
async function doctorCommand(options = {}) {
|
|
274
|
+
writeLine();
|
|
275
|
+
writeLine(` ${gradient("squads")} ${colors.dim}doctor${RESET}`);
|
|
276
|
+
writeLine();
|
|
277
|
+
const toolResults = TOOLS.map(checkTool);
|
|
278
|
+
const core = toolResults.filter((r) => r.tool.category === "core");
|
|
279
|
+
const recommended = toolResults.filter((r) => r.tool.category === "recommended");
|
|
280
|
+
const optional = toolResults.filter((r) => r.tool.category === "optional");
|
|
281
|
+
const coreInstalled = core.filter((r) => r.installed).length;
|
|
282
|
+
const authResults = checkAuth();
|
|
283
|
+
const project = checkProject();
|
|
284
|
+
const running = checkRunningSquads();
|
|
285
|
+
const daemon = checkDaemon();
|
|
286
|
+
const recentTranscripts = project.hasProject ? getRecentTranscripts(project.squadsDir) : [];
|
|
287
|
+
function printTools(label, items) {
|
|
288
|
+
const count = items.filter((r) => r.installed).length;
|
|
289
|
+
writeLine(` ${colors.dim}${label}${RESET} ${colors.dim}(${count}/${items.length})${RESET}`);
|
|
290
|
+
for (const r of items) {
|
|
291
|
+
const icon = r.installed ? `${colors.green}\u2713${RESET}` : `${colors.red}\u2717${RESET}`;
|
|
292
|
+
const ver = r.installed && r.version ? ` ${colors.dim}${r.version.slice(0, 20)}${RESET}` : "";
|
|
293
|
+
const hint = !r.installed ? ` ${colors.dim}\u2192 ${r.tool.unlocks}${RESET}` : "";
|
|
294
|
+
writeLine(` ${icon} ${colors.cyan}${padEnd(r.tool.name, 10)}${RESET}${r.tool.purpose}${ver}${hint}`);
|
|
295
|
+
if (!r.installed && options.verbose) {
|
|
296
|
+
writeLine(` ${colors.dim}$ ${r.tool.installHint}${RESET}`);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
printTools("Core", core);
|
|
301
|
+
printTools("Recommended", recommended);
|
|
302
|
+
if (options.verbose || optional.some((r) => r.installed)) {
|
|
303
|
+
printTools("Optional", optional);
|
|
304
|
+
}
|
|
305
|
+
writeLine();
|
|
306
|
+
const authLine = authResults.map((a) => {
|
|
307
|
+
const icon = a.authenticated ? `${colors.green}\u2713${RESET}` : `${colors.red}\u2717${RESET}`;
|
|
308
|
+
const detail = a.detail ? ` ${colors.dim}(${a.detail})${RESET}` : "";
|
|
309
|
+
return `${icon} ${a.name}${detail}`;
|
|
310
|
+
}).join(" ");
|
|
311
|
+
writeLine(` ${authLine}`);
|
|
312
|
+
writeLine();
|
|
313
|
+
if (project.hasProject) {
|
|
314
|
+
writeLine(` ${colors.cyan}${project.squadCount}${RESET} squads ${colors.dim}\u2502${RESET} ${colors.cyan}${project.agentCount}${RESET} agents ${colors.dim}\u2502${RESET} ${colors.dim}${project.squadsDir}${RESET}`);
|
|
315
|
+
} else {
|
|
316
|
+
writeLine(` ${colors.yellow}\u25CB${RESET} No project found ${colors.dim}\u2014 squads init${RESET}`);
|
|
317
|
+
}
|
|
318
|
+
writeLine();
|
|
319
|
+
const daemonStatus = daemon.running ? `${colors.green}\u2713${RESET} daemon` : `${colors.dim}\u25CB daemon off${RESET}`;
|
|
320
|
+
const runCount = running.length > 0 ? `${colors.green}${running.length}${RESET} running` : `${colors.dim}0 running${RESET}`;
|
|
321
|
+
writeLine(` ${daemonStatus} ${colors.dim}\u2502${RESET} ${runCount}`);
|
|
322
|
+
for (const r of running) {
|
|
323
|
+
const task = r.task ? `${colors.dim}${r.task.slice(0, 50)}${RESET}` : "";
|
|
324
|
+
writeLine(` ${colors.green}\u25B8${RESET} ${colors.cyan}${r.squad}${RESET} ${task}`);
|
|
325
|
+
}
|
|
326
|
+
if (recentTranscripts.length > 0) {
|
|
327
|
+
writeLine();
|
|
328
|
+
for (const t of recentTranscripts.slice(0, 5)) {
|
|
329
|
+
writeLine(` ${colors.dim}${padEnd(t.ago, 9)}${RESET} ${colors.cyan}${padEnd(t.squad, 13)}${RESET} ${colors.dim}${t.turns} turns ~$${t.cost}${RESET}`);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
writeLine();
|
|
333
|
+
if (coreInstalled === core.length && project.hasProject) {
|
|
334
|
+
writeLine(` ${colors.green}\u2713 Ready${RESET}`);
|
|
335
|
+
} else if (coreInstalled === core.length) {
|
|
336
|
+
writeLine(` ${colors.yellow}\u25CB Run: squads init${RESET}`);
|
|
337
|
+
} else {
|
|
338
|
+
const missing = core.filter((r) => !r.installed).map((r) => r.tool.name);
|
|
339
|
+
writeLine(` ${colors.red}\u2717 Missing: ${missing.join(", ")}${RESET}`);
|
|
340
|
+
}
|
|
341
|
+
writeLine();
|
|
342
|
+
}
|
|
343
|
+
export {
|
|
344
|
+
doctorCommand
|
|
345
|
+
};
|
|
346
|
+
//# sourceMappingURL=doctor-RG75M5RO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/doctor.ts"],"sourcesContent":["/**\n * squads doctor - Check local environment readiness\n *\n * Detects what tools are installed, what's missing, and what capabilities\n * the user has. Helps new users understand what they can do right now\n * vs what needs setup.\n */\n\nimport { execSync } from 'child_process';\nimport { existsSync } from 'fs';\nimport { join } from 'path';\nimport { homedir } from 'os';\nimport {\n colors,\n RESET,\n bold,\n gradient,\n icons,\n writeLine,\n padEnd,\n} from '../lib/terminal.js';\nimport { findProjectRoot } from '../lib/squad-parser.js';\n\n// Tool categories — ordered by importance for new users\ninterface Tool {\n name: string;\n command: string; // Command to check existence\n versionFlag: string; // Flag to get version\n category: 'core' | 'recommended' | 'optional';\n purpose: string;\n installHint: string;\n unlocks: string; // What capabilities this enables\n}\n\nconst TOOLS: Tool[] = [\n // Core — squads won't work well without these\n {\n name: 'claude',\n command: 'claude',\n versionFlag: '--version',\n category: 'core',\n purpose: 'AI agent execution engine',\n installHint: 'npm install -g @anthropic-ai/claude-code',\n unlocks: 'Agent execution (required)',\n },\n {\n name: 'git',\n command: 'git',\n versionFlag: '--version',\n category: 'core',\n purpose: 'Version control and state management',\n installHint: 'xcode-select --install (macOS) or apt install git',\n unlocks: 'Squad memory, conversation transcripts, PR workflows',\n },\n {\n name: 'node',\n command: 'node',\n versionFlag: '--version',\n category: 'core',\n purpose: 'JavaScript runtime',\n installHint: 'https://nodejs.org or nvm install --lts',\n unlocks: 'CLI execution, build tools',\n },\n\n // Recommended — significantly better experience\n {\n name: 'gh',\n command: 'gh',\n versionFlag: '--version',\n category: 'recommended',\n purpose: 'GitHub CLI for issues, PRs, and repos',\n installHint: 'brew install gh && gh auth login',\n unlocks: 'Issue tracking, PR workflows, cross-repo coordination',\n },\n {\n name: 'python3',\n command: 'python3',\n versionFlag: '--version',\n category: 'recommended',\n purpose: 'Python runtime for data and API agents',\n installHint: 'brew install python3 or https://python.org',\n unlocks: 'Data analysis, API integrations, ML workflows',\n },\n {\n name: 'jq',\n command: 'jq',\n versionFlag: '--version',\n category: 'recommended',\n purpose: 'JSON processor for API responses',\n installHint: 'brew install jq or apt install jq',\n unlocks: 'API response parsing, data extraction',\n },\n\n // Optional — enhance specific agent capabilities\n {\n name: 'curl',\n command: 'curl',\n versionFlag: '--version',\n category: 'optional',\n purpose: 'HTTP requests for API integrations',\n installHint: 'Usually pre-installed on macOS/Linux',\n unlocks: 'Slack notifications, webhook integrations, API calls',\n },\n];\n\ninterface ToolResult {\n tool: Tool;\n installed: boolean;\n version?: string;\n error?: string;\n}\n\ninterface AuthResult {\n name: string;\n authenticated: boolean;\n detail?: string;\n}\n\nfunction checkTool(tool: Tool): ToolResult {\n try {\n const output = execSync(`${tool.command} ${tool.versionFlag} 2>&1`, {\n encoding: 'utf-8',\n timeout: 5000,\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n // Extract version from first line\n const version = output.trim().split('\\n')[0].replace(/^[^0-9]*/, '').trim();\n return { tool, installed: true, version: version.slice(0, 30) };\n } catch {\n return { tool, installed: false };\n }\n}\n\nfunction checkAuth(): AuthResult[] {\n const results: AuthResult[] = [];\n\n // Claude auth — detect method and account\n try {\n const hasApiKey = !!process.env.ANTHROPIC_API_KEY;\n if (hasApiKey) {\n results.push({ name: 'Claude', authenticated: true, detail: 'API key' });\n } else {\n // Check whoami for account info\n try {\n const whoami = execSync('claude whoami 2>&1', { encoding: 'utf-8', timeout: 5000 });\n const emailMatch = whoami.match(/[\\w.+-]+@[\\w.-]+/);\n const email = emailMatch ? emailMatch[0] : 'OAuth';\n results.push({ name: 'Claude', authenticated: true, detail: email });\n } catch {\n results.push({ name: 'Claude', authenticated: true, detail: 'OAuth' });\n }\n }\n } catch {\n results.push({ name: 'Claude', authenticated: false });\n }\n\n // GitHub auth\n try {\n execSync('gh auth status 2>&1', { encoding: 'utf-8', timeout: 5000 });\n results.push({ name: 'GitHub', authenticated: true });\n } catch (err) {\n const output = (err as { stdout?: string; stderr?: string }).stderr || '';\n if (output.includes('Logged in')) {\n results.push({ name: 'GitHub', authenticated: true });\n } else {\n results.push({ name: 'GitHub', authenticated: false, detail: 'Run: gh auth login' });\n }\n }\n\n // Google Cloud auth — show active account\n try {\n const output = execSync('gcloud config get-value account 2>/dev/null', {\n encoding: 'utf-8',\n timeout: 5000,\n });\n const account = output.trim();\n if (account && account !== '(unset)') {\n results.push({ name: 'GCP', authenticated: true, detail: account });\n } else {\n results.push({ name: 'GCP', authenticated: false, detail: 'gcloud auth login' });\n }\n } catch {\n // gcloud not installed — skip\n }\n\n return results;\n}\n\ninterface ProjectResult {\n hasProject: boolean;\n squadsDir?: string;\n squadCount?: number;\n agentCount?: number;\n hasMemory?: boolean;\n hasConversations?: boolean;\n}\n\nfunction checkProject(): ProjectResult {\n const root = findProjectRoot();\n if (!root) {\n return { hasProject: false };\n }\n\n const squadsDir = join(root, '.agents', 'squads');\n let squadCount = 0;\n let agentCount = 0;\n\n if (existsSync(squadsDir)) {\n try {\n const entries = execSync(`ls -d ${squadsDir}/*/SQUAD.md 2>/dev/null | wc -l`, {\n encoding: 'utf-8',\n timeout: 3000,\n });\n squadCount = parseInt(entries.trim()) || 0;\n\n const agents = execSync(`find ${squadsDir} -name \"*.md\" ! -name \"SQUAD.md\" 2>/dev/null | wc -l`, {\n encoding: 'utf-8',\n timeout: 3000,\n });\n agentCount = parseInt(agents.trim()) || 0;\n } catch { /* ignore */ }\n }\n\n const memoryDir = join(root, '.agents', 'memory');\n const convDir = join(root, '.agents', 'conversations');\n\n return {\n hasProject: true,\n squadsDir: root,\n squadCount,\n agentCount,\n hasMemory: existsSync(memoryDir),\n hasConversations: existsSync(convDir),\n };\n}\n\ninterface RunningSquad {\n squad: string;\n pid: string;\n elapsed?: string;\n task?: string;\n}\n\nfunction checkRunningSquads(): RunningSquad[] {\n try {\n const output = execSync('ps aux 2>/dev/null', { encoding: 'utf-8', timeout: 3000 });\n const results: RunningSquad[] = [];\n\n for (const line of output.split('\\n')) {\n if (!line.includes('squads run') || line.includes('grep')) continue;\n\n const parts = line.trim().split(/\\s+/);\n const pid = parts[1];\n const fullCmd = parts.slice(10).join(' ');\n\n // Extract squad name from \"squads run <squad>\"\n const squadMatch = fullCmd.match(/squads\\s+run\\s+(\\S+)/);\n if (!squadMatch) continue;\n\n const squad = squadMatch[1];\n\n // Extract task if present\n const taskMatch = fullCmd.match(/--task\\s+(.+?)(?:\\s+--|$)/);\n const task = taskMatch ? taskMatch[1].replace(/^[\"']|[\"']$/g, '') : undefined;\n\n // Calculate elapsed from CPU time column (more reliable than START)\n const timeCol = parts[9]; // TIME column (mm:ss or h:mm:ss)\n let elapsed: string | undefined;\n if (timeCol && timeCol.includes(':')) {\n const timeParts = timeCol.split(':').map(Number);\n if (timeParts.length === 2 && timeParts.every(n => !isNaN(n))) {\n const totalMins = timeParts[0];\n elapsed = totalMins < 60 ? `${totalMins}m` : `${Math.floor(totalMins / 60)}h${totalMins % 60}m`;\n }\n }\n\n results.push({ squad, pid, elapsed, task });\n }\n\n return results;\n } catch {\n return [];\n }\n}\n\nfunction checkDaemon(): { running: boolean; pid?: string; routines?: number } {\n try {\n const output = execSync('ps aux 2>/dev/null', { encoding: 'utf-8', timeout: 3000 });\n for (const line of output.split('\\n')) {\n if (line.includes('squads autonomous') && !line.includes('grep')) {\n const pid = line.trim().split(/\\s+/)[1];\n // Try to count routines\n let routines = 0;\n try {\n const root = findProjectRoot();\n if (root) {\n const count = execSync(\n `grep -r \"schedule:\" ${join(root, '.agents', 'squads')}/*/SQUAD.md 2>/dev/null | wc -l`,\n { encoding: 'utf-8', timeout: 3000 }\n );\n routines = parseInt(count.trim()) || 0;\n }\n } catch { /* ignore */ }\n return { running: true, pid, routines };\n }\n }\n return { running: false };\n } catch {\n return { running: false };\n }\n}\n\ninterface RecentTranscript {\n squad: string;\n file: string;\n ago: string;\n turns: string;\n cost: string;\n}\n\nfunction getRecentTranscripts(projectRoot: string): RecentTranscript[] {\n try {\n const convDir = join(projectRoot, '.agents', 'conversations');\n if (!existsSync(convDir)) return [];\n\n const output = execSync(\n `find ${convDir} -name \"*.md\" -mmin -1440 -exec stat -f \"%m %N\" {} + 2>/dev/null | sort -rn | head -10`,\n { encoding: 'utf-8', timeout: 5000 }\n );\n\n const results: RecentTranscript[] = [];\n for (const line of output.trim().split('\\n')) {\n if (!line.trim()) continue;\n const [timestamp, filePath] = line.trim().split(' ', 2);\n if (!filePath) continue;\n\n const pathParts = filePath.split('/');\n const squad = pathParts[pathParts.length - 2];\n const file = pathParts[pathParts.length - 1];\n\n // Read first few lines for metadata\n let turns = '?';\n let cost = '?';\n try {\n const head = execSync(`head -5 \"${filePath}\" 2>/dev/null`, { encoding: 'utf-8', timeout: 2000 });\n const turnsMatch = head.match(/Turns:\\s*(\\d+)/);\n const costMatch = head.match(/cost:\\s*\\$?([\\d.]+)/);\n if (turnsMatch) turns = turnsMatch[1];\n if (costMatch) cost = costMatch[1];\n } catch { /* ignore */ }\n\n // Time ago\n const secs = Math.floor(Date.now() / 1000 - parseInt(timestamp));\n let ago: string;\n if (secs < 60) ago = 'just now';\n else if (secs < 3600) ago = `${Math.floor(secs / 60)}m ago`;\n else if (secs < 86400) ago = `${Math.floor(secs / 3600)}h ago`;\n else ago = `${Math.floor(secs / 86400)}d ago`;\n\n results.push({ squad, file, ago, turns, cost });\n }\n\n return results;\n } catch {\n return [];\n }\n}\n\nexport interface DoctorOptions {\n verbose?: boolean;\n}\n\nexport async function doctorCommand(options: DoctorOptions = {}): Promise<void> {\n writeLine();\n writeLine(` ${gradient('squads')} ${colors.dim}doctor${RESET}`);\n writeLine();\n\n // Gather all data\n const toolResults = TOOLS.map(checkTool);\n const core = toolResults.filter(r => r.tool.category === 'core');\n const recommended = toolResults.filter(r => r.tool.category === 'recommended');\n const optional = toolResults.filter(r => r.tool.category === 'optional');\n const coreInstalled = core.filter(r => r.installed).length;\n const authResults = checkAuth();\n const project = checkProject();\n const running = checkRunningSquads();\n const daemon = checkDaemon();\n const recentTranscripts = project.hasProject ? getRecentTranscripts(project.squadsDir!) : [];\n\n // === TOOLS ===\n function printTools(label: string, items: ToolResult[]) {\n const count = items.filter(r => r.installed).length;\n writeLine(` ${colors.dim}${label}${RESET} ${colors.dim}(${count}/${items.length})${RESET}`);\n for (const r of items) {\n const icon = r.installed ? `${colors.green}✓${RESET}` : `${colors.red}✗${RESET}`;\n const ver = r.installed && r.version ? ` ${colors.dim}${r.version.slice(0, 20)}${RESET}` : '';\n const hint = !r.installed ? ` ${colors.dim}→ ${r.tool.unlocks}${RESET}` : '';\n writeLine(` ${icon} ${colors.cyan}${padEnd(r.tool.name, 10)}${RESET}${r.tool.purpose}${ver}${hint}`);\n if (!r.installed && options.verbose) {\n writeLine(` ${colors.dim}$ ${r.tool.installHint}${RESET}`);\n }\n }\n }\n\n printTools('Core', core);\n printTools('Recommended', recommended);\n if (options.verbose || optional.some(r => r.installed)) {\n printTools('Optional', optional);\n }\n writeLine();\n\n // === AUTH ===\n const authLine = authResults.map(a => {\n const icon = a.authenticated ? `${colors.green}✓${RESET}` : `${colors.red}✗${RESET}`;\n const detail = a.detail ? ` ${colors.dim}(${a.detail})${RESET}` : '';\n return `${icon} ${a.name}${detail}`;\n }).join(' ');\n writeLine(` ${authLine}`);\n writeLine();\n\n // === PROJECT ===\n if (project.hasProject) {\n writeLine(` ${colors.cyan}${project.squadCount}${RESET} squads ${colors.dim}│${RESET} ${colors.cyan}${project.agentCount}${RESET} agents ${colors.dim}│${RESET} ${colors.dim}${project.squadsDir}${RESET}`);\n } else {\n writeLine(` ${colors.yellow}○${RESET} No project found ${colors.dim}— squads init${RESET}`);\n }\n writeLine();\n\n // === LIVE ===\n const daemonStatus = daemon.running\n ? `${colors.green}✓${RESET} daemon`\n : `${colors.dim}○ daemon off${RESET}`;\n const runCount = running.length > 0\n ? `${colors.green}${running.length}${RESET} running`\n : `${colors.dim}0 running${RESET}`;\n writeLine(` ${daemonStatus} ${colors.dim}│${RESET} ${runCount}`);\n\n for (const r of running) {\n const task = r.task ? `${colors.dim}${r.task.slice(0, 50)}${RESET}` : '';\n writeLine(` ${colors.green}▸${RESET} ${colors.cyan}${r.squad}${RESET} ${task}`);\n }\n\n if (recentTranscripts.length > 0) {\n writeLine();\n for (const t of recentTranscripts.slice(0, 5)) {\n writeLine(` ${colors.dim}${padEnd(t.ago, 9)}${RESET} ${colors.cyan}${padEnd(t.squad, 13)}${RESET} ${colors.dim}${t.turns} turns ~$${t.cost}${RESET}`);\n }\n }\n writeLine();\n\n // === READINESS ===\n if (coreInstalled === core.length && project.hasProject) {\n writeLine(` ${colors.green}✓ Ready${RESET}`);\n } else if (coreInstalled === core.length) {\n writeLine(` ${colors.yellow}○ Run: squads init${RESET}`);\n } else {\n const missing = core.filter(r => !r.installed).map(r => r.tool.name);\n writeLine(` ${colors.red}✗ Missing: ${missing.join(', ')}${RESET}`);\n }\n writeLine();\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
getApiUrl,
|
|
4
|
+
getBridgeUrl,
|
|
5
|
+
getConsoleUrl,
|
|
6
|
+
getEnv,
|
|
7
|
+
getEnvName,
|
|
8
|
+
loadConfig,
|
|
9
|
+
saveConfig
|
|
10
|
+
} from "./chunk-OQJHPULO.js";
|
|
11
|
+
import "./chunk-7OCVIDC7.js";
|
|
12
|
+
export {
|
|
13
|
+
getApiUrl,
|
|
14
|
+
getBridgeUrl,
|
|
15
|
+
getConsoleUrl,
|
|
16
|
+
getEnv,
|
|
17
|
+
getEnvName,
|
|
18
|
+
loadConfig,
|
|
19
|
+
saveConfig
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=env-config-KCLDBKYX.js.map
|