audiencemeter 0.1.1 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -11,13 +11,18 @@ var __export = (target, all) => {
11
11
  // src/lib/config.ts
12
12
  var config_exports = {};
13
13
  __export(config_exports, {
14
+ DEFAULT_API_URL: () => DEFAULT_API_URL,
14
15
  clearAuthToken: () => clearAuthToken,
15
16
  getApiUrl: () => getApiUrl,
16
17
  getAuthToken: () => getAuthToken,
17
18
  getConfig: () => getConfig,
19
+ getConfigPath: () => getConfigPath,
20
+ getPrivacyMode: () => getPrivacyMode,
18
21
  getRefreshToken: () => getRefreshToken,
22
+ resetApiUrl: () => resetApiUrl,
19
23
  setApiUrl: () => setApiUrl,
20
24
  setAuthToken: () => setAuthToken,
25
+ setPrivacyMode: () => setPrivacyMode,
21
26
  setRefreshToken: () => setRefreshToken
22
27
  });
23
28
  import Conf from "conf";
@@ -52,17 +57,32 @@ function getApiUrl() {
52
57
  function setApiUrl(url) {
53
58
  config.set("apiUrl", url);
54
59
  }
55
- var config;
60
+ function resetApiUrl() {
61
+ config.set("apiUrl", DEFAULT_API_URL);
62
+ return DEFAULT_API_URL;
63
+ }
64
+ function getConfigPath() {
65
+ return config.path;
66
+ }
67
+ function getPrivacyMode() {
68
+ return config.get("privacyMode");
69
+ }
70
+ function setPrivacyMode(value) {
71
+ config.set("privacyMode", value);
72
+ }
73
+ var DEFAULT_API_URL, STALE_API_HOSTS, config;
56
74
  var init_config = __esm({
57
75
  "src/lib/config.ts"() {
58
76
  "use strict";
77
+ DEFAULT_API_URL = "https://api.audiencemeter.pro/v1";
78
+ STALE_API_HOSTS = ["api.pulsechecker.com", "pulsechecker.com"];
59
79
  config = new Conf({
60
80
  projectName: "audiencemeter",
61
81
  projectSuffix: "",
62
82
  schema: {
63
83
  apiUrl: {
64
84
  type: "string",
65
- default: "https://api.audiencemeter.pro/v1"
85
+ default: DEFAULT_API_URL
66
86
  },
67
87
  authToken: {
68
88
  type: "string",
@@ -71,6 +91,10 @@ var init_config = __esm({
71
91
  refreshToken: {
72
92
  type: "string",
73
93
  default: ""
94
+ },
95
+ privacyMode: {
96
+ type: "boolean",
97
+ default: true
74
98
  }
75
99
  }
76
100
  });
@@ -87,13 +111,24 @@ var init_config = __esm({
87
111
  if (oldData.refreshToken) {
88
112
  config.set("refreshToken", oldData.refreshToken);
89
113
  }
90
- if (oldData.apiUrl && oldData.apiUrl !== "https://api.audiencemeter.pro/v1") {
114
+ if (oldData.apiUrl && oldData.apiUrl !== DEFAULT_API_URL) {
91
115
  config.set("apiUrl", oldData.apiUrl);
92
116
  }
93
117
  fs.rmSync(path.dirname(oldPath), { recursive: true, force: true });
94
118
  } catch {
95
119
  }
96
120
  })();
121
+ (function migrateStaleApiUrl() {
122
+ try {
123
+ const current = config.get("apiUrl");
124
+ if (!current) return;
125
+ const isStale = STALE_API_HOSTS.some((host) => current.includes(host));
126
+ if (isStale) {
127
+ config.set("apiUrl", DEFAULT_API_URL);
128
+ }
129
+ } catch {
130
+ }
131
+ })();
97
132
  }
98
133
  });
99
134
 
@@ -150,7 +185,7 @@ var init_theme = __esm({
150
185
  BRAND = {
151
186
  name: "AudienceMeter",
152
187
  tagline: "Speaker feedback, beautifully managed",
153
- version: "0.1.1"
188
+ version: "0.2.0"
154
189
  };
155
190
  }
156
191
  });
@@ -316,7 +351,7 @@ __export(auth_exports, {
316
351
  });
317
352
  import { Command } from "commander";
318
353
  import http from "http";
319
- import { URL } from "url";
354
+ import { URL as URL2 } from "url";
320
355
  import * as p from "@clack/prompts";
321
356
  var SUPABASE_URL, authCommand, loginCommand, logoutCommand;
322
357
  var init_auth = __esm({
@@ -343,7 +378,7 @@ var init_auth = __esm({
343
378
  res.end("Bad request");
344
379
  return;
345
380
  }
346
- const url = new URL(req.url, "http://localhost");
381
+ const url = new URL2(req.url, "http://localhost");
347
382
  if (url.pathname === "/callback") {
348
383
  res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
349
384
  res.end(`<!DOCTYPE html>
@@ -596,7 +631,31 @@ var init_api_client = __esm({
596
631
  if (body !== void 0) {
597
632
  options.body = JSON.stringify(body);
598
633
  }
599
- const response = await fetch(url, options);
634
+ let response;
635
+ try {
636
+ response = await fetch(url, options);
637
+ } catch (err) {
638
+ const cause = err?.cause;
639
+ const code = cause?.code;
640
+ const detail = cause?.message || (err instanceof Error ? err.message : String(err));
641
+ let hint = "";
642
+ if (code === "ENOTFOUND") {
643
+ hint = `
644
+ Cannot resolve host. The API URL may be wrong or out of date.
645
+ Fix: audiencemeter config api-url <url> (or: audiencemeter config reset)`;
646
+ } else if (code === "ECONNREFUSED") {
647
+ hint = `
648
+ Connection refused. Is the API server running and reachable?`;
649
+ } else if (code === "CERT_HAS_EXPIRED" || code === "UNABLE_TO_VERIFY_LEAF_SIGNATURE") {
650
+ hint = `
651
+ TLS certificate problem for the API host.`;
652
+ } else {
653
+ hint = `
654
+ Check your network connection and API URL.
655
+ Fix: audiencemeter config api-url <url> (or: audiencemeter config reset)`;
656
+ }
657
+ throw new Error(`Cannot reach ${this.baseUrl} (${code || "network error"}): ${detail}${hint}`);
658
+ }
600
659
  if (!response.ok) {
601
660
  let errorMessage;
602
661
  try {
@@ -916,6 +975,24 @@ var init_create = __esm({
916
975
  }
917
976
  });
918
977
 
978
+ // src/lib/pin-mask.ts
979
+ function maskPin(pin) {
980
+ if (!pin || pin === "--") return pin;
981
+ return getPrivacyMode() ? "*".repeat(pin.length) : pin;
982
+ }
983
+ function togglePrivacyMode() {
984
+ const newValue = !getPrivacyMode();
985
+ setPrivacyMode(newValue);
986
+ return newValue;
987
+ }
988
+ var init_pin_mask = __esm({
989
+ "src/lib/pin-mask.ts"() {
990
+ "use strict";
991
+ init_config();
992
+ init_config();
993
+ }
994
+ });
995
+
919
996
  // src/lib/node-backend.ts
920
997
  function createNodeBackend() {
921
998
  const stdout = process.stdout;
@@ -1089,7 +1166,10 @@ var init_TabBar = __esm({
1089
1166
  import { Text as Text3 } from "terminui/jsx";
1090
1167
  import { jsx as jsx5 } from "terminui/jsx-runtime";
1091
1168
  function ShortcutBar({ shortcuts }) {
1092
- const text2 = shortcuts.map((s) => `${s.key}: ${s.label}`).join(" | ");
1169
+ const text2 = shortcuts.map((s) => {
1170
+ if (s.active) return `${s.key}: [${s.label}]`;
1171
+ return `${s.key}: ${s.label}`;
1172
+ }).join(" | ");
1093
1173
  return /* @__PURE__ */ jsx5(Text3, { fg: BRAND_COLORS.dimCyan, children: ` ${text2}` });
1094
1174
  }
1095
1175
  var init_ShortcutBar = __esm({
@@ -1103,9 +1183,18 @@ var init_ShortcutBar = __esm({
1103
1183
  import { VStack as VStack2, HStack as HStack2, Box as Box2, Text as Text4, List, Gauge } from "terminui/jsx";
1104
1184
  import { fillConstraint as fillConstraint3, lengthConstraint as lengthConstraint3, createListState, createStyle as createStyle2, Modifier as Modifier2 } from "terminui";
1105
1185
  import { jsx as jsx6, jsxs as jsxs2 } from "terminui/jsx-runtime";
1186
+ function getShortcuts(privacyMode) {
1187
+ return [
1188
+ { key: "1-4", label: "tab" },
1189
+ { key: "j/k", label: "navigate" },
1190
+ { key: "Enter", label: "select" },
1191
+ { key: "p", label: privacyMode ? "privacy on" : "privacy", active: privacyMode },
1192
+ { key: "q", label: "quit" }
1193
+ ];
1194
+ }
1106
1195
  function DashboardTab({ sessions, stats, selectedIndex, loading }) {
1107
1196
  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."];
1197
+ 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
1198
  const listState = createListState();
1110
1199
  listState.selected = recent.length > 0 ? selectedIndex : void 0;
1111
1200
  return /* @__PURE__ */ jsxs2(HStack2, { constraints: [fillConstraint3(2), fillConstraint3(1)], children: [
@@ -1136,7 +1225,7 @@ function SessionsTab({ sessions, selectedIndex, loading }) {
1136
1225
  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
1226
  }
1138
1227
  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}`
1228
+ (s) => `${icon.session} ${s.name.padEnd(30).slice(0, 30)} ${maskPin(s.pin)} ${s.status.padEnd(10).slice(0, 10)} ${s.date}`
1140
1229
  );
1141
1230
  const listState = createListState();
1142
1231
  listState.selected = selectedIndex;
@@ -1159,7 +1248,7 @@ function AuthTab({ authEmail, authExpired }) {
1159
1248
  }
1160
1249
  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
1250
  }
1162
- function Dashboard({ selectedTab, sessions, stats, selectedIndex, authEmail, authExpired, loading, error }) {
1251
+ function Dashboard({ selectedTab, sessions, stats, selectedIndex, authEmail, authExpired, loading, error, privacyMode = false }) {
1163
1252
  let content;
1164
1253
  switch (selectedTab) {
1165
1254
  case 0:
@@ -1183,17 +1272,17 @@ function Dashboard({ selectedTab, sessions, stats, selectedIndex, authEmail, aut
1183
1272
  /* @__PURE__ */ jsx6(TabBar, { titles: [...TAB_TITLES], selected: selectedTab }),
1184
1273
  /* @__PURE__ */ jsx6(Text4, { fg: BRAND_COLORS.yellow, align: "center", children: `${icon.cross} ${error}` }),
1185
1274
  content,
1186
- /* @__PURE__ */ jsx6(ShortcutBar, { shortcuts: SHORTCUTS })
1275
+ /* @__PURE__ */ jsx6(ShortcutBar, { shortcuts: getShortcuts(privacyMode) })
1187
1276
  ] });
1188
1277
  }
1189
1278
  return /* @__PURE__ */ jsxs2(VStack2, { constraints: [lengthConstraint3(1), lengthConstraint3(3), fillConstraint3(1), lengthConstraint3(1)], children: [
1190
1279
  /* @__PURE__ */ jsx6(Header, {}),
1191
1280
  /* @__PURE__ */ jsx6(TabBar, { titles: [...TAB_TITLES], selected: selectedTab }),
1192
1281
  content,
1193
- /* @__PURE__ */ jsx6(ShortcutBar, { shortcuts: SHORTCUTS })
1282
+ /* @__PURE__ */ jsx6(ShortcutBar, { shortcuts: getShortcuts(privacyMode) })
1194
1283
  ] });
1195
1284
  }
1196
- var TAB_TITLES, SHORTCUTS;
1285
+ var TAB_TITLES;
1197
1286
  var init_Dashboard = __esm({
1198
1287
  "src/components/Dashboard.tsx"() {
1199
1288
  "use strict";
@@ -1201,13 +1290,8 @@ var init_Dashboard = __esm({
1201
1290
  init_Header();
1202
1291
  init_TabBar();
1203
1292
  init_ShortcutBar();
1293
+ init_pin_mask();
1204
1294
  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
1295
  }
1212
1296
  });
1213
1297
 
@@ -1295,7 +1379,7 @@ function SessionDetail({ session, metrics, timeline, analysis, status }) {
1295
1379
  const dateStr = session.date ? new Date(session.date).toLocaleString() : session.createdAt ? new Date(session.createdAt).toLocaleString() : "--";
1296
1380
  const durationStr = session.durationMinutes ? `${session.durationMinutes} minutes` : "--";
1297
1381
  const infoPairs = [
1298
- ["PIN", session.pin || "--"],
1382
+ ["PIN", maskPin(session.pin || "--")],
1299
1383
  ["Date", dateStr],
1300
1384
  ["Duration", durationStr]
1301
1385
  ];
@@ -1399,7 +1483,7 @@ function SessionDetail({ session, metrics, timeline, analysis, status }) {
1399
1483
  }
1400
1484
  if (session.pin) {
1401
1485
  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}` }) })
1486
+ /* @__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
1487
  );
1404
1488
  sectionConstraints.push(lengthConstraint5(3));
1405
1489
  }
@@ -1411,6 +1495,7 @@ var init_SessionDetail = __esm({
1411
1495
  init_theme();
1412
1496
  init_KeyValue();
1413
1497
  init_MetricsPanel();
1498
+ init_pin_mask();
1414
1499
  }
1415
1500
  });
1416
1501
 
@@ -1474,13 +1559,16 @@ function renderDashboard(terminal, state) {
1474
1559
  authEmail: state.authEmail,
1475
1560
  authExpired: state.authExpired,
1476
1561
  loading: state.loading,
1477
- error: state.error
1562
+ error: state.error,
1563
+ privacyMode: getPrivacyMode()
1478
1564
  }
1479
1565
  ));
1480
1566
  }
1481
1567
  function renderSessionDetail(terminal, session, metrics, timeline, analysis, status) {
1568
+ const privacyOn = getPrivacyMode();
1482
1569
  const detailShortcuts = [
1483
- { key: "Esc/q", label: "back" }
1570
+ { key: "q", label: "back" },
1571
+ { key: "p", label: privacyOn ? "privacy on" : "privacy", active: privacyOn }
1484
1572
  ];
1485
1573
  terminalDrawJsx2(terminal, /* @__PURE__ */ jsxs4(VStack5, { constraints: [fillConstraint5(1), lengthConstraint6(1)], children: [
1486
1574
  /* @__PURE__ */ jsx9(
@@ -1498,7 +1586,7 @@ function renderSessionDetail(terminal, session, metrics, timeline, analysis, sta
1498
1586
  }
1499
1587
  function renderInteractiveList(terminal, sessionRows, total, selectedIndex) {
1500
1588
  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}`
1589
+ (s) => `${icon.session} ${s.name.padEnd(30).slice(0, 30)} ${maskPin(s.pin)} ${s.status.padEnd(10).slice(0, 10)} ${s.date}`
1502
1590
  );
1503
1591
  const listState = createListState2();
1504
1592
  listState.selected = selectedIndex;
@@ -1513,7 +1601,12 @@ function renderInteractiveList(terminal, sessionRows, total, selectedIndex) {
1513
1601
  highlightStyle: createStyle3({ fg: BRAND_COLORS.purple, addModifier: Modifier3.BOLD })
1514
1602
  }
1515
1603
  ) }),
1516
- /* @__PURE__ */ jsx9(Text7, { fg: BRAND_COLORS.dimCyan, children: " j/k: navigate | Enter: view | q: quit" })
1604
+ /* @__PURE__ */ jsx9(ShortcutBar, { shortcuts: [
1605
+ { key: "j/k", label: "navigate" },
1606
+ { key: "Enter", label: "view" },
1607
+ { key: "p", label: getPrivacyMode() ? "privacy on" : "privacy", active: getPrivacyMode() },
1608
+ { key: "q", label: "quit" }
1609
+ ] })
1517
1610
  ] }));
1518
1611
  }
1519
1612
  async function fetchSessionDetail(sessionId) {
@@ -1620,6 +1713,11 @@ async function startDashboard() {
1620
1713
  return;
1621
1714
  }
1622
1715
  if (state.showingSession) {
1716
+ if (key.name === "p") {
1717
+ togglePrivacyMode();
1718
+ rerender();
1719
+ return;
1720
+ }
1623
1721
  if (key.name === "escape" || key.name === "q") {
1624
1722
  state.showingSession = null;
1625
1723
  detailData = null;
@@ -1705,6 +1803,12 @@ async function startDashboard() {
1705
1803
  return;
1706
1804
  }
1707
1805
  }
1806
+ if (key.name === "p") {
1807
+ togglePrivacyMode();
1808
+ state.sessions = toSessionRows(state.rawSessions);
1809
+ rerender();
1810
+ return;
1811
+ }
1708
1812
  if (key.name === "q" || key.name === "escape") {
1709
1813
  state.running = false;
1710
1814
  cleanupInput();
@@ -1806,6 +1910,11 @@ async function startInteractiveList(sessionRows, rawSessions, total) {
1806
1910
  return;
1807
1911
  }
1808
1912
  if (showingDetail) {
1913
+ if (key.name === "p") {
1914
+ togglePrivacyMode();
1915
+ rerender();
1916
+ return;
1917
+ }
1809
1918
  if (key.name === "escape" || key.name === "q") {
1810
1919
  showingDetail = false;
1811
1920
  detailData = null;
@@ -1853,6 +1962,11 @@ async function startInteractiveList(sessionRows, rawSessions, total) {
1853
1962
  }
1854
1963
  return;
1855
1964
  }
1965
+ if (key.name === "p") {
1966
+ togglePrivacyMode();
1967
+ rerender();
1968
+ return;
1969
+ }
1856
1970
  if (key.name === "q" || key.name === "escape") {
1857
1971
  running = false;
1858
1972
  cleanupInput();
@@ -1885,6 +1999,7 @@ var init_app = __esm({
1885
1999
  init_SessionDetail();
1886
2000
  init_ShortcutBar();
1887
2001
  init_theme();
2002
+ init_pin_mask();
1888
2003
  }
1889
2004
  });
1890
2005
 
@@ -1902,6 +2017,7 @@ import * as p3 from "@clack/prompts";
1902
2017
 
1903
2018
  // src/components/SessionTable.tsx
1904
2019
  init_theme();
2020
+ init_pin_mask();
1905
2021
  import { Table, Box } from "terminui/jsx";
1906
2022
  import { fillConstraint as fillConstraint2, lengthConstraint as lengthConstraint2 } from "terminui";
1907
2023
  import { jsx as jsx2 } from "terminui/jsx-runtime";
@@ -1923,7 +2039,7 @@ function SessionTable({ sessions, total }) {
1923
2039
  const header = ["Name", "PIN", "Status", "Date", "Duration", "Ppl"];
1924
2040
  const rows = sessions.map((s) => [
1925
2041
  s.name,
1926
- s.pin,
2042
+ maskPin(s.pin),
1927
2043
  s.status,
1928
2044
  s.date,
1929
2045
  s.duration,
@@ -2221,6 +2337,7 @@ var deleteCommand = new Command5("delete").alias("rm").description("Delete a ses
2221
2337
 
2222
2338
  // src/index.ts
2223
2339
  init_theme();
2340
+ init_config();
2224
2341
  var program = new Command6();
2225
2342
  program.name("audiencemeter").description(
2226
2343
  `${BRAND.name} CLI \u2014 ${BRAND.tagline}`
@@ -2232,6 +2349,44 @@ program.addCommand(createCommand);
2232
2349
  program.addCommand(listCommand);
2233
2350
  program.addCommand(showCommand);
2234
2351
  program.addCommand(deleteCommand);
2352
+ var configCommand = new Command6("config").description("Manage CLI preferences");
2353
+ configCommand.command("privacy [value]").description("Get or set privacy mode (true/false). When on, PINs are hidden.").action((value) => {
2354
+ if (value === void 0) {
2355
+ console.log(`privacy: ${getPrivacyMode()}`);
2356
+ } else {
2357
+ const boolValue = value === "true" || value === "1";
2358
+ setPrivacyMode(boolValue);
2359
+ console.log(`privacy mode ${boolValue ? "enabled" : "disabled"}`);
2360
+ }
2361
+ });
2362
+ configCommand.command("api-url [url]").description("Get or set the API base URL. Omit url to print the current value.").action((url) => {
2363
+ if (url === void 0) {
2364
+ console.log(`apiUrl: ${getApiUrl()}`);
2365
+ return;
2366
+ }
2367
+ try {
2368
+ new URL(url);
2369
+ } catch {
2370
+ console.error(`Invalid URL: ${url}`);
2371
+ process.exit(1);
2372
+ }
2373
+ setApiUrl(url);
2374
+ console.log(`apiUrl -> ${url}`);
2375
+ });
2376
+ configCommand.command("reset").description("Reset API URL to the default. Leaves auth tokens intact.").action(() => {
2377
+ const url = resetApiUrl();
2378
+ console.log(`apiUrl -> ${url} (default)`);
2379
+ });
2380
+ configCommand.command("path").description("Print the location of the CLI config file.").action(() => {
2381
+ console.log(getConfigPath());
2382
+ });
2383
+ configCommand.command("show").description("Print current config (auth tokens redacted).").action(() => {
2384
+ console.log(`configPath: ${getConfigPath()}`);
2385
+ console.log(`apiUrl: ${getApiUrl()}`);
2386
+ console.log(`privacy: ${getPrivacyMode()}`);
2387
+ console.log(`default: ${DEFAULT_API_URL}`);
2388
+ });
2389
+ program.addCommand(configCommand);
2235
2390
  var hasArgs = process.argv.length > 2;
2236
2391
  if (hasArgs) {
2237
2392
  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\nexport const DEFAULT_API_URL = 'https://api.audiencemeter.pro/v1';\n\n// Known-stale API hostnames that should be auto-migrated to the current default.\n// Any apiUrl whose host contains one of these substrings will be reset on startup.\nconst STALE_API_HOSTS = ['api.pulsechecker.com', 'pulsechecker.com'];\n\nconst config = new Conf({\n projectName: 'audiencemeter',\n projectSuffix: '',\n schema: {\n apiUrl: {\n type: 'string' as const,\n default: DEFAULT_API_URL,\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 !== DEFAULT_API_URL) {\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\n// Auto-migrate stale API URLs (e.g. the unprovisioned api.pulsechecker.com) to\n// the current default. Best-effort; never throws.\n(function migrateStaleApiUrl() {\n try {\n const current = config.get('apiUrl') as string;\n if (!current) return;\n const isStale = STALE_API_HOSTS.some((host) => current.includes(host));\n if (isStale) {\n config.set('apiUrl', DEFAULT_API_URL);\n }\n } catch {\n // best-effort\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 resetApiUrl(): string {\n config.set('apiUrl', DEFAULT_API_URL);\n return DEFAULT_API_URL;\n}\n\nexport function getConfigPath(): string {\n return config.path;\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.2.0',\n};\n","import {\n createTestBackendState,\n createTestBackend,\n createTerminal,\n testBackendCellAt,\n type Cell,\n} from 'terminui';\nimport { terminalDrawJsx } from 'terminui/jsx';\nimport type { JsxNode } from 'terminui/jsx-runtime';\n\n// ── ANSI Color Conversion (shared with node-backend.ts) ──────────────\n\ntype CellColor = { type: string; r?: number; g?: number; b?: number; index?: number };\n\nconst NAMED_FG: Record<string, string> = {\n black: '30', red: '31', green: '32', yellow: '33', blue: '34',\n magenta: '35', cyan: '36', gray: '37', white: '97',\n 'dark-gray': '90', 'light-red': '91', 'light-green': '92',\n 'light-yellow': '93', 'light-blue': '94', 'light-magenta': '95', 'light-cyan': '96',\n};\n\nconst NAMED_BG: Record<string, string> = {\n black: '40', red: '41', green: '42', yellow: '43', blue: '44',\n magenta: '45', cyan: '46', gray: '47', white: '107',\n 'dark-gray': '100', 'light-red': '101', 'light-green': '102',\n 'light-yellow': '103', 'light-blue': '104', 'light-magenta': '105', 'light-cyan': '106',\n};\n\nconst RESET = '\\x1b[0m';\n\nexport function fgAnsi(c: CellColor | undefined): string {\n if (!c || c.type === 'reset') return '';\n if (c.type === 'rgb') return `\\x1b[38;2;${c.r};${c.g};${c.b}m`;\n if (c.type === 'indexed') return `\\x1b[38;5;${c.index}m`;\n return NAMED_FG[c.type] ? `\\x1b[${NAMED_FG[c.type]}m` : '';\n}\n\nexport function bgAnsi(c: CellColor | undefined): string {\n if (!c || c.type === 'reset') return '';\n if (c.type === 'rgb') return `\\x1b[48;2;${c.r};${c.g};${c.b}m`;\n if (c.type === 'indexed') return `\\x1b[48;5;${c.index}m`;\n return NAMED_BG[c.type] ? `\\x1b[${NAMED_BG[c.type]}m` : '';\n}\n\nexport function modAnsi(mod: number | undefined): string {\n if (!mod) return '';\n let s = '';\n if (mod & 1) s += '\\x1b[1m'; // Bold\n if (mod & 2) s += '\\x1b[2m'; // Dim\n if (mod & 4) s += '\\x1b[3m'; // Italic\n if (mod & 8) s += '\\x1b[4m'; // Underline\n if (mod & 64) s += '\\x1b[7m'; // Reversed\n return s;\n}\n\n/**\n * Convert a terminui Cell to an ANSI escape string (style + symbol).\n */\nexport function cellToAnsi(cell: Cell): string {\n const fg = fgAnsi(cell.fg as CellColor);\n const bg = bgAnsi(cell.bg as CellColor);\n const mod = modAnsi(cell.modifier);\n const style = fg + bg + mod;\n if (style) {\n return style + cell.symbol + RESET;\n }\n return cell.symbol;\n}\n\n// ── Render JSX to String (static commands) ───────────────────────────\n\n/**\n * Renders a JSX node tree to a styled ANSI string using the test backend.\n * Used for print-and-exit commands (list, show, create, delete, auth).\n */\nexport function renderJsxToString(width: number, height: number, node: JsxNode): string {\n const state = createTestBackendState(width, height);\n const terminal = createTerminal(createTestBackend(state));\n terminalDrawJsx(terminal, node);\n\n // Reconstruct ANSI-styled output from the cell grid\n const lines: string[] = [];\n for (let y = 0; y < height; y++) {\n let line = '';\n let hasStyle = false;\n for (let x = 0; x < width; x++) {\n const cell = testBackendCellAt(state, x, y) as {\n symbol: string; fg?: CellColor; bg?: CellColor; modifier?: number;\n } | undefined;\n if (!cell) {\n if (hasStyle) { line += RESET; hasStyle = false; }\n line += ' ';\n continue;\n }\n const style = fgAnsi(cell.fg) + bgAnsi(cell.bg) + modAnsi(cell.modifier);\n if (style) {\n if (hasStyle) line += RESET;\n line += style + cell.symbol;\n hasStyle = true;\n } else {\n if (hasStyle) { line += RESET; hasStyle = false; }\n line += cell.symbol;\n }\n }\n if (hasStyle) line += RESET;\n lines.push(line.trimEnd());\n }\n\n // Trim trailing empty lines\n while (lines.length > 0 && stripAnsi(lines[lines.length - 1]!).trim() === '') {\n lines.pop();\n }\n\n return lines.join('\\n');\n}\n\n// ── Utilities ────────────────────────────────────────────────────────\n\n/**\n * Returns the usable terminal width, capped at 120 columns.\n */\nexport function getTermWidth(): number {\n return Math.min(process.stdout.columns || 80, 120);\n}\n\n/**\n * Strips all ANSI escape sequences from a string.\n */\nexport function stripAnsi(s: string): string {\n return s.replace(/\\x1b\\[[0-9;]*m/g, '');\n}\n","import { VStack, HStack, Text } from 'terminui/jsx';\nimport { lengthConstraint, fillConstraint } from 'terminui';\nimport { BRAND_COLORS } from '../lib/theme.js';\n\nexport interface KeyValueProps {\n readonly pairs: readonly (readonly [string, string])[];\n}\n\nexport function KeyValue({ pairs }: KeyValueProps) {\n const maxKeyLen = Math.max(...pairs.map(([k]) => k.length));\n const constraints = pairs.map(() => lengthConstraint(1));\n\n const rows = pairs.map(([key, value]) => {\n const padded = key.padStart(maxKeyLen);\n return (\n <HStack constraints={[lengthConstraint(maxKeyLen + 2), fillConstraint(1)]}>\n <Text fg={BRAND_COLORS.dim}>{padded + ' '}</Text>\n <Text bold fg={BRAND_COLORS.white}>{value}</Text>\n </HStack>\n );\n });\n\n return (\n <VStack constraints={constraints}>\n {rows}\n </VStack>\n );\n}\n","import { Command } from 'commander';\nimport http from 'node:http';\nimport { URL } from 'node:url';\nimport * as p from '@clack/prompts';\nimport { setAuthToken, clearAuthToken, getApiUrl, setRefreshToken } from '../lib/config.js';\nimport { BRAND, icon } from '../lib/theme.js';\nimport { renderJsxToString, getTermWidth } from '../lib/render.js';\nimport { KeyValue } from '../components/KeyValue.js';\n\nconst SUPABASE_URL = 'https://gflvvytymdmrbjpmymhb.supabase.co';\n\nexport const authCommand = new Command('auth').description(\n 'Manage authentication'\n);\n\nexport const loginCommand = new Command('login')\n .description('Log in via browser (Google OAuth)');\n\nloginCommand.action(async () => {\n p.intro(`${BRAND.name} -- Login`);\n\n const s = p.spinner();\n s.start('Starting local auth server...');\n\n try {\n const token = await new Promise<string>((resolve, reject) => {\n const server = http.createServer((req, res) => {\n if (!req.url) {\n res.writeHead(400);\n res.end('Bad request');\n return;\n }\n\n const url = new URL(req.url, 'http://localhost');\n\n if (url.pathname === '/callback') {\n res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });\n res.end(`<!DOCTYPE html>\n<html><head><meta charset=\"utf-8\"><title>${BRAND.name} — Login</title>\n<style>body{font-family:system-ui;display:flex;justify-content:center;align-items:center;height:100vh;margin:0;background:#0a0a0a;color:#e5e5e5}\n.card{text-align:center;padding:2rem;border-radius:12px;background:#171717;border:1px solid #333}</style></head>\n<body><div class=\"card\"><p>Processing authentication...</p></div>\n<script>\nconst h=window.location.hash.substring(1);const p=new URLSearchParams(h);const t=p.get('access_token');const r=p.get('refresh_token');\nif(t){let u='/token?access_token='+encodeURIComponent(t);if(r)u+='&refresh_token='+encodeURIComponent(r);window.location.href=u}\nelse{document.querySelector('.card').innerHTML='<p style=\"color:#f87171\">Authentication failed. No token found.</p><p>You can close this tab.</p>'}\n</script></body></html>`);\n return;\n }\n\n if (url.pathname === '/token') {\n const accessToken = url.searchParams.get('access_token');\n const refreshTokenParam = url.searchParams.get('refresh_token');\n if (accessToken) {\n if (refreshTokenParam) {\n setRefreshToken(refreshTokenParam);\n }\n res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });\n res.end(`<!DOCTYPE html>\n<html><head><meta charset=\"utf-8\"><title>${BRAND.name} — Logged In</title>\n<style>body{font-family:system-ui;display:flex;justify-content:center;align-items:center;height:100vh;margin:0;background:#0a0a0a;color:#e5e5e5}\n.card{text-align:center;padding:2rem;border-radius:12px;background:#171717;border:1px solid #333}\n.check{font-size:3rem;margin-bottom:1rem}</style></head>\n<body><div class=\"card\"><div class=\"check\">&#x2714;</div><h2>Logged in!</h2><p>Return to your terminal.</p></div></body></html>`);\n resolve(accessToken);\n server.close();\n } else {\n res.writeHead(400, { 'Content-Type': 'text/html' });\n res.end('<p>Missing access token.</p>');\n }\n return;\n }\n\n res.writeHead(404);\n res.end('Not found');\n });\n\n server.listen(0, () => {\n const address = server.address();\n if (!address || typeof address === 'string') {\n reject(new Error('Failed to start local server'));\n return;\n }\n\n const port = address.port;\n const redirectUrl = `http://localhost:${port}/callback`;\n const authUrl = `${SUPABASE_URL}/auth/v1/authorize?provider=google&redirect_to=${encodeURIComponent(redirectUrl)}`;\n\n s.message('Opening browser for authentication...');\n\n import('open')\n .then((m) => m.default(authUrl))\n .catch(() => {\n s.stop('Could not open browser automatically');\n p.note(authUrl, 'Open this URL manually');\n });\n });\n\n setTimeout(() => {\n server.close();\n reject(new Error('Authentication timed out after 120 seconds'));\n }, 120_000);\n });\n\n setAuthToken(token);\n s.stop(`${icon.check} Logged in successfully!`);\n\n // Show user info\n const payload = JSON.parse(\n Buffer.from(token.split('.')[1]!, 'base64').toString()\n ) as { email?: string };\n\n if (payload.email) {\n p.log.info(`Signed in as ${payload.email}`);\n }\n\n p.outro('Token stored. You can now use AudienceMeter CLI commands.');\n process.exit(0);\n } catch (error) {\n s.stop(\n `${icon.cross} Login failed: ${error instanceof Error ? error.message : 'Unknown error'}`\n );\n process.exit(1);\n }\n });\n\nexport const logoutCommand = new Command('logout')\n .description('Log out and clear stored credentials')\n .action(async () => {\n clearAuthToken();\n p.log.success(`${icon.check} Logged out successfully.`);\n });\n\nauthCommand\n .command('whoami')\n .description('Show current authenticated user')\n .action(async () => {\n try {\n const { getAuthToken } = await import('../lib/config.js');\n const token = getAuthToken();\n const apiUrl = getApiUrl();\n\n const payload = JSON.parse(\n Buffer.from(token.split('.')[1]!, 'base64').toString()\n ) as { email?: string; sub?: string };\n\n const output = renderJsxToString(\n getTermWidth(),\n 3,\n KeyValue({\n pairs: [\n ['Email', payload.email || 'unknown'],\n ['User ID', payload.sub || 'unknown'],\n ['API URL', apiUrl],\n ],\n })\n );\n console.log(output);\n } catch (error) {\n if (\n error instanceof Error &&\n error.message.includes('Not authenticated')\n ) {\n p.log.warn('Not logged in. Run: audiencemeter login');\n } else {\n p.log.error(\n error instanceof Error ? error.message : 'Unknown error'\n );\n }\n }\n });\n\nauthCommand\n .command('token')\n .description('Print the current stored auth token')\n .action(async () => {\n try {\n const { getAuthToken } = await import('../lib/config.js');\n const token = getAuthToken();\n console.log(token);\n } catch (error) {\n if (\n error instanceof Error &&\n error.message.includes('Not authenticated')\n ) {\n p.log.warn('Not logged in. Run: audiencemeter login');\n } else {\n p.log.error(\n error instanceof Error ? error.message : 'Unknown error'\n );\n }\n }\n });\n\n// Register login/logout as subcommands of auth so `auth login` / `auth logout` still works\nauthCommand.addCommand(loginCommand);\nauthCommand.addCommand(logoutCommand);\n","import { getAuthToken, getApiUrl, getRefreshToken, setAuthToken, setRefreshToken } from './config.js';\n\nconst SUPABASE_URL = 'https://gflvvytymdmrbjpmymhb.supabase.co';\nconst SUPABASE_ANON_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImdmbHZ2eXR5bWRtcmJqcG15bWhiIiwicm9sZSI6ImFub24iLCJpYXQiOjE2ODAyNTIwMjIsImV4cCI6MTk5NTgyODAyMn0.1m-3IhFB-87AKk_-UIPzB0O1URgBwl78oKu8sNe8aFU';\n\nexport function isTokenExpired(token: string): boolean {\n try {\n const payload = JSON.parse(\n Buffer.from(token.split('.')[1]!, 'base64').toString()\n ) as { exp?: number };\n if (!payload.exp) return false;\n // Consider expired 60s before actual expiry to avoid edge cases\n return Date.now() >= (payload.exp - 60) * 1000;\n } catch {\n return true;\n }\n}\n\nexport async function refreshAccessToken(): Promise<string | null> {\n const refreshToken = getRefreshToken();\n if (!refreshToken) return null;\n\n try {\n const response = await fetch(`${SUPABASE_URL}/auth/v1/token?grant_type=refresh_token`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'apikey': SUPABASE_ANON_KEY,\n },\n body: JSON.stringify({ refresh_token: refreshToken }),\n });\n\n if (!response.ok) return null;\n\n const data = await response.json() as {\n access_token?: string;\n refresh_token?: string;\n };\n\n if (data.access_token) {\n setAuthToken(data.access_token);\n if (data.refresh_token) {\n setRefreshToken(data.refresh_token);\n }\n return data.access_token;\n }\n return null;\n } catch {\n return null;\n }\n}\n\nexport class ApiClient {\n constructor(\n private baseUrl: string,\n private authToken: string\n ) {}\n\n private async request<T>(\n method: string,\n path: string,\n body?: unknown\n ): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n Authorization: this.authToken,\n };\n\n const options: RequestInit = { method, headers };\n\n if (body !== undefined) {\n options.body = JSON.stringify(body);\n }\n\n let response: Response;\n try {\n response = await fetch(url, options);\n } catch (err) {\n // Network-level failure (DNS, TLS, connection refused, offline, etc.)\n // Surface the actual cause and the URL so users can diagnose/fix config.\n const cause = (err as { cause?: { code?: string; message?: string } })?.cause;\n const code = cause?.code;\n const detail = cause?.message || (err instanceof Error ? err.message : String(err));\n let hint = '';\n if (code === 'ENOTFOUND') {\n hint = `\\nCannot resolve host. The API URL may be wrong or out of date.\\nFix: audiencemeter config api-url <url> (or: audiencemeter config reset)`;\n } else if (code === 'ECONNREFUSED') {\n hint = `\\nConnection refused. Is the API server running and reachable?`;\n } else if (code === 'CERT_HAS_EXPIRED' || code === 'UNABLE_TO_VERIFY_LEAF_SIGNATURE') {\n hint = `\\nTLS certificate problem for the API host.`;\n } else {\n hint = `\\nCheck your network connection and API URL.\\nFix: audiencemeter config api-url <url> (or: audiencemeter config reset)`;\n }\n throw new Error(`Cannot reach ${this.baseUrl} (${code || 'network error'}): ${detail}${hint}`);\n }\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 {\n getPrivacyMode,\n setPrivacyMode,\n getApiUrl,\n setApiUrl,\n resetApiUrl,\n getConfigPath,\n DEFAULT_API_URL,\n} 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\nconfigCommand\n .command('api-url [url]')\n .description('Get or set the API base URL. Omit url to print the current value.')\n .action((url?: string) => {\n if (url === undefined) {\n console.log(`apiUrl: ${getApiUrl()}`);\n return;\n }\n try {\n // Validate URL format; throws if malformed.\n // eslint-disable-next-line no-new\n new URL(url);\n } catch {\n console.error(`Invalid URL: ${url}`);\n process.exit(1);\n }\n setApiUrl(url);\n console.log(`apiUrl -> ${url}`);\n });\n\nconfigCommand\n .command('reset')\n .description('Reset API URL to the default. Leaves auth tokens intact.')\n .action(() => {\n const url = resetApiUrl();\n console.log(`apiUrl -> ${url} (default)`);\n });\n\nconfigCommand\n .command('path')\n .description('Print the location of the CLI config file.')\n .action(() => {\n console.log(getConfigPath());\n });\n\nconfigCommand\n .command('show')\n .description('Print current config (auth tokens redacted).')\n .action(() => {\n console.log(`configPath: ${getConfigPath()}`);\n console.log(`apiUrl: ${getApiUrl()}`);\n console.log(`privacy: ${getPrivacyMode()}`);\n console.log(`default: ${DEFAULT_API_URL}`);\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":["URL","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.1",
4
4
  "description": "AudienceMeter CLI - Beautiful terminal UI for managing speaker feedback sessions",
5
5
  "type": "module",
6
6
  "license": "MIT",