recappi 0.1.27 → 0.1.29

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
@@ -611,7 +611,7 @@ function AccountView({ status }) {
611
611
  function AccountBody({ status }) {
612
612
  return /* @__PURE__ */ jsxs2(Fragment, { children: [
613
613
  /* @__PURE__ */ jsxs2(Box2, { marginTop: 1, flexDirection: "column", children: [
614
- /* @__PURE__ */ jsx4(Text2, { bold: true, color: "magenta", children: status.email ?? status.userId ?? "Signed in" }),
614
+ /* @__PURE__ */ jsx4(Text2, { bold: true, color: "green", children: status.email ?? status.userId ?? "Signed in" }),
615
615
  status.email && status.userId ? /* @__PURE__ */ jsx4(Text2, { dimColor: true, children: status.userId }) : null,
616
616
  /* @__PURE__ */ jsx4(Text2, { dimColor: true, children: `origin ${status.origin}` })
617
617
  ] }),
@@ -677,9 +677,9 @@ import { Box as Box3, Text as Text3 } from "ink";
677
677
  import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
678
678
  function Header({ active }) {
679
679
  return /* @__PURE__ */ jsxs3(Box3, { children: [
680
- /* @__PURE__ */ jsxs3(Text3, { bold: true, color: "magenta", children: [
681
- "Recappi",
682
- " "
680
+ /* @__PURE__ */ jsxs3(Text3, { bold: true, color: "green", children: [
681
+ "\u25CF Recappi",
682
+ " "
683
683
  ] }),
684
684
  /* @__PURE__ */ jsx5(Tab, { num: "1", label: "Overview", active: active === "overview" }),
685
685
  /* @__PURE__ */ jsx5(Tab, { num: "2", label: "Jobs", active: active === "jobs" }),
@@ -691,14 +691,27 @@ function Tab({
691
691
  label,
692
692
  active
693
693
  }) {
694
- const text = ` ${num} ${label} `;
695
694
  if (active) {
696
- return /* @__PURE__ */ jsx5(Text3, { bold: true, inverse: true, color: "cyan", children: text });
695
+ return /* @__PURE__ */ jsx5(Text3, { bold: true, inverse: true, color: "cyan", children: ` ${num} ${label} ` });
697
696
  }
698
- return /* @__PURE__ */ jsx5(Text3, { children: text });
697
+ return /* @__PURE__ */ jsxs3(Text3, { dimColor: true, children: [
698
+ " ",
699
+ /* @__PURE__ */ jsx5(Text3, { color: "cyan", children: num }),
700
+ ` ${label} `
701
+ ] });
699
702
  }
700
703
  function Footer({ keys }) {
701
- return /* @__PURE__ */ jsx5(Box3, { marginTop: 1, children: /* @__PURE__ */ jsx5(Text3, { dimColor: true, children: keys }) });
704
+ const segments = keys.split(" \xB7 ");
705
+ return /* @__PURE__ */ jsx5(Box3, { marginTop: 1, children: /* @__PURE__ */ jsx5(Text3, { children: segments.map((segment, i) => {
706
+ const space = segment.indexOf(" ");
707
+ const key = space === -1 ? segment : segment.slice(0, space);
708
+ const desc = space === -1 ? "" : segment.slice(space);
709
+ return /* @__PURE__ */ jsxs3(Text3, { children: [
710
+ i > 0 ? /* @__PURE__ */ jsx5(Text3, { dimColor: true, children: " \xB7 " }) : null,
711
+ /* @__PURE__ */ jsx5(Text3, { color: "cyan", children: key }),
712
+ /* @__PURE__ */ jsx5(Text3, { dimColor: true, children: desc })
713
+ ] }, `${segment}-${i}`);
714
+ }) }) });
702
715
  }
703
716
  var init_chrome = __esm({
704
717
  "src/tui/chrome.tsx"() {
@@ -898,7 +911,7 @@ function PeekBody({
898
911
  item.contentType || null
899
912
  ].filter(Boolean).join(" \xB7 ");
900
913
  return /* @__PURE__ */ jsxs7(Fragment2, { children: [
901
- /* @__PURE__ */ jsx10(Text8, { bold: true, color: "magenta", wrap: "truncate-end", children: recordingTitle2(item) }),
914
+ /* @__PURE__ */ jsx10(Text8, { bold: true, color: "green", wrap: "truncate-end", children: recordingTitle2(item) }),
902
915
  /* @__PURE__ */ jsx10(Text8, { color: style.color, children: `${style.glyph} ${style.label}` }),
903
916
  meta3 ? /* @__PURE__ */ jsx10(Text8, { dimColor: true, children: meta3 }) : null,
904
917
  /* @__PURE__ */ jsx10(Text8, { dimColor: true, children: formatAge(item.createdAt, nowMs) }),
@@ -1195,7 +1208,7 @@ function RecordingDetailView({
1195
1208
  });
1196
1209
  return /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", paddingX: 1, children: [
1197
1210
  /* @__PURE__ */ jsx13(Text11, { dimColor: true, children: "\u2039 Recordings" }),
1198
- /* @__PURE__ */ jsx13(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx13(Text11, { bold: true, color: "magenta", children: title }) }),
1211
+ /* @__PURE__ */ jsx13(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx13(Text11, { bold: true, color: "green", children: title }) }),
1199
1212
  /* @__PURE__ */ jsxs10(Text11, { children: [
1200
1213
  /* @__PURE__ */ jsx13(Text11, { color: style.color, children: `${style.glyph} ${style.label}` }),
1201
1214
  /* @__PURE__ */ jsx13(Text11, { dimColor: true, children: ` ${formatAge(item.createdAt, nowMs) || "\u2014"}` })
@@ -1368,7 +1381,7 @@ function TranscriptView({ loading, data, error: error51 }) {
1368
1381
  const more = win.maxScroll > 0;
1369
1382
  const position = total === 0 ? "" : `${win.start + 1}\u2013${win.end} / ${total}`;
1370
1383
  return /* @__PURE__ */ jsxs11(Box12, { flexDirection: "column", paddingX: 1, children: [
1371
- /* @__PURE__ */ jsxs11(Text12, { bold: true, color: "magenta", children: [
1384
+ /* @__PURE__ */ jsxs11(Text12, { bold: true, color: "green", children: [
1372
1385
  title,
1373
1386
  more ? /* @__PURE__ */ jsx14(Text12, { dimColor: true, children: ` ${position}` }) : null
1374
1387
  ] }),
@@ -1415,22 +1428,43 @@ function PermissionPreflightView({
1415
1428
  items
1416
1429
  }) {
1417
1430
  const allGranted = items.length > 0 && items.every((item) => item.status === "granted" && !item.requiresProcessRestart);
1431
+ const hasRestartRequired = items.some((item) => item.requiresProcessRestart);
1418
1432
  return /* @__PURE__ */ jsxs12(Box13, { flexDirection: "column", paddingX: 1, children: [
1419
- /* @__PURE__ */ jsx15(Text13, { dimColor: true, children: "\u2039 Recording permissions" }),
1433
+ /* @__PURE__ */ jsxs12(Text13, { children: [
1434
+ /* @__PURE__ */ jsx15(Text13, { dimColor: true, children: "\u2039 " }),
1435
+ /* @__PURE__ */ jsx15(Text13, { bold: true, color: "cyan", children: "Recording permissions" })
1436
+ ] }),
1420
1437
  /* @__PURE__ */ jsx15(Box13, { marginTop: 1, flexDirection: "column", children: items.length === 0 ? /* @__PURE__ */ jsx15(Text13, { dimColor: true, children: "Checking permissions\u2026" }) : items.map((item) => {
1421
1438
  const status = statusGlyph2(item.status);
1422
- const hint = item.requiresProcessRestart ? "Screen Recording enabled. Run recappi record again to start." : item.status === "granted" ? void 0 : item.hint ?? DEFAULT_HINTS[item.name];
1439
+ const restart = item.requiresProcessRestart === true;
1440
+ const color = restart ? "yellow" : status.color;
1441
+ const hint = restart ? item.hint ?? `${item.name} enabled. Run recappi record again to start.` : item.status === "granted" ? void 0 : item.hint ?? DEFAULT_HINTS[item.name];
1423
1442
  return /* @__PURE__ */ jsxs12(Box13, { flexDirection: "column", children: [
1424
1443
  /* @__PURE__ */ jsxs12(Text13, { children: [
1425
- /* @__PURE__ */ jsx15(Text13, { color: status.color, children: status.glyph }),
1444
+ /* @__PURE__ */ jsx15(Text13, { bold: true, color, children: status.glyph }),
1426
1445
  /* @__PURE__ */ jsx15(Text13, { bold: true, children: ` ${item.name}` }),
1427
- /* @__PURE__ */ jsx15(Text13, { dimColor: true, children: ` ${status.label}` })
1446
+ /* @__PURE__ */ jsx15(Text13, { color, children: ` ${status.label}` })
1428
1447
  ] }),
1429
1448
  hint ? /* @__PURE__ */ jsx15(Text13, { dimColor: true, children: ` ${hint}` }) : null
1430
1449
  ] }, item.name);
1431
1450
  }) }),
1432
- /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: allGranted ? /* @__PURE__ */ jsx15(Text13, { color: "green", children: "All set \u2014 ready to record." }) : /* @__PURE__ */ jsx15(Text13, { dimColor: true, children: "Grant the permissions above, then press r to recheck." }) }),
1433
- /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(Text13, { dimColor: true, children: "r recheck \xB7 o open System Settings \xB7 esc back" }) })
1451
+ /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: allGranted ? /* @__PURE__ */ jsx15(Text13, { bold: true, color: "green", children: "\u2713 All set \u2014 ready to record." }) : hasRestartRequired ? /* @__PURE__ */ jsxs12(Text13, { children: [
1452
+ /* @__PURE__ */ jsx15(Text13, { dimColor: true, children: "Run recappi record again to start, or press " }),
1453
+ /* @__PURE__ */ jsx15(Text13, { bold: true, color: "cyan", children: "r" }),
1454
+ /* @__PURE__ */ jsx15(Text13, { dimColor: true, children: " to retry." })
1455
+ ] }) : /* @__PURE__ */ jsxs12(Text13, { children: [
1456
+ /* @__PURE__ */ jsx15(Text13, { dimColor: true, children: "Grant the permissions above, then press " }),
1457
+ /* @__PURE__ */ jsx15(Text13, { bold: true, color: "cyan", children: "r" }),
1458
+ /* @__PURE__ */ jsx15(Text13, { dimColor: true, children: " to recheck." })
1459
+ ] }) }),
1460
+ /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsxs12(Text13, { children: [
1461
+ /* @__PURE__ */ jsx15(Text13, { color: "cyan", children: "r" }),
1462
+ /* @__PURE__ */ jsx15(Text13, { dimColor: true, children: " recheck \xB7 " }),
1463
+ /* @__PURE__ */ jsx15(Text13, { color: "cyan", children: "o" }),
1464
+ /* @__PURE__ */ jsx15(Text13, { dimColor: true, children: " open System Settings \xB7 " }),
1465
+ /* @__PURE__ */ jsx15(Text13, { color: "cyan", children: "esc" }),
1466
+ /* @__PURE__ */ jsx15(Text13, { dimColor: true, children: " back" })
1467
+ ] }) })
1434
1468
  ] });
1435
1469
  }
1436
1470
  var DEFAULT_HINTS;
@@ -1439,7 +1473,7 @@ var init_PermissionPreflightView = __esm({
1439
1473
  "use strict";
1440
1474
  DEFAULT_HINTS = {
1441
1475
  "Screen Recording": "Open System Settings \u203A Privacy & Security \u203A Screen Recording, enable Recappi Recorder, then run recappi record again.",
1442
- Microphone: "Open System Settings \u203A Privacy & Security \u203A Microphone, enable Recappi Recorder, then recheck."
1476
+ Microphone: "Open System Settings \u203A Privacy & Security \u203A Microphone, enable Recappi Recorder, then run recappi record again."
1443
1477
  };
1444
1478
  }
1445
1479
  });
@@ -1509,7 +1543,7 @@ function RecordSetupView({
1509
1543
  "esc cancel"
1510
1544
  ].filter(Boolean).join(" \xB7 ");
1511
1545
  return /* @__PURE__ */ jsxs13(Box14, { flexDirection: "column", paddingX: 1, children: [
1512
- /* @__PURE__ */ jsx16(Text14, { bold: true, color: "magenta", children: "New recording" }),
1546
+ /* @__PURE__ */ jsx16(Text14, { bold: true, color: "green", children: "New recording" }),
1513
1547
  /* @__PURE__ */ jsxs13(Box14, { marginTop: 1, flexDirection: wide ? "row" : "column", children: [
1514
1548
  /* @__PURE__ */ jsx16(Box14, { flexGrow: 1, flexDirection: "column", children: sourceList }),
1515
1549
  /* @__PURE__ */ jsx16(Box14, { marginLeft: wide ? 4 : 0, marginTop: wide ? 0 : 1, children: capturePlan })
@@ -1608,7 +1642,7 @@ function RecordingHeroScreen({
1608
1642
  const badge = paused ? "\u23F8 PAUSED" : starting ? "\u2026" : "\u23FA REC";
1609
1643
  return /* @__PURE__ */ jsxs14(Box15, { flexDirection: "column", paddingX: 1, height: size.rows, children: [
1610
1644
  /* @__PURE__ */ jsxs14(Text15, { children: [
1611
- /* @__PURE__ */ jsx17(Text15, { bold: true, color: "magenta", children: "recappi" }),
1645
+ /* @__PURE__ */ jsx17(Text15, { bold: true, color: "green", children: "recappi" }),
1612
1646
  /* @__PURE__ */ jsx17(Text15, { dimColor: true, children: " \xB7 Recording" })
1613
1647
  ] }),
1614
1648
  /* @__PURE__ */ jsxs14(Box15, { flexGrow: 1, flexDirection: "column", justifyContent: "center", alignItems: "center", children: [
@@ -1703,20 +1737,20 @@ function recordErrorCopy(code, message) {
1703
1737
  }
1704
1738
  function recordErrorState(error51, selection) {
1705
1739
  if (error51 instanceof Error) {
1706
- const descriptor = isRecord7(error51) && isRecord7(error51.descriptor) ? error51.descriptor : void 0;
1740
+ const descriptor = isRecord8(error51) && isRecord8(error51.descriptor) ? error51.descriptor : void 0;
1707
1741
  return {
1708
1742
  kind: "error",
1709
1743
  message: error51.message,
1710
1744
  code: typeof descriptor?.code === "string" ? descriptor.code : "code" in error51 && typeof error51.code === "string" ? error51.code : void 0,
1711
- data: isRecord7(error51) ? error51.data : void 0,
1745
+ data: isRecord8(error51) ? error51.data : void 0,
1712
1746
  ...selection ? { selection } : {}
1713
1747
  };
1714
1748
  }
1715
1749
  return { kind: "error", message: String(error51), ...selection ? { selection } : {} };
1716
1750
  }
1717
1751
  function transcribeHandoffErrorCopy(error51) {
1718
- const descriptor = error51 instanceof Error && isRecord7(error51) && isRecord7(error51.descriptor) ? error51.descriptor : void 0;
1719
- const code = typeof descriptor?.code === "string" ? descriptor.code : isRecord7(error51) && typeof error51.code === "string" ? error51.code : void 0;
1752
+ const descriptor = error51 instanceof Error && isRecord8(error51) && isRecord8(error51.descriptor) ? error51.descriptor : void 0;
1753
+ const code = typeof descriptor?.code === "string" ? descriptor.code : isRecord8(error51) && typeof error51.code === "string" ? error51.code : void 0;
1720
1754
  switch (code) {
1721
1755
  case "auth.not_logged_in":
1722
1756
  return "Sign in to Recappi before transcribing this recording.";
@@ -1746,8 +1780,8 @@ function transcribeHandoffErrorCopy(error51) {
1746
1780
  }
1747
1781
  }
1748
1782
  function permissionItemsFromRecordError(data) {
1749
- const sidecarError = isRecord7(data) ? data : void 0;
1750
- const sidecarData = isRecord7(sidecarError?.data) ? sidecarError.data : void 0;
1783
+ const sidecarError = isRecord8(data) ? data : void 0;
1784
+ const sidecarData = isRecord8(sidecarError?.data) ? sidecarError.data : void 0;
1751
1785
  const permission = typeof sidecarData?.permission === "string" ? sidecarData.permission : "";
1752
1786
  const hint = typeof sidecarData?.recovery === "string" ? sidecarData.recovery : void 0;
1753
1787
  const requiresProcessRestart = sidecarData?.requiresProcessRestart === true || sidecarData?.requiresProcessRestart === "true";
@@ -1762,15 +1796,15 @@ function permissionItemsFromRecordError(data) {
1762
1796
  ];
1763
1797
  }
1764
1798
  function settingsUrlFromRecordError(data) {
1765
- const sidecarError = isRecord7(data) ? data : void 0;
1766
- const sidecarData = isRecord7(sidecarError?.data) ? sidecarError.data : void 0;
1799
+ const sidecarError = isRecord8(data) ? data : void 0;
1800
+ const sidecarData = isRecord8(sidecarError?.data) ? sidecarError.data : void 0;
1767
1801
  const permission = typeof sidecarData?.permission === "string" ? sidecarData.permission : "";
1768
1802
  if (permission === "microphone") {
1769
1803
  return "x-apple.systempreferences:com.apple.preference.security?Privacy_Microphone";
1770
1804
  }
1771
1805
  return "x-apple.systempreferences:com.apple.preference.security?Privacy_ScreenCapture";
1772
1806
  }
1773
- function isRecord7(value) {
1807
+ function isRecord8(value) {
1774
1808
  return typeof value === "object" && value !== null && !Array.isArray(value);
1775
1809
  }
1776
1810
  function AppShell({
@@ -20361,6 +20395,7 @@ init_LiveCaptionsScreen();
20361
20395
  import { jsx as jsx3 } from "react/jsx-runtime";
20362
20396
  var SIDECAR_COMMAND_ENV = "RECAPPI_MINI_SIDECAR";
20363
20397
  var SIDECAR_HELPER_NAME = "RecappiMiniSidecar";
20398
+ var SIDECAR_APP_BUNDLE_NAME = "Recappi Recorder.app";
20364
20399
  var requireFromCli = createRequire2(import.meta.url);
20365
20400
  async function recordViaSidecar(opts) {
20366
20401
  let liveRenderer;
@@ -20439,6 +20474,20 @@ async function listRecordInputs(opts) {
20439
20474
  }
20440
20475
  }
20441
20476
  async function startRecordSession(opts) {
20477
+ let retriedAfterMicrophoneGrant = false;
20478
+ while (true) {
20479
+ try {
20480
+ return await startRecordSessionOnce(opts);
20481
+ } catch (error51) {
20482
+ if (!retriedAfterMicrophoneGrant && isPermissionRestartRequiredError(error51, "microphone")) {
20483
+ retriedAfterMicrophoneGrant = true;
20484
+ continue;
20485
+ }
20486
+ throw error51;
20487
+ }
20488
+ }
20489
+ }
20490
+ async function startRecordSessionOnce(opts) {
20442
20491
  const command = resolveSidecarCommand(opts);
20443
20492
  const sidecarArgs = opts.sidecarArgs ?? [];
20444
20493
  const spawnSidecar = opts.runtime?.spawnSidecar ?? spawnMiniSidecar;
@@ -20542,6 +20591,17 @@ async function startRecordSession(opts) {
20542
20591
  throw error51;
20543
20592
  }
20544
20593
  }
20594
+ function isPermissionRestartRequiredError(error51, permissionName) {
20595
+ const root = isRecord7(error51) ? error51 : void 0;
20596
+ const descriptor = isRecord7(root?.descriptor) ? root.descriptor : void 0;
20597
+ if (descriptor?.code !== "record.permission_required") return false;
20598
+ const sidecarError = isRecord7(root?.data) ? root.data : void 0;
20599
+ const sidecarData = isRecord7(sidecarError?.data) ? sidecarError.data : void 0;
20600
+ return sidecarData?.permission === permissionName && (sidecarData.requiresProcessRestart === true || sidecarData.requiresProcessRestart === "true");
20601
+ }
20602
+ function isRecord7(value) {
20603
+ return typeof value === "object" && value !== null && !Array.isArray(value);
20604
+ }
20545
20605
  function normalizeSidecarSources(sources) {
20546
20606
  const seen = /* @__PURE__ */ new Set();
20547
20607
  const out = [];
@@ -20658,7 +20718,7 @@ function bundledSidecarCommand(platform, arch) {
20658
20718
  return fileURLToPath(new URL(`helpers/${platform}-${arch}/${executable}`, packageRoot));
20659
20719
  }
20660
20720
  function helperExecutableName(platform) {
20661
- if (platform === "darwin") return `${SIDECAR_HELPER_NAME}.app`;
20721
+ if (platform === "darwin") return SIDECAR_APP_BUNDLE_NAME;
20662
20722
  if (platform === "win32") return `${SIDECAR_HELPER_NAME}.exe`;
20663
20723
  return null;
20664
20724
  }