audiencemeter 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -21,6 +21,8 @@ __export(config_exports, {
21
21
  setRefreshToken: () => setRefreshToken
22
22
  });
23
23
  import Conf from "conf";
24
+ import fs from "fs";
25
+ import path from "path";
24
26
  function getConfig() {
25
27
  return config;
26
28
  }
@@ -56,6 +58,7 @@ var init_config = __esm({
56
58
  "use strict";
57
59
  config = new Conf({
58
60
  projectName: "audiencemeter",
61
+ projectSuffix: "",
59
62
  schema: {
60
63
  apiUrl: {
61
64
  type: "string",
@@ -71,6 +74,26 @@ var init_config = __esm({
71
74
  }
72
75
  }
73
76
  });
77
+ (function migrateOldConfig() {
78
+ const newPath = config.path;
79
+ const oldPath = path.join(path.dirname(path.dirname(newPath)), "audiencemeter-nodejs", "config.json");
80
+ try {
81
+ if (!fs.existsSync(oldPath)) return;
82
+ if (config.get("authToken")) return;
83
+ const oldData = JSON.parse(fs.readFileSync(oldPath, "utf-8"));
84
+ if (oldData.authToken) {
85
+ config.set("authToken", oldData.authToken);
86
+ }
87
+ if (oldData.refreshToken) {
88
+ config.set("refreshToken", oldData.refreshToken);
89
+ }
90
+ if (oldData.apiUrl && oldData.apiUrl !== "https://api.audiencemeter.pro/v1") {
91
+ config.set("apiUrl", oldData.apiUrl);
92
+ }
93
+ fs.rmSync(path.dirname(oldPath), { recursive: true, force: true });
94
+ } catch {
95
+ }
96
+ })();
74
97
  }
75
98
  });
76
99
 
@@ -127,7 +150,7 @@ var init_theme = __esm({
127
150
  BRAND = {
128
151
  name: "AudienceMeter",
129
152
  tagline: "Speaker feedback, beautifully managed",
130
- version: "0.1.0"
153
+ version: "0.1.1"
131
154
  };
132
155
  }
133
156
  });
@@ -520,7 +543,38 @@ function getUserEmailFromToken() {
520
543
  );
521
544
  return payload.email || "unknown";
522
545
  }
523
- var SUPABASE_URL2, SUPABASE_ANON_KEY, ApiClient;
546
+ function getTokenPayload() {
547
+ const token = getAuthToken();
548
+ return JSON.parse(
549
+ Buffer.from(token.split(".")[1], "base64").toString()
550
+ );
551
+ }
552
+ async function ensureUserExists(client) {
553
+ if (userEnsured) return;
554
+ const payload = getTokenPayload();
555
+ const userId = payload.sub;
556
+ const resp = await client.get(`/users/${userId}`);
557
+ if (resp.user) {
558
+ userEnsured = true;
559
+ return;
560
+ }
561
+ const meta = payload.user_metadata || {};
562
+ await client.post("/users", {
563
+ id: userId,
564
+ email: payload.email || "",
565
+ displayName: meta.full_name || payload.email || "",
566
+ avatarUrl: meta.avatar_url || "",
567
+ authProvider: payload.app_metadata?.provider || "google",
568
+ providerId: meta.provider_id || ""
569
+ });
570
+ userEnsured = true;
571
+ }
572
+ async function initApiClient() {
573
+ const client = await createApiClientWithRefresh();
574
+ await ensureUserExists(client);
575
+ return client;
576
+ }
577
+ var SUPABASE_URL2, SUPABASE_ANON_KEY, ApiClient, userEnsured;
524
578
  var init_api_client = __esm({
525
579
  "src/lib/api-client.ts"() {
526
580
  "use strict";
@@ -532,8 +586,8 @@ var init_api_client = __esm({
532
586
  this.baseUrl = baseUrl;
533
587
  this.authToken = authToken;
534
588
  }
535
- async request(method, path, body) {
536
- const url = `${this.baseUrl}${path}`;
589
+ async request(method, path2, body) {
590
+ const url = `${this.baseUrl}${path2}`;
537
591
  const headers = {
538
592
  "Content-Type": "application/json",
539
593
  Authorization: this.authToken
@@ -560,19 +614,20 @@ var init_api_client = __esm({
560
614
  if (!text2) return void 0;
561
615
  return JSON.parse(text2);
562
616
  }
563
- async get(path) {
564
- return this.request("GET", path);
617
+ async get(path2) {
618
+ return this.request("GET", path2);
565
619
  }
566
- async post(path, body) {
567
- return this.request("POST", path, body);
620
+ async post(path2, body) {
621
+ return this.request("POST", path2, body);
568
622
  }
569
- async patch(path, body) {
570
- return this.request("PATCH", path, body);
623
+ async patch(path2, body) {
624
+ return this.request("PATCH", path2, body);
571
625
  }
572
- async delete(path) {
573
- return this.request("DELETE", path);
626
+ async delete(path2) {
627
+ return this.request("DELETE", path2);
574
628
  }
575
629
  };
630
+ userEnsured = false;
576
631
  }
577
632
  });
578
633
 
@@ -776,7 +831,7 @@ var init_create = __esm({
776
831
  }
777
832
  const s = p2.spinner();
778
833
  s.start("Creating session...");
779
- const client = createApiClient();
834
+ const client = await initApiClient();
780
835
  const userId = getUserIdFromToken();
781
836
  let projectId;
782
837
  const projectName = options.project || "";
@@ -1464,8 +1519,8 @@ function renderInteractiveList(terminal, sessionRows, total, selectedIndex) {
1464
1519
  async function fetchSessionDetail(sessionId) {
1465
1520
  const client = createApiClient();
1466
1521
  const isUuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(sessionId);
1467
- const path = !isUuid ? `/sessions/by-pin/${sessionId}` : `/sessions/${sessionId}`;
1468
- const session = await client.get(path);
1522
+ const path2 = !isUuid ? `/sessions/by-pin/${sessionId}` : `/sessions/${sessionId}`;
1523
+ const session = await client.get(path2);
1469
1524
  let metrics = null;
1470
1525
  let timeline = [];
1471
1526
  let analysis = null;
@@ -1664,7 +1719,7 @@ async function startDashboard() {
1664
1719
  process.stdout.on("resize", onResize);
1665
1720
  (async () => {
1666
1721
  try {
1667
- const client = await createApiClientWithRefresh();
1722
+ const client = await initApiClient();
1668
1723
  if (state.authExpired) {
1669
1724
  state.authExpired = false;
1670
1725
  state.authEmail = getUserEmailFromToken();
@@ -1910,7 +1965,7 @@ var listCommand = new Command3("list").alias("ls").description("List your feedba
1910
1965
  const s = p3.spinner();
1911
1966
  s.start("Fetching sessions...");
1912
1967
  try {
1913
- const client = createApiClient();
1968
+ const client = await initApiClient();
1914
1969
  const userId = getUserIdFromToken();
1915
1970
  const queryParams = new URLSearchParams();
1916
1971
  queryParams.set("take", String(options.limit));
@@ -2005,10 +2060,10 @@ var showCommand = new Command4("show").description("Show session details with ri
2005
2060
  const s = p4.spinner();
2006
2061
  s.start("Fetching session...");
2007
2062
  try {
2008
- const client = createApiClient();
2063
+ const client = await initApiClient();
2009
2064
  const isUuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(sessionId);
2010
- const path = !isUuid ? `/sessions/by-pin/${sessionId}` : `/sessions/${sessionId}`;
2011
- const session = await client.get(path);
2065
+ const path2 = !isUuid ? `/sessions/by-pin/${sessionId}` : `/sessions/${sessionId}`;
2066
+ const session = await client.get(path2);
2012
2067
  let metrics = null;
2013
2068
  let timeline = [];
2014
2069
  let analysis = null;
@@ -2129,7 +2184,7 @@ import { Command as Command5 } from "commander";
2129
2184
  import * as p5 from "@clack/prompts";
2130
2185
  var deleteCommand = new Command5("delete").alias("rm").description("Delete a session").argument("<session-id>", "Session ID (UUID)").option("--force", "Skip confirmation prompt").action(async (sessionId, options) => {
2131
2186
  try {
2132
- const client = createApiClient();
2187
+ const client = await initApiClient();
2133
2188
  let sessionName = sessionId;
2134
2189
  try {
2135
2190
  const session = await client.get(
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/lib/config.ts","../src/lib/theme.ts","../src/lib/render.ts","../src/components/KeyValue.tsx","../src/commands/auth.ts","../src/lib/api-client.ts","../src/lib/templates.ts","../src/commands/create.ts","../src/lib/node-backend.ts","../src/lib/input.ts","../src/components/Header.tsx","../src/components/TabBar.tsx","../src/components/ShortcutBar.tsx","../src/components/Dashboard.tsx","../src/components/MetricsPanel.tsx","../src/components/SessionDetail.tsx","../src/lib/app.tsx","../src/index.ts","../src/commands/list.ts","../src/components/SessionTable.tsx","../src/commands/show.ts","../src/commands/delete.ts"],"sourcesContent":["import Conf from 'conf';\n\nconst config = new Conf({\n projectName: 'audiencemeter',\n schema: {\n apiUrl: {\n type: 'string' as const,\n default: 'https://api.audiencemeter.pro/v1',\n },\n authToken: {\n type: 'string' as const,\n default: '',\n },\n refreshToken: {\n type: 'string' as const,\n default: '',\n },\n },\n});\n\nexport function getConfig(): typeof config {\n return config;\n}\n\nexport function getAuthToken(): string {\n const token = config.get('authToken') as string;\n if (!token) {\n throw new Error('Not authenticated. Run: audiencemeter login');\n }\n return token;\n}\n\nexport function setAuthToken(token: string): void {\n config.set('authToken', token);\n}\n\nexport function clearAuthToken(): void {\n config.set('authToken', '');\n config.set('refreshToken', '');\n}\n\nexport function getRefreshToken(): string {\n return config.get('refreshToken') as string;\n}\n\nexport function setRefreshToken(token: string): void {\n config.set('refreshToken', token);\n}\n\nexport function getApiUrl(): string {\n return config.get('apiUrl') as string;\n}\n\nexport function setApiUrl(url: string): void {\n config.set('apiUrl', url);\n}\n","import { rgbColor, type Color } from 'terminui';\n\n// Brand colors as terminui Color objects (no ANSI escape strings)\nexport const BRAND_COLORS: Record<string, Color> = {\n purple: rgbColor(175, 95, 255), // Brand purple\n cyan: rgbColor(80, 220, 220), // Info/borders\n green: rgbColor(80, 220, 120), // Success/gauges\n yellow: rgbColor(255, 200, 60), // PINs\n dimCyan: rgbColor(60, 160, 170), // Borders, labels\n red: rgbColor(255, 100, 100), // Errors\n dim: rgbColor(128, 128, 128), // Dimmed text\n white: rgbColor(230, 230, 230), // Primary text\n};\n\nexport const icon = {\n session: '\\u25cf', // ●\n live: '\\u25cf', // ●\n ended: '\\u25cb', // ○\n upcoming: '\\u25d4', // ◔\n check: '\\u2714', // ✔\n cross: '\\u2718', // ✘\n arrow: '\\u276f', // ❯\n dot: '\\u00b7', // ·\n bar: '\\u2503', // ┃\n dash: '\\u2500', // ─\n star: '\\u2605', // ★\n sparkle: '\\u2728', // ✨\n};\n\nexport const BRAND = {\n name: 'AudienceMeter',\n tagline: 'Speaker feedback, beautifully managed',\n version: '0.1.0',\n};\n","import {\n createTestBackendState,\n createTestBackend,\n createTerminal,\n testBackendCellAt,\n type Cell,\n} from 'terminui';\nimport { terminalDrawJsx } from 'terminui/jsx';\nimport type { JsxNode } from 'terminui/jsx-runtime';\n\n// ── ANSI Color Conversion (shared with node-backend.ts) ──────────────\n\ntype CellColor = { type: string; r?: number; g?: number; b?: number; index?: number };\n\nconst NAMED_FG: Record<string, string> = {\n black: '30', red: '31', green: '32', yellow: '33', blue: '34',\n magenta: '35', cyan: '36', gray: '37', white: '97',\n 'dark-gray': '90', 'light-red': '91', 'light-green': '92',\n 'light-yellow': '93', 'light-blue': '94', 'light-magenta': '95', 'light-cyan': '96',\n};\n\nconst NAMED_BG: Record<string, string> = {\n black: '40', red: '41', green: '42', yellow: '43', blue: '44',\n magenta: '45', cyan: '46', gray: '47', white: '107',\n 'dark-gray': '100', 'light-red': '101', 'light-green': '102',\n 'light-yellow': '103', 'light-blue': '104', 'light-magenta': '105', 'light-cyan': '106',\n};\n\nconst RESET = '\\x1b[0m';\n\nexport function fgAnsi(c: CellColor | undefined): string {\n if (!c || c.type === 'reset') return '';\n if (c.type === 'rgb') return `\\x1b[38;2;${c.r};${c.g};${c.b}m`;\n if (c.type === 'indexed') return `\\x1b[38;5;${c.index}m`;\n return NAMED_FG[c.type] ? `\\x1b[${NAMED_FG[c.type]}m` : '';\n}\n\nexport function bgAnsi(c: CellColor | undefined): string {\n if (!c || c.type === 'reset') return '';\n if (c.type === 'rgb') return `\\x1b[48;2;${c.r};${c.g};${c.b}m`;\n if (c.type === 'indexed') return `\\x1b[48;5;${c.index}m`;\n return NAMED_BG[c.type] ? `\\x1b[${NAMED_BG[c.type]}m` : '';\n}\n\nexport function modAnsi(mod: number | undefined): string {\n if (!mod) return '';\n let s = '';\n if (mod & 1) s += '\\x1b[1m'; // Bold\n if (mod & 2) s += '\\x1b[2m'; // Dim\n if (mod & 4) s += '\\x1b[3m'; // Italic\n if (mod & 8) s += '\\x1b[4m'; // Underline\n if (mod & 64) s += '\\x1b[7m'; // Reversed\n return s;\n}\n\n/**\n * Convert a terminui Cell to an ANSI escape string (style + symbol).\n */\nexport function cellToAnsi(cell: Cell): string {\n const fg = fgAnsi(cell.fg as CellColor);\n const bg = bgAnsi(cell.bg as CellColor);\n const mod = modAnsi(cell.modifier);\n const style = fg + bg + mod;\n if (style) {\n return style + cell.symbol + RESET;\n }\n return cell.symbol;\n}\n\n// ── Render JSX to String (static commands) ───────────────────────────\n\n/**\n * Renders a JSX node tree to a styled ANSI string using the test backend.\n * Used for print-and-exit commands (list, show, create, delete, auth).\n */\nexport function renderJsxToString(width: number, height: number, node: JsxNode): string {\n const state = createTestBackendState(width, height);\n const terminal = createTerminal(createTestBackend(state));\n terminalDrawJsx(terminal, node);\n\n // Reconstruct ANSI-styled output from the cell grid\n const lines: string[] = [];\n for (let y = 0; y < height; y++) {\n let line = '';\n let hasStyle = false;\n for (let x = 0; x < width; x++) {\n const cell = testBackendCellAt(state, x, y) as {\n symbol: string; fg?: CellColor; bg?: CellColor; modifier?: number;\n } | undefined;\n if (!cell) {\n if (hasStyle) { line += RESET; hasStyle = false; }\n line += ' ';\n continue;\n }\n const style = fgAnsi(cell.fg) + bgAnsi(cell.bg) + modAnsi(cell.modifier);\n if (style) {\n if (hasStyle) line += RESET;\n line += style + cell.symbol;\n hasStyle = true;\n } else {\n if (hasStyle) { line += RESET; hasStyle = false; }\n line += cell.symbol;\n }\n }\n if (hasStyle) line += RESET;\n lines.push(line.trimEnd());\n }\n\n // Trim trailing empty lines\n while (lines.length > 0 && stripAnsi(lines[lines.length - 1]!).trim() === '') {\n lines.pop();\n }\n\n return lines.join('\\n');\n}\n\n// ── Utilities ────────────────────────────────────────────────────────\n\n/**\n * Returns the usable terminal width, capped at 120 columns.\n */\nexport function getTermWidth(): number {\n return Math.min(process.stdout.columns || 80, 120);\n}\n\n/**\n * Strips all ANSI escape sequences from a string.\n */\nexport function stripAnsi(s: string): string {\n return s.replace(/\\x1b\\[[0-9;]*m/g, '');\n}\n","import { VStack, HStack, Text } from 'terminui/jsx';\nimport { lengthConstraint, fillConstraint } from 'terminui';\nimport { BRAND_COLORS } from '../lib/theme.js';\n\nexport interface KeyValueProps {\n readonly pairs: readonly (readonly [string, string])[];\n}\n\nexport function KeyValue({ pairs }: KeyValueProps) {\n const maxKeyLen = Math.max(...pairs.map(([k]) => k.length));\n const constraints = pairs.map(() => lengthConstraint(1));\n\n const rows = pairs.map(([key, value]) => {\n const padded = key.padStart(maxKeyLen);\n return (\n <HStack constraints={[lengthConstraint(maxKeyLen + 2), fillConstraint(1)]}>\n <Text fg={BRAND_COLORS.dim}>{padded + ' '}</Text>\n <Text bold fg={BRAND_COLORS.white}>{value}</Text>\n </HStack>\n );\n });\n\n return (\n <VStack constraints={constraints}>\n {rows}\n </VStack>\n );\n}\n","import { Command } from 'commander';\nimport http from 'node:http';\nimport { URL } from 'node:url';\nimport * as p from '@clack/prompts';\nimport { setAuthToken, clearAuthToken, getApiUrl, setRefreshToken } from '../lib/config.js';\nimport { BRAND, icon } from '../lib/theme.js';\nimport { renderJsxToString, getTermWidth } from '../lib/render.js';\nimport { KeyValue } from '../components/KeyValue.js';\n\nconst SUPABASE_URL = 'https://gflvvytymdmrbjpmymhb.supabase.co';\n\nexport const authCommand = new Command('auth').description(\n 'Manage authentication'\n);\n\nexport const loginCommand = new Command('login')\n .description('Log in via browser (Google OAuth)');\n\nloginCommand.action(async () => {\n p.intro(`${BRAND.name} -- Login`);\n\n const s = p.spinner();\n s.start('Starting local auth server...');\n\n try {\n const token = await new Promise<string>((resolve, reject) => {\n const server = http.createServer((req, res) => {\n if (!req.url) {\n res.writeHead(400);\n res.end('Bad request');\n return;\n }\n\n const url = new URL(req.url, 'http://localhost');\n\n if (url.pathname === '/callback') {\n res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });\n res.end(`<!DOCTYPE html>\n<html><head><meta charset=\"utf-8\"><title>${BRAND.name} — Login</title>\n<style>body{font-family:system-ui;display:flex;justify-content:center;align-items:center;height:100vh;margin:0;background:#0a0a0a;color:#e5e5e5}\n.card{text-align:center;padding:2rem;border-radius:12px;background:#171717;border:1px solid #333}</style></head>\n<body><div class=\"card\"><p>Processing authentication...</p></div>\n<script>\nconst h=window.location.hash.substring(1);const p=new URLSearchParams(h);const t=p.get('access_token');const r=p.get('refresh_token');\nif(t){let u='/token?access_token='+encodeURIComponent(t);if(r)u+='&refresh_token='+encodeURIComponent(r);window.location.href=u}\nelse{document.querySelector('.card').innerHTML='<p style=\"color:#f87171\">Authentication failed. No token found.</p><p>You can close this tab.</p>'}\n</script></body></html>`);\n return;\n }\n\n if (url.pathname === '/token') {\n const accessToken = url.searchParams.get('access_token');\n const refreshTokenParam = url.searchParams.get('refresh_token');\n if (accessToken) {\n if (refreshTokenParam) {\n setRefreshToken(refreshTokenParam);\n }\n res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });\n res.end(`<!DOCTYPE html>\n<html><head><meta charset=\"utf-8\"><title>${BRAND.name} — Logged In</title>\n<style>body{font-family:system-ui;display:flex;justify-content:center;align-items:center;height:100vh;margin:0;background:#0a0a0a;color:#e5e5e5}\n.card{text-align:center;padding:2rem;border-radius:12px;background:#171717;border:1px solid #333}\n.check{font-size:3rem;margin-bottom:1rem}</style></head>\n<body><div class=\"card\"><div class=\"check\">&#x2714;</div><h2>Logged in!</h2><p>Return to your terminal.</p></div></body></html>`);\n resolve(accessToken);\n server.close();\n } else {\n res.writeHead(400, { 'Content-Type': 'text/html' });\n res.end('<p>Missing access token.</p>');\n }\n return;\n }\n\n res.writeHead(404);\n res.end('Not found');\n });\n\n server.listen(0, () => {\n const address = server.address();\n if (!address || typeof address === 'string') {\n reject(new Error('Failed to start local server'));\n return;\n }\n\n const port = address.port;\n const redirectUrl = `http://localhost:${port}/callback`;\n const authUrl = `${SUPABASE_URL}/auth/v1/authorize?provider=google&redirect_to=${encodeURIComponent(redirectUrl)}`;\n\n s.message('Opening browser for authentication...');\n\n import('open')\n .then((m) => m.default(authUrl))\n .catch(() => {\n s.stop('Could not open browser automatically');\n p.note(authUrl, 'Open this URL manually');\n });\n });\n\n setTimeout(() => {\n server.close();\n reject(new Error('Authentication timed out after 120 seconds'));\n }, 120_000);\n });\n\n setAuthToken(token);\n s.stop(`${icon.check} Logged in successfully!`);\n\n // Show user info\n const payload = JSON.parse(\n Buffer.from(token.split('.')[1]!, 'base64').toString()\n ) as { email?: string };\n\n if (payload.email) {\n p.log.info(`Signed in as ${payload.email}`);\n }\n\n p.outro('Token stored. You can now use AudienceMeter CLI commands.');\n process.exit(0);\n } catch (error) {\n s.stop(\n `${icon.cross} Login failed: ${error instanceof Error ? error.message : 'Unknown error'}`\n );\n process.exit(1);\n }\n });\n\nexport const logoutCommand = new Command('logout')\n .description('Log out and clear stored credentials')\n .action(async () => {\n clearAuthToken();\n p.log.success(`${icon.check} Logged out successfully.`);\n });\n\nauthCommand\n .command('whoami')\n .description('Show current authenticated user')\n .action(async () => {\n try {\n const { getAuthToken } = await import('../lib/config.js');\n const token = getAuthToken();\n const apiUrl = getApiUrl();\n\n const payload = JSON.parse(\n Buffer.from(token.split('.')[1]!, 'base64').toString()\n ) as { email?: string; sub?: string };\n\n const output = renderJsxToString(\n getTermWidth(),\n 3,\n KeyValue({\n pairs: [\n ['Email', payload.email || 'unknown'],\n ['User ID', payload.sub || 'unknown'],\n ['API URL', apiUrl],\n ],\n })\n );\n console.log(output);\n } catch (error) {\n if (\n error instanceof Error &&\n error.message.includes('Not authenticated')\n ) {\n p.log.warn('Not logged in. Run: audiencemeter login');\n } else {\n p.log.error(\n error instanceof Error ? error.message : 'Unknown error'\n );\n }\n }\n });\n\nauthCommand\n .command('token')\n .description('Print the current stored auth token')\n .action(async () => {\n try {\n const { getAuthToken } = await import('../lib/config.js');\n const token = getAuthToken();\n console.log(token);\n } catch (error) {\n if (\n error instanceof Error &&\n error.message.includes('Not authenticated')\n ) {\n p.log.warn('Not logged in. Run: audiencemeter login');\n } else {\n p.log.error(\n error instanceof Error ? error.message : 'Unknown error'\n );\n }\n }\n });\n\n// Register login/logout as subcommands of auth so `auth login` / `auth logout` still works\nauthCommand.addCommand(loginCommand);\nauthCommand.addCommand(logoutCommand);\n","import { getAuthToken, getApiUrl, getRefreshToken, setAuthToken, setRefreshToken } from './config.js';\n\nconst SUPABASE_URL = 'https://gflvvytymdmrbjpmymhb.supabase.co';\nconst SUPABASE_ANON_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImdmbHZ2eXR5bWRtcmJqcG15bWhiIiwicm9sZSI6ImFub24iLCJpYXQiOjE2ODAyNTIwMjIsImV4cCI6MTk5NTgyODAyMn0.1m-3IhFB-87AKk_-UIPzB0O1URgBwl78oKu8sNe8aFU';\n\nexport function isTokenExpired(token: string): boolean {\n try {\n const payload = JSON.parse(\n Buffer.from(token.split('.')[1]!, 'base64').toString()\n ) as { exp?: number };\n if (!payload.exp) return false;\n // Consider expired 60s before actual expiry to avoid edge cases\n return Date.now() >= (payload.exp - 60) * 1000;\n } catch {\n return true;\n }\n}\n\nexport async function refreshAccessToken(): Promise<string | null> {\n const refreshToken = getRefreshToken();\n if (!refreshToken) return null;\n\n try {\n const response = await fetch(`${SUPABASE_URL}/auth/v1/token?grant_type=refresh_token`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'apikey': SUPABASE_ANON_KEY,\n },\n body: JSON.stringify({ refresh_token: refreshToken }),\n });\n\n if (!response.ok) return null;\n\n const data = await response.json() as {\n access_token?: string;\n refresh_token?: string;\n };\n\n if (data.access_token) {\n setAuthToken(data.access_token);\n if (data.refresh_token) {\n setRefreshToken(data.refresh_token);\n }\n return data.access_token;\n }\n return null;\n } catch {\n return null;\n }\n}\n\nexport class ApiClient {\n constructor(\n private baseUrl: string,\n private authToken: string\n ) {}\n\n private async request<T>(\n method: string,\n path: string,\n body?: unknown\n ): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n Authorization: this.authToken,\n };\n\n const options: RequestInit = { method, headers };\n\n if (body !== undefined) {\n options.body = JSON.stringify(body);\n }\n\n const response = await fetch(url, options);\n\n if (!response.ok) {\n let errorMessage: string;\n try {\n const errorBody = (await response.json()) as Record<string, string>;\n errorMessage =\n errorBody.message || errorBody.error || response.statusText;\n } catch {\n errorMessage = response.statusText;\n }\n\n if (response.status === 401) {\n throw new Error('Not authenticated. Run: audiencemeter login');\n }\n\n throw new Error(`API error (${response.status}): ${errorMessage}`);\n }\n\n const text = await response.text();\n if (!text) return undefined as T;\n return JSON.parse(text) as T;\n }\n\n async get<T>(path: string): Promise<T> {\n return this.request<T>('GET', path);\n }\n\n async post<T>(path: string, body?: unknown): Promise<T> {\n return this.request<T>('POST', path, body);\n }\n\n async patch<T>(path: string, body?: unknown): Promise<T> {\n return this.request<T>('PATCH', path, body);\n }\n\n async delete<T>(path: string): Promise<T> {\n return this.request<T>('DELETE', path);\n }\n}\n\nexport async function ensureValidToken(): Promise<string> {\n const token = getAuthToken();\n if (!isTokenExpired(token)) return token;\n\n const newToken = await refreshAccessToken();\n if (newToken) return newToken;\n\n throw new Error('Session expired. Run: audiencemeter login');\n}\n\nexport function createApiClient(): ApiClient {\n const baseUrl = getApiUrl();\n const authToken = getAuthToken();\n return new ApiClient(baseUrl, authToken);\n}\n\nexport async function createApiClientWithRefresh(): Promise<ApiClient> {\n const baseUrl = getApiUrl();\n const authToken = await ensureValidToken();\n return new ApiClient(baseUrl, authToken);\n}\n\nexport function getUserIdFromToken(): string {\n const token = getAuthToken();\n const payload = JSON.parse(\n Buffer.from(token.split('.')[1]!, 'base64').toString()\n ) as { sub: string };\n return payload.sub;\n}\n\nexport function getUserEmailFromToken(): string {\n const token = getAuthToken();\n const payload = JSON.parse(\n Buffer.from(token.split('.')[1]!, 'base64').toString()\n ) as { email?: string };\n return payload.email || 'unknown';\n}\n","export const TEMPLATES = {\n talk: {\n description: 'Conference talk or presentation (45 min)',\n durationMinutes: 45,\n ratings: [\n { label: 'Content Quality', maxValue: 5 },\n { label: 'Delivery', maxValue: 5 },\n { label: 'Clarity', maxValue: 5 },\n ],\n links: [],\n },\n workshop: {\n description: 'Hands-on workshop or lab session (120 min)',\n durationMinutes: 120,\n ratings: [\n { label: 'Content Quality', maxValue: 5 },\n { label: 'Hands-on Experience', maxValue: 5 },\n { label: 'Pace', maxValue: 5 },\n { label: 'Clarity', maxValue: 5 },\n ],\n links: [],\n },\n lightning: {\n description: 'Lightning talk (10 min)',\n durationMinutes: 10,\n ratings: [\n { label: 'Content Quality', maxValue: 5 },\n { label: 'Delivery', maxValue: 5 },\n ],\n links: [],\n },\n panel: {\n description: 'Panel discussion (60 min)',\n durationMinutes: 60,\n ratings: [\n { label: 'Topic Relevance', maxValue: 5 },\n { label: 'Discussion Quality', maxValue: 5 },\n { label: 'Moderation', maxValue: 5 },\n ],\n links: [],\n },\n} as const;\n\nexport type TemplateName = keyof typeof TEMPLATES;\n\nexport function getTemplate(name: string) {\n if (!(name in TEMPLATES)) {\n return null;\n }\n return TEMPLATES[name as TemplateName];\n}\n\nexport function getTemplateNames(): string[] {\n return Object.keys(TEMPLATES);\n}\n","import { Command } from 'commander';\nimport * as p from '@clack/prompts';\nimport qrcode from 'qrcode-terminal';\nimport { createApiClient, getUserIdFromToken } from '../lib/api-client.js';\nimport {\n TEMPLATES,\n getTemplate,\n getTemplateNames,\n} from '../lib/templates.js';\nimport { BRAND, icon } from '../lib/theme.js';\nimport { renderJsxToString, getTermWidth } from '../lib/render.js';\nimport { KeyValue } from '../components/KeyValue.js';\n\ninterface Project {\n id: string;\n name: string;\n [key: string]: unknown;\n}\n\nfunction padDate(n: number): string {\n return String(n).padStart(2, '0');\n}\n\nfunction formatLocalDate(d: Date): string {\n return `${d.getFullYear()}-${padDate(d.getMonth() + 1)}-${padDate(d.getDate())}`;\n}\n\nfunction formatLocalTime(d: Date): string {\n return `${padDate(d.getHours())}:${padDate(d.getMinutes())}`;\n}\n\nexport const createCommand = new Command('create')\n .description('Create a new feedback session')\n .option('--template <type>', 'Session template')\n .option('--project <name>', 'Project name (optional)')\n .option('--name <name>', 'Session name')\n .option('--date <date>', 'Session date (YYYY-MM-DD)')\n .option('--time <time>', 'Session time (HH:MM, 24h format)')\n .option(\n '--duration <minutes>',\n 'Duration in minutes',\n parseInt\n )\n .option('--json', 'Output as JSON')\n .action(async (options) => {\n const isInteractive =\n !options.json && process.stdout.isTTY && !options.template;\n\n if (isInteractive) {\n p.intro(`${BRAND.name} -- Create Session`);\n }\n\n try {\n // -- Template selection ----------------------------------------\n let templateName: string = options.template;\n\n if (!templateName) {\n if (!isInteractive) {\n p.log.error(\n 'Missing --template. Available: ' + getTemplateNames().join(', ')\n );\n process.exit(1);\n }\n\n const selected = await p.select({\n message: 'What type of session?',\n options: Object.entries(TEMPLATES).map(([key, tmpl]) => ({\n value: key,\n label: key.charAt(0).toUpperCase() + key.slice(1),\n hint: tmpl.description,\n })),\n });\n\n if (p.isCancel(selected)) {\n p.cancel('Cancelled.');\n process.exit(0);\n }\n templateName = selected as string;\n }\n\n const template = getTemplate(templateName);\n if (!template) {\n p.log.error(\n `Unknown template: \"${templateName}\". Available: ${getTemplateNames().join(', ')}`\n );\n process.exit(1);\n }\n\n // -- Session name ------------------------------------------------\n let sessionName: string = options.name;\n\n if (!sessionName && isInteractive) {\n const input = await p.text({\n message: 'Session name?',\n placeholder: 'My Talk at DevFest 2026',\n validate: (v) => {\n if (!v?.trim()) return 'Session name is required';\n },\n });\n\n if (p.isCancel(input)) {\n p.cancel('Cancelled.');\n process.exit(0);\n }\n sessionName = input;\n }\n\n if (!sessionName) {\n p.log.error('Missing --name flag.');\n process.exit(1);\n }\n\n // -- Date & Time ------------------------------------------------\n const now = new Date();\n let sessionDate: string;\n\n if (options.date) {\n // Non-interactive: combine --date and optional --time\n const time = options.time || '00:00';\n sessionDate = new Date(`${options.date}T${time}`).toISOString();\n } else if (isInteractive) {\n const dateInput = await p.text({\n message: 'Session date? (YYYY-MM-DD)',\n placeholder: formatLocalDate(now),\n defaultValue: formatLocalDate(now),\n validate: (v) => {\n if (!/^\\d{4}-\\d{2}-\\d{2}$/.test(v || ''))\n return 'Use YYYY-MM-DD format';\n if (isNaN(new Date(v!).getTime()))\n return 'Invalid date';\n },\n });\n\n if (p.isCancel(dateInput)) {\n p.cancel('Cancelled.');\n process.exit(0);\n }\n\n const timeInput = await p.text({\n message: 'Start time? (24h format)',\n placeholder: formatLocalTime(now),\n defaultValue: formatLocalTime(now),\n validate: (v) => {\n if (!/^\\d{1,2}:\\d{2}$/.test(v || ''))\n return 'Use HH:MM format (e.g. 14:30)';\n },\n });\n\n if (p.isCancel(timeInput)) {\n p.cancel('Cancelled.');\n process.exit(0);\n }\n\n sessionDate = new Date(`${dateInput}T${timeInput}`).toISOString();\n } else {\n sessionDate = now.toISOString();\n }\n\n // -- Duration -----------------------------------------------\n let duration: number = options.duration || template.durationMinutes;\n\n if (!options.duration && isInteractive) {\n const input = await p.text({\n message: 'Duration (minutes)?',\n defaultValue: String(template.durationMinutes),\n placeholder: String(template.durationMinutes),\n validate: (v) => {\n const n = parseInt(v || '', 10);\n if (isNaN(n) || n < 1) return 'Enter a valid number of minutes';\n },\n });\n\n if (p.isCancel(input)) {\n p.cancel('Cancelled.');\n process.exit(0);\n }\n duration = parseInt(input, 10);\n }\n\n // -- Create session -----------------------------------------\n const s = p.spinner();\n s.start('Creating session...');\n\n const client = createApiClient();\n const userId = getUserIdFromToken();\n\n // Resolve project only if --project flag was passed\n let projectId: string | undefined;\n const projectName: string = options.project || '';\n if (projectName) {\n try {\n s.message('Resolving project...');\n const projectsResp = await client.get<Project[] | { data: Project[] }>(\n `/users/${userId}/projects`\n );\n const projects = Array.isArray(projectsResp)\n ? projectsResp\n : projectsResp?.data || [];\n\n const existing = projects.find(\n (proj: Project) =>\n proj.name.toLowerCase() === projectName.toLowerCase()\n );\n\n if (existing) {\n projectId = existing.id;\n } else {\n s.message('Creating project...');\n const newProject = await client.post<Project>(\n `/users/${userId}/projects`,\n { name: projectName }\n );\n projectId = newProject.id;\n }\n } catch {\n // Continue without project ID\n }\n }\n\n // Build session payload\n const sessionBody = {\n name: sessionName,\n date: sessionDate,\n durationMinutes: duration,\n ratings: [...template.ratings],\n links: [...template.links],\n ...(projectId && { projectId }),\n };\n\n s.message('Creating session...');\n const session = (await client.post('/sessions', sessionBody)) as Record<\n string,\n unknown\n >;\n\n s.stop(`${icon.check} Session created!`);\n\n if (options.json) {\n console.log(JSON.stringify(session, null, 2));\n } else {\n const pairs: [string, string][] = [\n ['Name', String(session.name || sessionName)],\n ['PIN', String(session.pin || '')],\n ['Template', templateName],\n ['Duration', `${duration} minutes`],\n ['Date', new Date(sessionDate).toLocaleString()],\n ];\n if (session.id) {\n pairs.push(['ID', String(session.id)]);\n }\n\n console.log();\n const output = renderJsxToString(\n getTermWidth(),\n pairs.length,\n KeyValue({ pairs })\n );\n console.log(output);\n\n if (session.pin) {\n const joinUrl = `https://app.audiencemeter.pro/s/${session.pin}`;\n console.log();\n p.note(joinUrl, 'Join URL');\n\n // Print QR code in terminal\n console.log();\n await new Promise<void>((resolve) => {\n qrcode.generate(joinUrl, { small: true }, (code: string) => {\n console.log(code);\n resolve();\n });\n });\n }\n\n p.outro('Share the PIN, URL, or QR code with your audience!');\n }\n } catch (error) {\n p.log.error(\n `Failed to create session: ${error instanceof Error ? error.message : 'Unknown error'}`\n );\n if (\n error instanceof Error &&\n error.message.includes('Not authenticated')\n ) {\n p.log.warn('Run: audiencemeter login');\n }\n process.exit(1);\n }\n });\n","import type { Backend, Cell } from 'terminui';\nimport { cellToAnsi } from './render.js';\n\nconst CSI = '\\x1b[';\n\n/**\n * Creates a Node.js stdout Backend implementing terminui's Backend interface.\n * Used for persistent full-screen TUI modes (dashboard, interactive list).\n *\n * The draw() method converts terminui Cell objects to ANSI escape sequences\n * and writes them to stdout with cursor positioning.\n */\nexport function createNodeBackend(): Backend {\n const stdout = process.stdout;\n\n return {\n size: () => ({\n width: stdout.columns || 80,\n height: stdout.rows || 24,\n }),\n\n draw: (content) => {\n let out = '';\n for (const { x, y, cell } of content) {\n // Move cursor to position (1-indexed)\n out += `${CSI}${y + 1};${x + 1}H`;\n out += cellToAnsi(cell);\n }\n stdout.write(out);\n },\n\n flush: () => {\n // stdout.write is already unbuffered for TTY -- no-op\n },\n\n hideCursor: () => {\n stdout.write(`${CSI}?25l`);\n },\n\n showCursor: () => {\n stdout.write(`${CSI}?25h`);\n },\n\n getCursorPosition: () => ({ x: 0, y: 0 }),\n\n setCursorPosition: (pos) => {\n stdout.write(`${CSI}${pos.y + 1};${pos.x + 1}H`);\n },\n\n clear: () => {\n stdout.write(`${CSI}2J${CSI}H`);\n },\n };\n}\n","import readline from 'node:readline';\n\n// ── Types ────────────────────────────────────────────────────────────\n\nexport interface KeypressInfo {\n name: string;\n ctrl: boolean;\n meta: boolean;\n shift: boolean;\n sequence: string;\n}\n\n// ── Alternate Screen Constants ───────────────────────────────────────\n\nconst ENTER_ALT_SCREEN = '\\x1b[?1049h';\nconst EXIT_ALT_SCREEN = '\\x1b[?1049l';\nconst HIDE_CURSOR = '\\x1b[?25l';\nconst SHOW_CURSOR = '\\x1b[?25h';\n\n// Module-level flag to track whether full screen is active.\n// Cleanup handlers only run exitFullScreen when this is true,\n// avoiding interference with normal non-fullscreen commands.\nlet isFullScreen = false;\n\n// ── Keyboard Input ───────────────────────────────────────────────────\n\n/**\n * Sets up keyboard input in raw mode and attaches a keypress handler.\n * Returns a cleanup function that removes the listener, disables raw mode,\n * and pauses stdin.\n */\nexport function setupKeyboardInput(handler: (key: KeypressInfo) => void): () => void {\n readline.emitKeypressEvents(process.stdin);\n\n if (process.stdin.isTTY) {\n process.stdin.setRawMode(true);\n }\n process.stdin.resume();\n\n const listener = (_str: string, key: { name: string; ctrl: boolean; meta: boolean; shift: boolean; sequence: string }) => {\n if (key) {\n handler({\n name: key.name ?? '',\n ctrl: key.ctrl ?? false,\n meta: key.meta ?? false,\n shift: key.shift ?? false,\n sequence: key.sequence ?? '',\n });\n }\n };\n\n process.stdin.on('keypress', listener);\n\n // Return cleanup function\n return () => {\n process.stdin.removeListener('keypress', listener);\n if (process.stdin.isTTY) {\n process.stdin.setRawMode(false);\n }\n process.stdin.pause();\n };\n}\n\n// ── Full Screen Management ───────────────────────────────────────────\n\n/**\n * Enters alternate screen buffer and hides the cursor.\n * Registers cleanup handlers for safe terminal restoration.\n */\nexport function enterFullScreen(): void {\n if (isFullScreen) return;\n isFullScreen = true;\n process.stdout.write(ENTER_ALT_SCREEN);\n process.stdout.write(HIDE_CURSOR);\n}\n\n/**\n * Shows the cursor and exits alternate screen buffer.\n * Safe to call multiple times (idempotent via flag check).\n */\nexport function exitFullScreen(): void {\n if (!isFullScreen) return;\n isFullScreen = false;\n process.stdout.write(SHOW_CURSOR);\n process.stdout.write(EXIT_ALT_SCREEN);\n}\n\n// ── Process Cleanup Handlers ─────────────────────────────────────────\n// These ensure the terminal is restored if the process exits while\n// full screen is active. The flag check prevents interference with\n// normal non-fullscreen commands.\n\nprocess.on('exit', () => {\n if (isFullScreen) {\n // Synchronous writes needed in 'exit' handler\n try { process.stdout.write(SHOW_CURSOR); } catch { /* ignore */ }\n try { process.stdout.write(EXIT_ALT_SCREEN); } catch { /* ignore */ }\n isFullScreen = false;\n }\n});\n\nprocess.on('SIGINT', () => {\n if (isFullScreen) {\n exitFullScreen();\n }\n process.exit(0);\n});\n\nprocess.on('SIGTERM', () => {\n if (isFullScreen) {\n exitFullScreen();\n }\n process.exit(0);\n});\n\nprocess.on('uncaughtException', (err) => {\n if (isFullScreen) {\n exitFullScreen();\n }\n console.error(err);\n process.exit(1);\n});\n","import { Text } from 'terminui/jsx';\nimport { BRAND_COLORS, BRAND } from '../lib/theme.js';\n\nexport interface HeaderProps {\n readonly version?: string;\n}\n\nexport function Header({ version }: HeaderProps = {}) {\n const ver = version || BRAND.version;\n return (\n <Text bold fg={BRAND_COLORS.purple} align=\"center\">\n {`${BRAND.name} v${ver}`}\n </Text>\n );\n}\n","import { Tabs } from 'terminui/jsx';\nimport { createStyle, Modifier } from 'terminui';\nimport { BRAND_COLORS } from '../lib/theme.js';\n\nexport interface TabBarProps {\n readonly titles: readonly string[];\n readonly selected: number;\n}\n\nexport function TabBar({ titles, selected }: TabBarProps) {\n return (\n <Tabs\n titles={titles}\n selected={selected}\n border\n fg={BRAND_COLORS.dimCyan}\n highlightStyle={createStyle({ fg: BRAND_COLORS.purple, addModifier: Modifier.BOLD })}\n />\n );\n}\n","import { Text } from 'terminui/jsx';\nimport { BRAND_COLORS } from '../lib/theme.js';\n\nexport interface ShortcutBarProps {\n readonly shortcuts: readonly { key: string; label: string }[];\n}\n\nexport function ShortcutBar({ shortcuts }: ShortcutBarProps) {\n const text = shortcuts.map((s) => `${s.key}: ${s.label}`).join(' | ');\n return (\n <Text fg={BRAND_COLORS.dimCyan}>{` ${text}`}</Text>\n );\n}\n","import { VStack, HStack, Box, Text, List, Gauge } from 'terminui/jsx';\nimport { fillConstraint, lengthConstraint, createListState, createStyle, Modifier } from 'terminui';\nimport type { ListState } from 'terminui';\nimport { BRAND_COLORS, icon } from '../lib/theme.js';\nimport { Header } from './Header.js';\nimport { TabBar } from './TabBar.js';\nimport { ShortcutBar } from './ShortcutBar.js';\nimport { SessionTable, type SessionRow } from './SessionTable.js';\n\nexport interface DashboardProps {\n readonly selectedTab: number;\n readonly sessions: readonly SessionRow[];\n readonly stats: {\n readonly totalSessions: number;\n readonly totalParticipants: number;\n readonly avgEngagement: number;\n };\n readonly selectedIndex: number;\n readonly authEmail: string | null;\n readonly authExpired?: boolean;\n readonly loading?: boolean;\n readonly error?: string | null;\n}\n\nconst TAB_TITLES = ['Dashboard', 'Sessions', 'Create', 'Auth'] as const;\n\nconst SHORTCUTS = [\n { key: 'Tab/1-4', label: 'switch' },\n { key: 'j/k', label: 'navigate' },\n { key: 'Enter', label: 'select' },\n { key: 'Esc/q', label: 'quit' },\n];\n\nfunction DashboardTab({ sessions, stats, selectedIndex, loading }: {\n sessions: readonly SessionRow[];\n stats: DashboardProps['stats'];\n selectedIndex: number;\n loading?: boolean;\n}) {\n const recent = sessions.slice(0, 5);\n const listItems = recent.length > 0\n ? recent.map((s) => `${icon.session} ${s.name} ${s.pin} ${s.status}`)\n : [loading ? 'Loading sessions...' : 'No sessions yet. Press Tab to go to Create.'];\n\n const listState: ListState = createListState();\n listState.selected = recent.length > 0 ? selectedIndex : undefined;\n\n return (\n <HStack constraints={[fillConstraint(2), fillConstraint(1)]}>\n <Box border borderType=\"rounded\" fg={BRAND_COLORS.dimCyan} title=\" Recent Sessions \">\n <List\n items={listItems}\n state={listState}\n fg={BRAND_COLORS.cyan}\n highlightStyle={createStyle({ fg: BRAND_COLORS.purple, addModifier: Modifier.BOLD })}\n />\n </Box>\n <VStack constraints={[lengthConstraint(3), lengthConstraint(3), fillConstraint(1)]}>\n <Box border borderType=\"rounded\" fg={BRAND_COLORS.dimCyan} title=\" Sessions \">\n <Text bold fg={BRAND_COLORS.white} align=\"center\">{String(stats.totalSessions)}</Text>\n </Box>\n <Box border borderType=\"rounded\" fg={BRAND_COLORS.dimCyan} title=\" Participants \">\n <Text bold fg={BRAND_COLORS.white} align=\"center\">{String(stats.totalParticipants)}</Text>\n </Box>\n <Box border borderType=\"rounded\" fg={BRAND_COLORS.dimCyan} title=\" Engagement \">\n <Gauge\n percent={stats.avgEngagement}\n fg={BRAND_COLORS.green}\n />\n </Box>\n </VStack>\n </HStack>\n );\n}\n\nfunction SessionsTab({ sessions, selectedIndex, loading }: {\n sessions: readonly SessionRow[];\n selectedIndex: number;\n loading?: boolean;\n}) {\n if (sessions.length === 0) {\n return (\n <Box border borderType=\"rounded\" fg={BRAND_COLORS.dimCyan}>\n <Text fg={BRAND_COLORS.dim}>{loading ? 'Loading sessions...' : 'No sessions found. Create one with the Create tab.'}</Text>\n </Box>\n );\n }\n\n const listItems = sessions.map((s) =>\n `${icon.session} ${s.name.padEnd(30).slice(0, 30)} ${s.pin} ${s.status.padEnd(10).slice(0, 10)} ${s.date}`\n );\n\n const listState: ListState = createListState();\n listState.selected = selectedIndex;\n\n return (\n <Box border borderType=\"rounded\" fg={BRAND_COLORS.dimCyan} title={` Sessions (${sessions.length}) `}>\n <List\n items={listItems}\n state={listState}\n fg={BRAND_COLORS.cyan}\n highlightStyle={createStyle({ fg: BRAND_COLORS.purple, addModifier: Modifier.BOLD })}\n />\n </Box>\n );\n}\n\nfunction CreateTab() {\n return (\n <Box border borderType=\"rounded\" fg={BRAND_COLORS.dimCyan} title=\" Create Session \">\n <Text fg={BRAND_COLORS.white}>{` Press Enter to create a new session`}</Text>\n </Box>\n );\n}\n\nfunction AuthTab({ authEmail, authExpired }: { authEmail: string | null; authExpired?: boolean }) {\n if (authExpired) {\n return (\n <Box border borderType=\"rounded\" title=\" Authentication \">\n <Text fg={BRAND_COLORS.yellow}>{` ${icon.cross} Session expired. Press Enter to re-login.`}</Text>\n </Box>\n );\n }\n\n return (\n <Box border borderType=\"rounded\" title=\" Authentication \">\n <Text fg={authEmail ? BRAND_COLORS.green : BRAND_COLORS.yellow}>\n {authEmail\n ? ` ${icon.check} Logged in as ${authEmail}`\n : ` ${icon.cross} Not logged in. Press Enter to login.`}\n </Text>\n </Box>\n );\n}\n\nexport function Dashboard({ selectedTab, sessions, stats, selectedIndex, authEmail, authExpired, loading, error }: DashboardProps) {\n let content;\n switch (selectedTab) {\n case 0:\n content = <DashboardTab sessions={sessions} stats={stats} selectedIndex={selectedIndex} loading={loading} />;\n break;\n case 1:\n content = <SessionsTab sessions={sessions} selectedIndex={selectedIndex} loading={loading} />;\n break;\n case 2:\n content = <CreateTab />;\n break;\n case 3:\n content = <AuthTab authEmail={authEmail} authExpired={authExpired} />;\n break;\n default:\n content = <DashboardTab sessions={sessions} stats={stats} selectedIndex={selectedIndex} />;\n }\n\n if (error) {\n return (\n <VStack constraints={[lengthConstraint(1), lengthConstraint(3), lengthConstraint(1), fillConstraint(1), lengthConstraint(1)]}>\n <Header />\n <TabBar titles={[...TAB_TITLES]} selected={selectedTab} />\n <Text fg={BRAND_COLORS.yellow} align=\"center\">{`${icon.cross} ${error}`}</Text>\n {content}\n <ShortcutBar shortcuts={SHORTCUTS} />\n </VStack>\n );\n }\n\n return (\n <VStack constraints={[lengthConstraint(1), lengthConstraint(3), fillConstraint(1), lengthConstraint(1)]}>\n <Header />\n <TabBar titles={[...TAB_TITLES]} selected={selectedTab} />\n {content}\n <ShortcutBar shortcuts={SHORTCUTS} />\n </VStack>\n );\n}\n","import { VStack, Gauge, LineGauge, Text, Box } from 'terminui/jsx';\nimport { lengthConstraint } from 'terminui';\nimport type { Color } from 'terminui';\nimport type { JsxNode } from 'terminui/jsx-runtime';\nimport { BRAND_COLORS } from '../lib/theme.js';\n\nexport interface MetricsPanelProps {\n readonly engagementRate?: number;\n readonly feedbackRate?: number;\n readonly participants?: number;\n}\n\nfunction gaugeColor(ratio: number): Color {\n if (ratio >= 70) return BRAND_COLORS.green;\n if (ratio >= 40) return BRAND_COLORS.cyan;\n return BRAND_COLORS.yellow;\n}\n\nexport function MetricsPanel({ engagementRate, feedbackRate, participants }: MetricsPanelProps) {\n const items: JsxNode[] = [];\n const constraints: ReturnType<typeof lengthConstraint>[] = [];\n\n if (participants !== undefined) {\n items.push(\n <Text bold fg={BRAND_COLORS.white}>{` ${String(participants)} participants`}</Text>\n );\n constraints.push(lengthConstraint(1));\n }\n\n if (engagementRate !== undefined && engagementRate > 0) {\n items.push(\n <Gauge\n percent={engagementRate}\n border\n title={` Engagement ${engagementRate}% `}\n fg={gaugeColor(engagementRate)}\n />\n );\n constraints.push(lengthConstraint(3));\n }\n\n if (feedbackRate !== undefined && feedbackRate > 0) {\n items.push(\n <LineGauge\n percent={feedbackRate}\n border\n title={` Feedback ${feedbackRate}% `}\n fg={gaugeColor(feedbackRate)}\n />\n );\n constraints.push(lengthConstraint(3));\n }\n\n if (items.length === 0) {\n return <Text fg={BRAND_COLORS.dim}>No metrics available</Text>;\n }\n\n return (\n <VStack constraints={constraints}>\n {items}\n </VStack>\n );\n}\n","import { VStack, HStack, Box, Text, Sparkline, BarChart } from 'terminui/jsx';\nimport { fillConstraint, lengthConstraint, createBarGroup, createBar } from 'terminui';\nimport type { BarGroup, Constraint } from 'terminui';\nimport type { JsxNode } from 'terminui/jsx-runtime';\nimport { BRAND_COLORS, icon } from '../lib/theme.js';\nimport { KeyValue } from './KeyValue.js';\nimport { MetricsPanel } from './MetricsPanel.js';\n\nexport interface SessionDetailSession {\n readonly id?: string;\n readonly name: string;\n readonly pin: string;\n readonly date?: string;\n readonly durationMinutes?: number;\n readonly createdAt?: string;\n readonly questions?: readonly { id: string; type: string; label: string }[];\n readonly links?: readonly { id: string; label: string; url: string }[];\n}\n\nexport interface SessionDetailMetrics {\n readonly totalParticipants?: number;\n readonly engagementRate?: number;\n readonly feedbackCompletionRate?: number;\n}\n\nexport interface TimelineBucket {\n readonly minute: number;\n readonly positive: number;\n readonly negative: number;\n readonly pace: number;\n}\n\nexport interface SessionDetailProps {\n readonly session: SessionDetailSession;\n readonly metrics: SessionDetailMetrics | null;\n readonly timeline: readonly TimelineBucket[];\n readonly analysis: Record<string, unknown> | null;\n readonly status: string;\n}\n\nfunction statusBadge(status: string): string {\n switch (status) {\n case 'live': return `${icon.live} live`;\n case 'ended': return `${icon.ended} ended`;\n case 'upcoming': return `${icon.upcoming} upcoming`;\n default: return status;\n }\n}\n\nexport function SessionDetail({ session, metrics, timeline, analysis, status }: SessionDetailProps) {\n // Build content sections as an array, then compose at the end\n const sections: JsxNode[] = [];\n const sectionConstraints: Constraint[] = [];\n\n // -- Header: session name + status --\n sections.push(\n <Text bold fg={BRAND_COLORS.purple}>\n {` ${session.name || 'Untitled Session'} ${statusBadge(status)}`}\n </Text>\n );\n sectionConstraints.push(lengthConstraint(1));\n\n // -- Info + Metrics side-by-side --\n const dateStr = session.date\n ? new Date(session.date).toLocaleString()\n : session.createdAt\n ? new Date(session.createdAt).toLocaleString()\n : '--';\n const durationStr = session.durationMinutes\n ? `${session.durationMinutes} minutes`\n : '--';\n\n const infoPairs: [string, string][] = [\n ['PIN', session.pin || '--'],\n ['Date', dateStr],\n ['Duration', durationStr],\n ];\n if (session.id) {\n infoPairs.push(['ID', session.id]);\n }\n\n const hasMetrics = metrics && (\n (metrics.engagementRate !== undefined && metrics.engagementRate > 0) ||\n (metrics.feedbackCompletionRate !== undefined && metrics.feedbackCompletionRate > 0) ||\n (metrics.totalParticipants !== undefined)\n );\n\n if (hasMetrics) {\n const metricsHeight = 1\n + (metrics!.totalParticipants !== undefined ? 1 : 0)\n + (metrics!.engagementRate !== undefined && metrics!.engagementRate! > 0 ? 3 : 0)\n + (metrics!.feedbackCompletionRate !== undefined && metrics!.feedbackCompletionRate! > 0 ? 3 : 0);\n const infoHeight = infoPairs.length + 2; // +2 for border\n const panelHeight = Math.max(infoHeight, metricsHeight + 2);\n\n sections.push(\n <HStack constraints={[fillConstraint(1), fillConstraint(1)]}>\n <Box border borderType=\"rounded\" fg={BRAND_COLORS.dimCyan} title=\" Session Info \">\n <KeyValue pairs={infoPairs} />\n </Box>\n <Box border borderType=\"rounded\" fg={BRAND_COLORS.dimCyan} title=\" Metrics \">\n <MetricsPanel\n engagementRate={metrics!.engagementRate}\n feedbackRate={metrics!.feedbackCompletionRate}\n participants={metrics!.totalParticipants}\n />\n </Box>\n </HStack>\n );\n sectionConstraints.push(lengthConstraint(panelHeight));\n } else {\n sections.push(\n <Box border borderType=\"rounded\" fg={BRAND_COLORS.dimCyan} title=\" Session Info \">\n <KeyValue pairs={infoPairs} />\n </Box>\n );\n sectionConstraints.push(lengthConstraint(infoPairs.length + 2));\n }\n\n // -- Sparkline: reaction timeline --\n const positiveData = timeline.map((b) => b.positive || 0);\n if (positiveData.some((v) => v > 0)) {\n sections.push(\n <Box border borderType=\"rounded\" fg={BRAND_COLORS.dimCyan} title=\" Reactions Over Time \">\n <Sparkline\n data={positiveData}\n fg={BRAND_COLORS.green}\n />\n </Box>\n );\n sectionConstraints.push(lengthConstraint(5));\n }\n\n // -- BarChart: reaction summary --\n const totalPositive = timeline.reduce((sum, b) => sum + (b.positive || 0), 0);\n const totalNegative = timeline.reduce((sum, b) => sum + (b.negative || 0), 0);\n if (totalPositive > 0 || totalNegative > 0) {\n const barData: BarGroup[] = [\n createBarGroup([createBar(totalPositive)], 'Positive'),\n createBarGroup([createBar(totalNegative)], 'Negative'),\n ];\n sections.push(\n <Box border borderType=\"rounded\" fg={BRAND_COLORS.dimCyan} title=\" Reaction Summary \">\n <BarChart\n data={barData}\n fg={BRAND_COLORS.cyan}\n />\n </Box>\n );\n const maxVal = Math.max(totalPositive, totalNegative, 1);\n sectionConstraints.push(lengthConstraint(Math.max(8, maxVal + 4)));\n }\n\n // -- AI Analysis --\n if (analysis && typeof analysis === 'object') {\n const summary = (analysis.summary as string) || (analysis.feedbackSummary as string) || '';\n if (summary) {\n sections.push(\n <Box border borderType=\"rounded\" fg={BRAND_COLORS.purple} title={` ${icon.sparkle} AI Analysis `}>\n <Text fg={BRAND_COLORS.white}>{summary}</Text>\n </Box>\n );\n const summaryLines = Math.ceil(summary.length / 70) + 2;\n sectionConstraints.push(lengthConstraint(summaryLines));\n }\n\n const insights = analysis.coachingInsights as string[] | undefined;\n if (insights && insights.length > 0) {\n const insightLines = insights.slice(0, 3).map((insight) =>\n ` ${icon.arrow} ${insight}`\n ).join('\\n');\n\n sections.push(\n <Box border borderType=\"rounded\" fg={BRAND_COLORS.dimCyan} title=\" Coaching Insights \">\n <Text fg={BRAND_COLORS.white}>{insightLines}</Text>\n </Box>\n );\n sectionConstraints.push(lengthConstraint(Math.min(insights.length, 3) + 2));\n }\n }\n\n // -- Questions --\n if (session.questions && session.questions.length > 0) {\n const questionLines = session.questions.map((q) =>\n ` ${icon.dot} [${q.type}] ${q.label}`\n ).join('\\n');\n\n sections.push(\n <Box border borderType=\"rounded\" fg={BRAND_COLORS.dimCyan} title=\" Rating Criteria \">\n <Text fg={BRAND_COLORS.white}>{questionLines}</Text>\n </Box>\n );\n sectionConstraints.push(lengthConstraint(session.questions.length + 2));\n }\n\n // -- Links --\n if (session.links && session.links.length > 0) {\n const linkLines = session.links.map((link) =>\n ` ${icon.dot} ${link.label}: ${link.url}`\n ).join('\\n');\n\n sections.push(\n <Box border borderType=\"rounded\" fg={BRAND_COLORS.dimCyan} title=\" Links \">\n <Text fg={BRAND_COLORS.white}>{linkLines}</Text>\n </Box>\n );\n sectionConstraints.push(lengthConstraint(session.links.length + 2));\n }\n\n // -- Join URL --\n if (session.pin) {\n sections.push(\n <Box border borderType=\"rounded\" fg={BRAND_COLORS.dimCyan} title=\" Join URL \">\n <Text bold fg={BRAND_COLORS.cyan}>{`https://app.audiencemeter.pro/s/${session.pin}`}</Text>\n </Box>\n );\n sectionConstraints.push(lengthConstraint(3));\n }\n\n return (\n <VStack constraints={sectionConstraints}>\n {sections}\n </VStack>\n );\n}\n","import { createTerminal, terminalResize, createListState } from 'terminui';\nimport type { Terminal, ListState } from 'terminui';\nimport { VStack, Box, List, Text, terminalDrawJsx } from 'terminui/jsx';\nimport type { JsxNode } from 'terminui/jsx-runtime';\nimport { createNodeBackend } from './node-backend.js';\nimport { setupKeyboardInput, enterFullScreen, exitFullScreen, type KeypressInfo } from './input.js';\nimport { createApiClient, createApiClientWithRefresh, getUserIdFromToken, getUserEmailFromToken, isTokenExpired } from './api-client.js';\nimport { Dashboard } from '../components/Dashboard.js';\nimport {\n SessionDetail,\n type SessionDetailSession,\n type SessionDetailMetrics,\n type TimelineBucket,\n} from '../components/SessionDetail.js';\nimport { ShortcutBar } from '../components/ShortcutBar.js';\nimport type { SessionRow } from '../components/SessionTable.js';\nimport { BRAND_COLORS, icon } from './theme.js';\nimport { fillConstraint, lengthConstraint, createStyle, Modifier } from 'terminui';\n\n// ── Types ────────────────────────────────────────────────────────────\n\ninterface SessionSummary {\n id?: string;\n name: string;\n pin: string;\n date?: string | Date;\n durationMinutes?: number;\n createdAt?: string | Date;\n [key: string]: unknown;\n}\n\ninterface SessionsResponse {\n data: SessionSummary[];\n total: number;\n page: number;\n take: number;\n}\n\ninterface Metrics {\n totalParticipants?: number;\n engagementRate?: number;\n feedbackCompletionRate?: number;\n [key: string]: unknown;\n}\n\ninterface AppState {\n selectedTab: number;\n sessions: SessionRow[];\n rawSessions: SessionSummary[];\n total: number;\n stats: {\n totalSessions: number;\n totalParticipants: number;\n avgEngagement: number;\n };\n selectedIndex: number;\n authEmail: string | null;\n authExpired: boolean;\n showingSession: string | null;\n running: boolean;\n loading: boolean;\n error: string | null;\n}\n\n// ── Helpers ──────────────────────────────────────────────────────────\n\nfunction getSessionStatus(session: SessionSummary): string {\n const sessionDate = session.date\n ? new Date(session.date as string)\n : session.createdAt\n ? new Date(session.createdAt as string)\n : null;\n\n if (!sessionDate) return 'unknown';\n\n const now = new Date();\n const durationMs = (session.durationMinutes || 60) * 60 * 1000;\n const endTime = new Date(sessionDate.getTime() + durationMs);\n\n if (now < sessionDate) return 'upcoming';\n if (now >= sessionDate && now <= endTime) return 'live';\n return 'ended';\n}\n\nfunction statusDisplay(status: string): string {\n switch (status) {\n case 'live': return `${icon.live} live`;\n case 'ended': return `${icon.ended} ended`;\n case 'upcoming': return `${icon.upcoming} soon`;\n default: return status;\n }\n}\n\nfunction toSessionRows(sessions: SessionSummary[]): SessionRow[] {\n return sessions.map((session) => {\n const date = session.date\n ? new Date(session.date as string).toLocaleDateString()\n : session.createdAt\n ? new Date(session.createdAt as string).toLocaleDateString()\n : '--';\n\n const duration = session.durationMinutes\n ? `${session.durationMinutes}min`\n : '--';\n\n const status = getSessionStatus(session);\n\n const raw = session as Record<string, unknown>;\n const count = (raw._count as Record<string, unknown> | undefined)?.attendees\n ?? raw.participantCount\n ?? '--';\n\n return {\n name: session.name || '--',\n pin: session.pin || '--',\n status: statusDisplay(status),\n date,\n duration,\n participants: String(count),\n };\n });\n}\n\n// ── Render helpers ───────────────────────────────────────────────────\n\nfunction renderDashboard(terminal: Terminal, state: AppState): void {\n terminalDrawJsx(terminal, (\n <Dashboard\n selectedTab={state.selectedTab}\n sessions={state.sessions}\n stats={state.stats}\n selectedIndex={state.selectedIndex}\n authEmail={state.authEmail}\n authExpired={state.authExpired}\n loading={state.loading}\n error={state.error}\n />\n ));\n}\n\nfunction renderSessionDetail(\n terminal: Terminal,\n session: SessionDetailSession,\n metrics: SessionDetailMetrics | null,\n timeline: readonly TimelineBucket[],\n analysis: Record<string, unknown> | null,\n status: string,\n): void {\n const detailShortcuts = [\n { key: 'Esc/q', label: 'back' },\n ];\n\n terminalDrawJsx(terminal, (\n <VStack constraints={[fillConstraint(1), lengthConstraint(1)]}>\n <SessionDetail\n session={session}\n metrics={metrics}\n timeline={timeline}\n analysis={analysis}\n status={status}\n />\n <ShortcutBar shortcuts={detailShortcuts} />\n </VStack>\n ));\n}\n\nfunction renderInteractiveList(\n terminal: Terminal,\n sessionRows: readonly SessionRow[],\n total: number,\n selectedIndex: number,\n): void {\n const listItems = sessionRows.map((s) =>\n `${icon.session} ${s.name.padEnd(30).slice(0, 30)} ${s.pin} ${s.status.padEnd(10).slice(0, 10)} ${s.date}`\n );\n\n const listState: ListState = createListState();\n listState.selected = selectedIndex;\n\n terminalDrawJsx(terminal, (\n <VStack constraints={[lengthConstraint(1), fillConstraint(1), lengthConstraint(1)]}>\n <Text bold fg={BRAND_COLORS.purple} align=\"center\">{`Sessions (${sessionRows.length} of ${total})`}</Text>\n <Box border borderType=\"rounded\" fg={BRAND_COLORS.dimCyan}>\n <List\n items={listItems}\n state={listState}\n fg={BRAND_COLORS.cyan}\n highlightStyle={createStyle({ fg: BRAND_COLORS.purple, addModifier: Modifier.BOLD })}\n />\n </Box>\n <Text fg={BRAND_COLORS.dimCyan}>{' j/k: navigate | Enter: view | q: quit'}</Text>\n </VStack>\n ));\n}\n\n// ── Session Detail Fetching ──────────────────────────────────────────\n\nasync function fetchSessionDetail(sessionId: string): Promise<{\n session: SessionDetailSession;\n metrics: SessionDetailMetrics | null;\n timeline: TimelineBucket[];\n analysis: Record<string, unknown> | null;\n status: string;\n}> {\n const client = createApiClient();\n const isUuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(sessionId);\n const path = !isUuid\n ? `/sessions/by-pin/${sessionId}`\n : `/sessions/${sessionId}`;\n\n const session = await client.get<SessionSummary>(path);\n\n let metrics: Metrics | null = null;\n let timeline: TimelineBucket[] = [];\n let analysis: Record<string, unknown> | null = null;\n\n if (session.id) {\n const results = await Promise.allSettled([\n client.get<Metrics>(`/sessions/${session.id}/metrics`),\n client.get<TimelineBucket[]>(`/sessions/${session.id}/sentiment-timeline`),\n client.get<Record<string, unknown>>(`/sessions/${session.id}/analysis`),\n ]);\n\n if (results[0]!.status === 'fulfilled') metrics = results[0]!.value;\n if (results[1]!.status === 'fulfilled') timeline = results[1]!.value || [];\n if (results[2]!.status === 'fulfilled') analysis = results[2]!.value;\n }\n\n const status = getSessionStatus(session);\n\n return {\n session: {\n id: session.id,\n name: session.name,\n pin: session.pin,\n date: session.date ? String(session.date) : undefined,\n durationMinutes: session.durationMinutes,\n createdAt: session.createdAt ? String(session.createdAt) : undefined,\n questions: (session as Record<string, unknown>).questions as SessionDetailSession['questions'],\n links: (session as Record<string, unknown>).links as SessionDetailSession['links'],\n },\n metrics: metrics ? {\n totalParticipants: metrics.totalParticipants,\n engagementRate: metrics.engagementRate,\n feedbackCompletionRate: metrics.feedbackCompletionRate,\n } : null,\n timeline,\n analysis,\n status,\n };\n}\n\n// ── Dashboard ────────────────────────────────────────────────────────\n\nexport async function startDashboard(): Promise<void> {\n // Check authentication\n let userId: string;\n try {\n userId = getUserIdFromToken();\n } catch {\n console.error('Not authenticated. Run: audiencemeter login');\n process.exit(1);\n return; // TypeScript needs this after process.exit\n }\n\n let authEmail: string | null = null;\n try {\n authEmail = getUserEmailFromToken();\n } catch {\n authEmail = null;\n }\n\n // Enter full screen\n enterFullScreen();\n\n const backend = createNodeBackend();\n const terminal = createTerminal(backend);\n\n // Check if token is expired before showing status\n let authExpired = false;\n try {\n const token = (await import('./config.js')).getAuthToken();\n authExpired = isTokenExpired(token);\n } catch {\n // no token at all\n }\n\n // Initialize state\n const state: AppState = {\n selectedTab: 0,\n sessions: [],\n rawSessions: [],\n total: 0,\n stats: { totalSessions: 0, totalParticipants: 0, avgEngagement: 0 },\n selectedIndex: 0,\n authEmail: authExpired ? null : authEmail,\n authExpired,\n showingSession: null,\n running: true,\n loading: true,\n error: null,\n };\n\n // Initial render with empty state (non-blocking)\n renderDashboard(terminal, state);\n\n // Session detail state\n let detailData: Awaited<ReturnType<typeof fetchSessionDetail>> | null = null;\n\n // Re-render helper\n const rerender = () => {\n if (state.showingSession && detailData) {\n renderSessionDetail(\n terminal,\n detailData.session,\n detailData.metrics,\n detailData.timeline,\n detailData.analysis,\n detailData.status,\n );\n } else {\n renderDashboard(terminal, state);\n }\n };\n\n // Setup keyboard input\n const cleanupInput = setupKeyboardInput(async (key: KeypressInfo) => {\n if (!state.running) return;\n\n // Ctrl+C always exits\n if (key.ctrl && key.name === 'c') {\n state.running = false;\n cleanupInput();\n exitFullScreen();\n process.exit(0);\n return;\n }\n\n // Showing session detail -- Esc/q goes back\n if (state.showingSession) {\n if (key.name === 'escape' || key.name === 'q') {\n state.showingSession = null;\n detailData = null;\n rerender();\n }\n return;\n }\n\n // Tab switching\n if (key.name === 'tab') {\n state.selectedTab = (state.selectedTab + 1) % 4;\n state.selectedIndex = 0;\n rerender();\n return;\n }\n\n // Number keys for tab selection\n if (['1', '2', '3', '4'].includes(key.name)) {\n state.selectedTab = parseInt(key.name, 10) - 1;\n state.selectedIndex = 0;\n rerender();\n return;\n }\n\n // Navigation (j/k/up/down)\n const itemCount = state.selectedTab === 0\n ? Math.min(state.sessions.length, 5)\n : state.sessions.length;\n\n if (itemCount > 0) {\n if (key.name === 'j' || key.name === 'down') {\n state.selectedIndex = (state.selectedIndex + 1) % itemCount;\n rerender();\n return;\n }\n\n if (key.name === 'k' || key.name === 'up') {\n state.selectedIndex = (state.selectedIndex - 1 + itemCount) % itemCount;\n rerender();\n return;\n }\n }\n\n // Enter key -- action depends on tab\n if (key.name === 'return') {\n if (state.selectedTab === 0 || state.selectedTab === 1) {\n // Dashboard or Sessions tab -- drill into session detail\n const rawSession = state.rawSessions[state.selectedIndex];\n if (rawSession) {\n const sessionId = rawSession.id || rawSession.pin;\n if (sessionId) {\n state.showingSession = sessionId;\n try {\n detailData = await fetchSessionDetail(sessionId);\n } catch {\n detailData = {\n session: {\n name: rawSession.name,\n pin: rawSession.pin,\n date: rawSession.date ? String(rawSession.date) : undefined,\n durationMinutes: rawSession.durationMinutes,\n createdAt: rawSession.createdAt ? String(rawSession.createdAt) : undefined,\n },\n metrics: null,\n timeline: [],\n analysis: null,\n status: getSessionStatus(rawSession),\n };\n }\n rerender();\n }\n }\n return;\n }\n\n if (state.selectedTab === 2) {\n // Create tab -- exit full screen, run create flow, then exit\n state.running = false;\n cleanupInput();\n exitFullScreen();\n\n try {\n const { createCommand } = await import('../commands/create.js');\n await createCommand.parseAsync(['node', 'audiencemeter'], { from: 'node' });\n } catch {\n // Command may throw on cancel\n }\n return;\n }\n\n if (state.selectedTab === 3) {\n // Auth tab -- exit full screen, run auth flow, then exit\n state.running = false;\n cleanupInput();\n exitFullScreen();\n\n try {\n const { authCommand } = await import('../commands/auth.js');\n const action = (state.authEmail && !state.authExpired) ? 'whoami' : 'login';\n await authCommand.parseAsync(['node', 'audiencemeter', action], { from: 'node' });\n } catch {\n // Command may throw on cancel\n }\n return;\n }\n }\n\n // Quit\n if (key.name === 'q' || key.name === 'escape') {\n state.running = false;\n cleanupInput();\n exitFullScreen();\n return;\n }\n });\n\n // Listen for terminal resize\n const onResize = () => {\n terminalResize(terminal, backend.size());\n rerender();\n };\n process.stdout.on('resize', onResize);\n\n // Fetch sessions asynchronously (non-blocking, with token auto-refresh)\n (async () => {\n try {\n const client = await createApiClientWithRefresh();\n\n // If token was refreshed, update auth display\n if (state.authExpired) {\n state.authExpired = false;\n state.authEmail = getUserEmailFromToken();\n state.error = null;\n }\n\n const queryParams = new URLSearchParams();\n queryParams.set('take', '50');\n queryParams.set('sort', 'createdAt');\n queryParams.set('order', 'desc');\n\n const response = await client.get<SessionsResponse | SessionSummary[]>(\n `/users/${userId}/sessions?${queryParams.toString()}`\n );\n\n const sessions: SessionSummary[] = Array.isArray(response)\n ? response\n : response?.data || [];\n const total = Array.isArray(response)\n ? sessions.length\n : response?.total || sessions.length;\n\n state.rawSessions = sessions;\n state.sessions = toSessionRows(sessions);\n state.total = total;\n\n // Calculate stats\n let totalParticipants = 0;\n for (const s of sessions) {\n const raw = s as Record<string, unknown>;\n const count = (raw._count as Record<string, unknown> | undefined)?.attendees\n ?? raw.participantCount\n ?? 0;\n totalParticipants += Number(count) || 0;\n }\n\n state.stats = {\n totalSessions: total,\n totalParticipants,\n avgEngagement: 0,\n };\n\n state.loading = false;\n rerender();\n } catch (err) {\n state.loading = false;\n const msg = err instanceof Error ? err.message : 'Failed to load sessions';\n if (msg.includes('expired') || msg.includes('Not authenticated')) {\n state.authExpired = true;\n state.authEmail = null;\n state.error = 'Session expired. Go to Auth tab and press Enter to re-login.';\n } else {\n state.error = msg;\n }\n rerender();\n }\n })();\n\n // Wait until the user quits\n return new Promise<void>((resolve) => {\n const check = setInterval(() => {\n if (!state.running) {\n clearInterval(check);\n process.stdout.removeListener('resize', onResize);\n resolve();\n }\n }, 100);\n });\n}\n\n// ── Interactive List ─────────────────────────────────────────────────\n\nexport async function startInteractiveList(\n sessionRows: SessionRow[],\n rawSessions: SessionSummary[],\n total: number,\n): Promise<void> {\n enterFullScreen();\n\n const backend = createNodeBackend();\n const terminal = createTerminal(backend);\n\n let selectedIndex = 0;\n let running = true;\n let showingDetail = false;\n let detailData: Awaited<ReturnType<typeof fetchSessionDetail>> | null = null;\n\n const rerender = () => {\n if (showingDetail && detailData) {\n renderSessionDetail(\n terminal,\n detailData.session,\n detailData.metrics,\n detailData.timeline,\n detailData.analysis,\n detailData.status,\n );\n } else {\n renderInteractiveList(terminal, sessionRows, total, selectedIndex);\n }\n };\n\n rerender();\n\n const cleanupInput = setupKeyboardInput(async (key: KeypressInfo) => {\n if (!running) return;\n\n if (key.ctrl && key.name === 'c') {\n running = false;\n cleanupInput();\n exitFullScreen();\n process.exit(0);\n return;\n }\n\n // Showing detail -- Esc/q goes back to list\n if (showingDetail) {\n if (key.name === 'escape' || key.name === 'q') {\n showingDetail = false;\n detailData = null;\n rerender();\n }\n return;\n }\n\n // Navigation\n if (sessionRows.length > 0) {\n if (key.name === 'j' || key.name === 'down') {\n selectedIndex = (selectedIndex + 1) % sessionRows.length;\n rerender();\n return;\n }\n\n if (key.name === 'k' || key.name === 'up') {\n selectedIndex = (selectedIndex - 1 + sessionRows.length) % sessionRows.length;\n rerender();\n return;\n }\n }\n\n // Enter -- drill into session detail\n if (key.name === 'return' && sessionRows.length > 0) {\n const rawSession = rawSessions[selectedIndex];\n if (rawSession) {\n const sessionId = rawSession.id || rawSession.pin;\n if (sessionId) {\n showingDetail = true;\n try {\n detailData = await fetchSessionDetail(sessionId);\n } catch {\n detailData = {\n session: {\n name: rawSession.name,\n pin: rawSession.pin,\n date: rawSession.date ? String(rawSession.date) : undefined,\n durationMinutes: rawSession.durationMinutes,\n createdAt: rawSession.createdAt ? String(rawSession.createdAt) : undefined,\n },\n metrics: null,\n timeline: [],\n analysis: null,\n status: getSessionStatus(rawSession),\n };\n }\n rerender();\n }\n }\n return;\n }\n\n // Quit\n if (key.name === 'q' || key.name === 'escape') {\n running = false;\n cleanupInput();\n exitFullScreen();\n return;\n }\n });\n\n // Listen for terminal resize\n const onResize = () => {\n terminalResize(terminal, backend.size());\n rerender();\n };\n process.stdout.on('resize', onResize);\n\n return new Promise<void>((resolve) => {\n const check = setInterval(() => {\n if (!running) {\n clearInterval(check);\n process.stdout.removeListener('resize', onResize);\n resolve();\n }\n }, 100);\n });\n}\n","import { Command } from 'commander';\nimport { authCommand, loginCommand, logoutCommand } from './commands/auth.js';\nimport { createCommand } from './commands/create.js';\nimport { listCommand } from './commands/list.js';\nimport { showCommand } from './commands/show.js';\nimport { deleteCommand } from './commands/delete.js';\nimport { BRAND } from './lib/theme.js';\n\nconst program = new Command();\n\nprogram\n .name('audiencemeter')\n .description(\n `${BRAND.name} CLI — ${BRAND.tagline}`\n )\n .version(BRAND.version, '-v, --version');\n\n// Register commands\nprogram.addCommand(loginCommand);\nprogram.addCommand(logoutCommand);\nprogram.addCommand(authCommand);\nprogram.addCommand(createCommand);\nprogram.addCommand(listCommand);\nprogram.addCommand(showCommand);\nprogram.addCommand(deleteCommand);\n\n// Detect if args were passed\nconst hasArgs = process.argv.length > 2;\n\nif (hasArgs) {\n // Subcommands: parse with Commander (static print-and-exit)\n program.parse(process.argv);\n} else if (process.stdout.isTTY) {\n // No args + TTY: launch persistent full-screen TUI dashboard\n import('./lib/app.js')\n .then(({ startDashboard }) => startDashboard())\n .catch((err) => {\n // Ensure terminal is restored on error\n import('./lib/input.js').then(({ exitFullScreen }) => {\n exitFullScreen();\n }).catch(() => { /* ignore */ });\n console.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n });\n} else {\n // No args + non-TTY (piped): show help text\n program.help();\n}\n","import { Command } from 'commander';\nimport * as p from '@clack/prompts';\nimport { createApiClient, getUserIdFromToken } from '../lib/api-client.js';\nimport { icon } from '../lib/theme.js';\nimport { renderJsxToString, getTermWidth } from '../lib/render.js';\nimport { SessionTable, type SessionRow } from '../components/SessionTable.js';\n\ninterface SessionSummary {\n id?: string;\n name: string;\n pin: string;\n date?: string | Date;\n durationMinutes?: number;\n createdAt?: string | Date;\n [key: string]: unknown;\n}\n\ninterface SessionsResponse {\n data: SessionSummary[];\n total: number;\n page: number;\n take: number;\n}\n\nfunction getSessionStatus(session: SessionSummary): string {\n const sessionDate = session.date\n ? new Date(session.date)\n : session.createdAt\n ? new Date(session.createdAt)\n : null;\n\n if (!sessionDate) return 'unknown';\n\n const now = new Date();\n const durationMs = (session.durationMinutes || 60) * 60 * 1000;\n const endTime = new Date(sessionDate.getTime() + durationMs);\n\n if (now < sessionDate) return 'upcoming';\n if (now >= sessionDate && now <= endTime) return 'live';\n return 'ended';\n}\n\nexport const listCommand = new Command('list')\n .alias('ls')\n .description('List your feedback sessions')\n .option('--project <name>', 'Filter by project name')\n .option('--limit <n>', 'Max sessions to display', parseInt, 20)\n .option('--json', 'Output as JSON')\n .action(async (options) => {\n const s = p.spinner();\n s.start('Fetching sessions...');\n\n try {\n const client = createApiClient();\n const userId = getUserIdFromToken();\n\n const queryParams = new URLSearchParams();\n queryParams.set('take', String(options.limit));\n queryParams.set('sort', 'createdAt');\n queryParams.set('order', 'desc');\n\n const response = await client.get<SessionsResponse | SessionSummary[]>(\n `/users/${userId}/sessions?${queryParams.toString()}`\n );\n\n s.stop();\n\n const sessions: SessionSummary[] = Array.isArray(response)\n ? response\n : response?.data || [];\n const total = Array.isArray(response)\n ? sessions.length\n : response?.total || sessions.length;\n\n if (sessions.length === 0) {\n p.log.warn('No sessions found.');\n p.log.info(\n 'Create one: audiencemeter create --template talk --project \"My Talk\"'\n );\n return;\n }\n\n if (options.json) {\n console.log(JSON.stringify(sessions, null, 2));\n return;\n }\n\n // Build rich table\n const statusDisplay = (status: string) => {\n switch (status) {\n case 'live':\n return `${icon.live} live`;\n case 'ended':\n return `${icon.ended} ended`;\n case 'upcoming':\n return `${icon.upcoming} soon`;\n default:\n return status;\n }\n };\n\n const rows: SessionRow[] = sessions.map((session) => {\n const date = session.date\n ? new Date(session.date).toLocaleDateString()\n : session.createdAt\n ? new Date(session.createdAt).toLocaleDateString()\n : '--';\n\n const duration = session.durationMinutes\n ? `${session.durationMinutes}min`\n : '--';\n\n const status = getSessionStatus(session);\n\n const raw = session as Record<string, unknown>;\n const count =\n (raw._count as Record<string, unknown> | undefined)?.attendees ??\n raw.participantCount ??\n '--';\n const participants = String(count);\n\n return {\n name: session.name || '--',\n pin: session.pin || '--',\n status: statusDisplay(status),\n date,\n duration,\n participants,\n };\n });\n\n // TTY mode: enter interactive full-screen list with keyboard navigation\n if (process.stdout.isTTY && !options.json) {\n const { startInteractiveList } = await import('../lib/app.js');\n await startInteractiveList(rows, sessions, total);\n return;\n }\n\n // Non-TTY / static output: render table and print\n const tableHeight = rows.length + 4; // header + border + rows\n const output = renderJsxToString(\n getTermWidth(),\n tableHeight,\n SessionTable({ sessions: rows, total })\n );\n console.log(output);\n } catch (error) {\n s.stop(\n `${icon.cross} Failed to list sessions: ${\n error instanceof Error ? error.message : 'Unknown error'\n }`\n );\n if (\n error instanceof Error &&\n error.message.includes('Not authenticated')\n ) {\n p.log.warn('Run: audiencemeter login');\n }\n process.exit(1);\n }\n });\n","import { Table, Box } from 'terminui/jsx';\nimport { fillConstraint, lengthConstraint } from 'terminui';\nimport { BRAND_COLORS } from '../lib/theme.js';\n\nexport interface SessionRow {\n readonly name: string;\n readonly pin: string;\n readonly status: string;\n readonly date: string;\n readonly duration: string;\n readonly participants: string;\n}\n\nexport interface SessionTableProps {\n readonly sessions: readonly SessionRow[];\n readonly total: number;\n}\n\nexport function SessionTable({ sessions, total }: SessionTableProps) {\n const widths = [\n fillConstraint(1), // Name -- takes remaining space\n lengthConstraint(7), // PIN\n lengthConstraint(10), // Status\n lengthConstraint(12), // Date\n lengthConstraint(10), // Duration\n lengthConstraint(6), // Ppl\n ];\n\n const header = ['Name', 'PIN', 'Status', 'Date', 'Duration', 'Ppl'];\n\n const rows = sessions.map((s) => [\n s.name,\n s.pin,\n s.status,\n s.date,\n s.duration,\n s.participants,\n ]);\n\n return (\n <Box\n border\n borderType=\"rounded\"\n fg={BRAND_COLORS.dimCyan}\n title={` Sessions (${sessions.length} of ${total}) `}\n >\n <Table\n widths={widths}\n header={header}\n rows={rows}\n fg={BRAND_COLORS.cyan}\n columnSpacing={1}\n />\n </Box>\n );\n}\n","import { Command } from 'commander';\nimport * as p from '@clack/prompts';\nimport { createApiClient, getUserIdFromToken } from '../lib/api-client.js';\nimport { icon } from '../lib/theme.js';\nimport { renderJsxToString, getTermWidth } from '../lib/render.js';\nimport {\n SessionDetail,\n type SessionDetailSession,\n type SessionDetailMetrics,\n type TimelineBucket,\n} from '../components/SessionDetail.js';\n\ninterface Session {\n id?: string;\n userId?: string;\n name: string;\n pin: string;\n date?: string;\n durationMinutes?: number;\n createdAt?: string;\n questions?: Array<{ id: string; type: string; label: string }>;\n links?: Array<{ id: string; label: string; url: string }>;\n [key: string]: unknown;\n}\n\ninterface Metrics {\n totalParticipants?: number;\n engagementRate?: number;\n feedbackCompletionRate?: number;\n [key: string]: unknown;\n}\n\nfunction getSessionStatus(session: Session): string {\n const sessionDate = session.date\n ? new Date(session.date)\n : session.createdAt\n ? new Date(session.createdAt)\n : null;\n\n if (!sessionDate) return 'unknown';\n\n const now = new Date();\n const durationMs = (session.durationMinutes || 60) * 60 * 1000;\n const endTime = new Date(sessionDate.getTime() + durationMs);\n\n if (now < sessionDate) return 'upcoming';\n if (now >= sessionDate && now <= endTime) return 'live';\n return 'ended';\n}\n\nexport const showCommand = new Command('show')\n .description('Show session details with rich metrics')\n .argument('<session-id>', 'Session ID (UUID) or PIN (5 characters)')\n .option('--json', 'Output as JSON')\n .action(async (sessionId: string, options) => {\n const s = p.spinner();\n s.start('Fetching session...');\n\n try {\n const client = createApiClient();\n\n // Determine if input looks like a UUID or a PIN\n const isUuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(sessionId);\n const path = !isUuid\n ? `/sessions/by-pin/${sessionId}`\n : `/sessions/${sessionId}`;\n\n const session = await client.get<Session>(path);\n\n // Fetch metrics, timeline, and AI analysis in parallel (owner only)\n let metrics: Metrics | null = null;\n let timeline: TimelineBucket[] = [];\n let analysis: Record<string, unknown> | null = null;\n\n let isOwner = false;\n try {\n isOwner = !!session.userId && session.userId === getUserIdFromToken();\n } catch {\n // Not authenticated — skip owner-only data\n }\n\n if (session.id && isOwner) {\n s.message('Fetching metrics...');\n\n const results = await Promise.allSettled([\n client.get<Metrics>(`/sessions/${session.id}/metrics`),\n client.get<TimelineBucket[]>(\n `/sessions/${session.id}/sentiment-timeline`\n ),\n client.get<Record<string, unknown>>(\n `/sessions/${session.id}/analysis`\n ),\n ]);\n\n if (results[0]!.status === 'fulfilled') metrics = results[0]!.value;\n if (results[1]!.status === 'fulfilled')\n timeline = results[1]!.value || [];\n if (results[2]!.status === 'fulfilled') analysis = results[2]!.value;\n }\n\n s.stop();\n\n // -- JSON output ------------------------------------------------\n if (options.json) {\n const output = {\n ...session,\n ...(metrics && { metrics }),\n ...(timeline.length && { timeline }),\n ...(analysis && { analysis }),\n };\n console.log(JSON.stringify(output, null, 2));\n return;\n }\n\n // -- Rich JSX output ------------------------------------------------\n const status = getSessionStatus(session);\n\n // Calculate height based on content\n let height = 3; // header + spacing\n const infoPairCount = 3 + (session.id ? 1 : 0);\n const hasMetrics = metrics && (\n (metrics.engagementRate !== undefined && metrics.engagementRate > 0) ||\n (metrics.feedbackCompletionRate !== undefined && metrics.feedbackCompletionRate > 0) ||\n (metrics.totalParticipants !== undefined)\n );\n\n if (hasMetrics) {\n const metricsH = 1\n + (metrics!.totalParticipants !== undefined ? 1 : 0)\n + (metrics!.engagementRate !== undefined && metrics!.engagementRate! > 0 ? 3 : 0)\n + (metrics!.feedbackCompletionRate !== undefined && metrics!.feedbackCompletionRate! > 0 ? 3 : 0);\n height += Math.max(infoPairCount + 2, metricsH + 2);\n } else {\n height += infoPairCount + 2;\n }\n\n // Timeline sparkline\n const positiveData = timeline.map((b) => b.positive || 0);\n if (positiveData.some((v) => v > 0)) {\n height += 5;\n }\n\n // Bar chart\n const totalPositive = timeline.reduce((sum, b) => sum + (b.positive || 0), 0);\n const totalNegative = timeline.reduce((sum, b) => sum + (b.negative || 0), 0);\n if (totalPositive > 0 || totalNegative > 0) {\n const maxVal = Math.max(totalPositive, totalNegative, 1);\n height += Math.max(8, maxVal + 4);\n }\n\n // AI Analysis\n if (analysis && typeof analysis === 'object') {\n const summary = (analysis.summary as string) || (analysis.feedbackSummary as string) || '';\n if (summary) {\n height += Math.ceil(summary.length / 70) + 2;\n }\n const insights = analysis.coachingInsights as string[] | undefined;\n if (insights && insights.length > 0) {\n height += Math.min(insights.length, 3) + 2;\n }\n }\n\n // Questions\n if (session.questions && session.questions.length > 0) {\n height += session.questions.length + 2;\n }\n\n // Links\n if (session.links && session.links.length > 0) {\n height += session.links.length + 2;\n }\n\n // Join URL\n if (session.pin) {\n height += 3;\n }\n\n const sessionData: SessionDetailSession = {\n id: session.id,\n name: session.name,\n pin: session.pin,\n date: session.date,\n durationMinutes: session.durationMinutes,\n createdAt: session.createdAt,\n questions: session.questions,\n links: session.links,\n };\n\n const metricsData: SessionDetailMetrics | null = metrics\n ? {\n totalParticipants: metrics.totalParticipants,\n engagementRate: metrics.engagementRate,\n feedbackCompletionRate: metrics.feedbackCompletionRate,\n }\n : null;\n\n console.log();\n const output = renderJsxToString(\n getTermWidth(),\n height,\n SessionDetail({\n session: sessionData,\n metrics: metricsData,\n timeline,\n analysis,\n status,\n })\n );\n console.log(output);\n } catch (error) {\n s.stop(\n `${icon.cross} Failed to fetch session: ${error instanceof Error ? error.message : 'Unknown error'}`\n );\n if (\n error instanceof Error &&\n error.message.includes('Not authenticated')\n ) {\n p.log.warn('Run: audiencemeter login');\n }\n process.exit(1);\n }\n });\n","import { Command } from 'commander';\nimport * as p from '@clack/prompts';\nimport { createApiClient } from '../lib/api-client.js';\nimport { icon } from '../lib/theme.js';\n\nexport const deleteCommand = new Command('delete')\n .alias('rm')\n .description('Delete a session')\n .argument('<session-id>', 'Session ID (UUID)')\n .option('--force', 'Skip confirmation prompt')\n .action(async (sessionId: string, options) => {\n try {\n const client = createApiClient();\n\n // Fetch session details to show name in confirmation\n let sessionName = sessionId;\n try {\n const session = await client.get<Record<string, unknown>>(\n `/sessions/${sessionId}`\n );\n if (session.name) {\n sessionName = session.name as string;\n }\n } catch {\n // If we can't fetch, proceed with the ID\n }\n\n // Confirm deletion unless --force\n if (!options.force) {\n const confirmed = await p.confirm({\n message: `Delete session \"${sessionName}\"? This cannot be undone.`,\n });\n\n if (p.isCancel(confirmed) || !confirmed) {\n p.log.info('Cancelled.');\n return;\n }\n }\n\n const s = p.spinner();\n s.start('Deleting session...');\n\n await client.delete(`/sessions/${sessionId}`);\n\n s.stop(`${icon.check} Session \"${sessionName}\" deleted.`);\n } catch (error) {\n p.log.error(\n `Failed to delete session: ${error instanceof Error ? error.message : 'Unknown error'}`\n );\n if (\n error instanceof Error &&\n error.message.includes('Not authenticated')\n ) {\n p.log.warn('Run: audiencemeter login');\n }\n process.exit(1);\n }\n });\n"],"mappings":"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","names":["getAuthToken","SUPABASE_URL","text","Command","p","Text","jsx","jsx","Text","jsx","text","VStack","HStack","Box","Text","fillConstraint","lengthConstraint","createStyle","Modifier","jsx","jsxs","VStack","Gauge","Text","lengthConstraint","jsx","VStack","HStack","Box","Text","fillConstraint","lengthConstraint","jsx","jsxs","createTerminal","createListState","VStack","Box","List","Text","terminalDrawJsx","fillConstraint","lengthConstraint","createStyle","Modifier","jsx","jsxs","createCommand","authCommand","Command","Command","p","fillConstraint","lengthConstraint","jsx","getSessionStatus","Command","statusDisplay","startInteractiveList","Command","p","getSessionStatus","output","Command","p","Command","startDashboard","exitFullScreen"]}
1
+ {"version":3,"sources":["../src/lib/config.ts","../src/lib/theme.ts","../src/lib/render.ts","../src/components/KeyValue.tsx","../src/commands/auth.ts","../src/lib/api-client.ts","../src/lib/templates.ts","../src/commands/create.ts","../src/lib/node-backend.ts","../src/lib/input.ts","../src/components/Header.tsx","../src/components/TabBar.tsx","../src/components/ShortcutBar.tsx","../src/components/Dashboard.tsx","../src/components/MetricsPanel.tsx","../src/components/SessionDetail.tsx","../src/lib/app.tsx","../src/index.ts","../src/commands/list.ts","../src/components/SessionTable.tsx","../src/commands/show.ts","../src/commands/delete.ts"],"sourcesContent":["import Conf from 'conf';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nconst config = new Conf({\n projectName: 'audiencemeter',\n projectSuffix: '',\n schema: {\n apiUrl: {\n type: 'string' as const,\n default: 'https://api.audiencemeter.pro/v1',\n },\n authToken: {\n type: 'string' as const,\n default: '',\n },\n refreshToken: {\n type: 'string' as const,\n default: '',\n },\n },\n});\n\n// One-time migration from old config path (audiencemeter-nodejs → audiencemeter)\n(function migrateOldConfig() {\n const newPath = config.path;\n const oldPath = path.join(path.dirname(path.dirname(newPath)), 'audiencemeter-nodejs', 'config.json');\n\n try {\n if (!fs.existsSync(oldPath)) return;\n // Only migrate if new config has no auth token (fresh install or first run after update)\n if (config.get('authToken')) return;\n\n const oldData = JSON.parse(fs.readFileSync(oldPath, 'utf-8'));\n if (oldData.authToken) {\n config.set('authToken', oldData.authToken);\n }\n if (oldData.refreshToken) {\n config.set('refreshToken', oldData.refreshToken);\n }\n if (oldData.apiUrl && oldData.apiUrl !== 'https://api.audiencemeter.pro/v1') {\n config.set('apiUrl', oldData.apiUrl);\n }\n\n // Remove old config directory\n fs.rmSync(path.dirname(oldPath), { recursive: true, force: true });\n } catch {\n // Migration is best-effort — don't break startup\n }\n})();\n\nexport function getConfig(): typeof config {\n return config;\n}\n\nexport function getAuthToken(): string {\n const token = config.get('authToken') as string;\n if (!token) {\n throw new Error('Not authenticated. Run: audiencemeter login');\n }\n return token;\n}\n\nexport function setAuthToken(token: string): void {\n config.set('authToken', token);\n}\n\nexport function clearAuthToken(): void {\n config.set('authToken', '');\n config.set('refreshToken', '');\n}\n\nexport function getRefreshToken(): string {\n return config.get('refreshToken') as string;\n}\n\nexport function setRefreshToken(token: string): void {\n config.set('refreshToken', token);\n}\n\nexport function getApiUrl(): string {\n return config.get('apiUrl') as string;\n}\n\nexport function setApiUrl(url: string): void {\n config.set('apiUrl', url);\n}\n","import { rgbColor, type Color } from 'terminui';\n\n// Brand colors as terminui Color objects (no ANSI escape strings)\nexport const BRAND_COLORS: Record<string, Color> = {\n purple: rgbColor(175, 95, 255), // Brand purple\n cyan: rgbColor(80, 220, 220), // Info/borders\n green: rgbColor(80, 220, 120), // Success/gauges\n yellow: rgbColor(255, 200, 60), // PINs\n dimCyan: rgbColor(60, 160, 170), // Borders, labels\n red: rgbColor(255, 100, 100), // Errors\n dim: rgbColor(128, 128, 128), // Dimmed text\n white: rgbColor(230, 230, 230), // Primary text\n};\n\nexport const icon = {\n session: '\\u25cf', // ●\n live: '\\u25cf', // ●\n ended: '\\u25cb', // ○\n upcoming: '\\u25d4', // ◔\n check: '\\u2714', // ✔\n cross: '\\u2718', // ✘\n arrow: '\\u276f', // ❯\n dot: '\\u00b7', // ·\n bar: '\\u2503', // ┃\n dash: '\\u2500', // ─\n star: '\\u2605', // ★\n sparkle: '\\u2728', // ✨\n};\n\nexport const BRAND = {\n name: 'AudienceMeter',\n tagline: 'Speaker feedback, beautifully managed',\n version: '0.1.1',\n};\n","import {\n createTestBackendState,\n createTestBackend,\n createTerminal,\n testBackendCellAt,\n type Cell,\n} from 'terminui';\nimport { terminalDrawJsx } from 'terminui/jsx';\nimport type { JsxNode } from 'terminui/jsx-runtime';\n\n// ── ANSI Color Conversion (shared with node-backend.ts) ──────────────\n\ntype CellColor = { type: string; r?: number; g?: number; b?: number; index?: number };\n\nconst NAMED_FG: Record<string, string> = {\n black: '30', red: '31', green: '32', yellow: '33', blue: '34',\n magenta: '35', cyan: '36', gray: '37', white: '97',\n 'dark-gray': '90', 'light-red': '91', 'light-green': '92',\n 'light-yellow': '93', 'light-blue': '94', 'light-magenta': '95', 'light-cyan': '96',\n};\n\nconst NAMED_BG: Record<string, string> = {\n black: '40', red: '41', green: '42', yellow: '43', blue: '44',\n magenta: '45', cyan: '46', gray: '47', white: '107',\n 'dark-gray': '100', 'light-red': '101', 'light-green': '102',\n 'light-yellow': '103', 'light-blue': '104', 'light-magenta': '105', 'light-cyan': '106',\n};\n\nconst RESET = '\\x1b[0m';\n\nexport function fgAnsi(c: CellColor | undefined): string {\n if (!c || c.type === 'reset') return '';\n if (c.type === 'rgb') return `\\x1b[38;2;${c.r};${c.g};${c.b}m`;\n if (c.type === 'indexed') return `\\x1b[38;5;${c.index}m`;\n return NAMED_FG[c.type] ? `\\x1b[${NAMED_FG[c.type]}m` : '';\n}\n\nexport function bgAnsi(c: CellColor | undefined): string {\n if (!c || c.type === 'reset') return '';\n if (c.type === 'rgb') return `\\x1b[48;2;${c.r};${c.g};${c.b}m`;\n if (c.type === 'indexed') return `\\x1b[48;5;${c.index}m`;\n return NAMED_BG[c.type] ? `\\x1b[${NAMED_BG[c.type]}m` : '';\n}\n\nexport function modAnsi(mod: number | undefined): string {\n if (!mod) return '';\n let s = '';\n if (mod & 1) s += '\\x1b[1m'; // Bold\n if (mod & 2) s += '\\x1b[2m'; // Dim\n if (mod & 4) s += '\\x1b[3m'; // Italic\n if (mod & 8) s += '\\x1b[4m'; // Underline\n if (mod & 64) s += '\\x1b[7m'; // Reversed\n return s;\n}\n\n/**\n * Convert a terminui Cell to an ANSI escape string (style + symbol).\n */\nexport function cellToAnsi(cell: Cell): string {\n const fg = fgAnsi(cell.fg as CellColor);\n const bg = bgAnsi(cell.bg as CellColor);\n const mod = modAnsi(cell.modifier);\n const style = fg + bg + mod;\n if (style) {\n return style + cell.symbol + RESET;\n }\n return cell.symbol;\n}\n\n// ── Render JSX to String (static commands) ───────────────────────────\n\n/**\n * Renders a JSX node tree to a styled ANSI string using the test backend.\n * Used for print-and-exit commands (list, show, create, delete, auth).\n */\nexport function renderJsxToString(width: number, height: number, node: JsxNode): string {\n const state = createTestBackendState(width, height);\n const terminal = createTerminal(createTestBackend(state));\n terminalDrawJsx(terminal, node);\n\n // Reconstruct ANSI-styled output from the cell grid\n const lines: string[] = [];\n for (let y = 0; y < height; y++) {\n let line = '';\n let hasStyle = false;\n for (let x = 0; x < width; x++) {\n const cell = testBackendCellAt(state, x, y) as {\n symbol: string; fg?: CellColor; bg?: CellColor; modifier?: number;\n } | undefined;\n if (!cell) {\n if (hasStyle) { line += RESET; hasStyle = false; }\n line += ' ';\n continue;\n }\n const style = fgAnsi(cell.fg) + bgAnsi(cell.bg) + modAnsi(cell.modifier);\n if (style) {\n if (hasStyle) line += RESET;\n line += style + cell.symbol;\n hasStyle = true;\n } else {\n if (hasStyle) { line += RESET; hasStyle = false; }\n line += cell.symbol;\n }\n }\n if (hasStyle) line += RESET;\n lines.push(line.trimEnd());\n }\n\n // Trim trailing empty lines\n while (lines.length > 0 && stripAnsi(lines[lines.length - 1]!).trim() === '') {\n lines.pop();\n }\n\n return lines.join('\\n');\n}\n\n// ── Utilities ────────────────────────────────────────────────────────\n\n/**\n * Returns the usable terminal width, capped at 120 columns.\n */\nexport function getTermWidth(): number {\n return Math.min(process.stdout.columns || 80, 120);\n}\n\n/**\n * Strips all ANSI escape sequences from a string.\n */\nexport function stripAnsi(s: string): string {\n return s.replace(/\\x1b\\[[0-9;]*m/g, '');\n}\n","import { VStack, HStack, Text } from 'terminui/jsx';\nimport { lengthConstraint, fillConstraint } from 'terminui';\nimport { BRAND_COLORS } from '../lib/theme.js';\n\nexport interface KeyValueProps {\n readonly pairs: readonly (readonly [string, string])[];\n}\n\nexport function KeyValue({ pairs }: KeyValueProps) {\n const maxKeyLen = Math.max(...pairs.map(([k]) => k.length));\n const constraints = pairs.map(() => lengthConstraint(1));\n\n const rows = pairs.map(([key, value]) => {\n const padded = key.padStart(maxKeyLen);\n return (\n <HStack constraints={[lengthConstraint(maxKeyLen + 2), fillConstraint(1)]}>\n <Text fg={BRAND_COLORS.dim}>{padded + ' '}</Text>\n <Text bold fg={BRAND_COLORS.white}>{value}</Text>\n </HStack>\n );\n });\n\n return (\n <VStack constraints={constraints}>\n {rows}\n </VStack>\n );\n}\n","import { Command } from 'commander';\nimport http from 'node:http';\nimport { URL } from 'node:url';\nimport * as p from '@clack/prompts';\nimport { setAuthToken, clearAuthToken, getApiUrl, setRefreshToken } from '../lib/config.js';\nimport { BRAND, icon } from '../lib/theme.js';\nimport { renderJsxToString, getTermWidth } from '../lib/render.js';\nimport { KeyValue } from '../components/KeyValue.js';\n\nconst SUPABASE_URL = 'https://gflvvytymdmrbjpmymhb.supabase.co';\n\nexport const authCommand = new Command('auth').description(\n 'Manage authentication'\n);\n\nexport const loginCommand = new Command('login')\n .description('Log in via browser (Google OAuth)');\n\nloginCommand.action(async () => {\n p.intro(`${BRAND.name} -- Login`);\n\n const s = p.spinner();\n s.start('Starting local auth server...');\n\n try {\n const token = await new Promise<string>((resolve, reject) => {\n const server = http.createServer((req, res) => {\n if (!req.url) {\n res.writeHead(400);\n res.end('Bad request');\n return;\n }\n\n const url = new URL(req.url, 'http://localhost');\n\n if (url.pathname === '/callback') {\n res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });\n res.end(`<!DOCTYPE html>\n<html><head><meta charset=\"utf-8\"><title>${BRAND.name} — Login</title>\n<style>body{font-family:system-ui;display:flex;justify-content:center;align-items:center;height:100vh;margin:0;background:#0a0a0a;color:#e5e5e5}\n.card{text-align:center;padding:2rem;border-radius:12px;background:#171717;border:1px solid #333}</style></head>\n<body><div class=\"card\"><p>Processing authentication...</p></div>\n<script>\nconst h=window.location.hash.substring(1);const p=new URLSearchParams(h);const t=p.get('access_token');const r=p.get('refresh_token');\nif(t){let u='/token?access_token='+encodeURIComponent(t);if(r)u+='&refresh_token='+encodeURIComponent(r);window.location.href=u}\nelse{document.querySelector('.card').innerHTML='<p style=\"color:#f87171\">Authentication failed. No token found.</p><p>You can close this tab.</p>'}\n</script></body></html>`);\n return;\n }\n\n if (url.pathname === '/token') {\n const accessToken = url.searchParams.get('access_token');\n const refreshTokenParam = url.searchParams.get('refresh_token');\n if (accessToken) {\n if (refreshTokenParam) {\n setRefreshToken(refreshTokenParam);\n }\n res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });\n res.end(`<!DOCTYPE html>\n<html><head><meta charset=\"utf-8\"><title>${BRAND.name} — Logged In</title>\n<style>body{font-family:system-ui;display:flex;justify-content:center;align-items:center;height:100vh;margin:0;background:#0a0a0a;color:#e5e5e5}\n.card{text-align:center;padding:2rem;border-radius:12px;background:#171717;border:1px solid #333}\n.check{font-size:3rem;margin-bottom:1rem}</style></head>\n<body><div class=\"card\"><div class=\"check\">&#x2714;</div><h2>Logged in!</h2><p>Return to your terminal.</p></div></body></html>`);\n resolve(accessToken);\n server.close();\n } else {\n res.writeHead(400, { 'Content-Type': 'text/html' });\n res.end('<p>Missing access token.</p>');\n }\n return;\n }\n\n res.writeHead(404);\n res.end('Not found');\n });\n\n server.listen(0, () => {\n const address = server.address();\n if (!address || typeof address === 'string') {\n reject(new Error('Failed to start local server'));\n return;\n }\n\n const port = address.port;\n const redirectUrl = `http://localhost:${port}/callback`;\n const authUrl = `${SUPABASE_URL}/auth/v1/authorize?provider=google&redirect_to=${encodeURIComponent(redirectUrl)}`;\n\n s.message('Opening browser for authentication...');\n\n import('open')\n .then((m) => m.default(authUrl))\n .catch(() => {\n s.stop('Could not open browser automatically');\n p.note(authUrl, 'Open this URL manually');\n });\n });\n\n setTimeout(() => {\n server.close();\n reject(new Error('Authentication timed out after 120 seconds'));\n }, 120_000);\n });\n\n setAuthToken(token);\n s.stop(`${icon.check} Logged in successfully!`);\n\n // Show user info\n const payload = JSON.parse(\n Buffer.from(token.split('.')[1]!, 'base64').toString()\n ) as { email?: string };\n\n if (payload.email) {\n p.log.info(`Signed in as ${payload.email}`);\n }\n\n p.outro('Token stored. You can now use AudienceMeter CLI commands.');\n process.exit(0);\n } catch (error) {\n s.stop(\n `${icon.cross} Login failed: ${error instanceof Error ? error.message : 'Unknown error'}`\n );\n process.exit(1);\n }\n });\n\nexport const logoutCommand = new Command('logout')\n .description('Log out and clear stored credentials')\n .action(async () => {\n clearAuthToken();\n p.log.success(`${icon.check} Logged out successfully.`);\n });\n\nauthCommand\n .command('whoami')\n .description('Show current authenticated user')\n .action(async () => {\n try {\n const { getAuthToken } = await import('../lib/config.js');\n const token = getAuthToken();\n const apiUrl = getApiUrl();\n\n const payload = JSON.parse(\n Buffer.from(token.split('.')[1]!, 'base64').toString()\n ) as { email?: string; sub?: string };\n\n const output = renderJsxToString(\n getTermWidth(),\n 3,\n KeyValue({\n pairs: [\n ['Email', payload.email || 'unknown'],\n ['User ID', payload.sub || 'unknown'],\n ['API URL', apiUrl],\n ],\n })\n );\n console.log(output);\n } catch (error) {\n if (\n error instanceof Error &&\n error.message.includes('Not authenticated')\n ) {\n p.log.warn('Not logged in. Run: audiencemeter login');\n } else {\n p.log.error(\n error instanceof Error ? error.message : 'Unknown error'\n );\n }\n }\n });\n\nauthCommand\n .command('token')\n .description('Print the current stored auth token')\n .action(async () => {\n try {\n const { getAuthToken } = await import('../lib/config.js');\n const token = getAuthToken();\n console.log(token);\n } catch (error) {\n if (\n error instanceof Error &&\n error.message.includes('Not authenticated')\n ) {\n p.log.warn('Not logged in. Run: audiencemeter login');\n } else {\n p.log.error(\n error instanceof Error ? error.message : 'Unknown error'\n );\n }\n }\n });\n\n// Register login/logout as subcommands of auth so `auth login` / `auth logout` still works\nauthCommand.addCommand(loginCommand);\nauthCommand.addCommand(logoutCommand);\n","import { getAuthToken, getApiUrl, getRefreshToken, setAuthToken, setRefreshToken } from './config.js';\n\nconst SUPABASE_URL = 'https://gflvvytymdmrbjpmymhb.supabase.co';\nconst SUPABASE_ANON_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImdmbHZ2eXR5bWRtcmJqcG15bWhiIiwicm9sZSI6ImFub24iLCJpYXQiOjE2ODAyNTIwMjIsImV4cCI6MTk5NTgyODAyMn0.1m-3IhFB-87AKk_-UIPzB0O1URgBwl78oKu8sNe8aFU';\n\nexport function isTokenExpired(token: string): boolean {\n try {\n const payload = JSON.parse(\n Buffer.from(token.split('.')[1]!, 'base64').toString()\n ) as { exp?: number };\n if (!payload.exp) return false;\n // Consider expired 60s before actual expiry to avoid edge cases\n return Date.now() >= (payload.exp - 60) * 1000;\n } catch {\n return true;\n }\n}\n\nexport async function refreshAccessToken(): Promise<string | null> {\n const refreshToken = getRefreshToken();\n if (!refreshToken) return null;\n\n try {\n const response = await fetch(`${SUPABASE_URL}/auth/v1/token?grant_type=refresh_token`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'apikey': SUPABASE_ANON_KEY,\n },\n body: JSON.stringify({ refresh_token: refreshToken }),\n });\n\n if (!response.ok) return null;\n\n const data = await response.json() as {\n access_token?: string;\n refresh_token?: string;\n };\n\n if (data.access_token) {\n setAuthToken(data.access_token);\n if (data.refresh_token) {\n setRefreshToken(data.refresh_token);\n }\n return data.access_token;\n }\n return null;\n } catch {\n return null;\n }\n}\n\nexport class ApiClient {\n constructor(\n private baseUrl: string,\n private authToken: string\n ) {}\n\n private async request<T>(\n method: string,\n path: string,\n body?: unknown\n ): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n Authorization: this.authToken,\n };\n\n const options: RequestInit = { method, headers };\n\n if (body !== undefined) {\n options.body = JSON.stringify(body);\n }\n\n const response = await fetch(url, options);\n\n if (!response.ok) {\n let errorMessage: string;\n try {\n const errorBody = (await response.json()) as Record<string, string>;\n errorMessage =\n errorBody.message || errorBody.error || response.statusText;\n } catch {\n errorMessage = response.statusText;\n }\n\n if (response.status === 401) {\n throw new Error('Not authenticated. Run: audiencemeter login');\n }\n\n throw new Error(`API error (${response.status}): ${errorMessage}`);\n }\n\n const text = await response.text();\n if (!text) return undefined as T;\n return JSON.parse(text) as T;\n }\n\n async get<T>(path: string): Promise<T> {\n return this.request<T>('GET', path);\n }\n\n async post<T>(path: string, body?: unknown): Promise<T> {\n return this.request<T>('POST', path, body);\n }\n\n async patch<T>(path: string, body?: unknown): Promise<T> {\n return this.request<T>('PATCH', path, body);\n }\n\n async delete<T>(path: string): Promise<T> {\n return this.request<T>('DELETE', path);\n }\n}\n\nexport async function ensureValidToken(): Promise<string> {\n const token = getAuthToken();\n if (!isTokenExpired(token)) return token;\n\n const newToken = await refreshAccessToken();\n if (newToken) return newToken;\n\n throw new Error('Session expired. Run: audiencemeter login');\n}\n\nexport function createApiClient(): ApiClient {\n const baseUrl = getApiUrl();\n const authToken = getAuthToken();\n return new ApiClient(baseUrl, authToken);\n}\n\nexport async function createApiClientWithRefresh(): Promise<ApiClient> {\n const baseUrl = getApiUrl();\n const authToken = await ensureValidToken();\n return new ApiClient(baseUrl, authToken);\n}\n\nexport function getUserIdFromToken(): string {\n const token = getAuthToken();\n const payload = JSON.parse(\n Buffer.from(token.split('.')[1]!, 'base64').toString()\n ) as { sub: string };\n return payload.sub;\n}\n\nexport function getUserEmailFromToken(): string {\n const token = getAuthToken();\n const payload = JSON.parse(\n Buffer.from(token.split('.')[1]!, 'base64').toString()\n ) as { email?: string };\n return payload.email || 'unknown';\n}\n\nfunction getTokenPayload(): {\n sub: string;\n email?: string;\n user_metadata?: {\n full_name?: string;\n avatar_url?: string;\n provider_id?: string;\n };\n app_metadata?: { provider?: string };\n} {\n const token = getAuthToken();\n return JSON.parse(\n Buffer.from(token.split('.')[1]!, 'base64').toString()\n );\n}\n\nlet userEnsured = false;\n\n/**\n * Ensures a User row exists in the database for the current Supabase auth user.\n * The web app does this on every dashboard load; the CLI must do it before\n * creating sessions or other resources that have a FK to User.\n * Cached per process so repeated calls are no-ops.\n */\nexport async function ensureUserExists(client: ApiClient): Promise<void> {\n if (userEnsured) return;\n\n const payload = getTokenPayload();\n const userId = payload.sub;\n\n const resp = await client.get<{ user: unknown }>(`/users/${userId}`);\n if (resp.user) {\n userEnsured = true;\n return;\n }\n\n const meta = payload.user_metadata || {};\n await client.post('/users', {\n id: userId,\n email: payload.email || '',\n displayName: meta.full_name || payload.email || '',\n avatarUrl: meta.avatar_url || '',\n authProvider: payload.app_metadata?.provider || 'google',\n providerId: meta.provider_id || '',\n });\n userEnsured = true;\n}\n\n/**\n * Creates an API client with token refresh and ensures the user record exists.\n * Use this as the standard entry point for all authenticated commands.\n */\nexport async function initApiClient(): Promise<ApiClient> {\n const client = await createApiClientWithRefresh();\n await ensureUserExists(client);\n return client;\n}\n","export const TEMPLATES = {\n talk: {\n description: 'Conference talk or presentation (45 min)',\n durationMinutes: 45,\n ratings: [\n { label: 'Content Quality', maxValue: 5 },\n { label: 'Delivery', maxValue: 5 },\n { label: 'Clarity', maxValue: 5 },\n ],\n links: [],\n },\n workshop: {\n description: 'Hands-on workshop or lab session (120 min)',\n durationMinutes: 120,\n ratings: [\n { label: 'Content Quality', maxValue: 5 },\n { label: 'Hands-on Experience', maxValue: 5 },\n { label: 'Pace', maxValue: 5 },\n { label: 'Clarity', maxValue: 5 },\n ],\n links: [],\n },\n lightning: {\n description: 'Lightning talk (10 min)',\n durationMinutes: 10,\n ratings: [\n { label: 'Content Quality', maxValue: 5 },\n { label: 'Delivery', maxValue: 5 },\n ],\n links: [],\n },\n panel: {\n description: 'Panel discussion (60 min)',\n durationMinutes: 60,\n ratings: [\n { label: 'Topic Relevance', maxValue: 5 },\n { label: 'Discussion Quality', maxValue: 5 },\n { label: 'Moderation', maxValue: 5 },\n ],\n links: [],\n },\n} as const;\n\nexport type TemplateName = keyof typeof TEMPLATES;\n\nexport function getTemplate(name: string) {\n if (!(name in TEMPLATES)) {\n return null;\n }\n return TEMPLATES[name as TemplateName];\n}\n\nexport function getTemplateNames(): string[] {\n return Object.keys(TEMPLATES);\n}\n","import { Command } from 'commander';\nimport * as p from '@clack/prompts';\nimport qrcode from 'qrcode-terminal';\nimport { initApiClient, getUserIdFromToken } from '../lib/api-client.js';\nimport {\n TEMPLATES,\n getTemplate,\n getTemplateNames,\n} from '../lib/templates.js';\nimport { BRAND, icon } from '../lib/theme.js';\nimport { renderJsxToString, getTermWidth } from '../lib/render.js';\nimport { KeyValue } from '../components/KeyValue.js';\n\ninterface Project {\n id: string;\n name: string;\n [key: string]: unknown;\n}\n\nfunction padDate(n: number): string {\n return String(n).padStart(2, '0');\n}\n\nfunction formatLocalDate(d: Date): string {\n return `${d.getFullYear()}-${padDate(d.getMonth() + 1)}-${padDate(d.getDate())}`;\n}\n\nfunction formatLocalTime(d: Date): string {\n return `${padDate(d.getHours())}:${padDate(d.getMinutes())}`;\n}\n\nexport const createCommand = new Command('create')\n .description('Create a new feedback session')\n .option('--template <type>', 'Session template')\n .option('--project <name>', 'Project name (optional)')\n .option('--name <name>', 'Session name')\n .option('--date <date>', 'Session date (YYYY-MM-DD)')\n .option('--time <time>', 'Session time (HH:MM, 24h format)')\n .option(\n '--duration <minutes>',\n 'Duration in minutes',\n parseInt\n )\n .option('--json', 'Output as JSON')\n .action(async (options) => {\n const isInteractive =\n !options.json && process.stdout.isTTY && !options.template;\n\n if (isInteractive) {\n p.intro(`${BRAND.name} -- Create Session`);\n }\n\n try {\n // -- Template selection ----------------------------------------\n let templateName: string = options.template;\n\n if (!templateName) {\n if (!isInteractive) {\n p.log.error(\n 'Missing --template. Available: ' + getTemplateNames().join(', ')\n );\n process.exit(1);\n }\n\n const selected = await p.select({\n message: 'What type of session?',\n options: Object.entries(TEMPLATES).map(([key, tmpl]) => ({\n value: key,\n label: key.charAt(0).toUpperCase() + key.slice(1),\n hint: tmpl.description,\n })),\n });\n\n if (p.isCancel(selected)) {\n p.cancel('Cancelled.');\n process.exit(0);\n }\n templateName = selected as string;\n }\n\n const template = getTemplate(templateName);\n if (!template) {\n p.log.error(\n `Unknown template: \"${templateName}\". Available: ${getTemplateNames().join(', ')}`\n );\n process.exit(1);\n }\n\n // -- Session name ------------------------------------------------\n let sessionName: string = options.name;\n\n if (!sessionName && isInteractive) {\n const input = await p.text({\n message: 'Session name?',\n placeholder: 'My Talk at DevFest 2026',\n validate: (v) => {\n if (!v?.trim()) return 'Session name is required';\n },\n });\n\n if (p.isCancel(input)) {\n p.cancel('Cancelled.');\n process.exit(0);\n }\n sessionName = input;\n }\n\n if (!sessionName) {\n p.log.error('Missing --name flag.');\n process.exit(1);\n }\n\n // -- Date & Time ------------------------------------------------\n const now = new Date();\n let sessionDate: string;\n\n if (options.date) {\n // Non-interactive: combine --date and optional --time\n const time = options.time || '00:00';\n sessionDate = new Date(`${options.date}T${time}`).toISOString();\n } else if (isInteractive) {\n const dateInput = await p.text({\n message: 'Session date? (YYYY-MM-DD)',\n placeholder: formatLocalDate(now),\n defaultValue: formatLocalDate(now),\n validate: (v) => {\n if (!/^\\d{4}-\\d{2}-\\d{2}$/.test(v || ''))\n return 'Use YYYY-MM-DD format';\n if (isNaN(new Date(v!).getTime()))\n return 'Invalid date';\n },\n });\n\n if (p.isCancel(dateInput)) {\n p.cancel('Cancelled.');\n process.exit(0);\n }\n\n const timeInput = await p.text({\n message: 'Start time? (24h format)',\n placeholder: formatLocalTime(now),\n defaultValue: formatLocalTime(now),\n validate: (v) => {\n if (!/^\\d{1,2}:\\d{2}$/.test(v || ''))\n return 'Use HH:MM format (e.g. 14:30)';\n },\n });\n\n if (p.isCancel(timeInput)) {\n p.cancel('Cancelled.');\n process.exit(0);\n }\n\n sessionDate = new Date(`${dateInput}T${timeInput}`).toISOString();\n } else {\n sessionDate = now.toISOString();\n }\n\n // -- Duration -----------------------------------------------\n let duration: number = options.duration || template.durationMinutes;\n\n if (!options.duration && isInteractive) {\n const input = await p.text({\n message: 'Duration (minutes)?',\n defaultValue: String(template.durationMinutes),\n placeholder: String(template.durationMinutes),\n validate: (v) => {\n const n = parseInt(v || '', 10);\n if (isNaN(n) || n < 1) return 'Enter a valid number of minutes';\n },\n });\n\n if (p.isCancel(input)) {\n p.cancel('Cancelled.');\n process.exit(0);\n }\n duration = parseInt(input, 10);\n }\n\n // -- Create session -----------------------------------------\n const s = p.spinner();\n s.start('Creating session...');\n\n const client = await initApiClient();\n const userId = getUserIdFromToken();\n\n // Resolve project only if --project flag was passed\n let projectId: string | undefined;\n const projectName: string = options.project || '';\n if (projectName) {\n try {\n s.message('Resolving project...');\n const projectsResp = await client.get<Project[] | { data: Project[] }>(\n `/users/${userId}/projects`\n );\n const projects = Array.isArray(projectsResp)\n ? projectsResp\n : projectsResp?.data || [];\n\n const existing = projects.find(\n (proj: Project) =>\n proj.name.toLowerCase() === projectName.toLowerCase()\n );\n\n if (existing) {\n projectId = existing.id;\n } else {\n s.message('Creating project...');\n const newProject = await client.post<Project>(\n `/users/${userId}/projects`,\n { name: projectName }\n );\n projectId = newProject.id;\n }\n } catch {\n // Continue without project ID\n }\n }\n\n // Build session payload\n const sessionBody = {\n name: sessionName,\n date: sessionDate,\n durationMinutes: duration,\n ratings: [...template.ratings],\n links: [...template.links],\n ...(projectId && { projectId }),\n };\n\n s.message('Creating session...');\n const session = (await client.post('/sessions', sessionBody)) as Record<\n string,\n unknown\n >;\n\n s.stop(`${icon.check} Session created!`);\n\n if (options.json) {\n console.log(JSON.stringify(session, null, 2));\n } else {\n const pairs: [string, string][] = [\n ['Name', String(session.name || sessionName)],\n ['PIN', String(session.pin || '')],\n ['Template', templateName],\n ['Duration', `${duration} minutes`],\n ['Date', new Date(sessionDate).toLocaleString()],\n ];\n if (session.id) {\n pairs.push(['ID', String(session.id)]);\n }\n\n console.log();\n const output = renderJsxToString(\n getTermWidth(),\n pairs.length,\n KeyValue({ pairs })\n );\n console.log(output);\n\n if (session.pin) {\n const joinUrl = `https://app.audiencemeter.pro/s/${session.pin}`;\n console.log();\n p.note(joinUrl, 'Join URL');\n\n // Print QR code in terminal\n console.log();\n await new Promise<void>((resolve) => {\n qrcode.generate(joinUrl, { small: true }, (code: string) => {\n console.log(code);\n resolve();\n });\n });\n }\n\n p.outro('Share the PIN, URL, or QR code with your audience!');\n }\n } catch (error) {\n p.log.error(\n `Failed to create session: ${error instanceof Error ? error.message : 'Unknown error'}`\n );\n if (\n error instanceof Error &&\n error.message.includes('Not authenticated')\n ) {\n p.log.warn('Run: audiencemeter login');\n }\n process.exit(1);\n }\n });\n","import type { Backend, Cell } from 'terminui';\nimport { cellToAnsi } from './render.js';\n\nconst CSI = '\\x1b[';\n\n/**\n * Creates a Node.js stdout Backend implementing terminui's Backend interface.\n * Used for persistent full-screen TUI modes (dashboard, interactive list).\n *\n * The draw() method converts terminui Cell objects to ANSI escape sequences\n * and writes them to stdout with cursor positioning.\n */\nexport function createNodeBackend(): Backend {\n const stdout = process.stdout;\n\n return {\n size: () => ({\n width: stdout.columns || 80,\n height: stdout.rows || 24,\n }),\n\n draw: (content) => {\n let out = '';\n for (const { x, y, cell } of content) {\n // Move cursor to position (1-indexed)\n out += `${CSI}${y + 1};${x + 1}H`;\n out += cellToAnsi(cell);\n }\n stdout.write(out);\n },\n\n flush: () => {\n // stdout.write is already unbuffered for TTY -- no-op\n },\n\n hideCursor: () => {\n stdout.write(`${CSI}?25l`);\n },\n\n showCursor: () => {\n stdout.write(`${CSI}?25h`);\n },\n\n getCursorPosition: () => ({ x: 0, y: 0 }),\n\n setCursorPosition: (pos) => {\n stdout.write(`${CSI}${pos.y + 1};${pos.x + 1}H`);\n },\n\n clear: () => {\n stdout.write(`${CSI}2J${CSI}H`);\n },\n };\n}\n","import readline from 'node:readline';\n\n// ── Types ────────────────────────────────────────────────────────────\n\nexport interface KeypressInfo {\n name: string;\n ctrl: boolean;\n meta: boolean;\n shift: boolean;\n sequence: string;\n}\n\n// ── Alternate Screen Constants ───────────────────────────────────────\n\nconst ENTER_ALT_SCREEN = '\\x1b[?1049h';\nconst EXIT_ALT_SCREEN = '\\x1b[?1049l';\nconst HIDE_CURSOR = '\\x1b[?25l';\nconst SHOW_CURSOR = '\\x1b[?25h';\n\n// Module-level flag to track whether full screen is active.\n// Cleanup handlers only run exitFullScreen when this is true,\n// avoiding interference with normal non-fullscreen commands.\nlet isFullScreen = false;\n\n// ── Keyboard Input ───────────────────────────────────────────────────\n\n/**\n * Sets up keyboard input in raw mode and attaches a keypress handler.\n * Returns a cleanup function that removes the listener, disables raw mode,\n * and pauses stdin.\n */\nexport function setupKeyboardInput(handler: (key: KeypressInfo) => void): () => void {\n readline.emitKeypressEvents(process.stdin);\n\n if (process.stdin.isTTY) {\n process.stdin.setRawMode(true);\n }\n process.stdin.resume();\n\n const listener = (_str: string, key: { name: string; ctrl: boolean; meta: boolean; shift: boolean; sequence: string }) => {\n if (key) {\n handler({\n name: key.name ?? '',\n ctrl: key.ctrl ?? false,\n meta: key.meta ?? false,\n shift: key.shift ?? false,\n sequence: key.sequence ?? '',\n });\n }\n };\n\n process.stdin.on('keypress', listener);\n\n // Return cleanup function\n return () => {\n process.stdin.removeListener('keypress', listener);\n if (process.stdin.isTTY) {\n process.stdin.setRawMode(false);\n }\n process.stdin.pause();\n };\n}\n\n// ── Full Screen Management ───────────────────────────────────────────\n\n/**\n * Enters alternate screen buffer and hides the cursor.\n * Registers cleanup handlers for safe terminal restoration.\n */\nexport function enterFullScreen(): void {\n if (isFullScreen) return;\n isFullScreen = true;\n process.stdout.write(ENTER_ALT_SCREEN);\n process.stdout.write(HIDE_CURSOR);\n}\n\n/**\n * Shows the cursor and exits alternate screen buffer.\n * Safe to call multiple times (idempotent via flag check).\n */\nexport function exitFullScreen(): void {\n if (!isFullScreen) return;\n isFullScreen = false;\n process.stdout.write(SHOW_CURSOR);\n process.stdout.write(EXIT_ALT_SCREEN);\n}\n\n// ── Process Cleanup Handlers ─────────────────────────────────────────\n// These ensure the terminal is restored if the process exits while\n// full screen is active. The flag check prevents interference with\n// normal non-fullscreen commands.\n\nprocess.on('exit', () => {\n if (isFullScreen) {\n // Synchronous writes needed in 'exit' handler\n try { process.stdout.write(SHOW_CURSOR); } catch { /* ignore */ }\n try { process.stdout.write(EXIT_ALT_SCREEN); } catch { /* ignore */ }\n isFullScreen = false;\n }\n});\n\nprocess.on('SIGINT', () => {\n if (isFullScreen) {\n exitFullScreen();\n }\n process.exit(0);\n});\n\nprocess.on('SIGTERM', () => {\n if (isFullScreen) {\n exitFullScreen();\n }\n process.exit(0);\n});\n\nprocess.on('uncaughtException', (err) => {\n if (isFullScreen) {\n exitFullScreen();\n }\n console.error(err);\n process.exit(1);\n});\n","import { Text } from 'terminui/jsx';\nimport { BRAND_COLORS, BRAND } from '../lib/theme.js';\n\nexport interface HeaderProps {\n readonly version?: string;\n}\n\nexport function Header({ version }: HeaderProps = {}) {\n const ver = version || BRAND.version;\n return (\n <Text bold fg={BRAND_COLORS.purple} align=\"center\">\n {`${BRAND.name} v${ver}`}\n </Text>\n );\n}\n","import { Tabs } from 'terminui/jsx';\nimport { createStyle, Modifier } from 'terminui';\nimport { BRAND_COLORS } from '../lib/theme.js';\n\nexport interface TabBarProps {\n readonly titles: readonly string[];\n readonly selected: number;\n}\n\nexport function TabBar({ titles, selected }: TabBarProps) {\n return (\n <Tabs\n titles={titles}\n selected={selected}\n border\n fg={BRAND_COLORS.dimCyan}\n highlightStyle={createStyle({ fg: BRAND_COLORS.purple, addModifier: Modifier.BOLD })}\n />\n );\n}\n","import { Text } from 'terminui/jsx';\nimport { BRAND_COLORS } from '../lib/theme.js';\n\nexport interface ShortcutBarProps {\n readonly shortcuts: readonly { key: string; label: string }[];\n}\n\nexport function ShortcutBar({ shortcuts }: ShortcutBarProps) {\n const text = shortcuts.map((s) => `${s.key}: ${s.label}`).join(' | ');\n return (\n <Text fg={BRAND_COLORS.dimCyan}>{` ${text}`}</Text>\n );\n}\n","import { VStack, HStack, Box, Text, List, Gauge } from 'terminui/jsx';\nimport { fillConstraint, lengthConstraint, createListState, createStyle, Modifier } from 'terminui';\nimport type { ListState } from 'terminui';\nimport { BRAND_COLORS, icon } from '../lib/theme.js';\nimport { Header } from './Header.js';\nimport { TabBar } from './TabBar.js';\nimport { ShortcutBar } from './ShortcutBar.js';\nimport { SessionTable, type SessionRow } from './SessionTable.js';\n\nexport interface DashboardProps {\n readonly selectedTab: number;\n readonly sessions: readonly SessionRow[];\n readonly stats: {\n readonly totalSessions: number;\n readonly totalParticipants: number;\n readonly avgEngagement: number;\n };\n readonly selectedIndex: number;\n readonly authEmail: string | null;\n readonly authExpired?: boolean;\n readonly loading?: boolean;\n readonly error?: string | null;\n}\n\nconst TAB_TITLES = ['Dashboard', 'Sessions', 'Create', 'Auth'] as const;\n\nconst SHORTCUTS = [\n { key: 'Tab/1-4', label: 'switch' },\n { key: 'j/k', label: 'navigate' },\n { key: 'Enter', label: 'select' },\n { key: 'Esc/q', label: 'quit' },\n];\n\nfunction DashboardTab({ sessions, stats, selectedIndex, loading }: {\n sessions: readonly SessionRow[];\n stats: DashboardProps['stats'];\n selectedIndex: number;\n loading?: boolean;\n}) {\n const recent = sessions.slice(0, 5);\n const listItems = recent.length > 0\n ? recent.map((s) => `${icon.session} ${s.name} ${s.pin} ${s.status}`)\n : [loading ? 'Loading sessions...' : 'No sessions yet. Press Tab to go to Create.'];\n\n const listState: ListState = createListState();\n listState.selected = recent.length > 0 ? selectedIndex : undefined;\n\n return (\n <HStack constraints={[fillConstraint(2), fillConstraint(1)]}>\n <Box border borderType=\"rounded\" fg={BRAND_COLORS.dimCyan} title=\" Recent Sessions \">\n <List\n items={listItems}\n state={listState}\n fg={BRAND_COLORS.cyan}\n highlightStyle={createStyle({ fg: BRAND_COLORS.purple, addModifier: Modifier.BOLD })}\n />\n </Box>\n <VStack constraints={[lengthConstraint(3), lengthConstraint(3), fillConstraint(1)]}>\n <Box border borderType=\"rounded\" fg={BRAND_COLORS.dimCyan} title=\" Sessions \">\n <Text bold fg={BRAND_COLORS.white} align=\"center\">{String(stats.totalSessions)}</Text>\n </Box>\n <Box border borderType=\"rounded\" fg={BRAND_COLORS.dimCyan} title=\" Participants \">\n <Text bold fg={BRAND_COLORS.white} align=\"center\">{String(stats.totalParticipants)}</Text>\n </Box>\n <Box border borderType=\"rounded\" fg={BRAND_COLORS.dimCyan} title=\" Engagement \">\n <Gauge\n percent={stats.avgEngagement}\n fg={BRAND_COLORS.green}\n />\n </Box>\n </VStack>\n </HStack>\n );\n}\n\nfunction SessionsTab({ sessions, selectedIndex, loading }: {\n sessions: readonly SessionRow[];\n selectedIndex: number;\n loading?: boolean;\n}) {\n if (sessions.length === 0) {\n return (\n <Box border borderType=\"rounded\" fg={BRAND_COLORS.dimCyan}>\n <Text fg={BRAND_COLORS.dim}>{loading ? 'Loading sessions...' : 'No sessions found. Create one with the Create tab.'}</Text>\n </Box>\n );\n }\n\n const listItems = sessions.map((s) =>\n `${icon.session} ${s.name.padEnd(30).slice(0, 30)} ${s.pin} ${s.status.padEnd(10).slice(0, 10)} ${s.date}`\n );\n\n const listState: ListState = createListState();\n listState.selected = selectedIndex;\n\n return (\n <Box border borderType=\"rounded\" fg={BRAND_COLORS.dimCyan} title={` Sessions (${sessions.length}) `}>\n <List\n items={listItems}\n state={listState}\n fg={BRAND_COLORS.cyan}\n highlightStyle={createStyle({ fg: BRAND_COLORS.purple, addModifier: Modifier.BOLD })}\n />\n </Box>\n );\n}\n\nfunction CreateTab() {\n return (\n <Box border borderType=\"rounded\" fg={BRAND_COLORS.dimCyan} title=\" Create Session \">\n <Text fg={BRAND_COLORS.white}>{` Press Enter to create a new session`}</Text>\n </Box>\n );\n}\n\nfunction AuthTab({ authEmail, authExpired }: { authEmail: string | null; authExpired?: boolean }) {\n if (authExpired) {\n return (\n <Box border borderType=\"rounded\" title=\" Authentication \">\n <Text fg={BRAND_COLORS.yellow}>{` ${icon.cross} Session expired. Press Enter to re-login.`}</Text>\n </Box>\n );\n }\n\n return (\n <Box border borderType=\"rounded\" title=\" Authentication \">\n <Text fg={authEmail ? BRAND_COLORS.green : BRAND_COLORS.yellow}>\n {authEmail\n ? ` ${icon.check} Logged in as ${authEmail}`\n : ` ${icon.cross} Not logged in. Press Enter to login.`}\n </Text>\n </Box>\n );\n}\n\nexport function Dashboard({ selectedTab, sessions, stats, selectedIndex, authEmail, authExpired, loading, error }: DashboardProps) {\n let content;\n switch (selectedTab) {\n case 0:\n content = <DashboardTab sessions={sessions} stats={stats} selectedIndex={selectedIndex} loading={loading} />;\n break;\n case 1:\n content = <SessionsTab sessions={sessions} selectedIndex={selectedIndex} loading={loading} />;\n break;\n case 2:\n content = <CreateTab />;\n break;\n case 3:\n content = <AuthTab authEmail={authEmail} authExpired={authExpired} />;\n break;\n default:\n content = <DashboardTab sessions={sessions} stats={stats} selectedIndex={selectedIndex} />;\n }\n\n if (error) {\n return (\n <VStack constraints={[lengthConstraint(1), lengthConstraint(3), lengthConstraint(1), fillConstraint(1), lengthConstraint(1)]}>\n <Header />\n <TabBar titles={[...TAB_TITLES]} selected={selectedTab} />\n <Text fg={BRAND_COLORS.yellow} align=\"center\">{`${icon.cross} ${error}`}</Text>\n {content}\n <ShortcutBar shortcuts={SHORTCUTS} />\n </VStack>\n );\n }\n\n return (\n <VStack constraints={[lengthConstraint(1), lengthConstraint(3), fillConstraint(1), lengthConstraint(1)]}>\n <Header />\n <TabBar titles={[...TAB_TITLES]} selected={selectedTab} />\n {content}\n <ShortcutBar shortcuts={SHORTCUTS} />\n </VStack>\n );\n}\n","import { VStack, Gauge, LineGauge, Text, Box } from 'terminui/jsx';\nimport { lengthConstraint } from 'terminui';\nimport type { Color } from 'terminui';\nimport type { JsxNode } from 'terminui/jsx-runtime';\nimport { BRAND_COLORS } from '../lib/theme.js';\n\nexport interface MetricsPanelProps {\n readonly engagementRate?: number;\n readonly feedbackRate?: number;\n readonly participants?: number;\n}\n\nfunction gaugeColor(ratio: number): Color {\n if (ratio >= 70) return BRAND_COLORS.green;\n if (ratio >= 40) return BRAND_COLORS.cyan;\n return BRAND_COLORS.yellow;\n}\n\nexport function MetricsPanel({ engagementRate, feedbackRate, participants }: MetricsPanelProps) {\n const items: JsxNode[] = [];\n const constraints: ReturnType<typeof lengthConstraint>[] = [];\n\n if (participants !== undefined) {\n items.push(\n <Text bold fg={BRAND_COLORS.white}>{` ${String(participants)} participants`}</Text>\n );\n constraints.push(lengthConstraint(1));\n }\n\n if (engagementRate !== undefined && engagementRate > 0) {\n items.push(\n <Gauge\n percent={engagementRate}\n border\n title={` Engagement ${engagementRate}% `}\n fg={gaugeColor(engagementRate)}\n />\n );\n constraints.push(lengthConstraint(3));\n }\n\n if (feedbackRate !== undefined && feedbackRate > 0) {\n items.push(\n <LineGauge\n percent={feedbackRate}\n border\n title={` Feedback ${feedbackRate}% `}\n fg={gaugeColor(feedbackRate)}\n />\n );\n constraints.push(lengthConstraint(3));\n }\n\n if (items.length === 0) {\n return <Text fg={BRAND_COLORS.dim}>No metrics available</Text>;\n }\n\n return (\n <VStack constraints={constraints}>\n {items}\n </VStack>\n );\n}\n","import { VStack, HStack, Box, Text, Sparkline, BarChart } from 'terminui/jsx';\nimport { fillConstraint, lengthConstraint, createBarGroup, createBar } from 'terminui';\nimport type { BarGroup, Constraint } from 'terminui';\nimport type { JsxNode } from 'terminui/jsx-runtime';\nimport { BRAND_COLORS, icon } from '../lib/theme.js';\nimport { KeyValue } from './KeyValue.js';\nimport { MetricsPanel } from './MetricsPanel.js';\n\nexport interface SessionDetailSession {\n readonly id?: string;\n readonly name: string;\n readonly pin: string;\n readonly date?: string;\n readonly durationMinutes?: number;\n readonly createdAt?: string;\n readonly questions?: readonly { id: string; type: string; label: string }[];\n readonly links?: readonly { id: string; label: string; url: string }[];\n}\n\nexport interface SessionDetailMetrics {\n readonly totalParticipants?: number;\n readonly engagementRate?: number;\n readonly feedbackCompletionRate?: number;\n}\n\nexport interface TimelineBucket {\n readonly minute: number;\n readonly positive: number;\n readonly negative: number;\n readonly pace: number;\n}\n\nexport interface SessionDetailProps {\n readonly session: SessionDetailSession;\n readonly metrics: SessionDetailMetrics | null;\n readonly timeline: readonly TimelineBucket[];\n readonly analysis: Record<string, unknown> | null;\n readonly status: string;\n}\n\nfunction statusBadge(status: string): string {\n switch (status) {\n case 'live': return `${icon.live} live`;\n case 'ended': return `${icon.ended} ended`;\n case 'upcoming': return `${icon.upcoming} upcoming`;\n default: return status;\n }\n}\n\nexport function SessionDetail({ session, metrics, timeline, analysis, status }: SessionDetailProps) {\n // Build content sections as an array, then compose at the end\n const sections: JsxNode[] = [];\n const sectionConstraints: Constraint[] = [];\n\n // -- Header: session name + status --\n sections.push(\n <Text bold fg={BRAND_COLORS.purple}>\n {` ${session.name || 'Untitled Session'} ${statusBadge(status)}`}\n </Text>\n );\n sectionConstraints.push(lengthConstraint(1));\n\n // -- Info + Metrics side-by-side --\n const dateStr = session.date\n ? new Date(session.date).toLocaleString()\n : session.createdAt\n ? new Date(session.createdAt).toLocaleString()\n : '--';\n const durationStr = session.durationMinutes\n ? `${session.durationMinutes} minutes`\n : '--';\n\n const infoPairs: [string, string][] = [\n ['PIN', session.pin || '--'],\n ['Date', dateStr],\n ['Duration', durationStr],\n ];\n if (session.id) {\n infoPairs.push(['ID', session.id]);\n }\n\n const hasMetrics = metrics && (\n (metrics.engagementRate !== undefined && metrics.engagementRate > 0) ||\n (metrics.feedbackCompletionRate !== undefined && metrics.feedbackCompletionRate > 0) ||\n (metrics.totalParticipants !== undefined)\n );\n\n if (hasMetrics) {\n const metricsHeight = 1\n + (metrics!.totalParticipants !== undefined ? 1 : 0)\n + (metrics!.engagementRate !== undefined && metrics!.engagementRate! > 0 ? 3 : 0)\n + (metrics!.feedbackCompletionRate !== undefined && metrics!.feedbackCompletionRate! > 0 ? 3 : 0);\n const infoHeight = infoPairs.length + 2; // +2 for border\n const panelHeight = Math.max(infoHeight, metricsHeight + 2);\n\n sections.push(\n <HStack constraints={[fillConstraint(1), fillConstraint(1)]}>\n <Box border borderType=\"rounded\" fg={BRAND_COLORS.dimCyan} title=\" Session Info \">\n <KeyValue pairs={infoPairs} />\n </Box>\n <Box border borderType=\"rounded\" fg={BRAND_COLORS.dimCyan} title=\" Metrics \">\n <MetricsPanel\n engagementRate={metrics!.engagementRate}\n feedbackRate={metrics!.feedbackCompletionRate}\n participants={metrics!.totalParticipants}\n />\n </Box>\n </HStack>\n );\n sectionConstraints.push(lengthConstraint(panelHeight));\n } else {\n sections.push(\n <Box border borderType=\"rounded\" fg={BRAND_COLORS.dimCyan} title=\" Session Info \">\n <KeyValue pairs={infoPairs} />\n </Box>\n );\n sectionConstraints.push(lengthConstraint(infoPairs.length + 2));\n }\n\n // -- Sparkline: reaction timeline --\n const positiveData = timeline.map((b) => b.positive || 0);\n if (positiveData.some((v) => v > 0)) {\n sections.push(\n <Box border borderType=\"rounded\" fg={BRAND_COLORS.dimCyan} title=\" Reactions Over Time \">\n <Sparkline\n data={positiveData}\n fg={BRAND_COLORS.green}\n />\n </Box>\n );\n sectionConstraints.push(lengthConstraint(5));\n }\n\n // -- BarChart: reaction summary --\n const totalPositive = timeline.reduce((sum, b) => sum + (b.positive || 0), 0);\n const totalNegative = timeline.reduce((sum, b) => sum + (b.negative || 0), 0);\n if (totalPositive > 0 || totalNegative > 0) {\n const barData: BarGroup[] = [\n createBarGroup([createBar(totalPositive)], 'Positive'),\n createBarGroup([createBar(totalNegative)], 'Negative'),\n ];\n sections.push(\n <Box border borderType=\"rounded\" fg={BRAND_COLORS.dimCyan} title=\" Reaction Summary \">\n <BarChart\n data={barData}\n fg={BRAND_COLORS.cyan}\n />\n </Box>\n );\n const maxVal = Math.max(totalPositive, totalNegative, 1);\n sectionConstraints.push(lengthConstraint(Math.max(8, maxVal + 4)));\n }\n\n // -- AI Analysis --\n if (analysis && typeof analysis === 'object') {\n const summary = (analysis.summary as string) || (analysis.feedbackSummary as string) || '';\n if (summary) {\n sections.push(\n <Box border borderType=\"rounded\" fg={BRAND_COLORS.purple} title={` ${icon.sparkle} AI Analysis `}>\n <Text fg={BRAND_COLORS.white}>{summary}</Text>\n </Box>\n );\n const summaryLines = Math.ceil(summary.length / 70) + 2;\n sectionConstraints.push(lengthConstraint(summaryLines));\n }\n\n const insights = analysis.coachingInsights as string[] | undefined;\n if (insights && insights.length > 0) {\n const insightLines = insights.slice(0, 3).map((insight) =>\n ` ${icon.arrow} ${insight}`\n ).join('\\n');\n\n sections.push(\n <Box border borderType=\"rounded\" fg={BRAND_COLORS.dimCyan} title=\" Coaching Insights \">\n <Text fg={BRAND_COLORS.white}>{insightLines}</Text>\n </Box>\n );\n sectionConstraints.push(lengthConstraint(Math.min(insights.length, 3) + 2));\n }\n }\n\n // -- Questions --\n if (session.questions && session.questions.length > 0) {\n const questionLines = session.questions.map((q) =>\n ` ${icon.dot} [${q.type}] ${q.label}`\n ).join('\\n');\n\n sections.push(\n <Box border borderType=\"rounded\" fg={BRAND_COLORS.dimCyan} title=\" Rating Criteria \">\n <Text fg={BRAND_COLORS.white}>{questionLines}</Text>\n </Box>\n );\n sectionConstraints.push(lengthConstraint(session.questions.length + 2));\n }\n\n // -- Links --\n if (session.links && session.links.length > 0) {\n const linkLines = session.links.map((link) =>\n ` ${icon.dot} ${link.label}: ${link.url}`\n ).join('\\n');\n\n sections.push(\n <Box border borderType=\"rounded\" fg={BRAND_COLORS.dimCyan} title=\" Links \">\n <Text fg={BRAND_COLORS.white}>{linkLines}</Text>\n </Box>\n );\n sectionConstraints.push(lengthConstraint(session.links.length + 2));\n }\n\n // -- Join URL --\n if (session.pin) {\n sections.push(\n <Box border borderType=\"rounded\" fg={BRAND_COLORS.dimCyan} title=\" Join URL \">\n <Text bold fg={BRAND_COLORS.cyan}>{`https://app.audiencemeter.pro/s/${session.pin}`}</Text>\n </Box>\n );\n sectionConstraints.push(lengthConstraint(3));\n }\n\n return (\n <VStack constraints={sectionConstraints}>\n {sections}\n </VStack>\n );\n}\n","import { createTerminal, terminalResize, createListState } from 'terminui';\nimport type { Terminal, ListState } from 'terminui';\nimport { VStack, Box, List, Text, terminalDrawJsx } from 'terminui/jsx';\nimport type { JsxNode } from 'terminui/jsx-runtime';\nimport { createNodeBackend } from './node-backend.js';\nimport { setupKeyboardInput, enterFullScreen, exitFullScreen, type KeypressInfo } from './input.js';\nimport { createApiClient, initApiClient, getUserIdFromToken, getUserEmailFromToken, isTokenExpired } from './api-client.js';\nimport { Dashboard } from '../components/Dashboard.js';\nimport {\n SessionDetail,\n type SessionDetailSession,\n type SessionDetailMetrics,\n type TimelineBucket,\n} from '../components/SessionDetail.js';\nimport { ShortcutBar } from '../components/ShortcutBar.js';\nimport type { SessionRow } from '../components/SessionTable.js';\nimport { BRAND_COLORS, icon } from './theme.js';\nimport { fillConstraint, lengthConstraint, createStyle, Modifier } from 'terminui';\n\n// ── Types ────────────────────────────────────────────────────────────\n\ninterface SessionSummary {\n id?: string;\n name: string;\n pin: string;\n date?: string | Date;\n durationMinutes?: number;\n createdAt?: string | Date;\n [key: string]: unknown;\n}\n\ninterface SessionsResponse {\n data: SessionSummary[];\n total: number;\n page: number;\n take: number;\n}\n\ninterface Metrics {\n totalParticipants?: number;\n engagementRate?: number;\n feedbackCompletionRate?: number;\n [key: string]: unknown;\n}\n\ninterface AppState {\n selectedTab: number;\n sessions: SessionRow[];\n rawSessions: SessionSummary[];\n total: number;\n stats: {\n totalSessions: number;\n totalParticipants: number;\n avgEngagement: number;\n };\n selectedIndex: number;\n authEmail: string | null;\n authExpired: boolean;\n showingSession: string | null;\n running: boolean;\n loading: boolean;\n error: string | null;\n}\n\n// ── Helpers ──────────────────────────────────────────────────────────\n\nfunction getSessionStatus(session: SessionSummary): string {\n const sessionDate = session.date\n ? new Date(session.date as string)\n : session.createdAt\n ? new Date(session.createdAt as string)\n : null;\n\n if (!sessionDate) return 'unknown';\n\n const now = new Date();\n const durationMs = (session.durationMinutes || 60) * 60 * 1000;\n const endTime = new Date(sessionDate.getTime() + durationMs);\n\n if (now < sessionDate) return 'upcoming';\n if (now >= sessionDate && now <= endTime) return 'live';\n return 'ended';\n}\n\nfunction statusDisplay(status: string): string {\n switch (status) {\n case 'live': return `${icon.live} live`;\n case 'ended': return `${icon.ended} ended`;\n case 'upcoming': return `${icon.upcoming} soon`;\n default: return status;\n }\n}\n\nfunction toSessionRows(sessions: SessionSummary[]): SessionRow[] {\n return sessions.map((session) => {\n const date = session.date\n ? new Date(session.date as string).toLocaleDateString()\n : session.createdAt\n ? new Date(session.createdAt as string).toLocaleDateString()\n : '--';\n\n const duration = session.durationMinutes\n ? `${session.durationMinutes}min`\n : '--';\n\n const status = getSessionStatus(session);\n\n const raw = session as Record<string, unknown>;\n const count = (raw._count as Record<string, unknown> | undefined)?.attendees\n ?? raw.participantCount\n ?? '--';\n\n return {\n name: session.name || '--',\n pin: session.pin || '--',\n status: statusDisplay(status),\n date,\n duration,\n participants: String(count),\n };\n });\n}\n\n// ── Render helpers ───────────────────────────────────────────────────\n\nfunction renderDashboard(terminal: Terminal, state: AppState): void {\n terminalDrawJsx(terminal, (\n <Dashboard\n selectedTab={state.selectedTab}\n sessions={state.sessions}\n stats={state.stats}\n selectedIndex={state.selectedIndex}\n authEmail={state.authEmail}\n authExpired={state.authExpired}\n loading={state.loading}\n error={state.error}\n />\n ));\n}\n\nfunction renderSessionDetail(\n terminal: Terminal,\n session: SessionDetailSession,\n metrics: SessionDetailMetrics | null,\n timeline: readonly TimelineBucket[],\n analysis: Record<string, unknown> | null,\n status: string,\n): void {\n const detailShortcuts = [\n { key: 'Esc/q', label: 'back' },\n ];\n\n terminalDrawJsx(terminal, (\n <VStack constraints={[fillConstraint(1), lengthConstraint(1)]}>\n <SessionDetail\n session={session}\n metrics={metrics}\n timeline={timeline}\n analysis={analysis}\n status={status}\n />\n <ShortcutBar shortcuts={detailShortcuts} />\n </VStack>\n ));\n}\n\nfunction renderInteractiveList(\n terminal: Terminal,\n sessionRows: readonly SessionRow[],\n total: number,\n selectedIndex: number,\n): void {\n const listItems = sessionRows.map((s) =>\n `${icon.session} ${s.name.padEnd(30).slice(0, 30)} ${s.pin} ${s.status.padEnd(10).slice(0, 10)} ${s.date}`\n );\n\n const listState: ListState = createListState();\n listState.selected = selectedIndex;\n\n terminalDrawJsx(terminal, (\n <VStack constraints={[lengthConstraint(1), fillConstraint(1), lengthConstraint(1)]}>\n <Text bold fg={BRAND_COLORS.purple} align=\"center\">{`Sessions (${sessionRows.length} of ${total})`}</Text>\n <Box border borderType=\"rounded\" fg={BRAND_COLORS.dimCyan}>\n <List\n items={listItems}\n state={listState}\n fg={BRAND_COLORS.cyan}\n highlightStyle={createStyle({ fg: BRAND_COLORS.purple, addModifier: Modifier.BOLD })}\n />\n </Box>\n <Text fg={BRAND_COLORS.dimCyan}>{' j/k: navigate | Enter: view | q: quit'}</Text>\n </VStack>\n ));\n}\n\n// ── Session Detail Fetching ──────────────────────────────────────────\n\nasync function fetchSessionDetail(sessionId: string): Promise<{\n session: SessionDetailSession;\n metrics: SessionDetailMetrics | null;\n timeline: TimelineBucket[];\n analysis: Record<string, unknown> | null;\n status: string;\n}> {\n const client = createApiClient();\n const isUuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(sessionId);\n const path = !isUuid\n ? `/sessions/by-pin/${sessionId}`\n : `/sessions/${sessionId}`;\n\n const session = await client.get<SessionSummary>(path);\n\n let metrics: Metrics | null = null;\n let timeline: TimelineBucket[] = [];\n let analysis: Record<string, unknown> | null = null;\n\n if (session.id) {\n const results = await Promise.allSettled([\n client.get<Metrics>(`/sessions/${session.id}/metrics`),\n client.get<TimelineBucket[]>(`/sessions/${session.id}/sentiment-timeline`),\n client.get<Record<string, unknown>>(`/sessions/${session.id}/analysis`),\n ]);\n\n if (results[0]!.status === 'fulfilled') metrics = results[0]!.value;\n if (results[1]!.status === 'fulfilled') timeline = results[1]!.value || [];\n if (results[2]!.status === 'fulfilled') analysis = results[2]!.value;\n }\n\n const status = getSessionStatus(session);\n\n return {\n session: {\n id: session.id,\n name: session.name,\n pin: session.pin,\n date: session.date ? String(session.date) : undefined,\n durationMinutes: session.durationMinutes,\n createdAt: session.createdAt ? String(session.createdAt) : undefined,\n questions: (session as Record<string, unknown>).questions as SessionDetailSession['questions'],\n links: (session as Record<string, unknown>).links as SessionDetailSession['links'],\n },\n metrics: metrics ? {\n totalParticipants: metrics.totalParticipants,\n engagementRate: metrics.engagementRate,\n feedbackCompletionRate: metrics.feedbackCompletionRate,\n } : null,\n timeline,\n analysis,\n status,\n };\n}\n\n// ── Dashboard ────────────────────────────────────────────────────────\n\nexport async function startDashboard(): Promise<void> {\n // Check authentication\n let userId: string;\n try {\n userId = getUserIdFromToken();\n } catch {\n console.error('Not authenticated. Run: audiencemeter login');\n process.exit(1);\n return; // TypeScript needs this after process.exit\n }\n\n let authEmail: string | null = null;\n try {\n authEmail = getUserEmailFromToken();\n } catch {\n authEmail = null;\n }\n\n // Enter full screen\n enterFullScreen();\n\n const backend = createNodeBackend();\n const terminal = createTerminal(backend);\n\n // Check if token is expired before showing status\n let authExpired = false;\n try {\n const token = (await import('./config.js')).getAuthToken();\n authExpired = isTokenExpired(token);\n } catch {\n // no token at all\n }\n\n // Initialize state\n const state: AppState = {\n selectedTab: 0,\n sessions: [],\n rawSessions: [],\n total: 0,\n stats: { totalSessions: 0, totalParticipants: 0, avgEngagement: 0 },\n selectedIndex: 0,\n authEmail: authExpired ? null : authEmail,\n authExpired,\n showingSession: null,\n running: true,\n loading: true,\n error: null,\n };\n\n // Initial render with empty state (non-blocking)\n renderDashboard(terminal, state);\n\n // Session detail state\n let detailData: Awaited<ReturnType<typeof fetchSessionDetail>> | null = null;\n\n // Re-render helper\n const rerender = () => {\n if (state.showingSession && detailData) {\n renderSessionDetail(\n terminal,\n detailData.session,\n detailData.metrics,\n detailData.timeline,\n detailData.analysis,\n detailData.status,\n );\n } else {\n renderDashboard(terminal, state);\n }\n };\n\n // Setup keyboard input\n const cleanupInput = setupKeyboardInput(async (key: KeypressInfo) => {\n if (!state.running) return;\n\n // Ctrl+C always exits\n if (key.ctrl && key.name === 'c') {\n state.running = false;\n cleanupInput();\n exitFullScreen();\n process.exit(0);\n return;\n }\n\n // Showing session detail -- Esc/q goes back\n if (state.showingSession) {\n if (key.name === 'escape' || key.name === 'q') {\n state.showingSession = null;\n detailData = null;\n rerender();\n }\n return;\n }\n\n // Tab switching\n if (key.name === 'tab') {\n state.selectedTab = (state.selectedTab + 1) % 4;\n state.selectedIndex = 0;\n rerender();\n return;\n }\n\n // Number keys for tab selection\n if (['1', '2', '3', '4'].includes(key.name)) {\n state.selectedTab = parseInt(key.name, 10) - 1;\n state.selectedIndex = 0;\n rerender();\n return;\n }\n\n // Navigation (j/k/up/down)\n const itemCount = state.selectedTab === 0\n ? Math.min(state.sessions.length, 5)\n : state.sessions.length;\n\n if (itemCount > 0) {\n if (key.name === 'j' || key.name === 'down') {\n state.selectedIndex = (state.selectedIndex + 1) % itemCount;\n rerender();\n return;\n }\n\n if (key.name === 'k' || key.name === 'up') {\n state.selectedIndex = (state.selectedIndex - 1 + itemCount) % itemCount;\n rerender();\n return;\n }\n }\n\n // Enter key -- action depends on tab\n if (key.name === 'return') {\n if (state.selectedTab === 0 || state.selectedTab === 1) {\n // Dashboard or Sessions tab -- drill into session detail\n const rawSession = state.rawSessions[state.selectedIndex];\n if (rawSession) {\n const sessionId = rawSession.id || rawSession.pin;\n if (sessionId) {\n state.showingSession = sessionId;\n try {\n detailData = await fetchSessionDetail(sessionId);\n } catch {\n detailData = {\n session: {\n name: rawSession.name,\n pin: rawSession.pin,\n date: rawSession.date ? String(rawSession.date) : undefined,\n durationMinutes: rawSession.durationMinutes,\n createdAt: rawSession.createdAt ? String(rawSession.createdAt) : undefined,\n },\n metrics: null,\n timeline: [],\n analysis: null,\n status: getSessionStatus(rawSession),\n };\n }\n rerender();\n }\n }\n return;\n }\n\n if (state.selectedTab === 2) {\n // Create tab -- exit full screen, run create flow, then exit\n state.running = false;\n cleanupInput();\n exitFullScreen();\n\n try {\n const { createCommand } = await import('../commands/create.js');\n await createCommand.parseAsync(['node', 'audiencemeter'], { from: 'node' });\n } catch {\n // Command may throw on cancel\n }\n return;\n }\n\n if (state.selectedTab === 3) {\n // Auth tab -- exit full screen, run auth flow, then exit\n state.running = false;\n cleanupInput();\n exitFullScreen();\n\n try {\n const { authCommand } = await import('../commands/auth.js');\n const action = (state.authEmail && !state.authExpired) ? 'whoami' : 'login';\n await authCommand.parseAsync(['node', 'audiencemeter', action], { from: 'node' });\n } catch {\n // Command may throw on cancel\n }\n return;\n }\n }\n\n // Quit\n if (key.name === 'q' || key.name === 'escape') {\n state.running = false;\n cleanupInput();\n exitFullScreen();\n return;\n }\n });\n\n // Listen for terminal resize\n const onResize = () => {\n terminalResize(terminal, backend.size());\n rerender();\n };\n process.stdout.on('resize', onResize);\n\n // Fetch sessions asynchronously (non-blocking, with token auto-refresh)\n (async () => {\n try {\n const client = await initApiClient();\n\n // If token was refreshed, update auth display\n if (state.authExpired) {\n state.authExpired = false;\n state.authEmail = getUserEmailFromToken();\n state.error = null;\n }\n\n const queryParams = new URLSearchParams();\n queryParams.set('take', '50');\n queryParams.set('sort', 'createdAt');\n queryParams.set('order', 'desc');\n\n const response = await client.get<SessionsResponse | SessionSummary[]>(\n `/users/${userId}/sessions?${queryParams.toString()}`\n );\n\n const sessions: SessionSummary[] = Array.isArray(response)\n ? response\n : response?.data || [];\n const total = Array.isArray(response)\n ? sessions.length\n : response?.total || sessions.length;\n\n state.rawSessions = sessions;\n state.sessions = toSessionRows(sessions);\n state.total = total;\n\n // Calculate stats\n let totalParticipants = 0;\n for (const s of sessions) {\n const raw = s as Record<string, unknown>;\n const count = (raw._count as Record<string, unknown> | undefined)?.attendees\n ?? raw.participantCount\n ?? 0;\n totalParticipants += Number(count) || 0;\n }\n\n state.stats = {\n totalSessions: total,\n totalParticipants,\n avgEngagement: 0,\n };\n\n state.loading = false;\n rerender();\n } catch (err) {\n state.loading = false;\n const msg = err instanceof Error ? err.message : 'Failed to load sessions';\n if (msg.includes('expired') || msg.includes('Not authenticated')) {\n state.authExpired = true;\n state.authEmail = null;\n state.error = 'Session expired. Go to Auth tab and press Enter to re-login.';\n } else {\n state.error = msg;\n }\n rerender();\n }\n })();\n\n // Wait until the user quits\n return new Promise<void>((resolve) => {\n const check = setInterval(() => {\n if (!state.running) {\n clearInterval(check);\n process.stdout.removeListener('resize', onResize);\n resolve();\n }\n }, 100);\n });\n}\n\n// ── Interactive List ─────────────────────────────────────────────────\n\nexport async function startInteractiveList(\n sessionRows: SessionRow[],\n rawSessions: SessionSummary[],\n total: number,\n): Promise<void> {\n enterFullScreen();\n\n const backend = createNodeBackend();\n const terminal = createTerminal(backend);\n\n let selectedIndex = 0;\n let running = true;\n let showingDetail = false;\n let detailData: Awaited<ReturnType<typeof fetchSessionDetail>> | null = null;\n\n const rerender = () => {\n if (showingDetail && detailData) {\n renderSessionDetail(\n terminal,\n detailData.session,\n detailData.metrics,\n detailData.timeline,\n detailData.analysis,\n detailData.status,\n );\n } else {\n renderInteractiveList(terminal, sessionRows, total, selectedIndex);\n }\n };\n\n rerender();\n\n const cleanupInput = setupKeyboardInput(async (key: KeypressInfo) => {\n if (!running) return;\n\n if (key.ctrl && key.name === 'c') {\n running = false;\n cleanupInput();\n exitFullScreen();\n process.exit(0);\n return;\n }\n\n // Showing detail -- Esc/q goes back to list\n if (showingDetail) {\n if (key.name === 'escape' || key.name === 'q') {\n showingDetail = false;\n detailData = null;\n rerender();\n }\n return;\n }\n\n // Navigation\n if (sessionRows.length > 0) {\n if (key.name === 'j' || key.name === 'down') {\n selectedIndex = (selectedIndex + 1) % sessionRows.length;\n rerender();\n return;\n }\n\n if (key.name === 'k' || key.name === 'up') {\n selectedIndex = (selectedIndex - 1 + sessionRows.length) % sessionRows.length;\n rerender();\n return;\n }\n }\n\n // Enter -- drill into session detail\n if (key.name === 'return' && sessionRows.length > 0) {\n const rawSession = rawSessions[selectedIndex];\n if (rawSession) {\n const sessionId = rawSession.id || rawSession.pin;\n if (sessionId) {\n showingDetail = true;\n try {\n detailData = await fetchSessionDetail(sessionId);\n } catch {\n detailData = {\n session: {\n name: rawSession.name,\n pin: rawSession.pin,\n date: rawSession.date ? String(rawSession.date) : undefined,\n durationMinutes: rawSession.durationMinutes,\n createdAt: rawSession.createdAt ? String(rawSession.createdAt) : undefined,\n },\n metrics: null,\n timeline: [],\n analysis: null,\n status: getSessionStatus(rawSession),\n };\n }\n rerender();\n }\n }\n return;\n }\n\n // Quit\n if (key.name === 'q' || key.name === 'escape') {\n running = false;\n cleanupInput();\n exitFullScreen();\n return;\n }\n });\n\n // Listen for terminal resize\n const onResize = () => {\n terminalResize(terminal, backend.size());\n rerender();\n };\n process.stdout.on('resize', onResize);\n\n return new Promise<void>((resolve) => {\n const check = setInterval(() => {\n if (!running) {\n clearInterval(check);\n process.stdout.removeListener('resize', onResize);\n resolve();\n }\n }, 100);\n });\n}\n","import { Command } from 'commander';\nimport { authCommand, loginCommand, logoutCommand } from './commands/auth.js';\nimport { createCommand } from './commands/create.js';\nimport { listCommand } from './commands/list.js';\nimport { showCommand } from './commands/show.js';\nimport { deleteCommand } from './commands/delete.js';\nimport { BRAND } from './lib/theme.js';\n\nconst program = new Command();\n\nprogram\n .name('audiencemeter')\n .description(\n `${BRAND.name} CLI — ${BRAND.tagline}`\n )\n .version(BRAND.version, '-v, --version');\n\n// Register commands\nprogram.addCommand(loginCommand);\nprogram.addCommand(logoutCommand);\nprogram.addCommand(authCommand);\nprogram.addCommand(createCommand);\nprogram.addCommand(listCommand);\nprogram.addCommand(showCommand);\nprogram.addCommand(deleteCommand);\n\n// Detect if args were passed\nconst hasArgs = process.argv.length > 2;\n\nif (hasArgs) {\n // Subcommands: parse with Commander (static print-and-exit)\n program.parse(process.argv);\n} else if (process.stdout.isTTY) {\n // No args + TTY: launch persistent full-screen TUI dashboard\n import('./lib/app.js')\n .then(({ startDashboard }) => startDashboard())\n .catch((err) => {\n // Ensure terminal is restored on error\n import('./lib/input.js').then(({ exitFullScreen }) => {\n exitFullScreen();\n }).catch(() => { /* ignore */ });\n console.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n });\n} else {\n // No args + non-TTY (piped): show help text\n program.help();\n}\n","import { Command } from 'commander';\nimport * as p from '@clack/prompts';\nimport { initApiClient, getUserIdFromToken } from '../lib/api-client.js';\nimport { icon } from '../lib/theme.js';\nimport { renderJsxToString, getTermWidth } from '../lib/render.js';\nimport { SessionTable, type SessionRow } from '../components/SessionTable.js';\n\ninterface SessionSummary {\n id?: string;\n name: string;\n pin: string;\n date?: string | Date;\n durationMinutes?: number;\n createdAt?: string | Date;\n [key: string]: unknown;\n}\n\ninterface SessionsResponse {\n data: SessionSummary[];\n total: number;\n page: number;\n take: number;\n}\n\nfunction getSessionStatus(session: SessionSummary): string {\n const sessionDate = session.date\n ? new Date(session.date)\n : session.createdAt\n ? new Date(session.createdAt)\n : null;\n\n if (!sessionDate) return 'unknown';\n\n const now = new Date();\n const durationMs = (session.durationMinutes || 60) * 60 * 1000;\n const endTime = new Date(sessionDate.getTime() + durationMs);\n\n if (now < sessionDate) return 'upcoming';\n if (now >= sessionDate && now <= endTime) return 'live';\n return 'ended';\n}\n\nexport const listCommand = new Command('list')\n .alias('ls')\n .description('List your feedback sessions')\n .option('--project <name>', 'Filter by project name')\n .option('--limit <n>', 'Max sessions to display', parseInt, 20)\n .option('--json', 'Output as JSON')\n .action(async (options) => {\n const s = p.spinner();\n s.start('Fetching sessions...');\n\n try {\n const client = await initApiClient();\n const userId = getUserIdFromToken();\n\n const queryParams = new URLSearchParams();\n queryParams.set('take', String(options.limit));\n queryParams.set('sort', 'createdAt');\n queryParams.set('order', 'desc');\n\n const response = await client.get<SessionsResponse | SessionSummary[]>(\n `/users/${userId}/sessions?${queryParams.toString()}`\n );\n\n s.stop();\n\n const sessions: SessionSummary[] = Array.isArray(response)\n ? response\n : response?.data || [];\n const total = Array.isArray(response)\n ? sessions.length\n : response?.total || sessions.length;\n\n if (sessions.length === 0) {\n p.log.warn('No sessions found.');\n p.log.info(\n 'Create one: audiencemeter create --template talk --project \"My Talk\"'\n );\n return;\n }\n\n if (options.json) {\n console.log(JSON.stringify(sessions, null, 2));\n return;\n }\n\n // Build rich table\n const statusDisplay = (status: string) => {\n switch (status) {\n case 'live':\n return `${icon.live} live`;\n case 'ended':\n return `${icon.ended} ended`;\n case 'upcoming':\n return `${icon.upcoming} soon`;\n default:\n return status;\n }\n };\n\n const rows: SessionRow[] = sessions.map((session) => {\n const date = session.date\n ? new Date(session.date).toLocaleDateString()\n : session.createdAt\n ? new Date(session.createdAt).toLocaleDateString()\n : '--';\n\n const duration = session.durationMinutes\n ? `${session.durationMinutes}min`\n : '--';\n\n const status = getSessionStatus(session);\n\n const raw = session as Record<string, unknown>;\n const count =\n (raw._count as Record<string, unknown> | undefined)?.attendees ??\n raw.participantCount ??\n '--';\n const participants = String(count);\n\n return {\n name: session.name || '--',\n pin: session.pin || '--',\n status: statusDisplay(status),\n date,\n duration,\n participants,\n };\n });\n\n // TTY mode: enter interactive full-screen list with keyboard navigation\n if (process.stdout.isTTY && !options.json) {\n const { startInteractiveList } = await import('../lib/app.js');\n await startInteractiveList(rows, sessions, total);\n return;\n }\n\n // Non-TTY / static output: render table and print\n const tableHeight = rows.length + 4; // header + border + rows\n const output = renderJsxToString(\n getTermWidth(),\n tableHeight,\n SessionTable({ sessions: rows, total })\n );\n console.log(output);\n } catch (error) {\n s.stop(\n `${icon.cross} Failed to list sessions: ${\n error instanceof Error ? error.message : 'Unknown error'\n }`\n );\n if (\n error instanceof Error &&\n error.message.includes('Not authenticated')\n ) {\n p.log.warn('Run: audiencemeter login');\n }\n process.exit(1);\n }\n });\n","import { Table, Box } from 'terminui/jsx';\nimport { fillConstraint, lengthConstraint } from 'terminui';\nimport { BRAND_COLORS } from '../lib/theme.js';\n\nexport interface SessionRow {\n readonly name: string;\n readonly pin: string;\n readonly status: string;\n readonly date: string;\n readonly duration: string;\n readonly participants: string;\n}\n\nexport interface SessionTableProps {\n readonly sessions: readonly SessionRow[];\n readonly total: number;\n}\n\nexport function SessionTable({ sessions, total }: SessionTableProps) {\n const widths = [\n fillConstraint(1), // Name -- takes remaining space\n lengthConstraint(7), // PIN\n lengthConstraint(10), // Status\n lengthConstraint(12), // Date\n lengthConstraint(10), // Duration\n lengthConstraint(6), // Ppl\n ];\n\n const header = ['Name', 'PIN', 'Status', 'Date', 'Duration', 'Ppl'];\n\n const rows = sessions.map((s) => [\n s.name,\n s.pin,\n s.status,\n s.date,\n s.duration,\n s.participants,\n ]);\n\n return (\n <Box\n border\n borderType=\"rounded\"\n fg={BRAND_COLORS.dimCyan}\n title={` Sessions (${sessions.length} of ${total}) `}\n >\n <Table\n widths={widths}\n header={header}\n rows={rows}\n fg={BRAND_COLORS.cyan}\n columnSpacing={1}\n />\n </Box>\n );\n}\n","import { Command } from 'commander';\nimport * as p from '@clack/prompts';\nimport { initApiClient, getUserIdFromToken } from '../lib/api-client.js';\nimport { icon } from '../lib/theme.js';\nimport { renderJsxToString, getTermWidth } from '../lib/render.js';\nimport {\n SessionDetail,\n type SessionDetailSession,\n type SessionDetailMetrics,\n type TimelineBucket,\n} from '../components/SessionDetail.js';\n\ninterface Session {\n id?: string;\n userId?: string;\n name: string;\n pin: string;\n date?: string;\n durationMinutes?: number;\n createdAt?: string;\n questions?: Array<{ id: string; type: string; label: string }>;\n links?: Array<{ id: string; label: string; url: string }>;\n [key: string]: unknown;\n}\n\ninterface Metrics {\n totalParticipants?: number;\n engagementRate?: number;\n feedbackCompletionRate?: number;\n [key: string]: unknown;\n}\n\nfunction getSessionStatus(session: Session): string {\n const sessionDate = session.date\n ? new Date(session.date)\n : session.createdAt\n ? new Date(session.createdAt)\n : null;\n\n if (!sessionDate) return 'unknown';\n\n const now = new Date();\n const durationMs = (session.durationMinutes || 60) * 60 * 1000;\n const endTime = new Date(sessionDate.getTime() + durationMs);\n\n if (now < sessionDate) return 'upcoming';\n if (now >= sessionDate && now <= endTime) return 'live';\n return 'ended';\n}\n\nexport const showCommand = new Command('show')\n .description('Show session details with rich metrics')\n .argument('<session-id>', 'Session ID (UUID) or PIN (5 characters)')\n .option('--json', 'Output as JSON')\n .action(async (sessionId: string, options) => {\n const s = p.spinner();\n s.start('Fetching session...');\n\n try {\n const client = await initApiClient();\n\n // Determine if input looks like a UUID or a PIN\n const isUuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(sessionId);\n const path = !isUuid\n ? `/sessions/by-pin/${sessionId}`\n : `/sessions/${sessionId}`;\n\n const session = await client.get<Session>(path);\n\n // Fetch metrics, timeline, and AI analysis in parallel (owner only)\n let metrics: Metrics | null = null;\n let timeline: TimelineBucket[] = [];\n let analysis: Record<string, unknown> | null = null;\n\n let isOwner = false;\n try {\n isOwner = !!session.userId && session.userId === getUserIdFromToken();\n } catch {\n // Not authenticated — skip owner-only data\n }\n\n if (session.id && isOwner) {\n s.message('Fetching metrics...');\n\n const results = await Promise.allSettled([\n client.get<Metrics>(`/sessions/${session.id}/metrics`),\n client.get<TimelineBucket[]>(\n `/sessions/${session.id}/sentiment-timeline`\n ),\n client.get<Record<string, unknown>>(\n `/sessions/${session.id}/analysis`\n ),\n ]);\n\n if (results[0]!.status === 'fulfilled') metrics = results[0]!.value;\n if (results[1]!.status === 'fulfilled')\n timeline = results[1]!.value || [];\n if (results[2]!.status === 'fulfilled') analysis = results[2]!.value;\n }\n\n s.stop();\n\n // -- JSON output ------------------------------------------------\n if (options.json) {\n const output = {\n ...session,\n ...(metrics && { metrics }),\n ...(timeline.length && { timeline }),\n ...(analysis && { analysis }),\n };\n console.log(JSON.stringify(output, null, 2));\n return;\n }\n\n // -- Rich JSX output ------------------------------------------------\n const status = getSessionStatus(session);\n\n // Calculate height based on content\n let height = 3; // header + spacing\n const infoPairCount = 3 + (session.id ? 1 : 0);\n const hasMetrics = metrics && (\n (metrics.engagementRate !== undefined && metrics.engagementRate > 0) ||\n (metrics.feedbackCompletionRate !== undefined && metrics.feedbackCompletionRate > 0) ||\n (metrics.totalParticipants !== undefined)\n );\n\n if (hasMetrics) {\n const metricsH = 1\n + (metrics!.totalParticipants !== undefined ? 1 : 0)\n + (metrics!.engagementRate !== undefined && metrics!.engagementRate! > 0 ? 3 : 0)\n + (metrics!.feedbackCompletionRate !== undefined && metrics!.feedbackCompletionRate! > 0 ? 3 : 0);\n height += Math.max(infoPairCount + 2, metricsH + 2);\n } else {\n height += infoPairCount + 2;\n }\n\n // Timeline sparkline\n const positiveData = timeline.map((b) => b.positive || 0);\n if (positiveData.some((v) => v > 0)) {\n height += 5;\n }\n\n // Bar chart\n const totalPositive = timeline.reduce((sum, b) => sum + (b.positive || 0), 0);\n const totalNegative = timeline.reduce((sum, b) => sum + (b.negative || 0), 0);\n if (totalPositive > 0 || totalNegative > 0) {\n const maxVal = Math.max(totalPositive, totalNegative, 1);\n height += Math.max(8, maxVal + 4);\n }\n\n // AI Analysis\n if (analysis && typeof analysis === 'object') {\n const summary = (analysis.summary as string) || (analysis.feedbackSummary as string) || '';\n if (summary) {\n height += Math.ceil(summary.length / 70) + 2;\n }\n const insights = analysis.coachingInsights as string[] | undefined;\n if (insights && insights.length > 0) {\n height += Math.min(insights.length, 3) + 2;\n }\n }\n\n // Questions\n if (session.questions && session.questions.length > 0) {\n height += session.questions.length + 2;\n }\n\n // Links\n if (session.links && session.links.length > 0) {\n height += session.links.length + 2;\n }\n\n // Join URL\n if (session.pin) {\n height += 3;\n }\n\n const sessionData: SessionDetailSession = {\n id: session.id,\n name: session.name,\n pin: session.pin,\n date: session.date,\n durationMinutes: session.durationMinutes,\n createdAt: session.createdAt,\n questions: session.questions,\n links: session.links,\n };\n\n const metricsData: SessionDetailMetrics | null = metrics\n ? {\n totalParticipants: metrics.totalParticipants,\n engagementRate: metrics.engagementRate,\n feedbackCompletionRate: metrics.feedbackCompletionRate,\n }\n : null;\n\n console.log();\n const output = renderJsxToString(\n getTermWidth(),\n height,\n SessionDetail({\n session: sessionData,\n metrics: metricsData,\n timeline,\n analysis,\n status,\n })\n );\n console.log(output);\n } catch (error) {\n s.stop(\n `${icon.cross} Failed to fetch session: ${error instanceof Error ? error.message : 'Unknown error'}`\n );\n if (\n error instanceof Error &&\n error.message.includes('Not authenticated')\n ) {\n p.log.warn('Run: audiencemeter login');\n }\n process.exit(1);\n }\n });\n","import { Command } from 'commander';\nimport * as p from '@clack/prompts';\nimport { initApiClient } from '../lib/api-client.js';\nimport { icon } from '../lib/theme.js';\n\nexport const deleteCommand = new Command('delete')\n .alias('rm')\n .description('Delete a session')\n .argument('<session-id>', 'Session ID (UUID)')\n .option('--force', 'Skip confirmation prompt')\n .action(async (sessionId: string, options) => {\n try {\n const client = await initApiClient();\n\n // Fetch session details to show name in confirmation\n let sessionName = sessionId;\n try {\n const session = await client.get<Record<string, unknown>>(\n `/sessions/${sessionId}`\n );\n if (session.name) {\n sessionName = session.name as string;\n }\n } catch {\n // If we can't fetch, proceed with the ID\n }\n\n // Confirm deletion unless --force\n if (!options.force) {\n const confirmed = await p.confirm({\n message: `Delete session \"${sessionName}\"? This cannot be undone.`,\n });\n\n if (p.isCancel(confirmed) || !confirmed) {\n p.log.info('Cancelled.');\n return;\n }\n }\n\n const s = p.spinner();\n s.start('Deleting session...');\n\n await client.delete(`/sessions/${sessionId}`);\n\n s.stop(`${icon.check} Session \"${sessionName}\" deleted.`);\n } catch (error) {\n p.log.error(\n `Failed to delete session: ${error instanceof Error ? error.message : 'Unknown error'}`\n );\n if (\n error instanceof Error &&\n error.message.includes('Not authenticated')\n ) {\n p.log.warn('Run: audiencemeter login');\n }\n process.exit(1);\n }\n });\n"],"mappings":"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","names":["getAuthToken","SUPABASE_URL","path","text","Command","p","Text","jsx","jsx","Text","jsx","text","VStack","HStack","Box","Text","fillConstraint","lengthConstraint","createStyle","Modifier","jsx","jsxs","VStack","Gauge","Text","lengthConstraint","jsx","VStack","HStack","Box","Text","fillConstraint","lengthConstraint","jsx","jsxs","createTerminal","createListState","VStack","Box","List","Text","terminalDrawJsx","fillConstraint","lengthConstraint","createStyle","Modifier","jsx","jsxs","path","createCommand","authCommand","Command","Command","p","fillConstraint","lengthConstraint","jsx","getSessionStatus","Command","statusDisplay","startInteractiveList","Command","p","getSessionStatus","path","output","Command","p","Command","startDashboard","exitFullScreen"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "audiencemeter",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "AudienceMeter CLI - Beautiful terminal UI for managing speaker feedback sessions",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -33,7 +33,8 @@
33
33
  "images/"
34
34
  ],
35
35
  "scripts": {
36
- "build": "npx tsup"
36
+ "build": "npx tsup",
37
+ "test": "vitest run"
37
38
  },
38
39
  "publishConfig": {
39
40
  "access": "public"
@@ -49,6 +50,7 @@
49
50
  "devDependencies": {
50
51
  "@types/node": "^22.0.0",
51
52
  "tsup": "^8.5.1",
52
- "typescript": "5.7.3"
53
+ "typescript": "5.7.3",
54
+ "vitest": "^4.0.18"
53
55
  }
54
56
  }