@routecraft/cli 0.4.0-canary.9 → 0.4.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.
@@ -0,0 +1,140 @@
1
+ function u(s){return s.replace(/[%_\\]/g,"\\$&")}var g=class s{db;stmtCache=new Map;constructor(t){this.db=t;}stmt(t,e){let n=this.stmtCache.get(t);return n||(n=this.db.prepare(e),this.stmtCache.set(t,n)),n}static async open(t){let e;try{let r=await import('better-sqlite3');e="default"in r&&typeof r.default=="function"?r.default:r;}catch{throw new Error("better-sqlite3 is not installed. Install it with: pnpm add better-sqlite3")}let n=new e(t,{readonly:true});try{n.pragma("journal_mode = WAL");}catch{}{let r=new e(t);try{r.prepare("CREATE INDEX IF NOT EXISTS idx_exchanges_started_at ON exchanges(started_at)").run(),r.prepare("CREATE INDEX IF NOT EXISTS idx_exchanges_route_started ON exchanges(route_id, started_at)").run(),r.prepare("CREATE INDEX IF NOT EXISTS idx_exchanges_correlation_id ON exchanges(correlation_id)").run(),r.prepare("PRAGMA table_info(events)").all().some(o=>o.name==="exchange_id")||(r.prepare("ALTER TABLE events ADD COLUMN exchange_id TEXT").run(),r.prepare("ALTER TABLE events ADD COLUMN correlation_id TEXT").run()),r.prepare("CREATE INDEX IF NOT EXISTS idx_events_exchange_id ON events(exchange_id)").run(),r.prepare("CREATE INDEX IF NOT EXISTS idx_events_correlation_id ON events(correlation_id)").run(),r.prepare(`CREATE TABLE IF NOT EXISTS exchange_snapshots (
2
+ exchange_id TEXT NOT NULL,
3
+ context_id TEXT NOT NULL,
4
+ headers TEXT NOT NULL,
5
+ body TEXT,
6
+ truncated INTEGER NOT NULL DEFAULT 0,
7
+ captured_at TEXT NOT NULL DEFAULT (datetime('now')),
8
+ PRIMARY KEY (exchange_id, context_id)
9
+ )`).run();}catch{}finally{r.close();}}return new s(n)}getRouteSummary(){return this.stmt("routeSummary",`WITH unique_routes AS (
10
+ SELECT
11
+ id,
12
+ MAX(registered_at) AS registered_at,
13
+ (SELECT r2.status FROM routes r2
14
+ WHERE r2.id = r.id
15
+ ORDER BY r2.registered_at DESC LIMIT 1) AS status
16
+ FROM routes r
17
+ GROUP BY id
18
+ ),
19
+ exchange_counts AS (
20
+ SELECT
21
+ route_id,
22
+ COUNT(*) AS total,
23
+ SUM(CASE WHEN status = 'completed' THEN 1 ELSE 0 END) AS completed,
24
+ SUM(CASE WHEN status = 'failed' THEN 1 ELSE 0 END) AS failed,
25
+ SUM(CASE WHEN status = 'dropped' THEN 1 ELSE 0 END) AS dropped
26
+ FROM exchanges
27
+ GROUP BY route_id
28
+ ),
29
+ recent_avg AS (
30
+ SELECT route_id, AVG(duration_ms) AS avgDur
31
+ FROM exchanges
32
+ WHERE started_at >= datetime('now', '-5 minutes')
33
+ GROUP BY route_id
34
+ )
35
+ SELECT
36
+ ur.id,
37
+ ur.status,
38
+ COALESCE(ec.total, 0) AS totalExchanges,
39
+ COALESCE(ec.completed, 0) AS completedExchanges,
40
+ COALESCE(ec.failed, 0) AS failedExchanges,
41
+ COALESCE(ec.dropped, 0) AS droppedExchanges,
42
+ ra.avgDur AS avgDurationMs
43
+ FROM unique_routes ur
44
+ LEFT JOIN exchange_counts ec ON ur.id = ec.route_id
45
+ LEFT JOIN recent_avg ra ON ur.id = ra.route_id
46
+ ORDER BY ur.registered_at DESC`).all()}getExchangesByRoute(t,e=-1){return this.stmt("exchangesByRoute",`SELECT
47
+ id,
48
+ route_id AS routeId,
49
+ context_id AS contextId,
50
+ correlation_id AS correlationId,
51
+ status,
52
+ started_at AS startedAt,
53
+ completed_at AS completedAt,
54
+ duration_ms AS durationMs,
55
+ error
56
+ FROM exchanges
57
+ WHERE route_id = ?
58
+ ORDER BY started_at DESC
59
+ LIMIT ?`).all(t,e)}getAllExchanges(t=-1){return this.stmt("allExchanges",`SELECT
60
+ id,
61
+ route_id AS routeId,
62
+ context_id AS contextId,
63
+ correlation_id AS correlationId,
64
+ status,
65
+ started_at AS startedAt,
66
+ completed_at AS completedAt,
67
+ duration_ms AS durationMs,
68
+ error
69
+ FROM exchanges
70
+ ORDER BY started_at DESC
71
+ LIMIT ?`).all(t)}getFailedExchanges(t=-1){return this.stmt("failedExchanges",`SELECT
72
+ id,
73
+ route_id AS routeId,
74
+ context_id AS contextId,
75
+ correlation_id AS correlationId,
76
+ status,
77
+ started_at AS startedAt,
78
+ completed_at AS completedAt,
79
+ duration_ms AS durationMs,
80
+ error
81
+ FROM exchanges
82
+ WHERE status = 'failed'
83
+ ORDER BY started_at DESC
84
+ LIMIT ?`).all(t)}getEventsByExchange(t,e){let n=e||t;return this.hasEventIdColumns()?this.stmt("eventsByExchangeIndexed",`SELECT
85
+ id,
86
+ timestamp,
87
+ context_id AS contextId,
88
+ event_name AS eventName,
89
+ details
90
+ FROM events
91
+ WHERE exchange_id = ? OR correlation_id = ?
92
+ ORDER BY id ASC`).all(n,n):this.stmt("eventsByExchangeFallback",`SELECT
93
+ id,
94
+ timestamp,
95
+ context_id AS contextId,
96
+ event_name AS eventName,
97
+ details
98
+ FROM events
99
+ WHERE details LIKE '%' || ? || '%' ESCAPE '\\'
100
+ ORDER BY id ASC`).all(u(n))}hasEventIdColumns(){if(this._hasEventIdColumns!==void 0)return this._hasEventIdColumns;try{let t=this.db.prepare("PRAGMA table_info(events)").all();this._hasEventIdColumns=t.some(e=>e.name==="exchange_id");}catch{this._hasEventIdColumns=false;}return this._hasEventIdColumns}_hasEventIdColumns;getRecentEvents(t){let e=t?.limit??100,n=t?.sinceId??0,r=`
101
+ SELECT
102
+ id,
103
+ timestamp,
104
+ context_id AS contextId,
105
+ event_name AS eventName,
106
+ details
107
+ FROM events
108
+ WHERE id > ?
109
+ `,a=[n];if(t?.eventNameFilter&&(r+=" AND event_name LIKE ? ESCAPE '\\'",a.push(`%${u(t.eventNameFilter)}%`)),t?.routeIdFilter){r+=" AND (event_name LIKE ? ESCAPE '\\' OR details LIKE ? ESCAPE '\\')";let i=u(t.routeIdFilter);a.push(`%${i}%`,`%${i}%`);}return r+=" ORDER BY id DESC LIMIT ?",a.push(e),this.db.prepare(r).all(...a)}getMetrics(){let e=this.stmt("metrics",`SELECT
110
+ (SELECT COUNT(DISTINCT id) FROM routes) AS totalRoutes,
111
+ (SELECT COUNT(*) FROM exchanges) AS totalExchanges,
112
+ (SELECT COUNT(*) FROM exchanges WHERE status = 'completed') AS completedExchanges,
113
+ (SELECT COUNT(*) FROM exchanges WHERE status = 'failed') AS failedExchanges,
114
+ (SELECT COUNT(*) FROM exchanges WHERE status = 'dropped') AS droppedExchanges,
115
+ (SELECT AVG(duration_ms) FROM exchanges
116
+ WHERE started_at >= datetime('now', '-5 minutes')) AS avgDurationMs`).get(),r=this.stmt("percentiles",`SELECT duration_ms
117
+ FROM exchanges
118
+ WHERE duration_ms IS NOT NULL
119
+ AND started_at >= datetime('now', '-5 minutes')
120
+ ORDER BY duration_ms ASC`).all().map(a=>a.duration_ms);return {...e,errorRate:e.totalExchanges>0?e.failedExchanges/e.totalExchanges:0,p90DurationMs:l(r,.9),p95DurationMs:l(r,.95),p99DurationMs:l(r,.99)}}getLiveTrafficBuckets(t=60,e=5){let n=Math.floor(Date.now()/1e3),r=Math.floor(n/e)*e,a=r-(t-1)*e,i=this.stmt("liveTraffic",`SELECT
121
+ CAST((CAST(strftime('%s', started_at) AS INTEGER) - ?) / ? AS INTEGER) AS bucket,
122
+ COUNT(*) AS cnt
123
+ FROM exchanges
124
+ WHERE CAST(strftime('%s', started_at) AS INTEGER) >= ?
125
+ AND CAST(strftime('%s', started_at) AS INTEGER) <= ?
126
+ GROUP BY bucket`).all(a,e,a,r+e),c=new Array(t).fill(0);for(let E of i)E.bucket>=0&&E.bucket<t&&(c[E.bucket]+=E.cnt);return c}getSingleRouteActivity(t,e=12,n=5){let r=Math.floor(Date.now()/1e3),o=Math.floor(r/n)*n-(e-1)*n,c=this.stmt("singleRouteActivity",`SELECT
127
+ CAST((CAST(strftime('%s', started_at) AS INTEGER) - ?) / ? AS INTEGER) AS bucket,
128
+ COUNT(*) AS cnt
129
+ FROM exchanges
130
+ WHERE route_id = ?
131
+ AND CAST(strftime('%s', started_at) AS INTEGER) >= ?
132
+ GROUP BY bucket`).all(o,n,t,o),S=this.stmt("singleRouteErrors",`SELECT COUNT(*) AS cnt
133
+ FROM exchanges
134
+ WHERE route_id = ?
135
+ AND status = 'failed'
136
+ AND CAST(strftime('%s', started_at) AS INTEGER) >= ?`).get(t,o),m=new Array(e).fill(0);for(let d of c)d.bucket>=0&&d.bucket<e&&(m[d.bucket]=d.cnt);return {throughput:m,recentErrors:S?.cnt??0}}getMaxEventId(){return this.db.prepare("SELECT COALESCE(MAX(id), 0) AS maxId FROM events").get().maxId}getExchangeSnapshot(t){try{let n=this.stmt("exchangeSnapshot",`SELECT headers, body, truncated
137
+ FROM exchange_snapshots
138
+ WHERE exchange_id = ?
139
+ LIMIT 1`).get(t);return n?{headers:n.headers,body:n.body,truncated:n.truncated!==0}:null}catch{return null}}close(){this.db.close();}};function l(s,t){if(s.length===0)return null;let e=t*(s.length-1),n=Math.floor(e),r=Math.ceil(e);return n===r?s[n]:s[n]+(s[r]-s[n])*(e-n)}export{g as a};//# sourceMappingURL=chunk-DPJWCR2V.js.map
140
+ //# sourceMappingURL=chunk-DPJWCR2V.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/tui/db.ts"],"names":["escapeLike","TelemetryDb","_TelemetryDb","db","key","sql","s","dbPath","Database","mod","wdb","c","routeId","limit","exchangeId","correlationId","searchId","info","col","options","sinceId","params","escaped","row","durations","r","percentile","bucketCount","bucketWidthSec","nowSec","snapped","windowStart","rows","result","tRows","eRow","throughput","sorted","p","idx","lo","hi"],"mappings":"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","file":"chunk-DPJWCR2V.js","sourcesContent":["import type { TelemetryEvent } from \"@routecraft/routecraft\";\n\n/** Exchange row shape from the telemetry SQLite database. */\ninterface TelemetryExchange {\n id: string;\n routeId: string;\n contextId: string;\n correlationId: string;\n status: string;\n startedAt: string;\n completedAt: string | null;\n durationMs: number | null;\n error: string | null;\n}\n\n/**\n * Minimal type for the better-sqlite3 database to avoid hard dependency.\n */\ninterface Database {\n prepare(sql: string): Statement;\n close(): void;\n pragma(pragma: string): unknown;\n}\n\ninterface Statement {\n all(...params: unknown[]): unknown[];\n get(...params: unknown[]): unknown;\n run(...params: unknown[]): unknown;\n}\n\ntype DatabaseConstructor = new (\n filename: string,\n options?: { readonly?: boolean },\n) => Database;\n\n/**\n * Read-only accessor for the telemetry SQLite database.\n * Used by the TUI to query historical data without affecting the running engine.\n *\n * Use the static `open()` factory instead of the constructor directly.\n */\n/** Escape LIKE metacharacters so they match literally. */\nfunction escapeLike(s: string): string {\n return s.replace(/[%_\\\\]/g, \"\\\\$&\");\n}\n\nexport class TelemetryDb {\n private db: Database;\n private stmtCache = new Map<string, Statement>();\n\n private constructor(db: Database) {\n this.db = db;\n }\n\n /** Prepare and cache a statement by key. Avoids re-parsing on every call. */\n private stmt(key: string, sql: string): Statement {\n let s = this.stmtCache.get(key);\n if (!s) {\n s = this.db.prepare(sql);\n this.stmtCache.set(key, s);\n }\n return s;\n }\n\n /**\n * Open a telemetry database in read-only mode.\n *\n * Uses dynamic `import()` so the module resolves correctly under pnpm's\n * strict hoisting (CJS `require()` from an ESM bundle does not follow\n * the package's own dependency graph).\n */\n static async open(dbPath: string): Promise<TelemetryDb> {\n let Database: DatabaseConstructor;\n try {\n const mod = await import(\"better-sqlite3\");\n Database = (\n \"default\" in mod && typeof mod.default === \"function\"\n ? mod.default\n : mod\n ) as DatabaseConstructor;\n } catch {\n throw new Error(\n \"better-sqlite3 is not installed. Install it with: pnpm add better-sqlite3\",\n );\n }\n\n const db = new Database(dbPath, { readonly: true });\n try {\n db.pragma(\"journal_mode = WAL\");\n } catch {\n // Read-only connection cannot change journal mode; safe to ignore\n }\n\n // Ensure indexes exist for TUI query performance.\n // If the DB was created before indexes were added, create them now\n // using a separate writable connection.\n {\n const wdb = new Database(dbPath);\n try {\n wdb\n .prepare(\n \"CREATE INDEX IF NOT EXISTS idx_exchanges_started_at ON exchanges(started_at)\",\n )\n .run();\n wdb\n .prepare(\n \"CREATE INDEX IF NOT EXISTS idx_exchanges_route_started ON exchanges(route_id, started_at)\",\n )\n .run();\n wdb\n .prepare(\n \"CREATE INDEX IF NOT EXISTS idx_exchanges_correlation_id ON exchanges(correlation_id)\",\n )\n .run();\n // Add exchange_id/correlation_id columns to events table if missing\n const cols = wdb.prepare(\"PRAGMA table_info(events)\").all() as Array<{\n name: string;\n }>;\n if (!cols.some((c) => c.name === \"exchange_id\")) {\n wdb.prepare(\"ALTER TABLE events ADD COLUMN exchange_id TEXT\").run();\n wdb\n .prepare(\"ALTER TABLE events ADD COLUMN correlation_id TEXT\")\n .run();\n }\n wdb\n .prepare(\n \"CREATE INDEX IF NOT EXISTS idx_events_exchange_id ON events(exchange_id)\",\n )\n .run();\n wdb\n .prepare(\n \"CREATE INDEX IF NOT EXISTS idx_events_correlation_id ON events(correlation_id)\",\n )\n .run();\n // Ensure exchange_snapshots table exists for older databases\n wdb\n .prepare(\n `CREATE TABLE IF NOT EXISTS exchange_snapshots (\n exchange_id TEXT NOT NULL,\n context_id TEXT NOT NULL,\n headers TEXT NOT NULL,\n body TEXT,\n truncated INTEGER NOT NULL DEFAULT 0,\n captured_at TEXT NOT NULL DEFAULT (datetime('now')),\n PRIMARY KEY (exchange_id, context_id)\n )`,\n )\n .run();\n } catch {\n // Best-effort; the writer will create them on next restart\n } finally {\n wdb.close();\n }\n }\n\n return new TelemetryDb(db);\n }\n\n /**\n * Get a summary of all routes with aggregated metrics.\n * Routes are grouped by ID across all context runs so that restarting\n * the same application does not create duplicate rows.\n */\n getRouteSummary(): Array<{\n id: string;\n status: string;\n totalExchanges: number;\n completedExchanges: number;\n failedExchanges: number;\n droppedExchanges: number;\n avgDurationMs: number | null;\n }> {\n const s = this.stmt(\n \"routeSummary\",\n `WITH unique_routes AS (\n SELECT\n id,\n MAX(registered_at) AS registered_at,\n (SELECT r2.status FROM routes r2\n WHERE r2.id = r.id\n ORDER BY r2.registered_at DESC LIMIT 1) AS status\n FROM routes r\n GROUP BY id\n ),\n exchange_counts AS (\n SELECT\n route_id,\n COUNT(*) AS total,\n SUM(CASE WHEN status = 'completed' THEN 1 ELSE 0 END) AS completed,\n SUM(CASE WHEN status = 'failed' THEN 1 ELSE 0 END) AS failed,\n SUM(CASE WHEN status = 'dropped' THEN 1 ELSE 0 END) AS dropped\n FROM exchanges\n GROUP BY route_id\n ),\n recent_avg AS (\n SELECT route_id, AVG(duration_ms) AS avgDur\n FROM exchanges\n WHERE started_at >= datetime('now', '-5 minutes')\n GROUP BY route_id\n )\n SELECT\n ur.id,\n ur.status,\n COALESCE(ec.total, 0) AS totalExchanges,\n COALESCE(ec.completed, 0) AS completedExchanges,\n COALESCE(ec.failed, 0) AS failedExchanges,\n COALESCE(ec.dropped, 0) AS droppedExchanges,\n ra.avgDur AS avgDurationMs\n FROM unique_routes ur\n LEFT JOIN exchange_counts ec ON ur.id = ec.route_id\n LEFT JOIN recent_avg ra ON ur.id = ra.route_id\n ORDER BY ur.registered_at DESC`,\n );\n return s.all() as Array<{\n id: string;\n status: string;\n totalExchanges: number;\n completedExchanges: number;\n failedExchanges: number;\n droppedExchanges: number;\n avgDurationMs: number | null;\n }>;\n }\n\n /**\n * Get exchanges for a specific route, ordered by most recent first.\n */\n getExchangesByRoute(routeId: string, limit = -1): TelemetryExchange[] {\n const s = this.stmt(\n \"exchangesByRoute\",\n `SELECT\n id,\n route_id AS routeId,\n context_id AS contextId,\n correlation_id AS correlationId,\n status,\n started_at AS startedAt,\n completed_at AS completedAt,\n duration_ms AS durationMs,\n error\n FROM exchanges\n WHERE route_id = ?\n ORDER BY started_at DESC\n LIMIT ?`,\n );\n return s.all(routeId, limit) as TelemetryExchange[];\n }\n\n /**\n * Get all exchanges across all routes, ordered by most recent first.\n */\n getAllExchanges(limit = -1): TelemetryExchange[] {\n const s = this.stmt(\n \"allExchanges\",\n `SELECT\n id,\n route_id AS routeId,\n context_id AS contextId,\n correlation_id AS correlationId,\n status,\n started_at AS startedAt,\n completed_at AS completedAt,\n duration_ms AS durationMs,\n error\n FROM exchanges\n ORDER BY started_at DESC\n LIMIT ?`,\n );\n return s.all(limit) as TelemetryExchange[];\n }\n\n /**\n * Get all failed exchanges across all routes, ordered by most recent first.\n * Shows every failed exchange including child exchanges from split/multicast,\n * without deduplication by correlation chain.\n */\n getFailedExchanges(limit = -1): TelemetryExchange[] {\n const s = this.stmt(\n \"failedExchanges\",\n `SELECT\n id,\n route_id AS routeId,\n context_id AS contextId,\n correlation_id AS correlationId,\n status,\n started_at AS startedAt,\n completed_at AS completedAt,\n duration_ms AS durationMs,\n error\n FROM exchanges\n WHERE status = 'failed'\n ORDER BY started_at DESC\n LIMIT ?`,\n );\n return s.all(limit) as TelemetryExchange[];\n }\n\n /**\n * Get events for an exchange and all related exchanges sharing the\n * same correlation ID. Uses indexed exchange_id/correlation_id columns\n * with a fallback to details LIKE for databases created before the\n * column migration.\n */\n getEventsByExchange(\n exchangeId: string,\n correlationId: string,\n ): TelemetryEvent[] {\n const searchId = correlationId || exchangeId;\n\n // Try indexed column lookup first (fast path)\n const hasColumns = this.hasEventIdColumns();\n if (hasColumns) {\n const s = this.stmt(\n \"eventsByExchangeIndexed\",\n `SELECT\n id,\n timestamp,\n context_id AS contextId,\n event_name AS eventName,\n details\n FROM events\n WHERE exchange_id = ? OR correlation_id = ?\n ORDER BY id ASC`,\n );\n return s.all(searchId, searchId) as TelemetryEvent[];\n }\n\n // Fallback: full-text LIKE scan for older databases\n const s = this.stmt(\n \"eventsByExchangeFallback\",\n `SELECT\n id,\n timestamp,\n context_id AS contextId,\n event_name AS eventName,\n details\n FROM events\n WHERE details LIKE '%' || ? || '%' ESCAPE '\\\\'\n ORDER BY id ASC`,\n );\n return s.all(escapeLike(searchId)) as TelemetryEvent[];\n }\n\n /** Check whether the events table has the exchange_id column. */\n private hasEventIdColumns(): boolean {\n if (this._hasEventIdColumns !== undefined) return this._hasEventIdColumns;\n try {\n const info = this.db.prepare(\"PRAGMA table_info(events)\").all() as Array<{\n name: string;\n }>;\n this._hasEventIdColumns = info.some((col) => col.name === \"exchange_id\");\n } catch {\n this._hasEventIdColumns = false;\n }\n return this._hasEventIdColumns;\n }\n private _hasEventIdColumns: boolean | undefined;\n\n /**\n * Get recent events, optionally filtered by event name pattern or route ID.\n */\n getRecentEvents(options?: {\n limit?: number;\n eventNameFilter?: string;\n routeIdFilter?: string;\n sinceId?: number;\n }): TelemetryEvent[] {\n const limit = options?.limit ?? 100;\n const sinceId = options?.sinceId ?? 0;\n\n let sql = `\n SELECT\n id,\n timestamp,\n context_id AS contextId,\n event_name AS eventName,\n details\n FROM events\n WHERE id > ?\n `;\n const params: unknown[] = [sinceId];\n\n if (options?.eventNameFilter) {\n sql += \" AND event_name LIKE ? ESCAPE '\\\\'\";\n params.push(`%${escapeLike(options.eventNameFilter)}%`);\n }\n\n if (options?.routeIdFilter) {\n sql +=\n \" AND (event_name LIKE ? ESCAPE '\\\\' OR details LIKE ? ESCAPE '\\\\')\";\n const escaped = escapeLike(options.routeIdFilter);\n params.push(`%${escaped}%`, `%${escaped}%`);\n }\n\n sql += \" ORDER BY id DESC LIMIT ?\";\n params.push(limit);\n\n const stmt = this.db.prepare(sql);\n return stmt.all(...params) as TelemetryEvent[];\n }\n\n /**\n * Get aggregated metrics for the dashboard, including duration percentiles.\n * Percentiles are computed over exchanges from the last 5 minutes.\n */\n getMetrics(): import(\"./types.js\").Metrics {\n const s = this.stmt(\n \"metrics\",\n `SELECT\n (SELECT COUNT(DISTINCT id) FROM routes) AS totalRoutes,\n (SELECT COUNT(*) FROM exchanges) AS totalExchanges,\n (SELECT COUNT(*) FROM exchanges WHERE status = 'completed') AS completedExchanges,\n (SELECT COUNT(*) FROM exchanges WHERE status = 'failed') AS failedExchanges,\n (SELECT COUNT(*) FROM exchanges WHERE status = 'dropped') AS droppedExchanges,\n (SELECT AVG(duration_ms) FROM exchanges\n WHERE started_at >= datetime('now', '-5 minutes')) AS avgDurationMs`,\n );\n const row = s.get() as {\n totalRoutes: number;\n totalExchanges: number;\n completedExchanges: number;\n failedExchanges: number;\n droppedExchanges: number;\n avgDurationMs: number | null;\n };\n\n // Compute percentiles from recent exchanges with non-null durations\n const pctStmt = this.stmt(\n \"percentiles\",\n `SELECT duration_ms\n FROM exchanges\n WHERE duration_ms IS NOT NULL\n AND started_at >= datetime('now', '-5 minutes')\n ORDER BY duration_ms ASC`,\n );\n const durations = (pctStmt.all() as Array<{ duration_ms: number }>).map(\n (r) => r.duration_ms,\n );\n\n return {\n ...row,\n errorRate:\n row.totalExchanges > 0 ? row.failedExchanges / row.totalExchanges : 0,\n p90DurationMs: percentile(durations, 0.9),\n p95DurationMs: percentile(durations, 0.95),\n p99DurationMs: percentile(durations, 0.99),\n };\n }\n\n /**\n * Get exchange counts for a rolling window using fine-grained buckets.\n * Default: 60 buckets of 5 seconds = 5-minute rolling window.\n * Returns values oldest-first for sparkline rendering.\n */\n getLiveTrafficBuckets(bucketCount = 60, bucketWidthSec = 5): number[] {\n const nowSec = Math.floor(Date.now() / 1000);\n const snapped = Math.floor(nowSec / bucketWidthSec) * bucketWidthSec;\n const windowStart = snapped - (bucketCount - 1) * bucketWidthSec;\n\n const s = this.stmt(\n \"liveTraffic\",\n `SELECT\n CAST((CAST(strftime('%s', started_at) AS INTEGER) - ?) / ? AS INTEGER) AS bucket,\n COUNT(*) AS cnt\n FROM exchanges\n WHERE CAST(strftime('%s', started_at) AS INTEGER) >= ?\n AND CAST(strftime('%s', started_at) AS INTEGER) <= ?\n GROUP BY bucket`,\n );\n const rows = s.all(\n windowStart,\n bucketWidthSec,\n windowStart,\n snapped + bucketWidthSec,\n ) as Array<{ bucket: number; cnt: number }>;\n\n const result = new Array(bucketCount).fill(0) as number[];\n for (const row of rows) {\n if (row.bucket >= 0 && row.bucket < bucketCount) {\n result[row.bucket] += row.cnt;\n }\n }\n return result;\n }\n\n /**\n * Get activity data for a single route: throughput sparkline + recent error count.\n */\n getSingleRouteActivity(\n routeId: string,\n bucketCount = 12,\n bucketWidthSec = 5,\n ): { throughput: number[]; recentErrors: number } {\n const nowSec = Math.floor(Date.now() / 1000);\n const snapped = Math.floor(nowSec / bucketWidthSec) * bucketWidthSec;\n const windowStart = snapped - (bucketCount - 1) * bucketWidthSec;\n\n const tStmt = this.stmt(\n \"singleRouteActivity\",\n `SELECT\n CAST((CAST(strftime('%s', started_at) AS INTEGER) - ?) / ? AS INTEGER) AS bucket,\n COUNT(*) AS cnt\n FROM exchanges\n WHERE route_id = ?\n AND CAST(strftime('%s', started_at) AS INTEGER) >= ?\n GROUP BY bucket`,\n );\n const tRows = tStmt.all(\n windowStart,\n bucketWidthSec,\n routeId,\n windowStart,\n ) as Array<{ bucket: number; cnt: number }>;\n\n const eStmt = this.stmt(\n \"singleRouteErrors\",\n `SELECT COUNT(*) AS cnt\n FROM exchanges\n WHERE route_id = ?\n AND status = 'failed'\n AND CAST(strftime('%s', started_at) AS INTEGER) >= ?`,\n );\n const eRow = eStmt.get(routeId, windowStart) as { cnt: number } | undefined;\n\n const throughput = new Array(bucketCount).fill(0) as number[];\n for (const row of tRows) {\n if (row.bucket >= 0 && row.bucket < bucketCount) {\n throughput[row.bucket] = row.cnt;\n }\n }\n\n return { throughput, recentErrors: eRow?.cnt ?? 0 };\n }\n\n /**\n * Get the maximum event ID (for tailing/polling).\n */\n getMaxEventId(): number {\n const stmt = this.db.prepare(\n \"SELECT COALESCE(MAX(id), 0) AS maxId FROM events\",\n );\n const row = stmt.get() as { maxId: number };\n return row.maxId;\n }\n\n /**\n * Get the exchange snapshot (headers and body) for a given exchange.\n * Returns null if no snapshot was captured.\n */\n getExchangeSnapshot(\n exchangeId: string,\n ): import(\"./types.js\").ExchangeSnapshot | null {\n try {\n const s = this.stmt(\n \"exchangeSnapshot\",\n `SELECT headers, body, truncated\n FROM exchange_snapshots\n WHERE exchange_id = ?\n LIMIT 1`,\n );\n const row = s.get(exchangeId) as\n | { headers: string; body: string | null; truncated: number }\n | undefined;\n if (!row) return null;\n return {\n headers: row.headers,\n body: row.body,\n truncated: row.truncated !== 0,\n };\n } catch {\n // Table may not exist in very old databases\n return null;\n }\n }\n\n /**\n * Close the database connection.\n */\n close(): void {\n this.db.close();\n }\n}\n\n/**\n * Compute a percentile from a sorted array of numbers using linear interpolation.\n * Returns null if the array is empty.\n */\nfunction percentile(sorted: number[], p: number): number | null {\n if (sorted.length === 0) return null;\n const idx = p * (sorted.length - 1);\n const lo = Math.floor(idx);\n const hi = Math.ceil(idx);\n if (lo === hi) return sorted[lo]!;\n return sorted[lo]! + (sorted[hi]! - sorted[lo]!) * (idx - lo);\n}\n"]}
@@ -0,0 +1,2 @@
1
+ import {logger}from'@routecraft/routecraft';import {resolve}from'path';import {config}from'dotenv';function g(e){let n={quiet:true};if(e){let l=resolve(process.cwd(),e),t=config({path:l,...n});return t.error?logger.info(`Could not load .env file from ${e}: ${t.error.message}`):t.parsed&&logger.debug(`Loaded ${Object.keys(t.parsed).length} environment variables from ${e}`),t}let r=config({path:resolve(process.cwd(),".env"),...n});r.parsed?logger.debug(`Loaded ${Object.keys(r.parsed).length} environment variables from .env`):r.error&&logger.debug("No .env file found");let o=config({path:resolve(process.cwd(),".env.local"),override:true,...n});return o.parsed&&logger.debug(`Loaded ${Object.keys(o.parsed).length} environment variables from .env.local`),o.parsed?o:r.parsed?r:o}function u(e){let n=false,r=async o=>{n&&(e.logger.warn(`Received ${o} again, forcing exit`),process.exit(1)),n=true,e.logger.info(`Shutting down (${o})...`),await e.stop(),e.logger.info("Cleanup complete"),process.exit(0);};process.on("SIGINT",()=>r("SIGINT")),process.on("SIGTERM",()=>r("SIGTERM"));}export{g as a,u as b};//# sourceMappingURL=chunk-PW5RNJFH.js.map
2
+ //# sourceMappingURL=chunk-PW5RNJFH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/util.ts"],"names":["loadEnvFile","path","dotenvOpts","envPath","resolve","result","loadDotenv","logger","envResult","envLocalResult","registerContextSignalHandlers","context","shuttingDown","shutdown","signal"],"mappings":"mGAUO,SAASA,CAAAA,CAAYC,CAAAA,CAAe,CACzC,IAAMC,CAAAA,CAAa,CAAE,KAAA,CAAO,IAAK,CAAA,CACjC,GAAID,CAAAA,CAAM,CAER,IAAME,CAAAA,CAAUC,OAAAA,CAAQ,QAAQ,GAAA,EAAI,CAAGH,CAAI,CAAA,CACrCI,CAAAA,CAASC,MAAAA,CAAW,CAAE,IAAA,CAAMH,CAAAA,CAAS,GAAGD,CAAW,CAAC,EAE1D,OAAIG,CAAAA,CAAO,MACTE,MAAAA,CAAO,IAAA,CACL,CAAA,8BAAA,EAAiCN,CAAI,CAAA,EAAA,EAAKI,CAAAA,CAAO,MAAM,OAAO,CAAA,CAChE,EACSA,CAAAA,CAAO,MAAA,EAChBE,OAAO,KAAA,CACL,CAAA,OAAA,EAAU,MAAA,CAAO,IAAA,CAAKF,CAAAA,CAAO,MAAM,EAAE,MAAM,CAAA,4BAAA,EAA+BJ,CAAI,CAAA,CAChF,CAAA,CAGKI,CACT,CAIA,IAAMG,CAAAA,CAAYF,MAAAA,CAAW,CAC3B,IAAA,CAAMF,QAAQ,OAAA,CAAQ,GAAA,GAAO,MAAM,CAAA,CACnC,GAAGF,CACL,CAAC,CAAA,CACGM,CAAAA,CAAU,MAAA,CACZD,MAAAA,CAAO,MACL,CAAA,OAAA,EAAU,MAAA,CAAO,KAAKC,CAAAA,CAAU,MAAM,EAAE,MAAM,CAAA,gCAAA,CAChD,CAAA,CACSA,CAAAA,CAAU,KAAA,EACnBD,MAAAA,CAAO,MAAM,oBAAoB,CAAA,CAInC,IAAME,CAAAA,CAAiBH,MAAAA,CAAW,CAChC,IAAA,CAAMF,OAAAA,CAAQ,OAAA,CAAQ,GAAA,EAAI,CAAG,YAAY,EACzC,QAAA,CAAU,IAAA,CACV,GAAGF,CACL,CAAC,EAWD,OAVIO,CAAAA,CAAe,MAAA,EACjBF,MAAAA,CAAO,KAAA,CACL,CAAA,OAAA,EAAU,OAAO,IAAA,CAAKE,CAAAA,CAAe,MAAM,CAAA,CAAE,MAAM,wCACrD,CAAA,CAOEA,CAAAA,CAAe,MAAA,CACVA,CAAAA,CAELD,CAAAA,CAAU,MAAA,CACLA,EAEFC,CACT,CAWO,SAASC,CAAAA,CACdC,CAAAA,CACA,CACA,IAAIC,CAAAA,CAAe,KAAA,CAEbC,CAAAA,CAAW,MAAOC,CAAAA,EAAmB,CACrCF,CAAAA,GACFD,CAAAA,CAAQ,OAAO,IAAA,CAAK,CAAA,SAAA,EAAYG,CAAM,CAAA,oBAAA,CAAsB,CAAA,CAC5D,OAAA,CAAQ,IAAA,CAAK,CAAC,CAAA,CAAA,CAGhBF,EAAe,IAAA,CACfD,CAAAA,CAAQ,OAAO,IAAA,CAAK,CAAA,eAAA,EAAkBG,CAAM,CAAA,IAAA,CAAM,CAAA,CAClD,MAAMH,CAAAA,CAAQ,IAAA,EAAK,CACnBA,EAAQ,MAAA,CAAO,IAAA,CAAK,kBAAkB,CAAA,CACtC,OAAA,CAAQ,KAAK,CAAC,EAChB,CAAA,CAEA,OAAA,CAAQ,EAAA,CAAG,QAAA,CAAU,IAAME,CAAAA,CAAS,QAAQ,CAAC,CAAA,CAC7C,OAAA,CAAQ,EAAA,CAAG,UAAW,IAAMA,CAAAA,CAAS,SAAS,CAAC,EACjD","file":"chunk-PW5RNJFH.js","sourcesContent":["import { logger, CraftContext } from \"@routecraft/routecraft\";\nimport { resolve } from \"node:path\";\nimport { config as loadDotenv } from \"dotenv\";\n\n/**\n * Loads environment variables from .env files\n *\n * @param path Optional path to .env file. If not specified, loads .env and .env.local (if they exist)\n * @returns The parsed dotenv config result\n */\nexport function loadEnvFile(path?: string) {\n const dotenvOpts = { quiet: true };\n if (path) {\n // Explicit path provided - load that file only\n const envPath = resolve(process.cwd(), path);\n const result = loadDotenv({ path: envPath, ...dotenvOpts });\n\n if (result.error) {\n logger.info(\n `Could not load .env file from ${path}: ${result.error.message}`,\n );\n } else if (result.parsed) {\n logger.debug(\n `Loaded ${Object.keys(result.parsed).length} environment variables from ${path}`,\n );\n }\n\n return result;\n }\n\n // No path provided - load .env, then .env.local (with override)\n // Load .env first\n const envResult = loadDotenv({\n path: resolve(process.cwd(), \".env\"),\n ...dotenvOpts,\n });\n if (envResult.parsed) {\n logger.debug(\n `Loaded ${Object.keys(envResult.parsed).length} environment variables from .env`,\n );\n } else if (envResult.error) {\n logger.debug(`No .env file found`);\n }\n\n // Load .env.local next, allowing it to override .env values\n const envLocalResult = loadDotenv({\n path: resolve(process.cwd(), \".env.local\"),\n override: true,\n ...dotenvOpts,\n });\n if (envLocalResult.parsed) {\n logger.debug(\n `Loaded ${Object.keys(envLocalResult.parsed).length} environment variables from .env.local`,\n );\n }\n\n // Return the most successful result:\n // - If .env.local loaded successfully, return it\n // - If .env loaded successfully but .env.local failed (doesn't exist), return .env result\n // - If both failed, return the last error (from .env.local)\n if (envLocalResult.parsed) {\n return envLocalResult;\n }\n if (envResult.parsed) {\n return envResult;\n }\n return envLocalResult;\n}\n\n/**\n * Registers SIGINT and SIGTERM handlers for a CraftContext instance.\n *\n * First signal triggers graceful shutdown (stop sources, drain in-flight work,\n * tear down servers and plugins). A second signal during shutdown forces an\n * immediate exit.\n *\n * @param context The CraftContext instance\n */\nexport function registerContextSignalHandlers(\n context: InstanceType<typeof CraftContext>,\n) {\n let shuttingDown = false;\n\n const shutdown = async (signal: string) => {\n if (shuttingDown) {\n context.logger.warn(`Received ${signal} again, forcing exit`);\n process.exit(1);\n }\n\n shuttingDown = true;\n context.logger.info(`Shutting down (${signal})...`);\n await context.stop();\n context.logger.info(\"Cleanup complete\");\n process.exit(0);\n };\n\n process.on(\"SIGINT\", () => shutdown(\"SIGINT\"));\n process.on(\"SIGTERM\", () => shutdown(\"SIGTERM\"));\n}\n"]}
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env node
2
- var[i,l]=process.version.slice(1).split(".").map(Number);i>18||i===18&&l>=19||(console.error(`[routecraft] Node.js ${process.version} is not supported. Routecraft requires Node.js 18.19.0 or later (e.g. 20 or 22). Please upgrade Node or configure your MCP client to use a newer Node.`),process.exit(1));var p=process.argv.slice(2).some(e=>!e.startsWith("-")&&e.endsWith(".ts"));if(p&&!process.env.CRAFT_TSX_LOADER){let{execFileSync:e}=await import('child_process'),{createRequire:s}=await import('module'),o=s(import.meta.url).resolve("tsx/esm");try{e(process.execPath,["--import",o,...process.execArgv,process.argv[1],...process.argv.slice(2)],{stdio:"inherit",env:{...process.env,CRAFT_TSX_LOADER:"1"}}),process.exit(0);}catch(t){process.exit(t.status??1);}}var{Command:m}=await import('commander'),r=new m;r.name("craft").description("A modern routing framework for TypeScript").version("0.4.0-canary.9").option("--log-level <level>","Log level (e.g. info, warn, error, silent to disable)").option("--log-file <path>","Write logs to a file (keeps stdout clear for MCP stdio)").showSuggestionAfterError().showHelpAfterError().exitOverride(e=>{e.code==="commander.unknownCommand"&&process.exit(0);});process.argv.length<=2&&r.help({error:false});r.command("run").description("Run routes from a single TypeScript/JavaScript file").argument("<file>","Path to a file containing routes").option("--env <path>","Load environment variables from a .env file (default: .env)").action(async(e,s)=>{let o=r.opts();o.logLevel!==void 0&&(process.env.LOG_LEVEL=o.logLevel,process.env.CRAFT_LOG_LEVEL=o.logLevel),o.logFile!==void 0&&(process.env.LOG_FILE=o.logFile,process.env.CRAFT_LOG_FILE=o.logFile);let{loadEnvFile:t}=await import('./util-5TR67ZZL.js');s.env!==void 0?t(s.env):t();let{runCommand:a}=await import('./run-265W63J5.js'),n=await a(e);if(!n.success){n.message&&console.error(n.message);let c=n.code??1;setImmediate(()=>process.exit(c));return}});r.parse();//# sourceMappingURL=index.js.map
2
+ var[a,l]=process.version.slice(1).split(".").map(Number);a>18||a===18&&l>=19||(console.error(`[routecraft] Node.js ${process.version} is not supported. Routecraft requires Node.js 18.19.0 or later (e.g. 20 or 22). Please upgrade Node or configure your MCP client to use a newer Node.`),process.exit(1));var p=process.argv.slice(2).some(e=>!e.startsWith("-")&&e.endsWith(".ts"));if(p&&!process.env.CRAFT_TSX_LOADER){let{execFileSync:e}=await import('child_process'),{createRequire:r}=await import('module'),o=r(import.meta.url).resolve("tsx/esm");process.on("SIGINT",()=>{}),process.on("SIGTERM",()=>{});try{e(process.execPath,["--import",o,...process.execArgv,process.argv[1],...process.argv.slice(2)],{stdio:"inherit",env:{...process.env,CRAFT_TSX_LOADER:"1"}}),process.exit(0);}catch(t){process.exit(t.status??1);}}var{Command:m}=await import('commander'),s=new m;s.name("craft").description("A modern routing framework for TypeScript").version("0.4.0").option("--log-level <level>","Log level (e.g. info, warn, error, silent to disable)").option("--log-file <path>","Write logs to a file (keeps stdout clear for MCP stdio)").showSuggestionAfterError().showHelpAfterError().exitOverride(e=>{e.code==="commander.unknownCommand"&&process.exit(0);});process.argv.length<=2&&s.help({error:false});s.command("run").description("Run routes from a single TypeScript/JavaScript file").argument("<file>","Path to a file containing routes").option("--env <path>","Load environment variables from a .env file (default: .env)").action(async(e,r)=>{let o=s.opts();o.logLevel!==void 0&&(process.env.LOG_LEVEL=o.logLevel,process.env.CRAFT_LOG_LEVEL=o.logLevel),o.logFile!==void 0&&(process.env.LOG_FILE=o.logFile,process.env.CRAFT_LOG_FILE=o.logFile);let{loadEnvFile:t}=await import('./util-EC5TOA6Q.js');r.env!==void 0?t(r.env):t();let{runCommand:i}=await import('./run-QBFQZ7ZW.js'),n=await i(e);if(!n.success){n.message&&console.error(n.message);let c=n.code??1;setImmediate(()=>process.exit(c));return}});s.command("tui").description("Launch the Terminal UI to monitor Routecraft execution history").option("--db <path>","Path to the telemetry SQLite database",".routecraft/telemetry.db").action(async e=>{let{resolve:r,isAbsolute:o}=await import('path'),t=o(e.db)?e.db:r(process.cwd(),e.db),{renderTui:i}=await import('./tui/app.js');await i(t);});s.parse();//# sourceMappingURL=index.js.map
3
3
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"names":["major","minor","hasTSFile","arg","execFileSync","createRequire","tsxEsmPath","err","Command","program","filePath","options","globalOpts","loadEnvFile","runCommand","result","code"],"mappings":"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","file":"index.js","sourcesContent":["#!/usr/bin/env node\n\n/**\n * Routecraft CLI — single entry point.\n *\n * 1. Check Node version (Pino 10 needs Node 18.19+)\n * 2. Define program and parse; log options are global and applied before lazy-loading run/util (which load the logger)\n */\n\n// ── 1. Node version gate ────────────────────────────────────────────\nconst [major, minor] = process.version.slice(1).split(\".\").map(Number) as [\n number,\n number,\n];\n\nif (!(major > 18 || (major === 18 && minor >= 19))) {\n // eslint-disable-next-line no-console\n console.error(\n `[routecraft] Node.js ${process.version} is not supported. ` +\n `Routecraft requires Node.js 18.19.0 or later (e.g. 20 or 22). ` +\n `Please upgrade Node or configure your MCP client to use a newer Node.`,\n );\n process.exit(1);\n}\n\n// ── 2. Re-exec with tsx loader if a .ts file is being run ───────────────────\n// Node's native --experimental-strip-types does not handle extensionless\n// imports or .js-to-.ts resolution. tsx (via --import tsx/esm) does.\n// We set CRAFT_TSX_LOADER=1 before re-execing to avoid an infinite loop.\nconst hasTSFile = process.argv\n .slice(2)\n .some((arg) => !arg.startsWith(\"-\") && arg.endsWith(\".ts\"));\n\nif (hasTSFile && !process.env[\"CRAFT_TSX_LOADER\"]) {\n const { execFileSync } = await import(\"node:child_process\");\n const { createRequire } = await import(\"node:module\");\n // Resolve tsx/esm relative to the CLI package so it works regardless of CWD\n const tsxEsmPath = createRequire(import.meta.url).resolve(\"tsx/esm\");\n try {\n execFileSync(\n process.execPath,\n [\n \"--import\",\n tsxEsmPath,\n ...process.execArgv,\n process.argv[1]!,\n ...process.argv.slice(2),\n ],\n { stdio: \"inherit\", env: { ...process.env, CRAFT_TSX_LOADER: \"1\" } },\n );\n process.exit(0);\n } catch (err: unknown) {\n process.exit(\n (err as NodeJS.ErrnoException & { status?: number }).status ?? 1,\n );\n }\n}\n\n// ── 3. CLI definition (only Commander; run/util are lazy-loaded so logger sees env) ─\nconst { Command } = await import(\"commander\");\nconst program = new Command();\n\nprogram\n .name(\"craft\")\n .description(\"A modern routing framework for TypeScript\")\n .version(\"0.4.0-canary.9\")\n .option(\n \"--log-level <level>\",\n \"Log level (e.g. info, warn, error, silent to disable)\",\n )\n .option(\n \"--log-file <path>\",\n \"Write logs to a file (keeps stdout clear for MCP stdio)\",\n )\n .showSuggestionAfterError()\n .showHelpAfterError()\n .exitOverride((err) => {\n if (err.code === \"commander.unknownCommand\") {\n process.exit(0);\n }\n });\n\n// Show help by default if no arguments provided\nif (process.argv.length <= 2) {\n program.help({ error: false });\n}\n\n/**\n * The 'run' command executes routes from a single file.\n *\n * Example:\n * craft run ./my-routes.ts\n */\nprogram\n .command(\"run\")\n .description(\"Run routes from a single TypeScript/JavaScript file\")\n .argument(\"<file>\", \"Path to a file containing routes\")\n .option(\n \"--env <path>\",\n \"Load environment variables from a .env file (default: .env)\",\n )\n .action(async (filePath, options) => {\n // Apply global log options to env before any import that creates the logger\n const globalOpts = program.opts();\n if (globalOpts[\"logLevel\"] !== undefined) {\n process.env[\"LOG_LEVEL\"] = globalOpts[\"logLevel\"];\n process.env[\"CRAFT_LOG_LEVEL\"] = globalOpts[\"logLevel\"];\n }\n if (globalOpts[\"logFile\"] !== undefined) {\n process.env[\"LOG_FILE\"] = globalOpts[\"logFile\"];\n process.env[\"CRAFT_LOG_FILE\"] = globalOpts[\"logFile\"];\n }\n\n const { loadEnvFile } = await import(\"./util.js\");\n if (options.env !== undefined) {\n loadEnvFile(options.env);\n } else {\n loadEnvFile();\n }\n\n const { runCommand } = await import(\"./run.js\");\n const result = await runCommand(filePath);\n if (!result.success) {\n if (result.message) {\n // eslint-disable-next-line no-console\n console.error(result.message);\n }\n // Defer exit so pino/sonic-boom can finish initializing and avoid \"sonic boom is not ready yet\"\n const code = result.code ?? 1;\n setImmediate(() => process.exit(code));\n return;\n }\n // Don't call process.exit() — let the event loop drain naturally.\n // process.exit() triggers C++ static destructors that race with ONNX\n // Runtime cleanup (onnxruntime#25038: \"mutex lock failed\").\n });\n\n// Parse the command line arguments and execute the appropriate command\nprogram.parse();\n"]}
1
+ {"version":3,"sources":["../src/index.ts"],"names":["major","minor","hasTSFile","arg","execFileSync","createRequire","tsxEsmPath","err","Command","program","filePath","options","globalOpts","loadEnvFile","runCommand","result","code","resolve","isAbsolute","dbPath","renderTui"],"mappings":"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","file":"index.js","sourcesContent":["#!/usr/bin/env node\n\n/**\n * Routecraft CLI — single entry point.\n *\n * 1. Check Node version (Pino 10 needs Node 18.19+)\n * 2. Define program and parse; log options are global and applied before lazy-loading run/util (which load the logger)\n */\n\n// ── 1. Node version gate ────────────────────────────────────────────\nconst [major, minor] = process.version.slice(1).split(\".\").map(Number) as [\n number,\n number,\n];\n\nif (!(major > 18 || (major === 18 && minor >= 19))) {\n // eslint-disable-next-line no-console\n console.error(\n `[routecraft] Node.js ${process.version} is not supported. ` +\n `Routecraft requires Node.js 18.19.0 or later (e.g. 20 or 22). ` +\n `Please upgrade Node or configure your MCP client to use a newer Node.`,\n );\n process.exit(1);\n}\n\n// ── 2. Re-exec with tsx loader if a .ts file is being run ───────────────────\n// Node's native --experimental-strip-types does not handle extensionless\n// imports or .js-to-.ts resolution. tsx (via --import tsx/esm) does.\n// We set CRAFT_TSX_LOADER=1 before re-execing to avoid an infinite loop.\nconst hasTSFile = process.argv\n .slice(2)\n .some((arg) => !arg.startsWith(\"-\") && arg.endsWith(\".ts\"));\n\nif (hasTSFile && !process.env[\"CRAFT_TSX_LOADER\"]) {\n const { execFileSync } = await import(\"node:child_process\");\n const { createRequire } = await import(\"node:module\");\n // Resolve tsx/esm relative to the CLI package so it works regardless of CWD\n const tsxEsmPath = createRequire(import.meta.url).resolve(\"tsx/esm\");\n\n // Let the child handle SIGINT/SIGTERM for graceful shutdown.\n // Without this the parent dies on the first signal, orphaning the child\n // mid-teardown (connections not closed, logs truncated).\n process.on(\"SIGINT\", () => {});\n process.on(\"SIGTERM\", () => {});\n\n try {\n execFileSync(\n process.execPath,\n [\n \"--import\",\n tsxEsmPath,\n ...process.execArgv,\n process.argv[1]!,\n ...process.argv.slice(2),\n ],\n { stdio: \"inherit\", env: { ...process.env, CRAFT_TSX_LOADER: \"1\" } },\n );\n process.exit(0);\n } catch (err: unknown) {\n process.exit(\n (err as NodeJS.ErrnoException & { status?: number }).status ?? 1,\n );\n }\n}\n\n// ── 3. CLI definition (only Commander; run/util are lazy-loaded so logger sees env) ─\nconst { Command } = await import(\"commander\");\nconst program = new Command();\n\nprogram\n .name(\"craft\")\n .description(\"A modern routing framework for TypeScript\")\n .version(\"0.4.0\")\n .option(\n \"--log-level <level>\",\n \"Log level (e.g. info, warn, error, silent to disable)\",\n )\n .option(\n \"--log-file <path>\",\n \"Write logs to a file (keeps stdout clear for MCP stdio)\",\n )\n .showSuggestionAfterError()\n .showHelpAfterError()\n .exitOverride((err) => {\n if (err.code === \"commander.unknownCommand\") {\n process.exit(0);\n }\n });\n\n// Show help by default if no arguments provided\nif (process.argv.length <= 2) {\n program.help({ error: false });\n}\n\n/**\n * The 'run' command executes routes from a single file.\n *\n * Example:\n * craft run ./my-routes.ts\n */\nprogram\n .command(\"run\")\n .description(\"Run routes from a single TypeScript/JavaScript file\")\n .argument(\"<file>\", \"Path to a file containing routes\")\n .option(\n \"--env <path>\",\n \"Load environment variables from a .env file (default: .env)\",\n )\n .action(async (filePath, options) => {\n // Apply global log options to env before any import that creates the logger\n const globalOpts = program.opts();\n if (globalOpts[\"logLevel\"] !== undefined) {\n process.env[\"LOG_LEVEL\"] = globalOpts[\"logLevel\"];\n process.env[\"CRAFT_LOG_LEVEL\"] = globalOpts[\"logLevel\"];\n }\n if (globalOpts[\"logFile\"] !== undefined) {\n process.env[\"LOG_FILE\"] = globalOpts[\"logFile\"];\n process.env[\"CRAFT_LOG_FILE\"] = globalOpts[\"logFile\"];\n }\n\n const { loadEnvFile } = await import(\"./util.js\");\n if (options.env !== undefined) {\n loadEnvFile(options.env);\n } else {\n loadEnvFile();\n }\n\n const { runCommand } = await import(\"./run.js\");\n const result = await runCommand(filePath);\n if (!result.success) {\n if (result.message) {\n // eslint-disable-next-line no-console\n console.error(result.message);\n }\n // Defer exit so pino/sonic-boom can finish initializing and avoid \"sonic boom is not ready yet\"\n const code = result.code ?? 1;\n setImmediate(() => process.exit(code));\n return;\n }\n // Don't call process.exit() — let the event loop drain naturally.\n // process.exit() triggers C++ static destructors that race with ONNX\n // Runtime cleanup (onnxruntime#25038: \"mutex lock failed\").\n });\n\n/**\n * The 'tui' command launches the Terminal UI for monitoring Routecraft execution.\n *\n * Example:\n * craft tui\n * craft tui --db .routecraft/telemetry.db\n */\nprogram\n .command(\"tui\")\n .description(\"Launch the Terminal UI to monitor Routecraft execution history\")\n .option(\n \"--db <path>\",\n \"Path to the telemetry SQLite database\",\n \".routecraft/telemetry.db\",\n )\n .action(async (options) => {\n const { resolve, isAbsolute } = await import(\"node:path\");\n const dbPath = isAbsolute(options.db)\n ? options.db\n : resolve(process.cwd(), options.db);\n\n const { renderTui } = await import(\"./tui/app.js\");\n await renderTui(dbPath);\n });\n\n// Parse the command line arguments and execute the appropriate command\nprogram.parse();\n"]}
@@ -1,2 +1,2 @@
1
- import {b}from'./chunk-MEHNJKKK.js';import {resolve,extname}from'path';import {logger,ContextBuilder,isRouteBuilder,isRouteDefinition}from'@routecraft/routecraft';var l=[".mjs",".js",".cjs",".ts"];async function C(t){let e=resolve(process.cwd(),t),o=extname(e);if(!l.includes(o))return {success:false,code:1,message:`Error: Only the following file types are supported: ${l.join(", ")}`};try{let s=await import(e),u=s.craftConfig;logger.info(`Loading file: ${e}`);let n=new ContextBuilder;u&&(logger.info("Found craftConfig export, applying configuration"),n.with(u));let i=R(n,s.default);if(!i.success)return i;let a=await n.build();return b(a),await a.start(),{success:!0}}catch(s){return s instanceof Error?(logger.error(`Failed to run ${e}: ${s.message}`),{success:false,code:1,message:s.message}):(logger.error(`Failed to run ${e}: Unknown error occurred`),{success:false,code:1,message:"Unknown error"})}}function R(t,e){return e?isRouteBuilder(e)?(t.routes(e),logger.info("Loaded single RouteBuilder from default export"),{success:true}):isRouteDefinition(e)?(t.routes(e),logger.info("Loaded single route from default export"),{success:true}):Array.isArray(e)?e.every(o=>isRouteBuilder(o)||isRouteDefinition(o))?(e.forEach(o=>t.routes(o)),logger.info(`Loaded ${e.length} routes from default export array`),{success:true}):(logger.error("All items in default export array must be RouteDefinition or RouteBuilder"),{success:false,code:1,message:"Invalid items in default export array"}):(logger.error("Invalid default export. Expected: RouteDefinition, RouteBuilder, or array of those."),{success:false,code:1,message:"Invalid default export. Expected: RouteDefinition, RouteBuilder, or array of those."}):(logger.error("No default export found. Expected routes as default export."),{success:false,code:1,message:"No default export found"})}export{C as runCommand};//# sourceMappingURL=run-265W63J5.js.map
2
- //# sourceMappingURL=run-265W63J5.js.map
1
+ import {b}from'./chunk-PW5RNJFH.js';import {resolve,extname}from'path';import {logger,ContextBuilder,isRouteBuilder,isRouteDefinition}from'@routecraft/routecraft';var l=[".mjs",".js",".cjs",".ts"];async function C(t){let e=resolve(process.cwd(),t),o=extname(e);if(!l.includes(o))return {success:false,code:1,message:`Error: Only the following file types are supported: ${l.join(", ")}`};try{let s=await import(e),u=s.craftConfig;logger.info(`Loading file: ${e}`);let n=new ContextBuilder;u&&(logger.info("Found craftConfig export, applying configuration"),n.with(u));let i=R(n,s.default);if(!i.success)return i;let a=await n.build();return b(a),await a.start(),{success:!0}}catch(s){return s instanceof Error?(logger.error(`Failed to run ${e}: ${s.message}`),{success:false,code:1,message:s.message}):(logger.error(`Failed to run ${e}: Unknown error occurred`),{success:false,code:1,message:"Unknown error"})}}function R(t,e){return e?isRouteBuilder(e)?(t.routes(e),logger.info("Loaded single RouteBuilder from default export"),{success:true}):isRouteDefinition(e)?(t.routes(e),logger.info("Loaded single route from default export"),{success:true}):Array.isArray(e)?e.every(o=>isRouteBuilder(o)||isRouteDefinition(o))?(e.forEach(o=>t.routes(o)),logger.info(`Loaded ${e.length} routes from default export array`),{success:true}):(logger.error("All items in default export array must be RouteDefinition or RouteBuilder"),{success:false,code:1,message:"Invalid items in default export array"}):(logger.error("Invalid default export. Expected: RouteDefinition, RouteBuilder, or array of those."),{success:false,code:1,message:"Invalid default export. Expected: RouteDefinition, RouteBuilder, or array of those."}):(logger.error("No default export found. Expected routes as default export."),{success:false,code:1,message:"No default export found"})}export{C as runCommand};//# sourceMappingURL=run-QBFQZ7ZW.js.map
2
+ //# sourceMappingURL=run-QBFQZ7ZW.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/run.ts"],"names":["SUPPORTED_EXTENSIONS","runCommand","filePath","absFilePath","resolve","ext","extname","module","craftConfig","logger","contextBuilder","ContextBuilder","configured","configureRoutes","context","registerContextSignalHandlers","error","defaultExport","isRouteBuilder","isRouteDefinition","item","routeOrBuilder"],"mappings":"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","file":"run-265W63J5.js","sourcesContent":["import { resolve, extname } from \"node:path\";\nimport {\n ContextBuilder,\n type CraftConfig,\n isRouteBuilder,\n isRouteDefinition,\n logger,\n type RouteBuilder,\n type RouteDefinition,\n} from \"@routecraft/routecraft\";\nimport { registerContextSignalHandlers } from \"./util\";\n\nconst SUPPORTED_EXTENSIONS = [\".mjs\", \".js\", \".cjs\", \".ts\"] as const;\n\ntype RunResult =\n | { success: true }\n | { success: false; code?: number; message: string };\n\nexport async function runCommand(filePath: string): Promise<RunResult> {\n const absFilePath = resolve(process.cwd(), filePath);\n const ext = extname(absFilePath);\n\n // Validate file extension\n if (\n !SUPPORTED_EXTENSIONS.includes(ext as (typeof SUPPORTED_EXTENSIONS)[number])\n ) {\n return {\n success: false,\n code: 1,\n message: `Error: Only the following file types are supported: ${SUPPORTED_EXTENSIONS.join(\", \")}`,\n };\n }\n\n try {\n // Load the module (CLI already set LOG_LEVEL / LOG_FILE from argv in index.ts).\n // Logger uses env first; context will apply craftConfig.log when built (env wins if set).\n const module = await import(absFilePath);\n const craftConfig = module.craftConfig as CraftConfig | undefined;\n\n logger.info(`Loading file: ${absFilePath}`);\n\n // Create context builder\n const contextBuilder = new ContextBuilder();\n\n // Apply craftConfig (routes, plugins, etc.); context applies config.log when built.\n if (craftConfig) {\n logger.info(\"Found craftConfig export, applying configuration\");\n contextBuilder.with(craftConfig);\n }\n\n // Handle routes from the default export\n const configured = configureRoutes(contextBuilder, module.default);\n if (!configured.success) {\n return configured;\n }\n\n // Build and start the context\n const context = await contextBuilder.build();\n registerContextSignalHandlers(context);\n await context.start();\n\n return { success: true };\n } catch (error: unknown) {\n if (error instanceof Error) {\n logger.error(`Failed to run ${absFilePath}: ${error.message}`);\n return { success: false, code: 1, message: error.message };\n }\n logger.error(`Failed to run ${absFilePath}: Unknown error occurred`);\n return { success: false, code: 1, message: \"Unknown error\" };\n }\n}\n\nfunction configureRoutes(\n contextBuilder: InstanceType<typeof ContextBuilder>,\n defaultExport: unknown,\n): RunResult {\n if (!defaultExport) {\n logger.error(\"No default export found. Expected routes as default export.\");\n return { success: false, code: 1, message: \"No default export found\" };\n }\n\n // Handle single RouteBuilder or RouteDefinition (brand-based guards for cross-instance)\n if (isRouteBuilder(defaultExport)) {\n contextBuilder.routes(defaultExport as RouteBuilder<unknown>);\n logger.info(\"Loaded single RouteBuilder from default export\");\n return { success: true };\n }\n\n if (isRouteDefinition(defaultExport)) {\n contextBuilder.routes(defaultExport as RouteDefinition);\n logger.info(\"Loaded single route from default export\");\n return { success: true };\n }\n\n // Handle array of routes\n if (Array.isArray(defaultExport)) {\n // Check each item, prioritizing RouteBuilder check\n if (\n !defaultExport.every(\n (item) => isRouteBuilder(item) || isRouteDefinition(item),\n )\n ) {\n logger.error(\n \"All items in default export array must be RouteDefinition or RouteBuilder\",\n );\n return {\n success: false,\n code: 1,\n message: \"Invalid items in default export array\",\n };\n }\n\n defaultExport.forEach((routeOrBuilder) =>\n contextBuilder.routes(\n routeOrBuilder as RouteDefinition | RouteBuilder<unknown>,\n ),\n );\n logger.info(\n `Loaded ${defaultExport.length} routes from default export array`,\n );\n return { success: true };\n }\n\n // Invalid default export\n logger.error(\n \"Invalid default export. Expected: RouteDefinition, RouteBuilder, or array of those.\",\n );\n return {\n success: false,\n code: 1,\n message:\n \"Invalid default export. Expected: RouteDefinition, RouteBuilder, or array of those.\",\n };\n}\n"]}
1
+ {"version":3,"sources":["../src/run.ts"],"names":["SUPPORTED_EXTENSIONS","runCommand","filePath","absFilePath","resolve","ext","extname","module","craftConfig","logger","contextBuilder","ContextBuilder","configured","configureRoutes","context","registerContextSignalHandlers","error","defaultExport","isRouteBuilder","isRouteDefinition","item","routeOrBuilder"],"mappings":"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","file":"run-QBFQZ7ZW.js","sourcesContent":["import { resolve, extname } from \"node:path\";\nimport {\n ContextBuilder,\n type CraftConfig,\n isRouteBuilder,\n isRouteDefinition,\n logger,\n type RouteBuilder,\n type RouteDefinition,\n} from \"@routecraft/routecraft\";\nimport { registerContextSignalHandlers } from \"./util\";\n\nconst SUPPORTED_EXTENSIONS = [\".mjs\", \".js\", \".cjs\", \".ts\"] as const;\n\ntype RunResult =\n | { success: true }\n | { success: false; code?: number; message: string };\n\nexport async function runCommand(filePath: string): Promise<RunResult> {\n const absFilePath = resolve(process.cwd(), filePath);\n const ext = extname(absFilePath);\n\n // Validate file extension\n if (\n !SUPPORTED_EXTENSIONS.includes(ext as (typeof SUPPORTED_EXTENSIONS)[number])\n ) {\n return {\n success: false,\n code: 1,\n message: `Error: Only the following file types are supported: ${SUPPORTED_EXTENSIONS.join(\", \")}`,\n };\n }\n\n try {\n // Load the module (CLI already set LOG_LEVEL / LOG_FILE from argv in index.ts).\n // Logger uses env first; context will apply craftConfig.log when built (env wins if set).\n const module = await import(absFilePath);\n const craftConfig = module.craftConfig as CraftConfig | undefined;\n\n logger.info(`Loading file: ${absFilePath}`);\n\n // Create context builder\n const contextBuilder = new ContextBuilder();\n\n // Apply craftConfig (routes, plugins, etc.); context applies config.log when built.\n if (craftConfig) {\n logger.info(\"Found craftConfig export, applying configuration\");\n contextBuilder.with(craftConfig);\n }\n\n // Handle routes from the default export\n const configured = configureRoutes(contextBuilder, module.default);\n if (!configured.success) {\n return configured;\n }\n\n // Build and start the context\n const context = await contextBuilder.build();\n registerContextSignalHandlers(context);\n await context.start();\n\n return { success: true };\n } catch (error: unknown) {\n if (error instanceof Error) {\n logger.error(`Failed to run ${absFilePath}: ${error.message}`);\n return { success: false, code: 1, message: error.message };\n }\n logger.error(`Failed to run ${absFilePath}: Unknown error occurred`);\n return { success: false, code: 1, message: \"Unknown error\" };\n }\n}\n\nfunction configureRoutes(\n contextBuilder: InstanceType<typeof ContextBuilder>,\n defaultExport: unknown,\n): RunResult {\n if (!defaultExport) {\n logger.error(\"No default export found. Expected routes as default export.\");\n return { success: false, code: 1, message: \"No default export found\" };\n }\n\n // Handle single RouteBuilder or RouteDefinition (brand-based guards for cross-instance)\n if (isRouteBuilder(defaultExport)) {\n contextBuilder.routes(defaultExport as RouteBuilder<unknown>);\n logger.info(\"Loaded single RouteBuilder from default export\");\n return { success: true };\n }\n\n if (isRouteDefinition(defaultExport)) {\n contextBuilder.routes(defaultExport as RouteDefinition);\n logger.info(\"Loaded single route from default export\");\n return { success: true };\n }\n\n // Handle array of routes\n if (Array.isArray(defaultExport)) {\n // Check each item, prioritizing RouteBuilder check\n if (\n !defaultExport.every(\n (item) => isRouteBuilder(item) || isRouteDefinition(item),\n )\n ) {\n logger.error(\n \"All items in default export array must be RouteDefinition or RouteBuilder\",\n );\n return {\n success: false,\n code: 1,\n message: \"Invalid items in default export array\",\n };\n }\n\n defaultExport.forEach((routeOrBuilder) =>\n contextBuilder.routes(\n routeOrBuilder as RouteDefinition | RouteBuilder<unknown>,\n ),\n );\n logger.info(\n `Loaded ${defaultExport.length} routes from default export array`,\n );\n return { success: true };\n }\n\n // Invalid default export\n logger.error(\n \"Invalid default export. Expected: RouteDefinition, RouteBuilder, or array of those.\",\n );\n return {\n success: false,\n code: 1,\n message:\n \"Invalid default export. Expected: RouteDefinition, RouteBuilder, or array of those.\",\n };\n}\n"]}
@@ -0,0 +1,3 @@
1
+ declare function renderTui(dbPath: string): Promise<void>;
2
+
3
+ export { renderTui };
@@ -0,0 +1,7 @@
1
+ import {a}from'../chunk-DPJWCR2V.js';import {useState,useCallback,useEffect,Fragment as Fragment$1}from'react';import {render,useApp,useStdout,useInput,Box,Text}from'ink';import {jsx,jsxs,Fragment}from'react/jsx-runtime';var st=[{items:[{key:"capabilities",label:"Capabilities",shortcut:"1"}]},{items:[{key:"exchanges",label:"Exchanges",shortcut:"2"},{key:"errors",label:"Errors",shortcut:"3"},{key:"events",label:"Events",shortcut:"4"}]}],Ct=st.flatMap(e=>e.items);function ge(e,t){return t<=0?"":e.length>t?e.slice(0,t-1)+"\u2026":e}function _(e){return e==null||!Number.isFinite(e)||e<0?"-":e===0?"<1ms":e<1e3?`${Math.round(e)}ms`:`${(e/1e3).toFixed(1)}s`}function oe(e){switch(e){case "completed":case "started":return "green";case "failed":return "red";case "stopped":case "dropped":return "yellow";default:return "white"}}function N(e,t){return t===void 0?e:t<=0?"":e.length>t?e.slice(0,t-1)+"\u2026":e.padEnd(t)}function Ut(e){try{let t=JSON.parse(e),o="exchangeId"in t?`${String(t.exchangeId).slice(0,8)}`:"",s="duration"in t?_(t.duration):"";if("operation"in t&&"routeId"in t){let r="adapter"in t?`(${t.adapter})`:"adapterId"in t?`(${t.adapterId})`:"",n="";if("metadata"in t&&typeof t.metadata=="object"&&t.metadata!==null){let u=t.metadata,l=Object.keys(u).slice(0,2);l.length>0&&(n=l.map(m=>`${m}=${u[m]}`).join(" "));}return {step:String(t.operation),adapter:r,exchange:o,duration:s,meta:n}}if("routeId"in t&&"exchangeId"in t){let r="error"in t?"(err)":"reason"in t?`(${String(t.reason).slice(0,8)})`:"";return {step:String(t.routeId),adapter:r,exchange:o,duration:s,meta:""}}if("route"in t&&typeof t.route=="object"&&t.route!==null){let r=t.route;return {step:r.routeId??r.definition?.id??"?",adapter:"",exchange:"",duration:"",meta:""}}if("pluginId"in t)return {step:`plugin=${t.pluginId}`,adapter:"",exchange:"",duration:"",meta:""};if("error"in t){let r=t.error;return {step:typeof r=="object"&&r!==null&&"message"in r?String(r.message):String(r),adapter:"",exchange:"",duration:"",meta:""}}return null}catch{return null}}function Dt(e,t){let o=Ut(t);return o||{step:t,adapter:"",exchange:"",duration:"",meta:""}}function q(e){return e.toLocaleString("en-US")}function at(e,t,o){return o<=0?t:e<t?e:e>=t+o?e-o+1:t}function Ce(e=0){let[t,o]=useState(e),[s,r]=useState(0),n=useCallback((m,d,g)=>{let p=Math.max(0,Math.min(m,d-1));o(p),r(f=>at(p,f,g));},[]),u=useCallback((m,d,g)=>{o(p=>{let f=Math.max(0,Math.min(p+m,d-1));return r(i=>at(f,i,g)),f});},[]),l=useCallback(()=>{o(0),r(0);},[]);return {selectedIndex:t,scrollOffset:s,moveBy:u,moveTo:n,reset:l}}function S({title:e,subtitle:t,color:o="gray",width:s,flexGrow:r,paddingX:n=1,children:u}){let l=s?s-2-n*2:20;return jsxs(Box,{flexDirection:"column",borderStyle:"round",borderColor:o,paddingX:n,width:s,flexGrow:r,children:[e&&jsxs(Fragment,{children:[jsxs(Text,{bold:true,children:[e,t&&jsxs(Fragment,{children:[" ",t]})]}),jsx(Text,{dimColor:true,children:"\u2500".repeat(Math.max(l,1))})]}),u]})}var Kt=[192,36,18,9],qt=10240,De=[{max:0,color:"gray"},{max:10,color:"green"},{max:20,color:"green"},{max:30,color:"yellow"},{max:40,color:"yellow"},{max:50,color:"red"}];function He({values:e,columns:t,steps:o=De,label:s}){let r=o.length-1,n=e.length>=t?e.slice(e.length-t):[...new Array(t-e.length).fill(0),...e],u=n.map(d=>{if(d<=0)return 0;for(let g=1;g<o.length;g++)if(d<o[g].max)return g;return r}),l=Math.ceil(r/4),m=[];for(let d=l-1;d>=0;d--){let g=d*4,p=[];for(let f=0;f<n.length;f++){let i=u[f],y=0,k="";for(let W=0;W<4;W++){let E=g+W+1;if(E>r)break;(i>=E||i===0&&E===1)&&(y|=Kt[W],k=i===0?o[0].color:o[E].color);}let L=String.fromCharCode(qt+y),K=p[p.length-1];K&&K.color===k?K.text+=L:p.push({text:L,color:k});}m.push(jsx(Text,{children:p.map((f,i)=>f.color?jsx(Text,{color:f.color,children:f.text},i):jsx(Text,{children:f.text},i))},d));}return jsxs(Fragment,{children:[m,s&&jsx(Text,{dimColor:true,children:s})]})}function Nt({route:e}){return jsxs(Fragment,{children:[jsxs(Text,{children:["Capability:"," ",jsx(Text,{bold:true,color:"cyan",children:e.id})]}),jsxs(Text,{children:["Status:"," ",jsx(Text,{bold:true,color:oe(e.status),children:e.status})," ","Exchanges: ",jsx(Text,{bold:true,children:q(e.totalExchanges)})," ","Errors:"," ",jsx(Text,{bold:true,...e.failedExchanges>0?{color:"red"}:{},children:q(e.failedExchanges)})," ","Dropped:"," ",jsx(Text,{bold:true,...e.droppedExchanges>0?{color:"yellow"}:{},children:q(e.droppedExchanges)})," ","Avg: ",jsx(Text,{bold:true,children:_(e.avgDurationMs)})]})]})}function Ee({columns:e,data:t,rowKey:o,selectedIndex:s,scrollOffset:r,visibleRows:n,gap:u=2,emptyMessage:l="No data",renderFullRow:m}){let d=" ".repeat(u),g=jsx(Box,{children:e.map((i,y)=>{let L=y===e.length-1?"":d;if(i.width==="flex")return jsxs(Fragment$1,{children:[jsx(Box,{flexGrow:1,children:jsx(Text,{bold:true,dimColor:true,children:i.header})}),L&&jsx(Text,{children:L})]},y);let K=i.align==="right"?i.header.padStart(i.width):N(i.header,i.width);return jsxs(Fragment$1,{children:[jsx(Text,{bold:true,dimColor:true,children:K}),L&&jsx(Text,{children:L})]},y)})});if(t.length===0)return jsxs(Fragment,{children:[g,jsx(Text,{dimColor:true,children:l})]});let p=t.slice(r,r+n),f=t.length-r-n;return jsxs(Fragment,{children:[g,p.map((i,y)=>{let k=r+y,L=k===s,K=m?.(i,k);return K!==void 0?jsx(Box,{children:K},o(i,k)):jsx(Box,{children:e.map((W,E)=>{let O=E===e.length-1?"":d,T=W.width==="flex"?void 0:W.width,w=W.render(i,L,T);return W.width==="flex"?jsxs(Fragment$1,{children:[jsx(Box,{flexGrow:1,children:jsx(Text,{wrap:"truncate",children:w})}),O&&jsx(Text,{children:O})]},E):jsxs(Fragment$1,{children:[w,O&&jsx(Text,{children:O})]},E)})},o(i,k))}),jsx(Text,{dimColor:true,children:f>0?"\u2193 more":" "})]})}function Je(e){let t=new WeakMap;function o(s){let r=e(s);if(!r)return;let n=t.get(r);return n||(n=Dt(r.eventName,r.details),t.set(r,n)),n}return [{header:"Step",width:10,render:(s,r,n)=>{let u=o(s);return u?jsx(Text,{children:N(u.step,n)}):jsx(Text,{children:N("",n)})}},{header:"Adapter",width:10,render:(s,r,n)=>{let u=o(s);return u?jsx(Text,{children:N(u.adapter,n)}):jsx(Text,{children:N("",n)})}},{header:"Exchange",width:12,render:(s,r,n)=>{let u=o(s);return u?jsx(Text,{children:N(u.exchange,n)}):jsx(Text,{children:N("",n)})}},{header:"Duration",width:8,align:"right",render:s=>{let r=o(s);return r?jsx(Text,{children:r.duration.padStart(8)}):jsx(Text,{children:""})}}]}function Te(){return {header:"",width:2,render:(e,t)=>jsx(Text,{...t?{color:"cyan"}:{},bold:t,children:t?"> ":" "})}}var er=[Te(),{header:"ID",width:"flex",render:(e,t)=>jsx(Text,{...t?{color:"cyan"}:{},bold:t,children:e.id})},{header:"Status",width:9,render:(e,t,o)=>jsx(Text,{color:oe(e.status),children:N(e.status,o)})},{header:"Duration",width:8,align:"right",render:e=>jsx(Text,{children:_(e.durationMs).padStart(8)})},{header:"Time",width:8,render:(e,t,o)=>jsx(Text,{dimColor:true,children:N(e.startedAt.replace("T"," ").slice(11,19),o)})}];function Ve({capabilityId:e,route:t,exchanges:o,selectedIndex:s,scrollOffset:r,width:n,height:u,color:l="gray",activity:m}){let d=Math.ceil((De.length-1)/4),g=t?2+d+2:0,p=Math.max(u-6-g,3),f=t?"EXCHANGES":`EXCHANGES: ${e}`;return jsxs(Box,{flexDirection:"column",width:n,flexGrow:1,children:[t&&jsxs(S,{width:n,children:[jsx(Nt,{route:t}),jsx(Text,{children:" "}),jsx(He,{values:m?m.throughput:[],columns:n-4,label:"Exchanges per 5s bucket"})]}),jsx(S,{title:f,width:n,flexGrow:1,color:l,children:jsx(Ee,{columns:er,data:o,rowKey:i=>i.id+i.contextId,selectedIndex:s,scrollOffset:r,visibleRows:p,emptyMessage:"No exchanges"})})]})}function tr(e){let t=[],o=/("(?:[^"\\]|\\.)*")\s*:|("(?:[^"\\]|\\.)*")|(-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?)|(\btrue\b|\bfalse\b)|(\bnull\b)|([{}[\],:])/g,s=0,r;for(;(r=o.exec(e))!==null;)r.index>s&&t.push({text:e.slice(s,r.index),type:"brace"}),r[1]!==void 0?(t.push({text:r[1],type:"key"}),t.push({text:":",type:"brace"})):r[2]!==void 0?t.push({text:r[2],type:"string"}):r[3]!==void 0?t.push({text:r[3],type:"number"}):r[4]!==void 0?t.push({text:r[4],type:"boolean"}):r[5]!==void 0?t.push({text:r[5],type:"null"}):r[6]!==void 0&&t.push({text:r[6],type:"brace"}),s=r.index+r[0].length;return s<e.length&&t.push({text:e.slice(s),type:"brace"}),t}var rr={key:"cyan",string:"green",number:"yellow",boolean:"yellow",null:"red",brace:"gray"};function Ae(e,t){try{let o=JSON.parse(e);return JSON.stringify(o,null,2).split(`
2
+ `).map(r=>{let n=Math.max(1,t);return r.length>n?r.slice(0,Math.max(0,n-1))+"\u2026":r})}catch{let o=Math.max(1,t);return e.split(`
3
+ `).map(s=>s.length>o?s.slice(0,Math.max(0,o-1))+"\u2026":s)}}function Ue({line:e}){let t=tr(e);return t.length===0?jsx(Text,{children:e}):jsx(Text,{children:t.map((o,s)=>jsx(Text,{color:rr[o.type],children:o.text},s))})}function We(e){try{let t=JSON.parse(e);return typeof t!="object"||t===null||Array.isArray(t)?null:t}catch{return null}}function or(e,t){let o=new Map,s=0;o.set(t,{exchangeId:t,label:"parent",events:[]});for(let r of e){let n=We(r.details),u=n?String(n.exchangeId??""):"",l=!u||u===t?t:u;o.has(l)||(s++,o.set(l,{exchangeId:l,label:`child ${s}`,events:[]})),o.get(l).events.push(r);}return Array.from(o.values())}var sr=[Te(),{header:"Time",width:8,render:(e,t,o)=>{if(!e.event)return jsx(Text,{children:N("",o)});let s=" ".repeat(e.indent);return jsxs(Text,{dimColor:true,children:[s,e.event.timestamp.replace("T"," ").slice(11,19)]})}},{header:"Event",width:"flex",render:e=>e.event?jsx(Text,{color:"cyan",children:e.event.eventName}):jsx(Text,{})},...Je(e=>e.event)];function Xe({exchange:e,events:t,width:o,height:s,scrollOffset:r,selectedIndex:n=-1,color:u="gray"}){let l=e.error?2:0,m=Math.max(s-9-l,3),d=or(t,e.id),g=d.length>1,p=[];for(let i of d){g&&p.push({type:"header",text:`${i.label} (${i.exchangeId.slice(0,8)}) - ${i.events.length} events`,indent:0});for(let y of i.events)p.push({type:"event",event:y,indent:g?2:0});}let f=g?`EXCHANGE FLOW (${d.length} exchanges, ${t.length} events)`:`RELATED EVENTS (${t.length})`;return jsxs(Box,{flexDirection:"column",width:o,flexGrow:1,children:[jsxs(S,{width:o,children:[jsxs(Text,{children:["Capability:"," ",jsx(Text,{bold:true,color:"cyan",children:e.routeId})]}),jsxs(Text,{children:["Exchange:"," ",jsx(Text,{bold:true,color:"cyan",children:ge(e.id,o-14)})]}),jsxs(Text,{children:["Status:"," ",jsx(Text,{bold:true,color:oe(e.status),children:e.status}),e.durationMs!==null&&jsxs(Text,{children:[" ","Duration:"," ",jsx(Text,{bold:true,children:_(e.durationMs)})]})," ","Started: ",jsx(Text,{bold:true,children:e.startedAt}),e.completedAt&&jsxs(Text,{children:[" ","Completed: ",jsx(Text,{bold:true,children:e.completedAt})]})]}),e.error&&e.status==="failed"&&jsxs(Fragment,{children:[jsx(Text,{children:" "}),jsxs(Text,{color:"red",children:["Error: ",e.error]})]}),e.error&&e.status==="dropped"&&jsxs(Fragment,{children:[jsx(Text,{children:" "}),jsxs(Text,{color:"yellow",children:["Reason: ",e.error]})]})]}),jsx(S,{title:f,width:o,flexGrow:1,color:u,children:jsx(Ee,{columns:sr,data:p,rowKey:(i,y)=>i.type==="header"?`h-${y}`:`${i.event?.id??i.event?.timestamp}-${y}`,selectedIndex:n,scrollOffset:r,visibleRows:m,emptyMessage:"No related events found",renderFullRow:i=>i.type==="header"?jsx(Text,{bold:true,color:"yellow",children:i.text}):void 0})})]})}var ar=[Te(),{header:"Time",width:19,render:(e,t,o)=>jsx(Text,{...t?{color:"cyan"}:{},bold:t,children:N(e.timestamp.replace("T"," ").slice(0,19),o)})},{header:"Event",width:"flex",render:e=>jsx(Text,{color:"cyan",children:e.eventName})},...Je(e=>e)];function Ot({events:e,selectedIndex:t,scrollOffset:o,width:s,height:r,color:n="gray"}){let u=Math.max(r-6,5);return jsx(S,{title:"EVENTS",subtitle:jsxs(Text,{dimColor:true,children:["(",e.length," total)"]}),width:s,flexGrow:1,color:n,children:jsx(Ee,{columns:ar,data:e,rowKey:(l,m)=>l.id!==void 0?String(l.id):`${l.timestamp}-${m}`,selectedIndex:t,scrollOffset:o,visibleRows:u,emptyMessage:"No events recorded yet."})})}function Ne({event:e,width:t,height:o,scrollOffset:s,color:r="cyan"}){let n=We(e.details),u=n&&typeof n.routeId=="string"?n.routeId:void 0,l=n&&typeof n.exchangeId=="string"?n.exchangeId:void 0,d=2+(1+(u?1:0)+(l?1:0)+2),g=5,p=Math.max(t-6,20),f=Ae(e.details,p),i=Math.max(o-d-g,3),y=f.slice(s,s+i);return jsxs(Box,{flexDirection:"column",width:t,flexGrow:1,children:[jsxs(S,{width:t,children:[jsxs(Text,{children:["Context:"," ",jsx(Text,{bold:true,color:"cyan",children:e.contextId})]}),u&&jsxs(Text,{children:["Capability:"," ",jsx(Text,{bold:true,color:"cyan",children:u})]}),l&&jsxs(Text,{children:["Exchange:"," ",jsx(Text,{bold:true,color:"cyan",children:l})]}),jsxs(Text,{children:["Event:"," ",jsx(Text,{bold:true,color:"cyan",children:e.eventName})]}),jsxs(Text,{children:["Time: ",jsx(Text,{bold:true,children:e.timestamp.replace("T"," ")})]})]}),jsxs(S,{title:"DETAILS",subtitle:jsxs(Text,{dimColor:true,children:["(",s+1,"-",Math.min(s+i,f.length),"/",f.length," lines)"]}),width:t,flexGrow:1,color:r,children:[y.map((k,L)=>jsx(Ue,{line:k},s+L)),y.length<i&&Array.from({length:i-y.length}).map((k,L)=>jsx(Text,{children:" "},`pad-${L}`))]})]})}function dr(e,t){let o=[];return o.push("HEADERS"),o.push(...Ae(e.headers,t)),o.push(""),o.push("BODY"),e.body!==null?(o.push(...Ae(e.body,t)),e.truncated&&(o.push(""),o.push("[Body truncated to configured limit]"))):o.push("[null]"),o}function qe({exchange:e,snapshot:t,width:o,height:s,scrollOffset:r,color:n="cyan"}){let m=Math.max(o-6,20),d=Math.max(s-5-5,3),p=t!==null?dr(t,m):["[Snapshots not captured]","","Enable with:"," telemetry({ sqlite: { captureSnapshots: true } })"],f=p.slice(r,r+d);return jsxs(Box,{flexDirection:"column",width:o,flexGrow:1,children:[jsxs(S,{width:o,children:[jsxs(Text,{children:["Capability:"," ",jsx(Text,{bold:true,color:"cyan",children:e.routeId})]}),jsxs(Text,{children:["Exchange:"," ",jsx(Text,{bold:true,color:"cyan",children:ge(e.id,o-14)})]}),jsxs(Text,{children:["Status:"," ",jsx(Text,{bold:true,color:oe(e.status),children:e.status}),e.durationMs!==null&&jsxs(Text,{children:[" ","Duration:"," ",jsx(Text,{bold:true,children:_(e.durationMs)})]})]})]}),jsxs(S,{title:"EXCHANGE SNAPSHOT",subtitle:jsxs(Text,{dimColor:true,children:["(",r+1,"-",Math.min(r+d,p.length),"/",p.length," lines)"]}),width:o,flexGrow:1,color:n,children:[f.map((i,y)=>i==="HEADERS"||i==="BODY"?jsx(Text,{bold:true,color:"yellow",children:i},r+y):i.startsWith("[")?jsx(Text,{dimColor:true,children:i},r+y):jsx(Ue,{line:i},r+y)),f.length<d&&Array.from({length:d-f.length}).map((i,y)=>jsx(Text,{children:" "},`pad-${y}`))]})]})}function ur(e){return e.failedExchanges>0?"red":e.totalExchanges>0?"green":"yellow"}function _t({routes:e,selectedIndex:t,listOffset:o,visibleRows:s,width:r}){let n=o;return jsxs(Fragment,{children:[jsx(Text,{children:" "}),jsx(Text,{bold:true,dimColor:true,children:"\u2500".repeat(r+2)}),e.length===0?jsx(Text,{dimColor:true,children:"No capabilities"}):e.slice(n,n+s).map((u,l)=>{let m=n+l;return jsxs(Text,{wrap:"truncate",children:[jsx(Text,{...m===t?{color:"cyan"}:{},bold:m===t,children:m===t?"> ":" "}),jsx(Text,{color:ur(u),children:"\u25CF "}),jsx(Text,{...m===t?{color:"cyan"}:{},bold:m===t,children:ge(u.id,r-2)})]},u.id)}),e.length>s&&jsxs(Text,{dimColor:true,children:[t+1,"/",e.length]})]})}function yr({db:e}){let{exit:t}=useApp(),{stdout:o}=useStdout(),s=o?.columns??80,r=o?.rows??24,[n,u]=useState("capabilities"),[l,m]=useState("nav"),[d,g]=useState(false),[p,f]=useState([]),[i,y]=useState({totalRoutes:0,totalExchanges:0,completedExchanges:0,failedExchanges:0,droppedExchanges:0,errorRate:0,avgDurationMs:null,p90DurationMs:null,p95DurationMs:null,p99DurationMs:null}),[k,L]=useState([]),[K,W]=useState(void 0),E=Ce(),[X,O]=useState([]),T=Ce(),[w,ht]=useState(void 0),[he,ft]=useState([]),[Be,gt]=useState([]),te=Ce(),F=Ce(),[re,bt]=useState(void 0),[G,ce]=useState(false),[Le,ne]=useState(0),[H,Ye]=useState(false),[ze,ke]=useState(0),[Qe,Pt]=useState(null),fe=50,de=10,Oe=Math.max(Math.min(Math.floor(s*.18),26),16),ue=Math.max(Math.min(Math.floor(s*.22),30),20),A=Math.max(s-Oe-ue,30),R=Math.max(r-5,10),Ze=Math.max(R-10,3),et=useCallback(()=>{try{let c=e.getRouteSummary();f(c),y(e.getMetrics());let a=ue-4;L(e.getLiveTrafficBuckets(a,5));let I=A-4,b=c[E.selectedIndex];if(b&&W(e.getSingleRouteActivity(b.id,I,5)),l==="center")return;if(n==="capabilities"){let h=c[E.selectedIndex];h&&O(e.getExchangesByRoute(h.id,fe));}else n==="exchanges"?O(e.getAllExchanges(fe)):n==="errors"?O(e.getFailedExchanges(fe)):n==="events"&&gt(e.getRecentEvents({limit:200}));}catch{}},[e,n,E.selectedIndex,ue,A,l]);useEffect(()=>{et();let c=setInterval(et,2e3);return ()=>{clearInterval(c);}},[et]);let yt=useCallback(c=>{E.moveTo(c,p.length,Ze),T.reset();let a=p[c];a&&O(e.getExchangesByRoute(a.id,fe));},[e,p,E,T,Ze]),jt=useCallback(c=>{u(c),g(false),ce(false),Ye(false),m("nav"),T.reset(),c==="exchanges"?O(e.getAllExchanges(fe)):c==="errors"?O(e.getFailedExchanges(fe)):c==="events"&&(te.reset(),gt(e.getRecentEvents({limit:200})));},[e,T,te]),tt=p[E.selectedIndex],Gt=Math.ceil((De.length-1)/4),Ft=tt?2+Gt+2:0,_e=Math.max(R-6-Ft,3),Et=Math.max(R-6,5);useInput((c,a)=>{if(c==="q"){e.close(),t();return}let I=Ct.find(b=>b.shortcut===c);if(I){jt(I.key);return}if(n==="events"){if(G){let b=a.ctrl?de:1;c==="j"||a.downArrow?ne(h=>h+b):c==="k"||a.upArrow?ne(h=>Math.max(h-b,0)):(a.escape||a.backspace||a.delete)&&(ce(false),ne(0));return}if(l==="nav")a.return&&m("center");else {let b=a.ctrl?de:1;if(c==="j"||a.downArrow)te.moveBy(b,Be.length,Et);else if(c==="k"||a.upArrow)te.moveBy(-b,Be.length,Et);else if(a.return){let h=Be[te.selectedIndex];h&&(bt(h),ne(0),ce(true));}else (a.escape||a.backspace||a.delete)&&(m("nav"),te.reset());}return}if(H){let b=a.ctrl?de:1;c==="j"||a.downArrow?ke(h=>h+b):c==="k"||a.upArrow?ke(h=>Math.max(h-b,0)):(a.escape||a.backspace||a.delete)&&(Ye(false),ke(0));return}if(d&&!G){let b=w?.error?2:0,h=Math.max(R-9-b,3),$t=new Set(he.map(me=>{try{let Re=JSON.parse(me.details);return String(Re.exchangeId??"")}catch{return ""}})),vt=Math.max($t.size,1),Jt=vt>1?vt:0,wt=he.length+Jt,Rt=a.ctrl?de:1;if(c==="j"||a.downArrow)F.moveBy(Rt,wt,h);else if(c==="k"||a.upArrow)F.moveBy(-Rt,wt,h);else if(a.return){let me=0,Re,Pe=w?.id??"",xe=new Map;xe.set(Pe,[]);for(let Se of he)try{let rt=JSON.parse(Se.details),nt=String(rt.exchangeId??""),ot=!nt||nt===Pe?Pe:nt;xe.has(ot)||xe.set(ot,[]),xe.get(ot).push(Se);}catch{xe.get(Pe).push(Se);}let Vt=xe.size>1;for(let[,Se]of xe){Vt&&me++;for(let rt of Se)me===F.selectedIndex&&(Re=rt),me++;}Re&&(bt(Re),ne(0),ce(true));}else if(c==="e"&&w){let me=e.getExchangeSnapshot(w.id);Pt(me),ke(0),Ye(true);}else (a.escape||a.backspace||a.delete)&&(F.reset(),g(false));return}if(d&&G){let b=a.ctrl?de:1;c==="j"||a.downArrow?ne(h=>h+b):c==="k"||a.upArrow?ne(h=>Math.max(h-b,0)):(a.escape||a.backspace||a.delete)&&(ce(false),ne(0));return}if(n==="capabilities"&&l==="nav"){if(c==="j"||a.downArrow)yt(Math.min(E.selectedIndex+1,p.length-1));else if(c==="k"||a.upArrow)yt(Math.max(E.selectedIndex-1,0));else if(a.return){m("center");let b=p[E.selectedIndex];b&&O(e.getExchangesByRoute(b.id));}return}if(n==="capabilities"&&l==="center"){let b=a.ctrl?de:1;if(c==="j"||a.downArrow)T.moveBy(b,X.length,_e);else if(c==="k"||a.upArrow)T.moveBy(-b,X.length,_e);else if(a.return){let h=X[T.selectedIndex];h&&(ht(h),ft(e.getEventsByExchange(h.id,h.correlationId)),F.reset(),ce(false),g(true));}else (a.escape||a.backspace||a.delete)&&(m("nav"),T.reset());return}if(n==="exchanges"||n==="errors"){if(l==="nav")a.return&&(m("center"),O(n==="exchanges"?e.getAllExchanges():e.getFailedExchanges()));else {let b=a.ctrl?de:1;if(c==="j"||a.downArrow)T.moveBy(b,X.length,_e);else if(c==="k"||a.upArrow)T.moveBy(-b,X.length,_e);else if(a.return){let h=X[T.selectedIndex];h&&(ht(h),ft(e.getEventsByExchange(h.id,h.correlationId)),F.reset(),ce(false),g(true));}else (a.escape||a.backspace||a.delete)&&(m("nav"),T.reset());}return}});let Tt=n==="capabilities"&&l==="nav"&&!d,Ht=!Tt,D=[];return H?(D.push({key:"j/k",action:"Scroll"}),D.push({key:"Ctrl+j/k",action:"Jump 10"}),D.push({key:"Esc",action:"Back"})):l==="center"&&(D.push({key:"j/k",action:"Navigate"}),D.push({key:"Ctrl+j/k",action:"Jump 10"})),H||(l==="nav"?n==="capabilities"?(D.push({key:"j/k",action:"Navigate"}),D.push({key:"Enter",action:"Exchanges"})):D.push({key:"Enter",action:"Browse"}):!d&&!G?(D.push({key:"Enter",action:"Detail"}),D.push({key:"Esc",action:"Back"})):d&&!G?(D.push({key:"Enter",action:"Event detail"}),D.push({key:"e",action:"Snapshot"}),D.push({key:"Esc",action:"Back"})):D.push({key:"Esc",action:"Back"})),D.push({key:"1..4",action:"Switch view"}),D.push({key:"q",action:"Quit"}),jsxs(Box,{flexDirection:"column",width:s,height:r,children:[jsxs(Box,{borderStyle:"round",borderColor:"cyan",paddingX:1,width:s,children:[jsx(Text,{bold:true,color:"cyan",children:"ROUTECRAFT TUI"}),jsx(Text,{children:" "}),jsx(Text,{dimColor:true,children:"v0.4.0"})]}),jsxs(Box,{flexDirection:"row",width:s,flexGrow:1,children:[jsx(Box,{flexDirection:"column",width:Oe,children:jsxs(S,{title:"NAVIGATION",color:Tt?"cyan":"gray",width:Oe,flexGrow:1,children:[st.map((c,a)=>jsxs(Box,{flexDirection:"column",children:[a>0&&jsx(Text,{children:" "}),c.label&&jsx(Text,{dimColor:true,bold:true,children:c.label}),c.items.map(I=>jsxs(Text,{children:[jsxs(Text,{bold:n===I.key,...n===I.key?{color:"cyan"}:{},children:[n===I.key?"> ":" ",I.label]}),jsxs(Text,{dimColor:true,children:[" (",I.shortcut,")"]})]},I.key))]},c.label??a)),n==="capabilities"&&jsx(_t,{routes:p,selectedIndex:E.selectedIndex,listOffset:E.scrollOffset,visibleRows:Ze,width:Oe-6})]})}),n==="capabilities"&&!d&&jsx(Ve,{capabilityId:tt?.id??"",route:tt,exchanges:X,selectedIndex:l==="center"?T.selectedIndex:-1,scrollOffset:l==="center"?T.scrollOffset:0,width:A,height:R,color:Ht?"cyan":"gray",activity:K}),n==="capabilities"&&H&&w&&jsx(qe,{exchange:w,snapshot:Qe,width:A,height:R,scrollOffset:ze,color:"cyan"}),n==="capabilities"&&d&&w&&!G&&!H&&jsx(Xe,{exchange:w,events:he,width:A,height:R,selectedIndex:F.selectedIndex,scrollOffset:F.scrollOffset,color:"cyan"}),n==="capabilities"&&d&&G&&!H&&re&&jsx(Ne,{event:re,width:A,height:R,scrollOffset:Le,color:"cyan"}),n==="exchanges"&&!d&&jsx(Ve,{capabilityId:"All Capabilities",exchanges:X,selectedIndex:l==="center"?T.selectedIndex:-1,scrollOffset:l==="center"?T.scrollOffset:0,width:A,height:R,color:l==="center"?"cyan":"gray"}),n==="exchanges"&&H&&w&&jsx(qe,{exchange:w,snapshot:Qe,width:A,height:R,scrollOffset:ze,color:"cyan"}),n==="exchanges"&&d&&w&&!G&&!H&&jsx(Xe,{exchange:w,events:he,width:A,height:R,selectedIndex:F.selectedIndex,scrollOffset:F.scrollOffset,color:"cyan"}),n==="exchanges"&&d&&G&&!H&&re&&jsx(Ne,{event:re,width:A,height:R,scrollOffset:Le,color:"cyan"}),n==="errors"&&!d&&jsx(Ve,{capabilityId:"Failed Exchanges",exchanges:X,selectedIndex:l==="center"?T.selectedIndex:-1,scrollOffset:l==="center"?T.scrollOffset:0,width:A,height:R,color:l==="center"?"cyan":"gray"}),n==="errors"&&H&&w&&jsx(qe,{exchange:w,snapshot:Qe,width:A,height:R,scrollOffset:ze,color:"cyan"}),n==="errors"&&d&&w&&!G&&!H&&jsx(Xe,{exchange:w,events:he,width:A,height:R,selectedIndex:F.selectedIndex,scrollOffset:F.scrollOffset,color:"cyan"}),n==="errors"&&d&&G&&!H&&re&&jsx(Ne,{event:re,width:A,height:R,scrollOffset:Le,color:"cyan"}),n==="events"&&!G&&jsx(Ot,{events:Be,selectedIndex:l==="center"?te.selectedIndex:-1,scrollOffset:l==="center"?te.scrollOffset:0,width:A,height:R,color:l==="center"?"cyan":"gray"}),n==="events"&&G&&re&&jsx(Ne,{event:re,width:A,height:R,scrollOffset:Le,color:"cyan"}),jsxs(Box,{flexDirection:"column",width:ue,children:[jsxs(S,{title:"METRICS",width:ue,flexGrow:1,children:[jsx(He,{values:k,columns:ue-4,steps:[{max:0,color:"gray"},...Array.from({length:7},(c,a)=>({max:(a+1)*5,color:"green"})),...Array.from({length:7},(c,a)=>({max:35+(a+1)*10,color:"yellow"})),...Array.from({length:6},(c,a)=>({max:105+(a+1)*25,color:"red"}))],label:"Exchanges per 5s bucket"}),jsx(Text,{children:" "}),jsx(Text,{bold:true,dimColor:true,children:"THROUGHPUT"}),[["Exchanges",q(i.totalExchanges),"cyan"],["Completed",q(i.completedExchanges),"green"],["Errors",q(i.failedExchanges),i.failedExchanges>0?"red":"green"],["Dropped",q(i.droppedExchanges),i.droppedExchanges>0?"yellow":"green"],["Error Rate",`${(i.errorRate*100).toFixed(1)}%`,i.errorRate>.1?"red":"green"],["Capabilities",q(i.totalRoutes),""]].map(([c,a,I])=>jsxs(Box,{children:[jsxs(Text,{children:[c,":"]}),jsx(Box,{flexGrow:1,justifyContent:"flex-end",children:jsx(Text,{bold:true,...I?{color:I}:{},children:a})})]},c)),jsx(Text,{children:" "}),jsx(Text,{bold:true,dimColor:true,children:"LATENCY (5m)"}),[["Avg",_(i.avgDurationMs),""],["p90",_(i.p90DurationMs),""],["p95",_(i.p95DurationMs),""],["p99",_(i.p99DurationMs),""]].map(([c,a,I])=>jsxs(Box,{children:[jsxs(Text,{children:[c,":"]}),jsx(Box,{flexGrow:1,justifyContent:"flex-end",children:jsx(Text,{bold:true,...I?{color:I}:{},children:a})})]},c))]}),jsx(S,{title:"KEYMAP",width:ue,children:D.map(c=>jsxs(Box,{children:[jsx(Text,{children:c.action}),jsx(Box,{flexGrow:1,justifyContent:"flex-end",children:jsxs(Text,{color:"yellow",children:["[",c.key,"]"]})})]},c.key))})]})]})]})}async function Zn(e){let t;try{t=await a.open(e);}catch(s){let r=s instanceof Error?s.message:String(s);process.stderr.write(`Failed to open telemetry database: ${r}
4
+ `),process.stderr.write(`Path: ${e}
5
+ `),process.stderr.write(`Make sure you have a running Routecraft context with telemetry() enabled.
6
+ `),process.exit(1);}await render(jsx(yr,{db:t})).waitUntilExit();}export{Zn as renderTui};//# sourceMappingURL=app.js.map
7
+ //# sourceMappingURL=app.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/tui/types.ts","../../src/tui/utils.ts","../../src/tui/hooks/use-scroll-list.ts","../../src/tui/components/panel.tsx","../../src/tui/components/dot-graph.tsx","../../src/tui/components/route-header.tsx","../../src/tui/components/table.tsx","../../src/tui/components/event-columns.tsx","../../src/tui/components/center-exchange-list.tsx","../../src/tui/components/json-format.tsx","../../src/tui/components/center-exchange-detail.tsx","../../src/tui/components/events-view.tsx","../../src/tui/components/event-detail.tsx","../../src/tui/components/exchange-deep-view.tsx","../../src/tui/components/capability-list.tsx","../../src/tui/app.tsx"],"names":["NAV_SECTIONS","ALL_NAV_ITEMS","s","truncate","str","maxLen","formatDuration","ms","statusColor","status","col","len","parseEventDetail","raw","d","exchange","duration","adapter","meta","m","keys","k","qualifier","route","err","formatDetailColumns","_eventName","parsed","fmtNum","n","adjustScrollOffset","selected","currentOffset","visibleRows","useScrollList","initialIndex","selectedIndex","setSelectedIndex","useState","scrollOffset","setScrollOffset","moveTo","useCallback","index","listLength","clamped","off","moveBy","delta","prev","next","reset","Panel","title","subtitle","color","width","flexGrow","paddingX","children","innerWidth","jsxs","Box","Fragment","Text","jsx","BRAILLE_DOTS","BRAILLE_BASE","DEFAULT_STEPS","DotGraph","values","columns","steps","label","dotHeight","data","heights","v","i","termRows","rows","tr","baseStep","segments","ci","h","bits","sr","stepLevel","char","last","RouteHeader","Table","rowKey","gap","emptyMessage","renderFullRow","gapStr","header","c","after","text","visible","remaining","row","vi","dataIndex","fullRow","resolved","cell","eventDetailColumns","accessor","cache","getColumns","ev","cols","_sel","w","selectorColumn","_row","exchangeColumns","CenterExchangeList","capabilityId","exchanges","height","activity","graphTermRows","headerRows","tableRows","ex","tokenizeLine","line","tokens","re","lastIndex","match","TOKEN_COLORS","formatJson","maxWidth","clampedMax","ColoredJsonLine","token","parseDetails","groupEventsByExchange","events","parentExchangeId","groups","childIndex","exId","key","detailColumns","indent","CenterExchangeDetail","hasExtra","eventRows","hasChildren","displayRows","group","eventsTitle","eventColumns","EventsView","EventDetail","event","routeId","exchangeId","headerHeight","jsonChrome","jsonWidth","jsonLines","_","buildSnapshotLines","snapshot","lines","ExchangeDeepView","dotColor","CapabilityList","routes","listOffset","offset","App","db","exit","useApp","stdout","useStdout","activeNav","setActiveNav","focus","setFocus","showDetail","setShowDetail","setRoutes","metrics","setMetrics","liveTraffic","setLiveTraffic","selectedRouteActivity","setSelectedRouteActivity","routeScroll","setExchanges","exchangeScroll","selectedExchange","setSelectedExchange","exchangeEvents","setExchangeEvents","setEvents","eventScroll","detailScroll","selectedEvent","setSelectedEvent","showEventDetail","setShowEventDetail","eventDetailScroll","setEventDetailScroll","showDeepView","setShowDeepView","deepViewScroll","setDeepViewScroll","exchangeSnapshot","setExchangeSnapshot","PAGE_SIZE","JUMP","leftWidth","rightWidth","centerWidth","bodyHeight","navListHeight","refresh","routeSummary","liveCols","routeCols","curRoute","useEffect","timer","selectRoute","switchNav","nav","selectedRoute","exchangeHeaderRows","exchangeTableRows","eventsTableRows","useInput","input","navByShortcut","step","detailEventRows","uniqueExchangeIds","groupCount","totalDisplayRows","rowIndex","targetEvent","parentId","gKey","groupEvents","navActive","centerActive","keymapItems","section","si","item","value","renderTui","dbPath","TelemetryDb","msg","render"],"mappings":"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","file":"app.js","sourcesContent":["export type NavItem = \"capabilities\" | \"exchanges\" | \"errors\" | \"events\";\n\nexport type NavSection = {\n label?: string;\n items: { key: NavItem; label: string; shortcut: string }[];\n};\n\nexport const NAV_SECTIONS: NavSection[] = [\n {\n items: [{ key: \"capabilities\", label: \"Capabilities\", shortcut: \"1\" }],\n },\n {\n items: [\n { key: \"exchanges\", label: \"Exchanges\", shortcut: \"2\" },\n { key: \"errors\", label: \"Errors\", shortcut: \"3\" },\n { key: \"events\", label: \"Events\", shortcut: \"4\" },\n ],\n },\n];\n\nexport const ALL_NAV_ITEMS = NAV_SECTIONS.flatMap((s) => s.items);\n\nexport interface RouteSummary {\n id: string;\n status: string;\n totalExchanges: number;\n completedExchanges: number;\n failedExchanges: number;\n droppedExchanges: number;\n avgDurationMs: number | null;\n}\n\nexport interface ExchangeRecord {\n id: string;\n routeId: string;\n contextId: string;\n correlationId: string;\n status: string;\n startedAt: string;\n completedAt: string | null;\n durationMs: number | null;\n error: string | null;\n}\n\nexport interface EventRecord {\n id?: number;\n timestamp: string;\n contextId: string;\n eventName: string;\n details: string;\n}\n\nexport interface Metrics {\n totalRoutes: number;\n totalExchanges: number;\n completedExchanges: number;\n failedExchanges: number;\n droppedExchanges: number;\n errorRate: number;\n avgDurationMs: number | null;\n p90DurationMs: number | null;\n p95DurationMs: number | null;\n p99DurationMs: number | null;\n}\n\nexport interface ExchangeSnapshot {\n headers: string;\n body: string | null;\n truncated: boolean;\n}\n\nexport interface RouteActivity {\n throughput: number[];\n recentErrors: number;\n}\n","export function truncate(str: string, maxLen: number): string {\n if (maxLen <= 0) return \"\";\n return str.length > maxLen ? str.slice(0, maxLen - 1) + \"\\u2026\" : str;\n}\n\nexport function formatDuration(ms: number | null): string {\n if (ms === null || ms === undefined) return \"-\";\n if (!Number.isFinite(ms) || ms < 0) return \"-\";\n if (ms === 0) return \"<1ms\";\n if (ms < 1000) return `${Math.round(ms)}ms`;\n return `${(ms / 1000).toFixed(1)}s`;\n}\n\nexport function statusColor(status: string): string {\n switch (status) {\n case \"completed\":\n case \"started\":\n return \"green\";\n case \"failed\":\n return \"red\";\n case \"stopped\":\n case \"dropped\":\n return \"yellow\";\n default:\n return \"white\";\n }\n}\n\nexport function col(str: string, len: number | undefined): string {\n if (len === undefined) return str;\n if (len <= 0) return \"\";\n if (str.length > len) return str.slice(0, len - 1) + \"\\u2026\";\n return str.padEnd(len);\n}\n\n// Fixed column widths for the Details column so fields line up across rows.\n// All event types share the same 4-column layout:\n// [col1: 10] [col2: 10] [exId: 12] [dur: 6] [extra]\n// Step events: operation (adapter) id… dur metadata\n// Exchange events: routeId (status) id… dur\nconst DET = {\n COL1: 10, // operation or routeId\n COL2: 10, // (adapter) or (err)/(reason)/(dropped)\n EX: 12, // \"789003e7 \"\n DUR: 6, // \"1ms \" \"10.0s \"\n} as const;\n\nexport interface DetailColumns {\n step: string;\n adapter: string;\n exchange: string;\n duration: string;\n meta: string;\n}\n\n/**\n * Parse a JSON event detail string into structured columns.\n * Shared normalizer used by both formatDetails and formatDetailColumns.\n */\nfunction parseEventDetail(raw: string): DetailColumns | null {\n try {\n const d = JSON.parse(raw) as Record<string, unknown>;\n\n const exchange =\n \"exchangeId\" in d ? `${String(d[\"exchangeId\"]).slice(0, 8)}` : \"\";\n const duration =\n \"duration\" in d ? formatDuration(d[\"duration\"] as number) : \"\";\n\n // Step/operation events\n if (\"operation\" in d && \"routeId\" in d) {\n const adapter =\n \"adapter\" in d\n ? `(${d[\"adapter\"]})`\n : \"adapterId\" in d\n ? `(${d[\"adapterId\"]})`\n : \"\";\n let meta = \"\";\n if (\n \"metadata\" in d &&\n typeof d[\"metadata\"] === \"object\" &&\n d[\"metadata\"] !== null\n ) {\n const m = d[\"metadata\"] as Record<string, unknown>;\n const keys = Object.keys(m).slice(0, 2);\n if (keys.length > 0) meta = keys.map((k) => `${k}=${m[k]}`).join(\" \");\n }\n return {\n step: String(d[\"operation\"]),\n adapter,\n exchange,\n duration,\n meta,\n };\n }\n\n // Exchange events\n if (\"routeId\" in d && \"exchangeId\" in d) {\n const qualifier =\n \"error\" in d\n ? \"(err)\"\n : \"reason\" in d\n ? `(${String(d[\"reason\"]).slice(0, 8)})`\n : \"\";\n return {\n step: String(d[\"routeId\"]),\n adapter: qualifier,\n exchange,\n duration,\n meta: \"\",\n };\n }\n\n // Route lifecycle events\n if (\"route\" in d && typeof d[\"route\"] === \"object\" && d[\"route\"] !== null) {\n const route = d[\"route\"] as {\n routeId?: string;\n definition?: { id?: string };\n };\n return {\n step: route.routeId ?? route.definition?.id ?? \"?\",\n adapter: \"\",\n exchange: \"\",\n duration: \"\",\n meta: \"\",\n };\n }\n\n // Plugin events\n if (\"pluginId\" in d) {\n return {\n step: `plugin=${d[\"pluginId\"]}`,\n adapter: \"\",\n exchange: \"\",\n duration: \"\",\n meta: \"\",\n };\n }\n\n // Error events\n if (\"error\" in d) {\n const err = d[\"error\"];\n const msg =\n typeof err === \"object\" && err !== null && \"message\" in err\n ? String((err as { message: string }).message)\n : String(err);\n return {\n step: msg,\n adapter: \"\",\n exchange: \"\",\n duration: \"\",\n meta: \"\",\n };\n }\n\n return null;\n } catch {\n return null;\n }\n}\n\nexport function formatDetails(_eventName: string, raw: string): string {\n const parsed = parseEventDetail(raw);\n if (!parsed) {\n return raw.length > 100 ? raw.slice(0, 97) + \"...\" : raw;\n }\n\n // Non-columnar events (plugin, route lifecycle, error) have no exchange/duration\n if (!parsed.exchange && !parsed.duration && !parsed.adapter) {\n return parsed.step;\n }\n\n return [\n col(parsed.step, DET.COL1),\n col(parsed.adapter, DET.COL2),\n col(parsed.exchange, DET.EX),\n col(parsed.duration, DET.DUR),\n parsed.meta,\n ]\n .join(\" \")\n .trimEnd();\n}\n\n/**\n * Structured version of formatDetails that returns individual columns\n * so the component can control alignment per-column.\n */\nexport function formatDetailColumns(\n _eventName: string,\n raw: string,\n): DetailColumns {\n const parsed = parseEventDetail(raw);\n if (!parsed) {\n return { step: raw, adapter: \"\", exchange: \"\", duration: \"\", meta: \"\" };\n }\n return parsed;\n}\n\n/**\n * Render a single-line sparkline from an array of values.\n * Uses Unicode block characters (▁▂▃▄▅▆▇█).\n * Empty/zero-only input returns spaces of the same length.\n */\nexport function sparkline(values: number[]): string {\n if (values.length === 0) return \"\";\n const blocks = [\n \" \",\n \"\\u2581\",\n \"\\u2582\",\n \"\\u2583\",\n \"\\u2584\",\n \"\\u2585\",\n \"\\u2586\",\n \"\\u2587\",\n \"\\u2588\",\n ];\n const max = Math.max(...values, 1);\n return values\n .map((v) => {\n const idx = Math.max(0, Math.min(8, Math.round((v / max) * 8)));\n return blocks[Number.isFinite(idx) ? idx : 0];\n })\n .join(\"\");\n}\n\nexport function fmtNum(n: number): string {\n return n.toLocaleString(\"en-US\");\n}\n\n/**\n * Adjust scroll offset so the selected item stays visible without centering.\n * The cursor moves freely within the visible window; the list only scrolls\n * when the cursor hits the top or bottom edge.\n *\n * @param selected - New selected index\n * @param currentOffset - Current scroll offset (tracked as state by the caller)\n * @param visibleRows - Number of rows visible in the list\n * @returns Updated scroll offset\n */\nexport function adjustScrollOffset(\n selected: number,\n currentOffset: number,\n visibleRows: number,\n): number {\n if (visibleRows <= 0) return currentOffset;\n if (selected < currentOffset) return selected;\n if (selected >= currentOffset + visibleRows)\n return selected - visibleRows + 1;\n return currentOffset;\n}\n","import { useState, useCallback } from \"react\";\nimport { adjustScrollOffset } from \"../utils.js\";\n\nexport interface ScrollListState {\n selectedIndex: number;\n scrollOffset: number;\n /** Move selection by delta (positive = down, negative = up). */\n moveBy: (delta: number, listLength: number, visibleRows: number) => void;\n /** Jump to an absolute index. */\n moveTo: (index: number, listLength: number, visibleRows: number) => void;\n /** Reset selection and scroll to the beginning. */\n reset: () => void;\n}\n\n/**\n * Manages a paired (selectedIndex, scrollOffset) state for scrollable lists.\n * Keeps the selected item visible without centering.\n *\n * `listLength` and `visibleRows` are passed at call time (not stored)\n * because they change every render (terminal resize, data load).\n */\nexport function useScrollList(initialIndex = 0): ScrollListState {\n const [selectedIndex, setSelectedIndex] = useState(initialIndex);\n const [scrollOffset, setScrollOffset] = useState(0);\n\n const moveTo = useCallback(\n (index: number, listLength: number, visibleRows: number) => {\n const clamped = Math.max(0, Math.min(index, listLength - 1));\n setSelectedIndex(clamped);\n setScrollOffset((off) => adjustScrollOffset(clamped, off, visibleRows));\n },\n [],\n );\n\n const moveBy = useCallback(\n (delta: number, listLength: number, visibleRows: number) => {\n setSelectedIndex((prev) => {\n const next = Math.max(0, Math.min(prev + delta, listLength - 1));\n setScrollOffset((off) => adjustScrollOffset(next, off, visibleRows));\n return next;\n });\n },\n [],\n );\n\n const reset = useCallback(() => {\n setSelectedIndex(0);\n setScrollOffset(0);\n }, []);\n\n return { selectedIndex, scrollOffset, moveBy, moveTo, reset };\n}\n","import type { ReactNode } from \"react\";\nimport { Box, Text } from \"ink\";\n\nexport function Panel({\n title,\n subtitle,\n color = \"gray\",\n width,\n flexGrow,\n paddingX = 1,\n children,\n}: {\n title?: string;\n subtitle?: ReactNode;\n color?: string;\n width?: number;\n flexGrow?: number;\n paddingX?: number;\n children: ReactNode;\n}) {\n // Border adds 2 chars per side; padding adds paddingX per side\n const innerWidth = width ? width - 2 - paddingX * 2 : 20;\n\n return (\n <Box\n flexDirection=\"column\"\n borderStyle=\"round\"\n borderColor={color}\n paddingX={paddingX}\n width={width}\n flexGrow={flexGrow}\n >\n {title && (\n <>\n <Text bold>\n {title}\n {subtitle && <> {subtitle}</>}\n </Text>\n <Text dimColor>{\"\\u2500\".repeat(Math.max(innerWidth, 1))}</Text>\n </>\n )}\n {children}\n </Box>\n );\n}\n","import { Text } from \"ink\";\n\n/**\n * Braille layout: 1 bucket per character, both columns.\n *\n * Left Right\n * 0x01 0x08 sub-row 0 (top)\n * 0x02 0x10 sub-row 1\n * 0x04 0x20 sub-row 2\n * 0x40 0x80 sub-row 3 (bottom)\n *\n * Each terminal character represents 1 time bucket.\n * Both columns mirror the same data for btop-style dot density.\n * Each terminal row packs up to 4 step levels vertically.\n */\nconst BRAILLE_DOTS = [\n 0x40 | 0x80,\n 0x04 | 0x20,\n 0x02 | 0x10,\n 0x01 | 0x08,\n] as const; // bottom to top\nconst BRAILLE_BASE = 0x2800;\n\nexport interface DotStep {\n max: number;\n color: string;\n}\n\n/** Default 5-step config: gray baseline, green low, yellow mid, red high. */\nexport const DEFAULT_STEPS: DotStep[] = [\n { max: 0, color: \"gray\" },\n { max: 10, color: \"green\" },\n { max: 20, color: \"green\" },\n { max: 30, color: \"yellow\" },\n { max: 40, color: \"yellow\" },\n { max: 50, color: \"red\" },\n];\n\n/**\n * Stacked dot graph using braille characters.\n *\n * 1 bucket = 1 terminal character. Both braille columns mirror the same\n * data for btop-style dot density. Each character can stack up to 4 step\n * levels vertically.\n *\n * - 0 exchanges: gray baseline dot (bottom)\n * - 1-9 exchanges: green dot (bottom)\n * - 10-19 exchanges: two green dots stacked\n * - etc., stacking upward with per-level colors\n */\nexport function DotGraph({\n values,\n columns,\n steps = DEFAULT_STEPS,\n label,\n}: {\n values: number[];\n columns: number;\n steps?: DotStep[];\n label?: string;\n}) {\n const dotHeight = steps.length - 1;\n\n // Right-align: newest on right, pad left with zeros\n const data =\n values.length >= columns\n ? values.slice(values.length - columns)\n : [\n ...(new Array(columns - values.length).fill(0) as number[]),\n ...values,\n ];\n\n // Map each value to a step index (0 = baseline, 1..dotHeight)\n const heights = data.map((v) => {\n if (v <= 0) return 0;\n for (let i = 1; i < steps.length; i++) {\n if (v < steps[i]!.max) return i;\n }\n return dotHeight;\n });\n\n const termRows = Math.ceil(dotHeight / 4);\n\n // Build terminal rows from top to bottom\n const rows: JSX.Element[] = [];\n for (let tr = termRows - 1; tr >= 0; tr--) {\n const baseStep = tr * 4;\n\n // For each bucket, compute the braille bits and color for this terminal row\n const segments: { text: string; color: string }[] = [];\n\n for (let ci = 0; ci < data.length; ci++) {\n const h = heights[ci]!;\n let bits = 0;\n let color = \"\";\n\n for (let sr = 0; sr < 4; sr++) {\n const stepLevel = baseStep + sr + 1;\n if (stepLevel > dotHeight) break;\n\n // Show dot if height reaches this level, or baseline dot for zero values\n const on = h >= stepLevel || (h === 0 && stepLevel === 1);\n if (on) {\n bits |= BRAILLE_DOTS[sr]!;\n // Color: gray for baseline (zero), step color for data\n color = h === 0 ? steps[0]!.color : steps[stepLevel]!.color;\n }\n }\n\n const char = String.fromCharCode(BRAILLE_BASE + bits);\n const last = segments[segments.length - 1];\n if (last && last.color === color) {\n last.text += char;\n } else {\n segments.push({ text: char, color });\n }\n }\n\n rows.push(\n <Text key={tr}>\n {segments.map((s, i) =>\n s.color ? (\n <Text key={i} color={s.color}>\n {s.text}\n </Text>\n ) : (\n <Text key={i}>{s.text}</Text>\n ),\n )}\n </Text>,\n );\n }\n\n return (\n <>\n {rows}\n {label && <Text dimColor>{label}</Text>}\n </>\n );\n}\n","import { Text } from \"ink\";\nimport type { RouteSummary } from \"../types.js\";\nimport { statusColor, fmtNum, formatDuration } from \"../utils.js\";\n\nexport function RouteHeader({ route }: { route: RouteSummary }) {\n return (\n <>\n <Text>\n Capability:{\" \"}\n <Text bold color=\"cyan\">\n {route.id}\n </Text>\n </Text>\n <Text>\n Status:{\" \"}\n <Text bold color={statusColor(route.status)}>\n {route.status}\n </Text>\n {\" \"}Exchanges: <Text bold>{fmtNum(route.totalExchanges)}</Text>\n {\" \"}Errors:{\" \"}\n <Text\n bold\n {...(route.failedExchanges > 0 ? { color: \"red\" as const } : {})}\n >\n {fmtNum(route.failedExchanges)}\n </Text>\n {\" \"}Dropped:{\" \"}\n <Text\n bold\n {...(route.droppedExchanges > 0 ? { color: \"yellow\" as const } : {})}\n >\n {fmtNum(route.droppedExchanges)}\n </Text>\n {\" \"}Avg: <Text bold>{formatDuration(route.avgDurationMs)}</Text>\n </Text>\n </>\n );\n}\n","import { Fragment, type ReactNode } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { col } from \"../utils.js\";\n\nexport interface ColumnDef<T> {\n /** Header label */\n header: string;\n /** Fixed character width, or \"flex\" to fill remaining space */\n width: number | \"flex\";\n /** Text alignment. Default: \"left\" */\n align?: \"left\" | \"right\";\n /** Render cell content. `colWidth` is the resolved width for fixed columns, undefined for flex. */\n render: (\n row: T,\n selected: boolean,\n colWidth: number | undefined,\n ) => ReactNode;\n}\n\nexport interface TableProps<T> {\n columns: ColumnDef<T>[];\n data: T[];\n /** Unique key for each row */\n rowKey: (row: T, index: number) => string;\n /** Selected row index in full data array, or -1/undefined for no selection */\n selectedIndex?: number;\n /** First visible row (scroll offset) */\n scrollOffset: number;\n /** Number of visible rows */\n visibleRows: number;\n /** Gap between columns in characters. Default: 2 */\n gap?: number;\n /** Message when data is empty */\n emptyMessage?: string;\n /**\n * Optional full-row override for special rows (e.g., group headers).\n * Return undefined to use normal column rendering.\n */\n renderFullRow?: (row: T, index: number) => ReactNode | undefined;\n}\n\nexport function Table<T>({\n columns,\n data,\n rowKey,\n selectedIndex,\n scrollOffset,\n visibleRows,\n gap = 2,\n emptyMessage = \"No data\",\n renderFullRow,\n}: TableProps<T>) {\n const gapStr = \" \".repeat(gap);\n\n // Header\n const header = (\n <Box>\n {columns.map((c, ci) => {\n const isLast = ci === columns.length - 1;\n const after = isLast ? \"\" : gapStr;\n\n if (c.width === \"flex\") {\n return (\n <Fragment key={ci}>\n <Box flexGrow={1}>\n <Text bold dimColor>\n {c.header}\n </Text>\n </Box>\n {after && <Text>{after}</Text>}\n </Fragment>\n );\n }\n\n const text =\n c.align === \"right\"\n ? c.header.padStart(c.width)\n : col(c.header, c.width);\n\n return (\n <Fragment key={ci}>\n <Text bold dimColor>\n {text}\n </Text>\n {after && <Text>{after}</Text>}\n </Fragment>\n );\n })}\n </Box>\n );\n\n if (data.length === 0) {\n return (\n <>\n {header}\n <Text dimColor>{emptyMessage}</Text>\n </>\n );\n }\n\n const visible = data.slice(scrollOffset, scrollOffset + visibleRows);\n const remaining = data.length - scrollOffset - visibleRows;\n\n return (\n <>\n {header}\n {visible.map((row, vi) => {\n const dataIndex = scrollOffset + vi;\n const selected = dataIndex === selectedIndex;\n\n // Full-row override (e.g., group headers)\n const fullRow = renderFullRow?.(row, dataIndex);\n if (fullRow !== undefined) {\n return <Box key={rowKey(row, dataIndex)}>{fullRow}</Box>;\n }\n\n return (\n <Box key={rowKey(row, dataIndex)}>\n {columns.map((c, ci) => {\n const isLast = ci === columns.length - 1;\n const after = isLast ? \"\" : gapStr;\n const resolved = c.width === \"flex\" ? undefined : c.width;\n const cell = c.render(row, selected, resolved);\n\n if (c.width === \"flex\") {\n return (\n <Fragment key={ci}>\n <Box flexGrow={1}>\n <Text wrap=\"truncate\">{cell}</Text>\n </Box>\n {after && <Text>{after}</Text>}\n </Fragment>\n );\n }\n\n return (\n <Fragment key={ci}>\n {cell}\n {after && <Text>{after}</Text>}\n </Fragment>\n );\n })}\n </Box>\n );\n })}\n <Text dimColor>{remaining > 0 ? \"\\u2193 more\" : \" \"}</Text>\n </>\n );\n}\n","import { Text } from \"ink\";\nimport type { EventRecord } from \"../types.js\";\nimport { col, formatDetailColumns, type DetailColumns } from \"../utils.js\";\nimport type { ColumnDef } from \"./table.js\";\n\n/**\n * Build the 4 standard event detail columns (Step, Adapter, Exchange, Duration).\n *\n * The accessor extracts an EventRecord from whatever row type T the table uses.\n * Returns undefined when the row has no event data (e.g., group headers).\n *\n * JSON is parsed once per row and shared across all 4 columns via a WeakMap cache.\n */\nexport function eventDetailColumns<T>(\n accessor: (row: T) => EventRecord | undefined,\n): ColumnDef<T>[] {\n const cache = new WeakMap<EventRecord, DetailColumns>();\n\n function getColumns(row: T): DetailColumns | undefined {\n const ev = accessor(row);\n if (!ev) return undefined;\n let cols = cache.get(ev);\n if (!cols) {\n cols = formatDetailColumns(ev.eventName, ev.details);\n cache.set(ev, cols);\n }\n return cols;\n }\n\n return [\n {\n header: \"Step\",\n width: 10,\n render: (row, _sel, w) => {\n const cols = getColumns(row);\n if (!cols) return <Text>{col(\"\", w)}</Text>;\n return <Text>{col(cols.step, w)}</Text>;\n },\n },\n {\n header: \"Adapter\",\n width: 10,\n render: (row, _sel, w) => {\n const cols = getColumns(row);\n if (!cols) return <Text>{col(\"\", w)}</Text>;\n return <Text>{col(cols.adapter, w)}</Text>;\n },\n },\n {\n header: \"Exchange\",\n width: 12,\n render: (row, _sel, w) => {\n const cols = getColumns(row);\n if (!cols) return <Text>{col(\"\", w)}</Text>;\n return <Text>{col(cols.exchange, w)}</Text>;\n },\n },\n {\n header: \"Duration\",\n width: 8,\n align: \"right\" as const,\n render: (row) => {\n const cols = getColumns(row);\n if (!cols) return <Text>{\"\"}</Text>;\n return <Text>{cols.duration.padStart(8)}</Text>;\n },\n },\n ];\n}\n\n/**\n * Selector column that shows \"> \" for the selected row.\n */\nexport function selectorColumn<T>(): ColumnDef<T> {\n return {\n header: \"\",\n width: 2,\n render: (_row, selected) => (\n <Text {...(selected ? { color: \"cyan\" as const } : {})} bold={selected}>\n {selected ? \"> \" : \" \"}\n </Text>\n ),\n };\n}\n","import { Box, Text } from \"ink\";\nimport type { ExchangeRecord, RouteSummary, RouteActivity } from \"../types.js\";\nimport { statusColor, formatDuration, col } from \"../utils.js\";\nimport { PANEL_TABLE_CHROME } from \"../layout.js\";\nimport { Panel } from \"./panel.js\";\nimport { RouteHeader } from \"./route-header.js\";\nimport { DotGraph, DEFAULT_STEPS } from \"./dot-graph.js\";\nimport { Table, type ColumnDef } from \"./table.js\";\nimport { selectorColumn } from \"./event-columns.js\";\n\nconst exchangeColumns: ColumnDef<ExchangeRecord>[] = [\n selectorColumn<ExchangeRecord>(),\n {\n header: \"ID\",\n width: \"flex\",\n render: (row, selected) => (\n <Text {...(selected ? { color: \"cyan\" as const } : {})} bold={selected}>\n {row.id}\n </Text>\n ),\n },\n {\n header: \"Status\",\n width: 9,\n render: (row, _sel, w) => (\n <Text color={statusColor(row.status)}>{col(row.status, w)}</Text>\n ),\n },\n {\n header: \"Duration\",\n width: 8,\n align: \"right\",\n render: (row) => <Text>{formatDuration(row.durationMs).padStart(8)}</Text>,\n },\n {\n header: \"Time\",\n width: 8,\n render: (row, _sel, w) => (\n <Text dimColor>\n {col(row.startedAt.replace(\"T\", \" \").slice(11, 19), w)}\n </Text>\n ),\n },\n];\n\nexport function CenterExchangeList({\n capabilityId,\n route,\n exchanges,\n selectedIndex,\n scrollOffset,\n width,\n height,\n color = \"gray\",\n activity,\n}: {\n capabilityId: string;\n route?: RouteSummary;\n exchanges: ExchangeRecord[];\n selectedIndex: number;\n scrollOffset: number;\n width: number;\n height: number;\n color?: string;\n activity?: RouteActivity | undefined;\n}) {\n const graphTermRows = Math.ceil((DEFAULT_STEPS.length - 1) / 4);\n const headerRows = route ? 2 + graphTermRows + 2 : 0;\n const tableRows = Math.max(height - PANEL_TABLE_CHROME - headerRows, 3);\n\n const title = route ? \"EXCHANGES\" : `EXCHANGES: ${capabilityId}`;\n\n return (\n <Box flexDirection=\"column\" width={width} flexGrow={1}>\n {route && (\n <Panel width={width}>\n <RouteHeader route={route} />\n <Text> </Text>\n <DotGraph\n values={activity ? activity.throughput : []}\n columns={width - 4}\n label=\"Exchanges per 5s bucket\"\n />\n </Panel>\n )}\n <Panel title={title} width={width} flexGrow={1} color={color}>\n <Table\n columns={exchangeColumns}\n data={exchanges}\n rowKey={(ex) => ex.id + ex.contextId}\n selectedIndex={selectedIndex}\n scrollOffset={scrollOffset}\n visibleRows={tableRows}\n emptyMessage=\"No exchanges\"\n />\n </Panel>\n </Box>\n );\n}\n","import { Text } from \"ink\";\n\n/** Token types for JSON syntax coloring. */\nexport type TokenType =\n | \"key\"\n | \"string\"\n | \"number\"\n | \"boolean\"\n | \"null\"\n | \"brace\";\n\nexport interface JsonToken {\n text: string;\n type: TokenType;\n}\n\n/**\n * Tokenize a single line of pretty-printed JSON into colored segments.\n * Handles: keys, string values, numbers, booleans, null, and structural chars.\n */\nexport function tokenizeLine(line: string): JsonToken[] {\n const tokens: JsonToken[] = [];\n const re =\n /(\"(?:[^\"\\\\]|\\\\.)*\")\\s*:|(\"(?:[^\"\\\\]|\\\\.)*\")|(-?\\d+(?:\\.\\d+)?(?:[eE][+-]?\\d+)?)|(\\btrue\\b|\\bfalse\\b)|(\\bnull\\b)|([{}[\\],:])/g;\n let lastIndex = 0;\n let match: RegExpExecArray | null;\n\n while ((match = re.exec(line)) !== null) {\n // Plain text before this match (whitespace / indent)\n if (match.index > lastIndex) {\n tokens.push({ text: line.slice(lastIndex, match.index), type: \"brace\" });\n }\n\n if (match[1] !== undefined) {\n // Key (the colon is part of the regex but we split it out)\n tokens.push({ text: match[1], type: \"key\" });\n tokens.push({ text: \":\", type: \"brace\" });\n } else if (match[2] !== undefined) {\n tokens.push({ text: match[2], type: \"string\" });\n } else if (match[3] !== undefined) {\n tokens.push({ text: match[3], type: \"number\" });\n } else if (match[4] !== undefined) {\n tokens.push({ text: match[4], type: \"boolean\" });\n } else if (match[5] !== undefined) {\n tokens.push({ text: match[5], type: \"null\" });\n } else if (match[6] !== undefined) {\n tokens.push({ text: match[6], type: \"brace\" });\n }\n\n lastIndex = match.index + match[0].length;\n }\n\n // Trailing text\n if (lastIndex < line.length) {\n tokens.push({ text: line.slice(lastIndex), type: \"brace\" });\n }\n\n return tokens;\n}\n\nexport const TOKEN_COLORS: Record<TokenType, string> = {\n key: \"cyan\",\n string: \"green\",\n number: \"yellow\",\n boolean: \"yellow\",\n null: \"red\",\n brace: \"gray\",\n};\n\n/**\n * Parse a JSON string into pretty-printed lines, truncating long lines.\n */\nexport function formatJson(raw: string, maxWidth: number): string[] {\n try {\n const parsed = JSON.parse(raw) as unknown;\n const pretty = JSON.stringify(parsed, null, 2);\n return pretty.split(\"\\n\").map((line) => {\n const clampedMax = Math.max(1, maxWidth);\n return line.length > clampedMax\n ? line.slice(0, Math.max(0, clampedMax - 1)) + \"\\u2026\"\n : line;\n });\n } catch {\n const clampedMax = Math.max(1, maxWidth);\n return raw\n .split(\"\\n\")\n .map((line) =>\n line.length > clampedMax\n ? line.slice(0, Math.max(0, clampedMax - 1)) + \"\\u2026\"\n : line,\n );\n }\n}\n\n/**\n * Render a single line of JSON with syntax coloring.\n */\nexport function ColoredJsonLine({ line }: { line: string }) {\n const tokens = tokenizeLine(line);\n if (tokens.length === 0) return <Text>{line}</Text>;\n return (\n <Text>\n {tokens.map((token, i) => (\n <Text key={i} color={TOKEN_COLORS[token.type]}>\n {token.text}\n </Text>\n ))}\n </Text>\n );\n}\n\n/**\n * Safely parse a JSON details string.\n */\nexport function parseDetails(raw: string): Record<string, unknown> | null {\n try {\n const parsed: unknown = JSON.parse(raw);\n if (\n typeof parsed !== \"object\" ||\n parsed === null ||\n Array.isArray(parsed)\n ) {\n return null;\n }\n return parsed as Record<string, unknown>;\n } catch {\n return null;\n }\n}\n","import { Box, Text } from \"ink\";\nimport type { ExchangeRecord, EventRecord } from \"../types.js\";\nimport { statusColor, formatDuration, col, truncate } from \"../utils.js\";\nimport { DETAIL_INFO_CHROME } from \"../layout.js\";\nimport { Panel } from \"./panel.js\";\nimport { Table, type ColumnDef } from \"./table.js\";\nimport { selectorColumn, eventDetailColumns } from \"./event-columns.js\";\nimport { parseDetails } from \"./json-format.js\";\n\ntype DisplayRow = {\n type: \"header\" | \"event\";\n text?: string;\n event?: EventRecord;\n indent: number;\n};\n\n/**\n * Group events by exchangeId to show parent/child flow.\n */\nfunction groupEventsByExchange(\n events: EventRecord[],\n parentExchangeId: string,\n): { exchangeId: string; label: string; events: EventRecord[] }[] {\n const groups = new Map<\n string,\n { exchangeId: string; label: string; events: EventRecord[] }\n >();\n let childIndex = 0;\n\n groups.set(parentExchangeId, {\n exchangeId: parentExchangeId,\n label: \"parent\",\n events: [],\n });\n\n for (const ev of events) {\n const d = parseDetails(ev.details);\n const exId = d ? String(d[\"exchangeId\"] ?? \"\") : \"\";\n const key = !exId || exId === parentExchangeId ? parentExchangeId : exId;\n\n if (!groups.has(key)) {\n childIndex++;\n groups.set(key, {\n exchangeId: key,\n label: `child ${childIndex}`,\n events: [],\n });\n }\n groups.get(key)!.events.push(ev);\n }\n\n return Array.from(groups.values());\n}\n\nconst detailColumns: ColumnDef<DisplayRow>[] = [\n selectorColumn<DisplayRow>(),\n {\n header: \"Time\",\n width: 8,\n render: (row, _sel, w) => {\n if (!row.event) return <Text>{col(\"\", w)}</Text>;\n const indent = \" \".repeat(row.indent);\n return (\n <Text dimColor>\n {indent}\n {row.event.timestamp.replace(\"T\", \" \").slice(11, 19)}\n </Text>\n );\n },\n },\n {\n header: \"Event\",\n width: \"flex\",\n render: (row) => {\n if (!row.event) return <Text />;\n return <Text color=\"cyan\">{row.event.eventName}</Text>;\n },\n },\n ...eventDetailColumns<DisplayRow>((row) => row.event),\n];\n\nexport function CenterExchangeDetail({\n exchange,\n events,\n width,\n height,\n scrollOffset,\n selectedIndex = -1,\n color = \"gray\",\n}: {\n exchange: ExchangeRecord;\n events: EventRecord[];\n width: number;\n height: number;\n scrollOffset: number;\n selectedIndex?: number;\n color?: string;\n}) {\n const hasExtra = exchange.error ? 2 : 0;\n const eventRows = Math.max(height - DETAIL_INFO_CHROME - hasExtra, 3);\n\n const groups = groupEventsByExchange(events, exchange.id);\n const hasChildren = groups.length > 1;\n\n const displayRows: DisplayRow[] = [];\n for (const group of groups) {\n if (hasChildren) {\n displayRows.push({\n type: \"header\",\n text: `${group.label} (${group.exchangeId.slice(0, 8)}) - ${group.events.length} events`,\n indent: 0,\n });\n }\n for (const ev of group.events) {\n displayRows.push({\n type: \"event\",\n event: ev,\n indent: hasChildren ? 2 : 0,\n });\n }\n }\n\n const eventsTitle = hasChildren\n ? `EXCHANGE FLOW (${groups.length} exchanges, ${events.length} events)`\n : `RELATED EVENTS (${events.length})`;\n\n return (\n <Box flexDirection=\"column\" width={width} flexGrow={1}>\n <Panel width={width}>\n <Text>\n Capability:{\" \"}\n <Text bold color=\"cyan\">\n {exchange.routeId}\n </Text>\n </Text>\n <Text>\n Exchange:{\" \"}\n <Text bold color=\"cyan\">\n {truncate(exchange.id, width - 14)}\n </Text>\n </Text>\n <Text>\n Status:{\" \"}\n <Text bold color={statusColor(exchange.status)}>\n {exchange.status}\n </Text>\n {exchange.durationMs !== null && (\n <Text>\n {\" \"}Duration:{\" \"}\n <Text bold>{formatDuration(exchange.durationMs)}</Text>\n </Text>\n )}\n {\" \"}Started: <Text bold>{exchange.startedAt}</Text>\n {exchange.completedAt && (\n <Text>\n {\" \"}Completed: <Text bold>{exchange.completedAt}</Text>\n </Text>\n )}\n </Text>\n {exchange.error && exchange.status === \"failed\" && (\n <>\n <Text> </Text>\n <Text color=\"red\">Error: {exchange.error}</Text>\n </>\n )}\n {exchange.error && exchange.status === \"dropped\" && (\n <>\n <Text> </Text>\n <Text color=\"yellow\">Reason: {exchange.error}</Text>\n </>\n )}\n </Panel>\n\n <Panel title={eventsTitle} width={width} flexGrow={1} color={color}>\n <Table\n columns={detailColumns}\n data={displayRows}\n rowKey={(row, i) =>\n row.type === \"header\"\n ? `h-${i}`\n : `${row.event?.id ?? row.event?.timestamp}-${i}`\n }\n selectedIndex={selectedIndex}\n scrollOffset={scrollOffset}\n visibleRows={eventRows}\n emptyMessage=\"No related events found\"\n renderFullRow={(row) =>\n row.type === \"header\" ? (\n <Text bold color=\"yellow\">\n {row.text}\n </Text>\n ) : undefined\n }\n />\n </Panel>\n </Box>\n );\n}\n","import { Text } from \"ink\";\nimport type { EventRecord } from \"../types.js\";\nimport { col } from \"../utils.js\";\nimport { PANEL_TABLE_CHROME } from \"../layout.js\";\nimport { Panel } from \"./panel.js\";\nimport { Table, type ColumnDef } from \"./table.js\";\nimport { selectorColumn, eventDetailColumns } from \"./event-columns.js\";\n\nconst eventColumns: ColumnDef<EventRecord>[] = [\n selectorColumn<EventRecord>(),\n {\n header: \"Time\",\n width: 19,\n render: (row, selected, w) => (\n <Text {...(selected ? { color: \"cyan\" as const } : {})} bold={selected}>\n {col(row.timestamp.replace(\"T\", \" \").slice(0, 19), w)}\n </Text>\n ),\n },\n {\n header: \"Event\",\n width: \"flex\",\n render: (row) => <Text color=\"cyan\">{row.eventName}</Text>,\n },\n ...eventDetailColumns<EventRecord>((row) => row),\n];\n\nexport function EventsView({\n events,\n selectedIndex,\n scrollOffset,\n width,\n height,\n color = \"gray\",\n}: {\n events: EventRecord[];\n selectedIndex: number;\n scrollOffset: number;\n width: number;\n height: number;\n color?: string;\n}) {\n const tableRows = Math.max(height - PANEL_TABLE_CHROME, 5);\n\n return (\n <Panel\n title=\"EVENTS\"\n subtitle={<Text dimColor>({events.length} total)</Text>}\n width={width}\n flexGrow={1}\n color={color}\n >\n <Table\n columns={eventColumns}\n data={events}\n rowKey={(ev, i) =>\n ev.id !== undefined ? String(ev.id) : `${ev.timestamp}-${i}`\n }\n selectedIndex={selectedIndex}\n scrollOffset={scrollOffset}\n visibleRows={tableRows}\n emptyMessage=\"No events recorded yet.\"\n />\n </Panel>\n );\n}\n","import { Box, Text } from \"ink\";\nimport type { EventRecord } from \"../types.js\";\nimport { Panel } from \"./panel.js\";\nimport { formatJson, ColoredJsonLine, parseDetails } from \"./json-format.js\";\n\nexport function EventDetail({\n event,\n width,\n height,\n scrollOffset,\n color = \"cyan\",\n}: {\n event: EventRecord;\n width: number;\n height: number;\n scrollOffset: number;\n color?: string;\n}) {\n const d = parseDetails(event.details);\n const routeId =\n d && typeof d[\"routeId\"] === \"string\" ? d[\"routeId\"] : undefined;\n const exchangeId =\n d && typeof d[\"exchangeId\"] === \"string\" ? d[\"exchangeId\"] : undefined;\n\n // Header lines: context (always) + capability + exchange + event + time\n const headerLines = 1 + (routeId ? 1 : 0) + (exchangeId ? 1 : 0) + 2;\n // Top panel: border (2) + content lines\n const headerHeight = 2 + headerLines;\n // Bottom panel: border (2) + title/separator (2) + footer (1) = 5\n const jsonChrome = 5;\n const jsonWidth = Math.max(width - 6, 20);\n const jsonLines = formatJson(event.details, jsonWidth);\n const visibleRows = Math.max(height - headerHeight - jsonChrome, 3);\n const visible = jsonLines.slice(scrollOffset, scrollOffset + visibleRows);\n\n return (\n <Box flexDirection=\"column\" width={width} flexGrow={1}>\n <Panel width={width}>\n <Text>\n Context:{\" \"}\n <Text bold color=\"cyan\">\n {event.contextId}\n </Text>\n </Text>\n {routeId && (\n <Text>\n Capability:{\" \"}\n <Text bold color=\"cyan\">\n {routeId}\n </Text>\n </Text>\n )}\n {exchangeId && (\n <Text>\n Exchange:{\" \"}\n <Text bold color=\"cyan\">\n {exchangeId}\n </Text>\n </Text>\n )}\n <Text>\n Event:{\" \"}\n <Text bold color=\"cyan\">\n {event.eventName}\n </Text>\n </Text>\n <Text>\n Time: <Text bold>{event.timestamp.replace(\"T\", \" \")}</Text>\n </Text>\n </Panel>\n\n <Panel\n title=\"DETAILS\"\n subtitle={\n <Text dimColor>\n ({scrollOffset + 1}-\n {Math.min(scrollOffset + visibleRows, jsonLines.length)}/\n {jsonLines.length} lines)\n </Text>\n }\n width={width}\n flexGrow={1}\n color={color}\n >\n {visible.map((line, i) => (\n <ColoredJsonLine key={scrollOffset + i} line={line} />\n ))}\n {visible.length < visibleRows &&\n Array.from({ length: visibleRows - visible.length }).map((_, i) => (\n <Text key={`pad-${i}`}> </Text>\n ))}\n </Panel>\n </Box>\n );\n}\n","import { Box, Text } from \"ink\";\nimport type { ExchangeRecord, ExchangeSnapshot } from \"../types.js\";\nimport { statusColor, formatDuration, truncate } from \"../utils.js\";\nimport { Panel } from \"./panel.js\";\nimport { formatJson, ColoredJsonLine } from \"./json-format.js\";\n\n/**\n * Build the scrollable lines for the deep view: headers + body sections.\n */\nfunction buildSnapshotLines(\n snapshot: ExchangeSnapshot,\n maxWidth: number,\n): string[] {\n const lines: string[] = [];\n\n lines.push(\"HEADERS\");\n lines.push(...formatJson(snapshot.headers, maxWidth));\n lines.push(\"\");\n lines.push(\"BODY\");\n if (snapshot.body !== null) {\n lines.push(...formatJson(snapshot.body, maxWidth));\n if (snapshot.truncated) {\n lines.push(\"\");\n lines.push(\"[Body truncated to configured limit]\");\n }\n } else {\n lines.push(\"[null]\");\n }\n\n return lines;\n}\n\nexport function ExchangeDeepView({\n exchange,\n snapshot,\n width,\n height,\n scrollOffset,\n color = \"cyan\",\n}: {\n exchange: ExchangeRecord;\n snapshot: ExchangeSnapshot | null;\n width: number;\n height: number;\n scrollOffset: number;\n color?: string;\n}) {\n // Header panel: border (2) + content (3 lines: capability + exchange + status)\n const headerHeight = 5;\n // JSON panel chrome: border (2) + title (1) + separator (1) + footer (1)\n const jsonChrome = 5;\n const jsonWidth = Math.max(width - 6, 20);\n const visibleRows = Math.max(height - headerHeight - jsonChrome, 3);\n\n const hasSnapshot = snapshot !== null;\n const jsonLines = hasSnapshot\n ? buildSnapshotLines(snapshot, jsonWidth)\n : [\n \"[Snapshots not captured]\",\n \"\",\n \"Enable with:\",\n \" telemetry({ sqlite: { captureSnapshots: true } })\",\n ];\n\n const visible = jsonLines.slice(scrollOffset, scrollOffset + visibleRows);\n\n return (\n <Box flexDirection=\"column\" width={width} flexGrow={1}>\n <Panel width={width}>\n <Text>\n Capability:{\" \"}\n <Text bold color=\"cyan\">\n {exchange.routeId}\n </Text>\n </Text>\n <Text>\n Exchange:{\" \"}\n <Text bold color=\"cyan\">\n {truncate(exchange.id, width - 14)}\n </Text>\n </Text>\n <Text>\n Status:{\" \"}\n <Text bold color={statusColor(exchange.status)}>\n {exchange.status}\n </Text>\n {exchange.durationMs !== null && (\n <Text>\n {\" \"}Duration:{\" \"}\n <Text bold>{formatDuration(exchange.durationMs)}</Text>\n </Text>\n )}\n </Text>\n </Panel>\n\n <Panel\n title=\"EXCHANGE SNAPSHOT\"\n subtitle={\n <Text dimColor>\n ({scrollOffset + 1}-\n {Math.min(scrollOffset + visibleRows, jsonLines.length)}/\n {jsonLines.length} lines)\n </Text>\n }\n width={width}\n flexGrow={1}\n color={color}\n >\n {visible.map((line, i) => {\n if (line === \"HEADERS\" || line === \"BODY\") {\n return (\n <Text key={scrollOffset + i} bold color=\"yellow\">\n {line}\n </Text>\n );\n }\n if (line.startsWith(\"[\")) {\n return (\n <Text key={scrollOffset + i} dimColor>\n {line}\n </Text>\n );\n }\n return <ColoredJsonLine key={scrollOffset + i} line={line} />;\n })}\n {visible.length < visibleRows &&\n Array.from({ length: visibleRows - visible.length }).map((_, i) => (\n <Text key={`pad-${i}`}> </Text>\n ))}\n </Panel>\n </Box>\n );\n}\n","import { Text } from \"ink\";\nimport type { RouteSummary } from \"../types.js\";\nimport { truncate } from \"../utils.js\";\n\nfunction dotColor(route: RouteSummary): string {\n if (route.failedExchanges > 0) return \"red\";\n if (route.totalExchanges > 0) return \"green\";\n return \"yellow\";\n}\n\nexport function CapabilityList({\n routes,\n selectedIndex,\n listOffset,\n visibleRows,\n width,\n}: {\n routes: RouteSummary[];\n selectedIndex: number;\n listOffset: number;\n visibleRows: number;\n width: number;\n}) {\n const offset = listOffset;\n\n return (\n <>\n <Text> </Text>\n <Text bold dimColor>\n {\"\\u2500\".repeat(width + 2)}\n </Text>\n {routes.length === 0 ? (\n <Text dimColor>No capabilities</Text>\n ) : (\n routes.slice(offset, offset + visibleRows).map((route, vi) => {\n const i = offset + vi;\n return (\n <Text key={route.id} wrap=\"truncate\">\n <Text\n {...(i === selectedIndex ? { color: \"cyan\" as const } : {})}\n bold={i === selectedIndex}\n >\n {i === selectedIndex ? \"> \" : \" \"}\n </Text>\n <Text color={dotColor(route)}>{\"\\u25CF \"}</Text>\n <Text\n {...(i === selectedIndex ? { color: \"cyan\" as const } : {})}\n bold={i === selectedIndex}\n >\n {truncate(route.id, width - 2)}\n </Text>\n </Text>\n );\n })\n )}\n {routes.length > visibleRows && (\n <Text dimColor>\n {selectedIndex + 1}/{routes.length}\n </Text>\n )}\n </>\n );\n}\n","import { useState, useEffect, useCallback } from \"react\";\nimport { render, Box, Text, useInput, useApp, useStdout } from \"ink\";\nimport { TelemetryDb } from \"./db.js\";\nimport type {\n NavItem,\n RouteSummary,\n ExchangeRecord,\n ExchangeSnapshot,\n EventRecord,\n Metrics,\n RouteActivity,\n} from \"./types.js\";\nimport { NAV_SECTIONS, ALL_NAV_ITEMS } from \"./types.js\";\nimport { fmtNum, formatDuration } from \"./utils.js\";\nimport { useScrollList } from \"./hooks/use-scroll-list.js\";\nimport { PANEL_TABLE_CHROME, DETAIL_INFO_CHROME, NAV_JUMP } from \"./layout.js\";\nimport { Panel } from \"./components/panel.js\";\nimport { DotGraph, DEFAULT_STEPS } from \"./components/dot-graph.js\";\nimport { CenterExchangeList } from \"./components/center-exchange-list.js\";\nimport { CenterExchangeDetail } from \"./components/center-exchange-detail.js\";\nimport { EventsView } from \"./components/events-view.js\";\nimport { EventDetail } from \"./components/event-detail.js\";\nimport { ExchangeDeepView } from \"./components/exchange-deep-view.js\";\nimport { CapabilityList } from \"./components/capability-list.js\";\n\n/**\n * Focus tracks which panel owns the cursor.\n * - \"nav\": left panel (route list / nav items)\n * - \"center\": center panel (exchange list, events, detail)\n */\ntype Focus = \"nav\" | \"center\";\n\nfunction App({ db }: { db: TelemetryDb }) {\n const { exit } = useApp();\n const { stdout } = useStdout();\n const width = stdout?.columns ?? 80;\n const height = stdout?.rows ?? 24;\n\n const [activeNav, setActiveNav] = useState<NavItem>(\"capabilities\");\n const [focus, setFocus] = useState<Focus>(\"nav\");\n const [showDetail, setShowDetail] = useState(false);\n\n const [routes, setRoutes] = useState<RouteSummary[]>([]);\n const [metrics, setMetrics] = useState<Metrics>({\n totalRoutes: 0,\n totalExchanges: 0,\n completedExchanges: 0,\n failedExchanges: 0,\n droppedExchanges: 0,\n errorRate: 0,\n avgDurationMs: null,\n p90DurationMs: null,\n p95DurationMs: null,\n p99DurationMs: null,\n });\n const [liveTraffic, setLiveTraffic] = useState<number[]>([]);\n const [selectedRouteActivity, setSelectedRouteActivity] = useState<\n RouteActivity | undefined\n >(undefined);\n const routeScroll = useScrollList();\n const [exchanges, setExchanges] = useState<ExchangeRecord[]>([]);\n const exchangeScroll = useScrollList();\n const [selectedExchange, setSelectedExchange] = useState<\n ExchangeRecord | undefined\n >(undefined);\n const [exchangeEvents, setExchangeEvents] = useState<EventRecord[]>([]);\n const [events, setEvents] = useState<EventRecord[]>([]);\n const eventScroll = useScrollList();\n const detailScroll = useScrollList();\n const [selectedEvent, setSelectedEvent] = useState<EventRecord | undefined>(\n undefined,\n );\n const [showEventDetail, setShowEventDetail] = useState(false);\n const [eventDetailScroll, setEventDetailScroll] = useState(0);\n const [showDeepView, setShowDeepView] = useState(false);\n const [deepViewScroll, setDeepViewScroll] = useState(0);\n const [exchangeSnapshot, setExchangeSnapshot] =\n useState<ExchangeSnapshot | null>(null);\n const PAGE_SIZE = 50;\n const JUMP = NAV_JUMP;\n\n // Layout dimensions (needed by both refresh and render)\n const leftWidth = Math.max(Math.min(Math.floor(width * 0.18), 26), 16);\n const rightWidth = Math.max(Math.min(Math.floor(width * 0.22), 30), 20);\n const centerWidth = Math.max(width - leftWidth - rightWidth, 30);\n const bodyHeight = Math.max(height - 5, 10);\n const navHeaderRows = 10;\n const navListHeight = Math.max(bodyHeight - navHeaderRows, 3);\n\n const refresh = useCallback(() => {\n try {\n // Always refresh: routes, metrics, graphs\n const routeSummary = db.getRouteSummary();\n setRoutes(routeSummary);\n setMetrics(db.getMetrics());\n const liveCols = rightWidth - 4;\n setLiveTraffic(db.getLiveTrafficBuckets(liveCols, 5));\n\n // Only load activity for the currently selected route\n const routeCols = centerWidth - 4;\n const curRoute = routeSummary[routeScroll.selectedIndex];\n if (curRoute) {\n setSelectedRouteActivity(\n db.getSingleRouteActivity(curRoute.id, routeCols, 5),\n );\n }\n\n // Skip list refresh when cursor is active (user is browsing)\n if (focus === \"center\") return;\n\n if (activeNav === \"capabilities\") {\n const route = routeSummary[routeScroll.selectedIndex];\n if (route) {\n setExchanges(db.getExchangesByRoute(route.id, PAGE_SIZE));\n }\n } else if (activeNav === \"exchanges\") {\n setExchanges(db.getAllExchanges(PAGE_SIZE));\n } else if (activeNav === \"errors\") {\n setExchanges(db.getFailedExchanges(PAGE_SIZE));\n } else if (activeNav === \"events\") {\n setEvents(db.getRecentEvents({ limit: 200 }));\n }\n } catch {\n // Database may be temporarily locked\n }\n }, [\n db,\n activeNav,\n routeScroll.selectedIndex,\n rightWidth,\n centerWidth,\n focus,\n ]);\n\n useEffect(() => {\n refresh();\n const timer = setInterval(refresh, 2000);\n return () => {\n clearInterval(timer);\n };\n }, [refresh]);\n\n const selectRoute = useCallback(\n (index: number) => {\n routeScroll.moveTo(index, routes.length, navListHeight);\n exchangeScroll.reset();\n const route = routes[index];\n if (route) {\n setExchanges(db.getExchangesByRoute(route.id, PAGE_SIZE));\n }\n },\n [db, routes, routeScroll, exchangeScroll, navListHeight],\n );\n\n const switchNav = useCallback(\n (nav: NavItem) => {\n setActiveNav(nav);\n setShowDetail(false);\n setShowEventDetail(false);\n setShowDeepView(false);\n setFocus(\"nav\");\n exchangeScroll.reset();\n if (nav === \"exchanges\") {\n setExchanges(db.getAllExchanges(PAGE_SIZE));\n } else if (nav === \"errors\") {\n setExchanges(db.getFailedExchanges(PAGE_SIZE));\n } else if (nav === \"events\") {\n eventScroll.reset();\n setEvents(db.getRecentEvents({ limit: 200 }));\n }\n },\n [db, exchangeScroll, eventScroll],\n );\n\n const selectedRoute = routes[routeScroll.selectedIndex];\n\n // Visible row counts mirror the view components\n // Must match CenterExchangeList: 2 (capability + stats) + graphTermRows + 2 (label + spacer)\n const graphTermRows = Math.ceil((DEFAULT_STEPS.length - 1) / 4);\n const exchangeHeaderRows = selectedRoute ? 2 + graphTermRows + 2 : 0;\n const exchangeTableRows = Math.max(\n bodyHeight - PANEL_TABLE_CHROME - exchangeHeaderRows,\n 3,\n );\n const eventsTableRows = Math.max(bodyHeight - PANEL_TABLE_CHROME, 5);\n\n useInput((input, key) => {\n if (input === \"q\") {\n db.close();\n exit();\n return;\n }\n\n // Number shortcuts to switch nav (always available)\n const navByShortcut = ALL_NAV_ITEMS.find((n) => n.shortcut === input);\n if (navByShortcut) {\n switchNav(navByShortcut.key);\n return;\n }\n\n // Events view: overview -> browse -> detail\n if (activeNav === \"events\") {\n if (showEventDetail) {\n // Detail view: scroll JSON, Esc to go back to list\n const step = key.ctrl ? JUMP : 1;\n if (input === \"j\" || key.downArrow) {\n setEventDetailScroll((i) => i + step);\n } else if (input === \"k\" || key.upArrow) {\n setEventDetailScroll((i) => Math.max(i - step, 0));\n } else if (key.escape || key.backspace || key.delete) {\n setShowEventDetail(false);\n setEventDetailScroll(0);\n }\n return;\n }\n if (focus === \"nav\") {\n if (key.return) {\n setFocus(\"center\");\n }\n } else {\n const step = key.ctrl ? JUMP : 1;\n if (input === \"j\" || key.downArrow) {\n eventScroll.moveBy(step, events.length, eventsTableRows);\n } else if (input === \"k\" || key.upArrow) {\n eventScroll.moveBy(-step, events.length, eventsTableRows);\n } else if (key.return) {\n const ev = events[eventScroll.selectedIndex];\n if (ev) {\n setSelectedEvent(ev);\n setEventDetailScroll(0);\n setShowEventDetail(true);\n }\n } else if (key.escape || key.backspace || key.delete) {\n setFocus(\"nav\");\n eventScroll.reset();\n }\n }\n return;\n }\n\n // Exchange deep view: scrollable JSON of headers + body\n if (showDeepView) {\n const step = key.ctrl ? JUMP : 1;\n if (input === \"j\" || key.downArrow) {\n setDeepViewScroll((i) => i + step);\n } else if (input === \"k\" || key.upArrow) {\n setDeepViewScroll((i) => Math.max(i - step, 0));\n } else if (key.escape || key.backspace || key.delete) {\n setShowDeepView(false);\n setDeepViewScroll(0);\n }\n return;\n }\n\n // Exchange detail (any nav)\n if (showDetail && !showEventDetail) {\n const hasExtra = selectedExchange?.error ? 2 : 0;\n const detailEventRows = Math.max(\n bodyHeight - DETAIL_INFO_CHROME - hasExtra,\n 3,\n );\n // Count group headers: when events span multiple exchanges, each group gets a header row\n const uniqueExchangeIds = new Set(\n exchangeEvents.map((ev) => {\n try {\n const d = JSON.parse(ev.details) as Record<string, unknown>;\n return String(d[\"exchangeId\"] ?? \"\");\n } catch {\n return \"\";\n }\n }),\n );\n const groupCount = Math.max(uniqueExchangeIds.size, 1);\n const headerRows = groupCount > 1 ? groupCount : 0;\n const totalDisplayRows = exchangeEvents.length + headerRows;\n const step = key.ctrl ? JUMP : 1;\n if (input === \"j\" || key.downArrow) {\n detailScroll.moveBy(step, totalDisplayRows, detailEventRows);\n } else if (input === \"k\" || key.upArrow) {\n detailScroll.moveBy(-step, totalDisplayRows, detailEventRows);\n } else if (key.return) {\n // Resolve the selected display row to an EventRecord (skip headers)\n // Build the same display row list the component builds\n let rowIndex = 0;\n let targetEvent: EventRecord | undefined;\n const parentId = selectedExchange?.id ?? \"\";\n const groups = new Map<string, EventRecord[]>();\n groups.set(parentId, []);\n for (const ev of exchangeEvents) {\n try {\n const d = JSON.parse(ev.details) as Record<string, unknown>;\n const exId = String(d[\"exchangeId\"] ?? \"\");\n const gKey = !exId || exId === parentId ? parentId : exId;\n if (!groups.has(gKey)) groups.set(gKey, []);\n groups.get(gKey)!.push(ev);\n } catch {\n groups.get(parentId)!.push(ev);\n }\n }\n const hasChildren = groups.size > 1;\n for (const [, groupEvents] of groups) {\n if (hasChildren) rowIndex++; // header row\n for (const ev of groupEvents) {\n if (rowIndex === detailScroll.selectedIndex) {\n targetEvent = ev;\n }\n rowIndex++;\n }\n }\n if (targetEvent) {\n setSelectedEvent(targetEvent);\n setEventDetailScroll(0);\n setShowEventDetail(true);\n }\n } else if (input === \"e\" && selectedExchange) {\n const snapshot = db.getExchangeSnapshot(selectedExchange.id);\n setExchangeSnapshot(snapshot);\n setDeepViewScroll(0);\n setShowDeepView(true);\n } else if (key.escape || key.backspace || key.delete) {\n detailScroll.reset();\n setShowDetail(false);\n }\n return;\n }\n\n // Event detail from exchange detail: Esc goes back to exchange detail\n if (showDetail && showEventDetail) {\n const step = key.ctrl ? JUMP : 1;\n if (input === \"j\" || key.downArrow) {\n setEventDetailScroll((i) => i + step);\n } else if (input === \"k\" || key.upArrow) {\n setEventDetailScroll((i) => Math.max(i - step, 0));\n } else if (key.escape || key.backspace || key.delete) {\n setShowEventDetail(false);\n setEventDetailScroll(0);\n }\n return;\n }\n\n // Capabilities: nav focus (left panel)\n if (activeNav === \"capabilities\" && focus === \"nav\") {\n if (input === \"j\" || key.downArrow) {\n selectRoute(Math.min(routeScroll.selectedIndex + 1, routes.length - 1));\n } else if (input === \"k\" || key.upArrow) {\n selectRoute(Math.max(routeScroll.selectedIndex - 1, 0));\n } else if (key.return) {\n setFocus(\"center\");\n // Load all exchanges for browsing (auto-refresh uses PAGE_SIZE)\n const route = routes[routeScroll.selectedIndex];\n if (route) {\n setExchanges(db.getExchangesByRoute(route.id));\n }\n }\n return;\n }\n\n // Capabilities: center focus (exchange list)\n if (activeNav === \"capabilities\" && focus === \"center\") {\n const step = key.ctrl ? JUMP : 1;\n if (input === \"j\" || key.downArrow) {\n exchangeScroll.moveBy(step, exchanges.length, exchangeTableRows);\n } else if (input === \"k\" || key.upArrow) {\n exchangeScroll.moveBy(-step, exchanges.length, exchangeTableRows);\n } else if (key.return) {\n const ex = exchanges[exchangeScroll.selectedIndex];\n if (ex) {\n setSelectedExchange(ex);\n setExchangeEvents(db.getEventsByExchange(ex.id, ex.correlationId));\n detailScroll.reset();\n setShowEventDetail(false);\n setShowDetail(true);\n }\n } else if (key.escape || key.backspace || key.delete) {\n setFocus(\"nav\");\n exchangeScroll.reset();\n }\n return;\n }\n\n // Exchanges / Errors: overview (nav focus) or browsing (center focus)\n if (activeNav === \"exchanges\" || activeNav === \"errors\") {\n if (focus === \"nav\") {\n // Overview mode: Enter to freeze and browse\n if (key.return) {\n setFocus(\"center\");\n // Load full data set for browsing\n if (activeNav === \"exchanges\") {\n setExchanges(db.getAllExchanges());\n } else {\n setExchanges(db.getFailedExchanges());\n }\n }\n } else {\n // Browsing mode: navigate with pointer\n const step = key.ctrl ? JUMP : 1;\n if (input === \"j\" || key.downArrow) {\n exchangeScroll.moveBy(step, exchanges.length, exchangeTableRows);\n } else if (input === \"k\" || key.upArrow) {\n exchangeScroll.moveBy(-step, exchanges.length, exchangeTableRows);\n } else if (key.return) {\n const ex = exchanges[exchangeScroll.selectedIndex];\n if (ex) {\n setSelectedExchange(ex);\n setExchangeEvents(db.getEventsByExchange(ex.id, ex.correlationId));\n detailScroll.reset();\n setShowEventDetail(false);\n setShowDetail(true);\n }\n } else if (key.escape || key.backspace || key.delete) {\n setFocus(\"nav\");\n exchangeScroll.reset();\n }\n }\n return;\n }\n });\n\n // Determine which panel is active for border highlighting\n const navActive =\n activeNav === \"capabilities\" && focus === \"nav\" && !showDetail;\n const centerActive = !navActive;\n\n // Keymap items based on context\n const keymapItems: { key: string; action: string }[] = [];\n if (showDeepView) {\n keymapItems.push({ key: \"j/k\", action: \"Scroll\" });\n keymapItems.push({ key: \"Ctrl+j/k\", action: \"Jump 10\" });\n keymapItems.push({ key: \"Esc\", action: \"Back\" });\n } else if (focus === \"center\") {\n keymapItems.push({ key: \"j/k\", action: \"Navigate\" });\n keymapItems.push({ key: \"Ctrl+j/k\", action: \"Jump 10\" });\n }\n if (!showDeepView) {\n if (focus === \"nav\") {\n if (activeNav === \"capabilities\") {\n keymapItems.push({ key: \"j/k\", action: \"Navigate\" });\n keymapItems.push({ key: \"Enter\", action: \"Exchanges\" });\n } else {\n keymapItems.push({ key: \"Enter\", action: \"Browse\" });\n }\n } else if (!showDetail && !showEventDetail) {\n keymapItems.push({ key: \"Enter\", action: \"Detail\" });\n keymapItems.push({ key: \"Esc\", action: \"Back\" });\n } else if (showDetail && !showEventDetail) {\n keymapItems.push({ key: \"Enter\", action: \"Event detail\" });\n keymapItems.push({ key: \"e\", action: \"Snapshot\" });\n keymapItems.push({ key: \"Esc\", action: \"Back\" });\n } else {\n keymapItems.push({ key: \"Esc\", action: \"Back\" });\n }\n }\n keymapItems.push({ key: \"1..4\", action: \"Switch view\" });\n keymapItems.push({ key: \"q\", action: \"Quit\" });\n\n return (\n <Box flexDirection=\"column\" width={width} height={height}>\n {/* Title bar */}\n <Box borderStyle=\"round\" borderColor=\"cyan\" paddingX={1} width={width}>\n <Text bold color=\"cyan\">\n ROUTECRAFT TUI\n </Text>\n <Text> </Text>\n <Text dimColor>v0.4.0</Text>\n </Box>\n\n {/* 3-column body */}\n <Box flexDirection=\"row\" width={width} flexGrow={1}>\n {/* Left column: Navigation (top) + Keymap (bottom) */}\n <Box flexDirection=\"column\" width={leftWidth}>\n <Panel\n title=\"NAVIGATION\"\n color={navActive ? \"cyan\" : \"gray\"}\n width={leftWidth}\n flexGrow={1}\n >\n {NAV_SECTIONS.map((section, si) => (\n <Box key={section.label ?? si} flexDirection=\"column\">\n {si > 0 && <Text> </Text>}\n {section.label && (\n <Text dimColor bold>\n {section.label}\n </Text>\n )}\n {section.items.map((item) => (\n <Text key={item.key}>\n <Text\n bold={activeNav === item.key}\n {...(activeNav === item.key\n ? { color: \"cyan\" as const }\n : {})}\n >\n {activeNav === item.key ? \"> \" : \" \"}\n {item.label}\n </Text>\n <Text dimColor> ({item.shortcut})</Text>\n </Text>\n ))}\n </Box>\n ))}\n\n {activeNav === \"capabilities\" && (\n <CapabilityList\n routes={routes}\n selectedIndex={routeScroll.selectedIndex}\n listOffset={routeScroll.scrollOffset}\n visibleRows={navListHeight}\n width={leftWidth - 6}\n />\n )}\n </Panel>\n </Box>\n\n {/* Center */}\n {activeNav === \"capabilities\" && !showDetail && (\n <CenterExchangeList\n capabilityId={selectedRoute?.id ?? \"\"}\n route={selectedRoute}\n exchanges={exchanges}\n selectedIndex={\n focus === \"center\" ? exchangeScroll.selectedIndex : -1\n }\n scrollOffset={focus === \"center\" ? exchangeScroll.scrollOffset : 0}\n width={centerWidth}\n height={bodyHeight}\n color={centerActive ? \"cyan\" : \"gray\"}\n activity={selectedRouteActivity}\n />\n )}\n {activeNav === \"capabilities\" && showDeepView && selectedExchange && (\n <ExchangeDeepView\n exchange={selectedExchange}\n snapshot={exchangeSnapshot}\n width={centerWidth}\n height={bodyHeight}\n scrollOffset={deepViewScroll}\n color=\"cyan\"\n />\n )}\n {activeNav === \"capabilities\" &&\n showDetail &&\n selectedExchange &&\n !showEventDetail &&\n !showDeepView && (\n <CenterExchangeDetail\n exchange={selectedExchange}\n events={exchangeEvents}\n width={centerWidth}\n height={bodyHeight}\n selectedIndex={detailScroll.selectedIndex}\n scrollOffset={detailScroll.scrollOffset}\n color=\"cyan\"\n />\n )}\n {activeNav === \"capabilities\" &&\n showDetail &&\n showEventDetail &&\n !showDeepView &&\n selectedEvent && (\n <EventDetail\n event={selectedEvent}\n width={centerWidth}\n height={bodyHeight}\n scrollOffset={eventDetailScroll}\n color=\"cyan\"\n />\n )}\n {activeNav === \"exchanges\" && !showDetail && (\n <CenterExchangeList\n capabilityId=\"All Capabilities\"\n exchanges={exchanges}\n selectedIndex={\n focus === \"center\" ? exchangeScroll.selectedIndex : -1\n }\n scrollOffset={focus === \"center\" ? exchangeScroll.scrollOffset : 0}\n width={centerWidth}\n height={bodyHeight}\n color={focus === \"center\" ? \"cyan\" : \"gray\"}\n />\n )}\n {activeNav === \"exchanges\" && showDeepView && selectedExchange && (\n <ExchangeDeepView\n exchange={selectedExchange}\n snapshot={exchangeSnapshot}\n width={centerWidth}\n height={bodyHeight}\n scrollOffset={deepViewScroll}\n color=\"cyan\"\n />\n )}\n {activeNav === \"exchanges\" &&\n showDetail &&\n selectedExchange &&\n !showEventDetail &&\n !showDeepView && (\n <CenterExchangeDetail\n exchange={selectedExchange}\n events={exchangeEvents}\n width={centerWidth}\n height={bodyHeight}\n selectedIndex={detailScroll.selectedIndex}\n scrollOffset={detailScroll.scrollOffset}\n color=\"cyan\"\n />\n )}\n {activeNav === \"exchanges\" &&\n showDetail &&\n showEventDetail &&\n !showDeepView &&\n selectedEvent && (\n <EventDetail\n event={selectedEvent}\n width={centerWidth}\n height={bodyHeight}\n scrollOffset={eventDetailScroll}\n color=\"cyan\"\n />\n )}\n {activeNav === \"errors\" && !showDetail && (\n <CenterExchangeList\n capabilityId=\"Failed Exchanges\"\n exchanges={exchanges}\n selectedIndex={\n focus === \"center\" ? exchangeScroll.selectedIndex : -1\n }\n scrollOffset={focus === \"center\" ? exchangeScroll.scrollOffset : 0}\n width={centerWidth}\n height={bodyHeight}\n color={focus === \"center\" ? \"cyan\" : \"gray\"}\n />\n )}\n {activeNav === \"errors\" && showDeepView && selectedExchange && (\n <ExchangeDeepView\n exchange={selectedExchange}\n snapshot={exchangeSnapshot}\n width={centerWidth}\n height={bodyHeight}\n scrollOffset={deepViewScroll}\n color=\"cyan\"\n />\n )}\n {activeNav === \"errors\" &&\n showDetail &&\n selectedExchange &&\n !showEventDetail &&\n !showDeepView && (\n <CenterExchangeDetail\n exchange={selectedExchange}\n events={exchangeEvents}\n width={centerWidth}\n height={bodyHeight}\n selectedIndex={detailScroll.selectedIndex}\n scrollOffset={detailScroll.scrollOffset}\n color=\"cyan\"\n />\n )}\n {activeNav === \"errors\" &&\n showDetail &&\n showEventDetail &&\n !showDeepView &&\n selectedEvent && (\n <EventDetail\n event={selectedEvent}\n width={centerWidth}\n height={bodyHeight}\n scrollOffset={eventDetailScroll}\n color=\"cyan\"\n />\n )}\n {activeNav === \"events\" && !showEventDetail && (\n <EventsView\n events={events}\n selectedIndex={focus === \"center\" ? eventScroll.selectedIndex : -1}\n scrollOffset={focus === \"center\" ? eventScroll.scrollOffset : 0}\n width={centerWidth}\n height={bodyHeight}\n color={focus === \"center\" ? \"cyan\" : \"gray\"}\n />\n )}\n {activeNav === \"events\" && showEventDetail && selectedEvent && (\n <EventDetail\n event={selectedEvent}\n width={centerWidth}\n height={bodyHeight}\n scrollOffset={eventDetailScroll}\n color=\"cyan\"\n />\n )}\n\n {/* Right: Metrics + Keymap */}\n <Box flexDirection=\"column\" width={rightWidth}>\n <Panel title=\"METRICS\" width={rightWidth} flexGrow={1}>\n <DotGraph\n values={liveTraffic}\n columns={rightWidth - 4}\n steps={[\n { max: 0, color: \"gray\" },\n ...(Array.from({ length: 7 }, (_, i) => ({\n max: (i + 1) * 5,\n color: \"green\",\n })) as { max: number; color: string }[]),\n ...(Array.from({ length: 7 }, (_, i) => ({\n max: 35 + (i + 1) * 10,\n color: \"yellow\",\n })) as { max: number; color: string }[]),\n ...(Array.from({ length: 6 }, (_, i) => ({\n max: 105 + (i + 1) * 25,\n color: \"red\",\n })) as { max: number; color: string }[]),\n ]}\n label=\"Exchanges per 5s bucket\"\n />\n <Text> </Text>\n <Text bold dimColor>\n THROUGHPUT\n </Text>\n {(\n [\n [\"Exchanges\", fmtNum(metrics.totalExchanges), \"cyan\"],\n [\"Completed\", fmtNum(metrics.completedExchanges), \"green\"],\n [\n \"Errors\",\n fmtNum(metrics.failedExchanges),\n metrics.failedExchanges > 0 ? \"red\" : \"green\",\n ],\n [\n \"Dropped\",\n fmtNum(metrics.droppedExchanges),\n metrics.droppedExchanges > 0 ? \"yellow\" : \"green\",\n ],\n [\n \"Error Rate\",\n `${(metrics.errorRate * 100).toFixed(1)}%`,\n metrics.errorRate > 0.1 ? \"red\" : \"green\",\n ],\n [\"Capabilities\", fmtNum(metrics.totalRoutes), \"\"],\n ] as [string, string, string][]\n ).map(([label, value, color]) => (\n <Box key={label}>\n <Text>{label}:</Text>\n <Box flexGrow={1} justifyContent=\"flex-end\">\n <Text bold {...(color ? { color } : {})}>\n {value}\n </Text>\n </Box>\n </Box>\n ))}\n <Text> </Text>\n <Text bold dimColor>\n LATENCY (5m)\n </Text>\n {(\n [\n [\"Avg\", formatDuration(metrics.avgDurationMs), \"\"],\n [\"p90\", formatDuration(metrics.p90DurationMs), \"\"],\n [\"p95\", formatDuration(metrics.p95DurationMs), \"\"],\n [\"p99\", formatDuration(metrics.p99DurationMs), \"\"],\n ] as [string, string, string][]\n ).map(([label, value, color]) => (\n <Box key={label}>\n <Text>{label}:</Text>\n <Box flexGrow={1} justifyContent=\"flex-end\">\n <Text bold {...(color ? { color } : {})}>\n {value}\n </Text>\n </Box>\n </Box>\n ))}\n </Panel>\n\n <Panel title=\"KEYMAP\" width={rightWidth}>\n {keymapItems.map((item) => (\n <Box key={item.key}>\n <Text>{item.action}</Text>\n <Box flexGrow={1} justifyContent=\"flex-end\">\n <Text color=\"yellow\">[{item.key}]</Text>\n </Box>\n </Box>\n ))}\n </Panel>\n </Box>\n </Box>\n </Box>\n );\n}\n\nexport async function renderTui(dbPath: string): Promise<void> {\n let db: TelemetryDb;\n try {\n db = await TelemetryDb.open(dbPath);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n process.stderr.write(`Failed to open telemetry database: ${msg}\\n`);\n process.stderr.write(`Path: ${dbPath}\\n`);\n process.stderr.write(\n \"Make sure you have a running Routecraft context with telemetry() enabled.\\n\",\n );\n process.exit(1);\n }\n\n const instance = render(<App db={db} />);\n await instance.waitUntilExit();\n}\n"]}
@@ -0,0 +1,127 @@
1
+ import { TelemetryEvent } from '@routecraft/routecraft';
2
+
3
+ interface Metrics {
4
+ totalRoutes: number;
5
+ totalExchanges: number;
6
+ completedExchanges: number;
7
+ failedExchanges: number;
8
+ droppedExchanges: number;
9
+ errorRate: number;
10
+ avgDurationMs: number | null;
11
+ p90DurationMs: number | null;
12
+ p95DurationMs: number | null;
13
+ p99DurationMs: number | null;
14
+ }
15
+ interface ExchangeSnapshot {
16
+ headers: string;
17
+ body: string | null;
18
+ truncated: boolean;
19
+ }
20
+
21
+ /** Exchange row shape from the telemetry SQLite database. */
22
+ interface TelemetryExchange {
23
+ id: string;
24
+ routeId: string;
25
+ contextId: string;
26
+ correlationId: string;
27
+ status: string;
28
+ startedAt: string;
29
+ completedAt: string | null;
30
+ durationMs: number | null;
31
+ error: string | null;
32
+ }
33
+ declare class TelemetryDb {
34
+ private db;
35
+ private stmtCache;
36
+ private constructor();
37
+ /** Prepare and cache a statement by key. Avoids re-parsing on every call. */
38
+ private stmt;
39
+ /**
40
+ * Open a telemetry database in read-only mode.
41
+ *
42
+ * Uses dynamic `import()` so the module resolves correctly under pnpm's
43
+ * strict hoisting (CJS `require()` from an ESM bundle does not follow
44
+ * the package's own dependency graph).
45
+ */
46
+ static open(dbPath: string): Promise<TelemetryDb>;
47
+ /**
48
+ * Get a summary of all routes with aggregated metrics.
49
+ * Routes are grouped by ID across all context runs so that restarting
50
+ * the same application does not create duplicate rows.
51
+ */
52
+ getRouteSummary(): Array<{
53
+ id: string;
54
+ status: string;
55
+ totalExchanges: number;
56
+ completedExchanges: number;
57
+ failedExchanges: number;
58
+ droppedExchanges: number;
59
+ avgDurationMs: number | null;
60
+ }>;
61
+ /**
62
+ * Get exchanges for a specific route, ordered by most recent first.
63
+ */
64
+ getExchangesByRoute(routeId: string, limit?: number): TelemetryExchange[];
65
+ /**
66
+ * Get all exchanges across all routes, ordered by most recent first.
67
+ */
68
+ getAllExchanges(limit?: number): TelemetryExchange[];
69
+ /**
70
+ * Get all failed exchanges across all routes, ordered by most recent first.
71
+ * Shows every failed exchange including child exchanges from split/multicast,
72
+ * without deduplication by correlation chain.
73
+ */
74
+ getFailedExchanges(limit?: number): TelemetryExchange[];
75
+ /**
76
+ * Get events for an exchange and all related exchanges sharing the
77
+ * same correlation ID. Uses indexed exchange_id/correlation_id columns
78
+ * with a fallback to details LIKE for databases created before the
79
+ * column migration.
80
+ */
81
+ getEventsByExchange(exchangeId: string, correlationId: string): TelemetryEvent[];
82
+ /** Check whether the events table has the exchange_id column. */
83
+ private hasEventIdColumns;
84
+ private _hasEventIdColumns;
85
+ /**
86
+ * Get recent events, optionally filtered by event name pattern or route ID.
87
+ */
88
+ getRecentEvents(options?: {
89
+ limit?: number;
90
+ eventNameFilter?: string;
91
+ routeIdFilter?: string;
92
+ sinceId?: number;
93
+ }): TelemetryEvent[];
94
+ /**
95
+ * Get aggregated metrics for the dashboard, including duration percentiles.
96
+ * Percentiles are computed over exchanges from the last 5 minutes.
97
+ */
98
+ getMetrics(): Metrics;
99
+ /**
100
+ * Get exchange counts for a rolling window using fine-grained buckets.
101
+ * Default: 60 buckets of 5 seconds = 5-minute rolling window.
102
+ * Returns values oldest-first for sparkline rendering.
103
+ */
104
+ getLiveTrafficBuckets(bucketCount?: number, bucketWidthSec?: number): number[];
105
+ /**
106
+ * Get activity data for a single route: throughput sparkline + recent error count.
107
+ */
108
+ getSingleRouteActivity(routeId: string, bucketCount?: number, bucketWidthSec?: number): {
109
+ throughput: number[];
110
+ recentErrors: number;
111
+ };
112
+ /**
113
+ * Get the maximum event ID (for tailing/polling).
114
+ */
115
+ getMaxEventId(): number;
116
+ /**
117
+ * Get the exchange snapshot (headers and body) for a given exchange.
118
+ * Returns null if no snapshot was captured.
119
+ */
120
+ getExchangeSnapshot(exchangeId: string): ExchangeSnapshot | null;
121
+ /**
122
+ * Close the database connection.
123
+ */
124
+ close(): void;
125
+ }
126
+
127
+ export { TelemetryDb };
package/dist/tui/db.js ADDED
@@ -0,0 +1,2 @@
1
+ export{a as TelemetryDb}from'../chunk-DPJWCR2V.js';//# sourceMappingURL=db.js.map
2
+ //# sourceMappingURL=db.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"db.js"}
@@ -0,0 +1,2 @@
1
+ export{a as loadEnvFile,b as registerContextSignalHandlers}from'./chunk-PW5RNJFH.js';//# sourceMappingURL=util-EC5TOA6Q.js.map
2
+ //# sourceMappingURL=util-EC5TOA6Q.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"util-5TR67ZZL.js"}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"util-EC5TOA6Q.js"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@routecraft/cli",
3
- "version": "0.4.0-canary.9",
3
+ "version": "0.4.0",
4
4
  "description": "CLI for running Routecraft routes",
5
5
  "private": false,
6
6
  "type": "module",
@@ -16,22 +16,36 @@
16
16
  "dist"
17
17
  ],
18
18
  "scripts": {
19
- "build": "tsup src/index.ts --format esm --dts",
19
+ "build": "tsup src/index.ts src/tui/app.tsx src/tui/db.ts --format esm --dts --external react --external ink --external better-sqlite3",
20
20
  "test": "vitest",
21
21
  "test:coverage": "vitest --coverage",
22
22
  "prepublishOnly": "pnpm run build"
23
23
  },
24
24
  "dependencies": {
25
- "@routecraft/routecraft": "^0.4.0-canary.9",
26
- "agent-browser": "^0.15.1",
25
+ "@opentelemetry/sdk-trace-base": "^2.6.0",
26
+ "@routecraft/routecraft": "^0.4.0",
27
+ "agent-browser": "^0.17.1",
28
+ "better-sqlite3": "^11.10.0",
27
29
  "cheerio": "^1.2.0",
28
30
  "commander": "^14.0.3",
29
31
  "croner": "^10.0.1",
30
32
  "dotenv": "^17.3.1",
31
- "papaparse": "^5.4.1",
33
+ "imapflow": "^1.0.0",
34
+ "ink": "^5.2.1",
35
+ "mailparser": "^3.7.0",
36
+ "nodemailer": "^6.0.0",
37
+ "papaparse": "^5.5.3",
32
38
  "pino-pretty": "^13.1.3",
39
+ "react": "^18.3.1",
33
40
  "tsx": "^4.21.0"
34
41
  },
42
+ "devDependencies": {
43
+ "@types/better-sqlite3": "^7.6.13",
44
+ "@types/mailparser": "^3.4.0",
45
+ "@types/nodemailer": "^6.4.0",
46
+ "@types/react": "^18.3.28",
47
+ "ink-testing-library": "^4.0.0"
48
+ },
35
49
  "publishConfig": {
36
50
  "access": "public"
37
51
  },
@@ -1,2 +0,0 @@
1
- import {logger}from'@routecraft/routecraft';import {resolve}from'path';import {config}from'dotenv';function c(e){let s={quiet:true};if(e){let l=resolve(process.cwd(),e),n=config({path:l,...s});return n.error?logger.info(`Could not load .env file from ${e}: ${n.error.message}`):n.parsed&&logger.debug(`Loaded ${Object.keys(n.parsed).length} environment variables from ${e}`),n}let o=config({path:resolve(process.cwd(),".env"),...s});o.parsed?logger.debug(`Loaded ${Object.keys(o.parsed).length} environment variables from .env`):o.error&&logger.debug("No .env file found");let r=config({path:resolve(process.cwd(),".env.local"),override:true,...s});return r.parsed&&logger.debug(`Loaded ${Object.keys(r.parsed).length} environment variables from .env.local`),r.parsed?r:o.parsed?o:r}function u(e){process.on("SIGINT",async()=>{e.logger.info("Shutting down (SIGINT)..."),await e.stop(),e.logger.info("Cleanup complete");}),process.on("SIGTERM",async()=>{e.logger.info("Shutting down (SIGTERM)..."),await e.stop(),e.logger.info("Cleanup complete");});}export{c as a,u as b};//# sourceMappingURL=chunk-MEHNJKKK.js.map
2
- //# sourceMappingURL=chunk-MEHNJKKK.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/util.ts"],"names":["loadEnvFile","path","dotenvOpts","envPath","resolve","result","loadDotenv","logger","envResult","envLocalResult","registerContextSignalHandlers","context"],"mappings":"mGAUO,SAASA,CAAAA,CAAYC,EAAe,CACzC,IAAMC,EAAa,CAAE,KAAA,CAAO,IAAK,CAAA,CACjC,GAAID,EAAM,CAER,IAAME,EAAUC,OAAAA,CAAQ,OAAA,CAAQ,KAAI,CAAGH,CAAI,EACrCI,CAAAA,CAASC,MAAAA,CAAW,CAAE,IAAA,CAAMH,CAAAA,CAAS,GAAGD,CAAW,CAAC,EAE1D,OAAIG,CAAAA,CAAO,MACTE,MAAAA,CAAO,IAAA,CACL,iCAAiCN,CAAI,CAAA,EAAA,EAAKI,EAAO,KAAA,CAAM,OAAO,EAChE,CAAA,CACSA,CAAAA,CAAO,QAChBE,MAAAA,CAAO,KAAA,CACL,UAAU,MAAA,CAAO,IAAA,CAAKF,EAAO,MAAM,CAAA,CAAE,MAAM,CAAA,4BAAA,EAA+BJ,CAAI,EAChF,CAAA,CAGKI,CACT,CAIA,IAAMG,CAAAA,CAAYF,OAAW,CAC3B,IAAA,CAAMF,QAAQ,OAAA,CAAQ,GAAA,GAAO,MAAM,CAAA,CACnC,GAAGF,CACL,CAAC,EACGM,CAAAA,CAAU,MAAA,CACZD,OAAO,KAAA,CACL,CAAA,OAAA,EAAU,OAAO,IAAA,CAAKC,CAAAA,CAAU,MAAM,CAAA,CAAE,MAAM,kCAChD,CAAA,CACSA,CAAAA,CAAU,OACnBD,MAAAA,CAAO,KAAA,CAAM,oBAAoB,CAAA,CAInC,IAAME,EAAiBH,MAAAA,CAAW,CAChC,KAAMF,OAAAA,CAAQ,OAAA,CAAQ,KAAI,CAAG,YAAY,EACzC,QAAA,CAAU,IAAA,CACV,GAAGF,CACL,CAAC,EAWD,OAVIO,CAAAA,CAAe,QACjBF,MAAAA,CAAO,KAAA,CACL,UAAU,MAAA,CAAO,IAAA,CAAKE,EAAe,MAAM,CAAA,CAAE,MAAM,CAAA,sCAAA,CACrD,CAAA,CAOEA,EAAe,MAAA,CACVA,CAAAA,CAELD,EAAU,MAAA,CACLA,CAAAA,CAEFC,CACT,CAQO,SAASC,EACdC,CAAAA,CACA,CACA,QAAQ,EAAA,CAAG,QAAA,CAAU,SAAY,CAC/BA,CAAAA,CAAQ,OAAO,IAAA,CAAK,2BAA2B,EAC/C,MAAMA,CAAAA,CAAQ,MAAK,CACnBA,CAAAA,CAAQ,OAAO,IAAA,CAAK,kBAAkB,EACxC,CAAC,CAAA,CACD,QAAQ,EAAA,CAAG,SAAA,CAAW,SAAY,CAChCA,CAAAA,CAAQ,OAAO,IAAA,CAAK,4BAA4B,EAChD,MAAMA,CAAAA,CAAQ,MAAK,CACnBA,CAAAA,CAAQ,OAAO,IAAA,CAAK,kBAAkB,EACxC,CAAC,EACH","file":"chunk-MEHNJKKK.js","sourcesContent":["import { logger, CraftContext } from \"@routecraft/routecraft\";\nimport { resolve } from \"node:path\";\nimport { config as loadDotenv } from \"dotenv\";\n\n/**\n * Loads environment variables from .env files\n *\n * @param path Optional path to .env file. If not specified, loads .env and .env.local (if they exist)\n * @returns The parsed dotenv config result\n */\nexport function loadEnvFile(path?: string) {\n const dotenvOpts = { quiet: true };\n if (path) {\n // Explicit path provided - load that file only\n const envPath = resolve(process.cwd(), path);\n const result = loadDotenv({ path: envPath, ...dotenvOpts });\n\n if (result.error) {\n logger.info(\n `Could not load .env file from ${path}: ${result.error.message}`,\n );\n } else if (result.parsed) {\n logger.debug(\n `Loaded ${Object.keys(result.parsed).length} environment variables from ${path}`,\n );\n }\n\n return result;\n }\n\n // No path provided - load .env, then .env.local (with override)\n // Load .env first\n const envResult = loadDotenv({\n path: resolve(process.cwd(), \".env\"),\n ...dotenvOpts,\n });\n if (envResult.parsed) {\n logger.debug(\n `Loaded ${Object.keys(envResult.parsed).length} environment variables from .env`,\n );\n } else if (envResult.error) {\n logger.debug(`No .env file found`);\n }\n\n // Load .env.local next, allowing it to override .env values\n const envLocalResult = loadDotenv({\n path: resolve(process.cwd(), \".env.local\"),\n override: true,\n ...dotenvOpts,\n });\n if (envLocalResult.parsed) {\n logger.debug(\n `Loaded ${Object.keys(envLocalResult.parsed).length} environment variables from .env.local`,\n );\n }\n\n // Return the most successful result:\n // - If .env.local loaded successfully, return it\n // - If .env loaded successfully but .env.local failed (doesn't exist), return .env result\n // - If both failed, return the last error (from .env.local)\n if (envLocalResult.parsed) {\n return envLocalResult;\n }\n if (envResult.parsed) {\n return envResult;\n }\n return envLocalResult;\n}\n\n/**\n * Registers SIGINT and SIGTERM handlers for a CraftContext instance.\n * Ensures graceful shutdown and logging.\n *\n * @param context The CraftContext instance\n */\nexport function registerContextSignalHandlers(\n context: InstanceType<typeof CraftContext>,\n) {\n process.on(\"SIGINT\", async () => {\n context.logger.info(\"Shutting down (SIGINT)...\");\n await context.stop();\n context.logger.info(\"Cleanup complete\");\n });\n process.on(\"SIGTERM\", async () => {\n context.logger.info(\"Shutting down (SIGTERM)...\");\n await context.stop();\n context.logger.info(\"Cleanup complete\");\n });\n}\n"]}
@@ -1,2 +0,0 @@
1
- export{a as loadEnvFile,b as registerContextSignalHandlers}from'./chunk-MEHNJKKK.js';//# sourceMappingURL=util-5TR67ZZL.js.map
2
- //# sourceMappingURL=util-5TR67ZZL.js.map