audiencemeter 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -15,9 +15,11 @@ __export(config_exports, {
15
15
  getApiUrl: () => getApiUrl,
16
16
  getAuthToken: () => getAuthToken,
17
17
  getConfig: () => getConfig,
18
+ getPrivacyMode: () => getPrivacyMode,
18
19
  getRefreshToken: () => getRefreshToken,
19
20
  setApiUrl: () => setApiUrl,
20
21
  setAuthToken: () => setAuthToken,
22
+ setPrivacyMode: () => setPrivacyMode,
21
23
  setRefreshToken: () => setRefreshToken
22
24
  });
23
25
  import Conf from "conf";
@@ -52,6 +54,12 @@ function getApiUrl() {
52
54
  function setApiUrl(url) {
53
55
  config.set("apiUrl", url);
54
56
  }
57
+ function getPrivacyMode() {
58
+ return config.get("privacyMode");
59
+ }
60
+ function setPrivacyMode(value) {
61
+ config.set("privacyMode", value);
62
+ }
55
63
  var config;
56
64
  var init_config = __esm({
57
65
  "src/lib/config.ts"() {
@@ -71,6 +79,10 @@ var init_config = __esm({
71
79
  refreshToken: {
72
80
  type: "string",
73
81
  default: ""
82
+ },
83
+ privacyMode: {
84
+ type: "boolean",
85
+ default: true
74
86
  }
75
87
  }
76
88
  });
@@ -916,6 +928,24 @@ var init_create = __esm({
916
928
  }
917
929
  });
918
930
 
931
+ // src/lib/pin-mask.ts
932
+ function maskPin(pin) {
933
+ if (!pin || pin === "--") return pin;
934
+ return getPrivacyMode() ? "*".repeat(pin.length) : pin;
935
+ }
936
+ function togglePrivacyMode() {
937
+ const newValue = !getPrivacyMode();
938
+ setPrivacyMode(newValue);
939
+ return newValue;
940
+ }
941
+ var init_pin_mask = __esm({
942
+ "src/lib/pin-mask.ts"() {
943
+ "use strict";
944
+ init_config();
945
+ init_config();
946
+ }
947
+ });
948
+
919
949
  // src/lib/node-backend.ts
920
950
  function createNodeBackend() {
921
951
  const stdout = process.stdout;
@@ -1089,7 +1119,10 @@ var init_TabBar = __esm({
1089
1119
  import { Text as Text3 } from "terminui/jsx";
1090
1120
  import { jsx as jsx5 } from "terminui/jsx-runtime";
1091
1121
  function ShortcutBar({ shortcuts }) {
1092
- const text2 = shortcuts.map((s) => `${s.key}: ${s.label}`).join(" | ");
1122
+ const text2 = shortcuts.map((s) => {
1123
+ if (s.active) return `${s.key}: [${s.label}]`;
1124
+ return `${s.key}: ${s.label}`;
1125
+ }).join(" | ");
1093
1126
  return /* @__PURE__ */ jsx5(Text3, { fg: BRAND_COLORS.dimCyan, children: ` ${text2}` });
1094
1127
  }
1095
1128
  var init_ShortcutBar = __esm({
@@ -1103,9 +1136,18 @@ var init_ShortcutBar = __esm({
1103
1136
  import { VStack as VStack2, HStack as HStack2, Box as Box2, Text as Text4, List, Gauge } from "terminui/jsx";
1104
1137
  import { fillConstraint as fillConstraint3, lengthConstraint as lengthConstraint3, createListState, createStyle as createStyle2, Modifier as Modifier2 } from "terminui";
1105
1138
  import { jsx as jsx6, jsxs as jsxs2 } from "terminui/jsx-runtime";
1139
+ function getShortcuts(privacyMode) {
1140
+ return [
1141
+ { key: "1-4", label: "tab" },
1142
+ { key: "j/k", label: "navigate" },
1143
+ { key: "Enter", label: "select" },
1144
+ { key: "p", label: privacyMode ? "privacy on" : "privacy", active: privacyMode },
1145
+ { key: "q", label: "quit" }
1146
+ ];
1147
+ }
1106
1148
  function DashboardTab({ sessions, stats, selectedIndex, loading }) {
1107
1149
  const recent = sessions.slice(0, 5);
1108
- const listItems = recent.length > 0 ? recent.map((s) => `${icon.session} ${s.name} ${s.pin} ${s.status}`) : [loading ? "Loading sessions..." : "No sessions yet. Press Tab to go to Create."];
1150
+ const listItems = recent.length > 0 ? recent.map((s) => `${icon.session} ${s.name} ${maskPin(s.pin)} ${s.status}`) : [loading ? "Loading sessions..." : "No sessions yet. Press Tab to go to Create."];
1109
1151
  const listState = createListState();
1110
1152
  listState.selected = recent.length > 0 ? selectedIndex : void 0;
1111
1153
  return /* @__PURE__ */ jsxs2(HStack2, { constraints: [fillConstraint3(2), fillConstraint3(1)], children: [
@@ -1136,7 +1178,7 @@ function SessionsTab({ sessions, selectedIndex, loading }) {
1136
1178
  return /* @__PURE__ */ jsx6(Box2, { border: true, borderType: "rounded", fg: BRAND_COLORS.dimCyan, children: /* @__PURE__ */ jsx6(Text4, { fg: BRAND_COLORS.dim, children: loading ? "Loading sessions..." : "No sessions found. Create one with the Create tab." }) });
1137
1179
  }
1138
1180
  const listItems = sessions.map(
1139
- (s) => `${icon.session} ${s.name.padEnd(30).slice(0, 30)} ${s.pin} ${s.status.padEnd(10).slice(0, 10)} ${s.date}`
1181
+ (s) => `${icon.session} ${s.name.padEnd(30).slice(0, 30)} ${maskPin(s.pin)} ${s.status.padEnd(10).slice(0, 10)} ${s.date}`
1140
1182
  );
1141
1183
  const listState = createListState();
1142
1184
  listState.selected = selectedIndex;
@@ -1159,7 +1201,7 @@ function AuthTab({ authEmail, authExpired }) {
1159
1201
  }
1160
1202
  return /* @__PURE__ */ jsx6(Box2, { border: true, borderType: "rounded", title: " Authentication ", children: /* @__PURE__ */ jsx6(Text4, { fg: authEmail ? BRAND_COLORS.green : BRAND_COLORS.yellow, children: authEmail ? ` ${icon.check} Logged in as ${authEmail}` : ` ${icon.cross} Not logged in. Press Enter to login.` }) });
1161
1203
  }
1162
- function Dashboard({ selectedTab, sessions, stats, selectedIndex, authEmail, authExpired, loading, error }) {
1204
+ function Dashboard({ selectedTab, sessions, stats, selectedIndex, authEmail, authExpired, loading, error, privacyMode = false }) {
1163
1205
  let content;
1164
1206
  switch (selectedTab) {
1165
1207
  case 0:
@@ -1183,17 +1225,17 @@ function Dashboard({ selectedTab, sessions, stats, selectedIndex, authEmail, aut
1183
1225
  /* @__PURE__ */ jsx6(TabBar, { titles: [...TAB_TITLES], selected: selectedTab }),
1184
1226
  /* @__PURE__ */ jsx6(Text4, { fg: BRAND_COLORS.yellow, align: "center", children: `${icon.cross} ${error}` }),
1185
1227
  content,
1186
- /* @__PURE__ */ jsx6(ShortcutBar, { shortcuts: SHORTCUTS })
1228
+ /* @__PURE__ */ jsx6(ShortcutBar, { shortcuts: getShortcuts(privacyMode) })
1187
1229
  ] });
1188
1230
  }
1189
1231
  return /* @__PURE__ */ jsxs2(VStack2, { constraints: [lengthConstraint3(1), lengthConstraint3(3), fillConstraint3(1), lengthConstraint3(1)], children: [
1190
1232
  /* @__PURE__ */ jsx6(Header, {}),
1191
1233
  /* @__PURE__ */ jsx6(TabBar, { titles: [...TAB_TITLES], selected: selectedTab }),
1192
1234
  content,
1193
- /* @__PURE__ */ jsx6(ShortcutBar, { shortcuts: SHORTCUTS })
1235
+ /* @__PURE__ */ jsx6(ShortcutBar, { shortcuts: getShortcuts(privacyMode) })
1194
1236
  ] });
1195
1237
  }
1196
- var TAB_TITLES, SHORTCUTS;
1238
+ var TAB_TITLES;
1197
1239
  var init_Dashboard = __esm({
1198
1240
  "src/components/Dashboard.tsx"() {
1199
1241
  "use strict";
@@ -1201,13 +1243,8 @@ var init_Dashboard = __esm({
1201
1243
  init_Header();
1202
1244
  init_TabBar();
1203
1245
  init_ShortcutBar();
1246
+ init_pin_mask();
1204
1247
  TAB_TITLES = ["Dashboard", "Sessions", "Create", "Auth"];
1205
- SHORTCUTS = [
1206
- { key: "Tab/1-4", label: "switch" },
1207
- { key: "j/k", label: "navigate" },
1208
- { key: "Enter", label: "select" },
1209
- { key: "Esc/q", label: "quit" }
1210
- ];
1211
1248
  }
1212
1249
  });
1213
1250
 
@@ -1295,7 +1332,7 @@ function SessionDetail({ session, metrics, timeline, analysis, status }) {
1295
1332
  const dateStr = session.date ? new Date(session.date).toLocaleString() : session.createdAt ? new Date(session.createdAt).toLocaleString() : "--";
1296
1333
  const durationStr = session.durationMinutes ? `${session.durationMinutes} minutes` : "--";
1297
1334
  const infoPairs = [
1298
- ["PIN", session.pin || "--"],
1335
+ ["PIN", maskPin(session.pin || "--")],
1299
1336
  ["Date", dateStr],
1300
1337
  ["Duration", durationStr]
1301
1338
  ];
@@ -1399,7 +1436,7 @@ function SessionDetail({ session, metrics, timeline, analysis, status }) {
1399
1436
  }
1400
1437
  if (session.pin) {
1401
1438
  sections.push(
1402
- /* @__PURE__ */ jsx8(Box4, { border: true, borderType: "rounded", fg: BRAND_COLORS.dimCyan, title: " Join URL ", children: /* @__PURE__ */ jsx8(Text6, { bold: true, fg: BRAND_COLORS.cyan, children: `https://app.audiencemeter.pro/s/${session.pin}` }) })
1439
+ /* @__PURE__ */ jsx8(Box4, { border: true, borderType: "rounded", fg: BRAND_COLORS.dimCyan, title: " Join URL ", children: /* @__PURE__ */ jsx8(Text6, { bold: true, fg: BRAND_COLORS.cyan, children: `https://app.audiencemeter.pro/s/${maskPin(session.pin)}` }) })
1403
1440
  );
1404
1441
  sectionConstraints.push(lengthConstraint5(3));
1405
1442
  }
@@ -1411,6 +1448,7 @@ var init_SessionDetail = __esm({
1411
1448
  init_theme();
1412
1449
  init_KeyValue();
1413
1450
  init_MetricsPanel();
1451
+ init_pin_mask();
1414
1452
  }
1415
1453
  });
1416
1454
 
@@ -1474,13 +1512,16 @@ function renderDashboard(terminal, state) {
1474
1512
  authEmail: state.authEmail,
1475
1513
  authExpired: state.authExpired,
1476
1514
  loading: state.loading,
1477
- error: state.error
1515
+ error: state.error,
1516
+ privacyMode: getPrivacyMode()
1478
1517
  }
1479
1518
  ));
1480
1519
  }
1481
1520
  function renderSessionDetail(terminal, session, metrics, timeline, analysis, status) {
1521
+ const privacyOn = getPrivacyMode();
1482
1522
  const detailShortcuts = [
1483
- { key: "Esc/q", label: "back" }
1523
+ { key: "q", label: "back" },
1524
+ { key: "p", label: privacyOn ? "privacy on" : "privacy", active: privacyOn }
1484
1525
  ];
1485
1526
  terminalDrawJsx2(terminal, /* @__PURE__ */ jsxs4(VStack5, { constraints: [fillConstraint5(1), lengthConstraint6(1)], children: [
1486
1527
  /* @__PURE__ */ jsx9(
@@ -1498,7 +1539,7 @@ function renderSessionDetail(terminal, session, metrics, timeline, analysis, sta
1498
1539
  }
1499
1540
  function renderInteractiveList(terminal, sessionRows, total, selectedIndex) {
1500
1541
  const listItems = sessionRows.map(
1501
- (s) => `${icon.session} ${s.name.padEnd(30).slice(0, 30)} ${s.pin} ${s.status.padEnd(10).slice(0, 10)} ${s.date}`
1542
+ (s) => `${icon.session} ${s.name.padEnd(30).slice(0, 30)} ${maskPin(s.pin)} ${s.status.padEnd(10).slice(0, 10)} ${s.date}`
1502
1543
  );
1503
1544
  const listState = createListState2();
1504
1545
  listState.selected = selectedIndex;
@@ -1513,7 +1554,12 @@ function renderInteractiveList(terminal, sessionRows, total, selectedIndex) {
1513
1554
  highlightStyle: createStyle3({ fg: BRAND_COLORS.purple, addModifier: Modifier3.BOLD })
1514
1555
  }
1515
1556
  ) }),
1516
- /* @__PURE__ */ jsx9(Text7, { fg: BRAND_COLORS.dimCyan, children: " j/k: navigate | Enter: view | q: quit" })
1557
+ /* @__PURE__ */ jsx9(ShortcutBar, { shortcuts: [
1558
+ { key: "j/k", label: "navigate" },
1559
+ { key: "Enter", label: "view" },
1560
+ { key: "p", label: getPrivacyMode() ? "privacy on" : "privacy", active: getPrivacyMode() },
1561
+ { key: "q", label: "quit" }
1562
+ ] })
1517
1563
  ] }));
1518
1564
  }
1519
1565
  async function fetchSessionDetail(sessionId) {
@@ -1620,6 +1666,11 @@ async function startDashboard() {
1620
1666
  return;
1621
1667
  }
1622
1668
  if (state.showingSession) {
1669
+ if (key.name === "p") {
1670
+ togglePrivacyMode();
1671
+ rerender();
1672
+ return;
1673
+ }
1623
1674
  if (key.name === "escape" || key.name === "q") {
1624
1675
  state.showingSession = null;
1625
1676
  detailData = null;
@@ -1705,6 +1756,12 @@ async function startDashboard() {
1705
1756
  return;
1706
1757
  }
1707
1758
  }
1759
+ if (key.name === "p") {
1760
+ togglePrivacyMode();
1761
+ state.sessions = toSessionRows(state.rawSessions);
1762
+ rerender();
1763
+ return;
1764
+ }
1708
1765
  if (key.name === "q" || key.name === "escape") {
1709
1766
  state.running = false;
1710
1767
  cleanupInput();
@@ -1806,6 +1863,11 @@ async function startInteractiveList(sessionRows, rawSessions, total) {
1806
1863
  return;
1807
1864
  }
1808
1865
  if (showingDetail) {
1866
+ if (key.name === "p") {
1867
+ togglePrivacyMode();
1868
+ rerender();
1869
+ return;
1870
+ }
1809
1871
  if (key.name === "escape" || key.name === "q") {
1810
1872
  showingDetail = false;
1811
1873
  detailData = null;
@@ -1853,6 +1915,11 @@ async function startInteractiveList(sessionRows, rawSessions, total) {
1853
1915
  }
1854
1916
  return;
1855
1917
  }
1918
+ if (key.name === "p") {
1919
+ togglePrivacyMode();
1920
+ rerender();
1921
+ return;
1922
+ }
1856
1923
  if (key.name === "q" || key.name === "escape") {
1857
1924
  running = false;
1858
1925
  cleanupInput();
@@ -1885,6 +1952,7 @@ var init_app = __esm({
1885
1952
  init_SessionDetail();
1886
1953
  init_ShortcutBar();
1887
1954
  init_theme();
1955
+ init_pin_mask();
1888
1956
  }
1889
1957
  });
1890
1958
 
@@ -1902,6 +1970,7 @@ import * as p3 from "@clack/prompts";
1902
1970
 
1903
1971
  // src/components/SessionTable.tsx
1904
1972
  init_theme();
1973
+ init_pin_mask();
1905
1974
  import { Table, Box } from "terminui/jsx";
1906
1975
  import { fillConstraint as fillConstraint2, lengthConstraint as lengthConstraint2 } from "terminui";
1907
1976
  import { jsx as jsx2 } from "terminui/jsx-runtime";
@@ -1923,7 +1992,7 @@ function SessionTable({ sessions, total }) {
1923
1992
  const header = ["Name", "PIN", "Status", "Date", "Duration", "Ppl"];
1924
1993
  const rows = sessions.map((s) => [
1925
1994
  s.name,
1926
- s.pin,
1995
+ maskPin(s.pin),
1927
1996
  s.status,
1928
1997
  s.date,
1929
1998
  s.duration,
@@ -2221,6 +2290,7 @@ var deleteCommand = new Command5("delete").alias("rm").description("Delete a ses
2221
2290
 
2222
2291
  // src/index.ts
2223
2292
  init_theme();
2293
+ init_config();
2224
2294
  var program = new Command6();
2225
2295
  program.name("audiencemeter").description(
2226
2296
  `${BRAND.name} CLI \u2014 ${BRAND.tagline}`
@@ -2232,6 +2302,17 @@ program.addCommand(createCommand);
2232
2302
  program.addCommand(listCommand);
2233
2303
  program.addCommand(showCommand);
2234
2304
  program.addCommand(deleteCommand);
2305
+ var configCommand = new Command6("config").description("Manage CLI preferences");
2306
+ configCommand.command("privacy [value]").description("Get or set privacy mode (true/false). When on, PINs are hidden.").action((value) => {
2307
+ if (value === void 0) {
2308
+ console.log(`privacy: ${getPrivacyMode()}`);
2309
+ } else {
2310
+ const boolValue = value === "true" || value === "1";
2311
+ setPrivacyMode(boolValue);
2312
+ console.log(`privacy mode ${boolValue ? "enabled" : "disabled"}`);
2313
+ }
2314
+ });
2315
+ program.addCommand(configCommand);
2235
2316
  var hasArgs = process.argv.length > 2;
2236
2317
  if (hasArgs) {
2237
2318
  program.parse(process.argv);
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';\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"]}
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/pin-mask.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 privacyMode: {\n type: 'boolean' as const,\n default: true,\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\nexport function getPrivacyMode(): boolean {\n return config.get('privacyMode') as boolean;\n}\n\nexport function setPrivacyMode(value: boolean): void {\n config.set('privacyMode', value);\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 { getPrivacyMode, setPrivacyMode } from './config.js';\n\nexport { getPrivacyMode } from './config.js';\n\n/**\n * Mask a PIN string when privacy mode is on.\n * Returns '*'.repeat(pin.length) when hidden, or the raw PIN when visible.\n */\nexport function maskPin(pin: string): string {\n if (!pin || pin === '--') return pin;\n return getPrivacyMode() ? '*'.repeat(pin.length) : pin;\n}\n\n/**\n * Toggle privacy mode and persist it. Returns the new value (true = private).\n */\nexport function togglePrivacyMode(): boolean {\n const newValue = !getPrivacyMode();\n setPrivacyMode(newValue);\n return newValue;\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 Shortcut {\n readonly key: string;\n readonly label: string;\n readonly active?: boolean;\n}\n\nexport interface ShortcutBarProps {\n readonly shortcuts: readonly Shortcut[];\n}\n\nexport function ShortcutBar({ shortcuts }: ShortcutBarProps) {\n const text = shortcuts.map((s) => {\n if (s.active) return `${s.key}: [${s.label}]`;\n return `${s.key}: ${s.label}`;\n }).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';\nimport { maskPin } from '../lib/pin-mask.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 readonly privacyMode?: boolean;\n}\n\nconst TAB_TITLES = ['Dashboard', 'Sessions', 'Create', 'Auth'] as const;\n\nfunction getShortcuts(privacyMode: boolean) {\n return [\n { key: '1-4', label: 'tab' },\n { key: 'j/k', label: 'navigate' },\n { key: 'Enter', label: 'select' },\n { key: 'p', label: privacyMode ? 'privacy on' : 'privacy', active: privacyMode },\n { key: 'q', label: 'quit' },\n ];\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} ${maskPin(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)} ${maskPin(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, privacyMode = false }: 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={getShortcuts(privacyMode)} />\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={getShortcuts(privacyMode)} />\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';\nimport { maskPin } from '../lib/pin-mask.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', maskPin(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/${maskPin(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 { maskPin, togglePrivacyMode, getPrivacyMode } from './pin-mask.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 privacyMode={getPrivacyMode()}\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 privacyOn = getPrivacyMode();\n const detailShortcuts = [\n { key: 'q', label: 'back' },\n { key: 'p', label: privacyOn ? 'privacy on' : 'privacy', active: privacyOn },\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)} ${maskPin(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 <ShortcutBar shortcuts={[\n { key: 'j/k', label: 'navigate' },\n { key: 'Enter', label: 'view' },\n { key: 'p', label: getPrivacyMode() ? 'privacy on' : 'privacy', active: getPrivacyMode() },\n { key: 'q', label: 'quit' },\n ]} />\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\n if (state.showingSession) {\n if (key.name === 'p') {\n togglePrivacyMode();\n rerender();\n return;\n }\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 // Toggle PIN visibility\n if (key.name === 'p') {\n togglePrivacyMode();\n state.sessions = toSessionRows(state.rawSessions);\n rerender();\n return;\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\n if (showingDetail) {\n if (key.name === 'p') {\n togglePrivacyMode();\n rerender();\n return;\n }\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 // Toggle PIN visibility\n if (key.name === 'p') {\n togglePrivacyMode();\n rerender();\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';\nimport { getPrivacyMode, setPrivacyMode } from './lib/config.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// Config command for CLI preferences\nconst configCommand = new Command('config')\n .description('Manage CLI preferences');\n\nconfigCommand\n .command('privacy [value]')\n .description('Get or set privacy mode (true/false). When on, PINs are hidden.')\n .action((value?: string) => {\n if (value === undefined) {\n console.log(`privacy: ${getPrivacyMode()}`);\n } else {\n const boolValue = value === 'true' || value === '1';\n setPrivacyMode(boolValue);\n console.log(`privacy mode ${boolValue ? 'enabled' : 'disabled'}`);\n }\n });\n\nprogram.addCommand(configCommand);\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';\nimport { maskPin } from '../lib/pin-mask.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 maskPin(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.1",
3
+ "version": "0.2.0",
4
4
  "description": "AudienceMeter CLI - Beautiful terminal UI for managing speaker feedback sessions",
5
5
  "type": "module",
6
6
  "license": "MIT",