recappi 0.1.12 → 0.1.14
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 +216 -51
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1293,10 +1293,56 @@ var init_TranscriptView = __esm({
|
|
|
1293
1293
|
}
|
|
1294
1294
|
});
|
|
1295
1295
|
|
|
1296
|
+
// src/tui/PermissionPreflightView.tsx
|
|
1297
|
+
import { Box as Box13, Text as Text13 } from "ink";
|
|
1298
|
+
import { jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1299
|
+
function statusGlyph2(status) {
|
|
1300
|
+
switch (status) {
|
|
1301
|
+
case "granted":
|
|
1302
|
+
return { glyph: "\u2713", color: "green", label: "granted" };
|
|
1303
|
+
case "denied":
|
|
1304
|
+
return { glyph: "\u2717", color: "red", label: "not allowed" };
|
|
1305
|
+
case "unknown":
|
|
1306
|
+
return { glyph: "\u25CB", color: "yellow", label: "not requested yet" };
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
function PermissionPreflightView({
|
|
1310
|
+
items
|
|
1311
|
+
}) {
|
|
1312
|
+
const allGranted = items.length > 0 && items.every((item) => item.status === "granted");
|
|
1313
|
+
return /* @__PURE__ */ jsxs12(Box13, { flexDirection: "column", paddingX: 1, children: [
|
|
1314
|
+
/* @__PURE__ */ jsx15(Text13, { dimColor: true, children: "\u2039 Recording permissions" }),
|
|
1315
|
+
/* @__PURE__ */ jsx15(Box13, { marginTop: 1, flexDirection: "column", children: items.length === 0 ? /* @__PURE__ */ jsx15(Text13, { dimColor: true, children: "Checking permissions\u2026" }) : items.map((item) => {
|
|
1316
|
+
const status = statusGlyph2(item.status);
|
|
1317
|
+
const hint = item.status === "granted" ? void 0 : item.hint ?? DEFAULT_HINTS[item.name];
|
|
1318
|
+
return /* @__PURE__ */ jsxs12(Box13, { flexDirection: "column", children: [
|
|
1319
|
+
/* @__PURE__ */ jsxs12(Text13, { children: [
|
|
1320
|
+
/* @__PURE__ */ jsx15(Text13, { color: status.color, children: status.glyph }),
|
|
1321
|
+
/* @__PURE__ */ jsx15(Text13, { bold: true, children: ` ${item.name}` }),
|
|
1322
|
+
/* @__PURE__ */ jsx15(Text13, { dimColor: true, children: ` ${status.label}` })
|
|
1323
|
+
] }),
|
|
1324
|
+
hint ? /* @__PURE__ */ jsx15(Text13, { dimColor: true, children: ` ${hint}` }) : null
|
|
1325
|
+
] }, item.name);
|
|
1326
|
+
}) }),
|
|
1327
|
+
/* @__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." }) }),
|
|
1328
|
+
/* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(Text13, { dimColor: true, children: "r recheck \xB7 o open System Settings \xB7 esc back" }) })
|
|
1329
|
+
] });
|
|
1330
|
+
}
|
|
1331
|
+
var DEFAULT_HINTS;
|
|
1332
|
+
var init_PermissionPreflightView = __esm({
|
|
1333
|
+
"src/tui/PermissionPreflightView.tsx"() {
|
|
1334
|
+
"use strict";
|
|
1335
|
+
DEFAULT_HINTS = {
|
|
1336
|
+
"Screen Recording": "Open System Settings \u203A Privacy & Security \u203A Screen Recording, enable recappi, then recheck.",
|
|
1337
|
+
Microphone: "Open System Settings \u203A Privacy & Security \u203A Microphone, enable recappi, then recheck."
|
|
1338
|
+
};
|
|
1339
|
+
}
|
|
1340
|
+
});
|
|
1341
|
+
|
|
1296
1342
|
// src/tui/AppShell.tsx
|
|
1297
1343
|
import { useCallback, useEffect as useEffect2, useState as useState5 } from "react";
|
|
1298
|
-
import { Box as
|
|
1299
|
-
import { Fragment as Fragment4, jsx as
|
|
1344
|
+
import { Box as Box14, Text as Text14, useApp, useInput as useInput5 } from "ink";
|
|
1345
|
+
import { Fragment as Fragment4, jsx as jsx16, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1300
1346
|
function recordErrorCopy(code, message) {
|
|
1301
1347
|
switch (code) {
|
|
1302
1348
|
case "record.helper_unavailable":
|
|
@@ -1317,10 +1363,54 @@ function recordErrorCopy(code, message) {
|
|
|
1317
1363
|
detail: "Use the Recappi Mini app to record for now; CLI recording is coming soon.",
|
|
1318
1364
|
tone: "yellow"
|
|
1319
1365
|
};
|
|
1366
|
+
case "record.permission_required":
|
|
1367
|
+
return {
|
|
1368
|
+
title: "Recording needs macOS permission first.",
|
|
1369
|
+
detail: "Open System Settings > Privacy & Security, allow recording access, then retry.",
|
|
1370
|
+
tone: "yellow"
|
|
1371
|
+
};
|
|
1372
|
+
case "record.capture_failed":
|
|
1373
|
+
return {
|
|
1374
|
+
title: "Couldn't start recording.",
|
|
1375
|
+
detail: "Recording failed to start \u2014 please try again.",
|
|
1376
|
+
tone: "red"
|
|
1377
|
+
};
|
|
1320
1378
|
default:
|
|
1321
1379
|
return { title: "Couldn't start recording.", detail: message, tone: "red" };
|
|
1322
1380
|
}
|
|
1323
1381
|
}
|
|
1382
|
+
function recordErrorState(error51) {
|
|
1383
|
+
if (error51 instanceof Error) {
|
|
1384
|
+
const descriptor = isRecord6(error51) && isRecord6(error51.descriptor) ? error51.descriptor : void 0;
|
|
1385
|
+
return {
|
|
1386
|
+
kind: "error",
|
|
1387
|
+
message: error51.message,
|
|
1388
|
+
code: typeof descriptor?.code === "string" ? descriptor.code : "code" in error51 && typeof error51.code === "string" ? error51.code : void 0,
|
|
1389
|
+
data: isRecord6(error51) ? error51.data : void 0
|
|
1390
|
+
};
|
|
1391
|
+
}
|
|
1392
|
+
return { kind: "error", message: String(error51) };
|
|
1393
|
+
}
|
|
1394
|
+
function permissionItemsFromRecordError(data) {
|
|
1395
|
+
const sidecarError = isRecord6(data) ? data : void 0;
|
|
1396
|
+
const sidecarData = isRecord6(sidecarError?.data) ? sidecarError.data : void 0;
|
|
1397
|
+
const permission = typeof sidecarData?.permission === "string" ? sidecarData.permission : "";
|
|
1398
|
+
const hint = typeof sidecarData?.recovery === "string" ? sidecarData.recovery : void 0;
|
|
1399
|
+
const item = permission === "microphone" ? "Microphone" : permission === "screen_recording" ? "Screen Recording" : "Recording";
|
|
1400
|
+
return [{ name: item, status: "denied", ...hint ? { hint } : {} }];
|
|
1401
|
+
}
|
|
1402
|
+
function settingsUrlFromRecordError(data) {
|
|
1403
|
+
const sidecarError = isRecord6(data) ? data : void 0;
|
|
1404
|
+
const sidecarData = isRecord6(sidecarError?.data) ? sidecarError.data : void 0;
|
|
1405
|
+
const permission = typeof sidecarData?.permission === "string" ? sidecarData.permission : "";
|
|
1406
|
+
if (permission === "microphone") {
|
|
1407
|
+
return "x-apple.systempreferences:com.apple.preference.security?Privacy_Microphone";
|
|
1408
|
+
}
|
|
1409
|
+
return "x-apple.systempreferences:com.apple.preference.security?Privacy_ScreenCapture";
|
|
1410
|
+
}
|
|
1411
|
+
function isRecord6(value) {
|
|
1412
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1413
|
+
}
|
|
1324
1414
|
function AppShell({
|
|
1325
1415
|
fetchJobs,
|
|
1326
1416
|
fetchTranscript,
|
|
@@ -1359,6 +1449,7 @@ function AppShell({
|
|
|
1359
1449
|
const [audioCache, setAudioCache] = useState5(() => /* @__PURE__ */ new Map());
|
|
1360
1450
|
const [downloadedIds, setDownloadedIds] = useState5(() => /* @__PURE__ */ new Set());
|
|
1361
1451
|
const [liveRecord, setLiveRecord] = useState5(void 0);
|
|
1452
|
+
const [recordRetryNonce, setRecordRetryNonce] = useState5(0);
|
|
1362
1453
|
const refreshDownloadedIds = useCallback(async () => {
|
|
1363
1454
|
if (!listDownloadedRecordingIds) return;
|
|
1364
1455
|
try {
|
|
@@ -1403,18 +1494,13 @@ function AppShell({
|
|
|
1403
1494
|
setLiveRecord({ kind: "live", session });
|
|
1404
1495
|
}).catch((error51) => {
|
|
1405
1496
|
if (!cancelled) {
|
|
1406
|
-
|
|
1407
|
-
setLiveRecord({
|
|
1408
|
-
kind: "error",
|
|
1409
|
-
code,
|
|
1410
|
-
message: error51 instanceof Error ? error51.message : String(error51)
|
|
1411
|
-
});
|
|
1497
|
+
setLiveRecord(recordErrorState(error51));
|
|
1412
1498
|
}
|
|
1413
1499
|
});
|
|
1414
1500
|
return () => {
|
|
1415
1501
|
cancelled = true;
|
|
1416
1502
|
};
|
|
1417
|
-
}, [screen.kind, startLiveRecord]);
|
|
1503
|
+
}, [screen.kind, startLiveRecord, recordRetryNonce]);
|
|
1418
1504
|
const selectedRecording = screen.kind === "overview" ? recordings[selected] : void 0;
|
|
1419
1505
|
const peekTranscriptId = selectedRecording?.activeTranscriptId ?? void 0;
|
|
1420
1506
|
useEffect2(() => {
|
|
@@ -1592,6 +1678,14 @@ function AppShell({
|
|
|
1592
1678
|
useInput5((input, key) => {
|
|
1593
1679
|
setNotice(void 0);
|
|
1594
1680
|
if (screen.kind === "record") {
|
|
1681
|
+
if (liveRecord?.kind === "error" && input === "r") {
|
|
1682
|
+
setRecordRetryNonce((value) => value + 1);
|
|
1683
|
+
return;
|
|
1684
|
+
}
|
|
1685
|
+
if (liveRecord?.kind === "error" && input === "o") {
|
|
1686
|
+
openUrl2?.(settingsUrlFromRecordError(liveRecord.data));
|
|
1687
|
+
return;
|
|
1688
|
+
}
|
|
1595
1689
|
if (input === "q" || key.escape || key.leftArrow) void stopLiveRecord();
|
|
1596
1690
|
return;
|
|
1597
1691
|
}
|
|
@@ -1647,18 +1741,18 @@ function AppShell({
|
|
|
1647
1741
|
}
|
|
1648
1742
|
});
|
|
1649
1743
|
if (screen.kind === "transcript") {
|
|
1650
|
-
return /* @__PURE__ */
|
|
1744
|
+
return /* @__PURE__ */ jsx16(TranscriptView, { loading: screen.loading, data: screen.data, error: screen.error });
|
|
1651
1745
|
}
|
|
1652
1746
|
if (screen.kind === "jobDetail") {
|
|
1653
1747
|
const job = jobs.find((j) => j.jobId === screen.jobId);
|
|
1654
|
-
if (!job) return /* @__PURE__ */
|
|
1655
|
-
return /* @__PURE__ */
|
|
1748
|
+
if (!job) return /* @__PURE__ */ jsx16(Missing, { label: "Job" });
|
|
1749
|
+
return /* @__PURE__ */ jsx16(Detail, { notice, children: /* @__PURE__ */ jsx16(JobDetailView, { item: job, origin, spinnerFrame, nowMs: now() }) });
|
|
1656
1750
|
}
|
|
1657
1751
|
if (screen.kind === "recordingDetail") {
|
|
1658
1752
|
const rec = recordings.find((r) => r.recordingId === screen.recordingId);
|
|
1659
|
-
if (!rec) return /* @__PURE__ */
|
|
1753
|
+
if (!rec) return /* @__PURE__ */ jsx16(Missing, { label: "Recording" });
|
|
1660
1754
|
const detailTranscript = rec.activeTranscriptId ? transcriptCache.get(rec.activeTranscriptId) : void 0;
|
|
1661
|
-
return /* @__PURE__ */
|
|
1755
|
+
return /* @__PURE__ */ jsx16(Detail, { notice, children: /* @__PURE__ */ jsx16(
|
|
1662
1756
|
RecordingDetailView,
|
|
1663
1757
|
{
|
|
1664
1758
|
item: rec,
|
|
@@ -1670,18 +1764,21 @@ function AppShell({
|
|
|
1670
1764
|
}
|
|
1671
1765
|
if (screen.kind === "record") {
|
|
1672
1766
|
if (liveRecord?.kind === "live") {
|
|
1673
|
-
return /* @__PURE__ */
|
|
1767
|
+
return /* @__PURE__ */ jsx16(LiveCaptionsScreen, { source: liveRecord.session.source, now });
|
|
1674
1768
|
}
|
|
1675
|
-
return /* @__PURE__ */
|
|
1676
|
-
/* @__PURE__ */
|
|
1677
|
-
/* @__PURE__ */
|
|
1769
|
+
return /* @__PURE__ */ jsxs13(Box14, { flexDirection: "column", height: size.rows, paddingX: 1, children: [
|
|
1770
|
+
/* @__PURE__ */ jsx16(Header, { active: "record" }),
|
|
1771
|
+
/* @__PURE__ */ jsx16(Box14, { flexGrow: 1, flexDirection: "column", paddingX: 1, paddingTop: 1, children: liveRecord?.kind === "error" ? (() => {
|
|
1772
|
+
if (liveRecord.code === "record.permission_required") {
|
|
1773
|
+
return /* @__PURE__ */ jsx16(PermissionPreflightView, { items: permissionItemsFromRecordError(liveRecord.data) });
|
|
1774
|
+
}
|
|
1678
1775
|
const copy = recordErrorCopy(liveRecord.code, liveRecord.message);
|
|
1679
|
-
return /* @__PURE__ */
|
|
1680
|
-
/* @__PURE__ */
|
|
1681
|
-
copy.detail ? /* @__PURE__ */
|
|
1776
|
+
return /* @__PURE__ */ jsxs13(Fragment4, { children: [
|
|
1777
|
+
/* @__PURE__ */ jsx16(Text14, { color: copy.tone, children: copy.title }),
|
|
1778
|
+
copy.detail ? /* @__PURE__ */ jsx16(Text14, { dimColor: true, children: copy.detail }) : null
|
|
1682
1779
|
] });
|
|
1683
|
-
})() : /* @__PURE__ */
|
|
1684
|
-
/* @__PURE__ */
|
|
1780
|
+
})() : /* @__PURE__ */ jsx16(Text14, { dimColor: true, children: "Starting live recording\u2026" }) }),
|
|
1781
|
+
/* @__PURE__ */ jsx16(Footer, { keys: "q / esc / \u2190 back" })
|
|
1685
1782
|
] });
|
|
1686
1783
|
}
|
|
1687
1784
|
const tab = screen.kind === "jobs" ? "jobs" : screen.kind === "account" ? "account" : "overview";
|
|
@@ -1699,7 +1796,7 @@ function AppShell({
|
|
|
1699
1796
|
const showPeek = size.columns >= 100;
|
|
1700
1797
|
const peekWidth = showPeek ? 34 : 0;
|
|
1701
1798
|
const listColumns = showPeek ? Math.max(30, size.columns - peekWidth - 3) : size.columns;
|
|
1702
|
-
body = /* @__PURE__ */
|
|
1799
|
+
body = /* @__PURE__ */ jsx16(
|
|
1703
1800
|
OverviewView,
|
|
1704
1801
|
{
|
|
1705
1802
|
recordings: recordings.slice(win.start, win.end),
|
|
@@ -1719,11 +1816,11 @@ function AppShell({
|
|
|
1719
1816
|
);
|
|
1720
1817
|
} else if (screen.kind === "account") {
|
|
1721
1818
|
position = "";
|
|
1722
|
-
body = /* @__PURE__ */
|
|
1819
|
+
body = /* @__PURE__ */ jsx16(AccountView, { status: accountStatus });
|
|
1723
1820
|
} else {
|
|
1724
1821
|
const win = listWindow(selected, jobs.length, Math.max(3, size.rows - 4));
|
|
1725
1822
|
position = jobs.length ? `${selected + 1} / ${jobs.length}` : "0";
|
|
1726
|
-
body = /* @__PURE__ */
|
|
1823
|
+
body = /* @__PURE__ */ jsx16(
|
|
1727
1824
|
JobsView,
|
|
1728
1825
|
{
|
|
1729
1826
|
items: jobs.slice(win.start, win.end),
|
|
@@ -1733,34 +1830,34 @@ function AppShell({
|
|
|
1733
1830
|
);
|
|
1734
1831
|
}
|
|
1735
1832
|
const footerKeys = screen.kind === "jobs" ? `${position} \xB7 \u2191\u2193 select \xB7 \u23CE job \xB7 t transcript \xB7 1 overview \xB7 3 account \xB7 4 record \xB7 r refresh \xB7 q quit` : screen.kind === "account" ? "3 account \xB7 1 overview \xB7 2 jobs \xB7 4 record \xB7 r refresh \xB7 q quit" : `${position} \xB7 \u2191\u2193 scroll \xB7 \u23CE open \xB7 t transcript \xB7 2 jobs \xB7 3 account \xB7 4 record \xB7 r refresh \xB7 q quit`;
|
|
1736
|
-
return /* @__PURE__ */
|
|
1737
|
-
/* @__PURE__ */
|
|
1738
|
-
/* @__PURE__ */
|
|
1833
|
+
return /* @__PURE__ */ jsxs13(Box14, { flexDirection: "column", height: size.rows, paddingX: 1, children: [
|
|
1834
|
+
/* @__PURE__ */ jsx16(Header, { active: tab }),
|
|
1835
|
+
/* @__PURE__ */ jsxs13(Box14, { flexGrow: 1, flexDirection: "column", children: [
|
|
1739
1836
|
body,
|
|
1740
|
-
loadError && jobs.length === 0 && recordings.length === 0 ? /* @__PURE__ */
|
|
1837
|
+
loadError && jobs.length === 0 && recordings.length === 0 ? /* @__PURE__ */ jsx16(Box14, { marginTop: 1, children: /* @__PURE__ */ jsxs13(Text14, { color: "red", children: [
|
|
1741
1838
|
"! ",
|
|
1742
1839
|
loadError
|
|
1743
1840
|
] }) }) : null
|
|
1744
1841
|
] }),
|
|
1745
|
-
/* @__PURE__ */
|
|
1842
|
+
/* @__PURE__ */ jsx16(Footer, { keys: footerKeys })
|
|
1746
1843
|
] });
|
|
1747
1844
|
}
|
|
1748
1845
|
function Detail({
|
|
1749
1846
|
notice,
|
|
1750
1847
|
children
|
|
1751
1848
|
}) {
|
|
1752
|
-
return /* @__PURE__ */
|
|
1849
|
+
return /* @__PURE__ */ jsxs13(Box14, { flexDirection: "column", children: [
|
|
1753
1850
|
children,
|
|
1754
|
-
notice ? /* @__PURE__ */
|
|
1851
|
+
notice ? /* @__PURE__ */ jsx16(Box14, { paddingX: 1, children: /* @__PURE__ */ jsx16(Text14, { color: "green", children: notice }) }) : null
|
|
1755
1852
|
] });
|
|
1756
1853
|
}
|
|
1757
1854
|
function Missing({ label }) {
|
|
1758
|
-
return /* @__PURE__ */
|
|
1759
|
-
/* @__PURE__ */
|
|
1855
|
+
return /* @__PURE__ */ jsxs13(Box14, { flexDirection: "column", paddingX: 1, children: [
|
|
1856
|
+
/* @__PURE__ */ jsxs13(Text14, { dimColor: true, children: [
|
|
1760
1857
|
label,
|
|
1761
1858
|
" no longer in the list."
|
|
1762
1859
|
] }),
|
|
1763
|
-
/* @__PURE__ */
|
|
1860
|
+
/* @__PURE__ */ jsx16(Text14, { dimColor: true, children: "esc back \xB7 q quit" })
|
|
1764
1861
|
] });
|
|
1765
1862
|
}
|
|
1766
1863
|
var RECORDINGS_PAGE_SIZE, RECORDINGS_PREFETCH_REMAINING;
|
|
@@ -1775,6 +1872,7 @@ var init_AppShell = __esm({
|
|
|
1775
1872
|
init_RecordingDetailView();
|
|
1776
1873
|
init_TranscriptView();
|
|
1777
1874
|
init_LiveCaptionsScreen();
|
|
1875
|
+
init_PermissionPreflightView();
|
|
1778
1876
|
init_format();
|
|
1779
1877
|
init_terminal();
|
|
1780
1878
|
RECORDINGS_PAGE_SIZE = 50;
|
|
@@ -16400,6 +16498,8 @@ var cliErrorCodeSchema = external_exports.enum([
|
|
|
16400
16498
|
"record.helper_unavailable",
|
|
16401
16499
|
"record.unsupported_platform",
|
|
16402
16500
|
"record.capture_unavailable",
|
|
16501
|
+
"record.permission_required",
|
|
16502
|
+
"record.capture_failed",
|
|
16403
16503
|
"cloud.conflict.upload_in_progress",
|
|
16404
16504
|
"cloud.recording_not_ready",
|
|
16405
16505
|
"cloud.job_failed",
|
|
@@ -16496,6 +16596,19 @@ var sidecarRecordingOptionsSchema = external_exports.object({
|
|
|
16496
16596
|
transcriptionLanguage: external_exports.string().optional(),
|
|
16497
16597
|
title: external_exports.string().optional()
|
|
16498
16598
|
});
|
|
16599
|
+
var sidecarPermissionNameSchema = external_exports.enum(["screen_recording", "microphone"]);
|
|
16600
|
+
var sidecarPermissionStatusSchema = external_exports.enum(["granted", "denied", "unknown"]);
|
|
16601
|
+
var sidecarPermissionItemSchema = external_exports.object({
|
|
16602
|
+
name: sidecarPermissionNameSchema,
|
|
16603
|
+
status: sidecarPermissionStatusSchema,
|
|
16604
|
+
hint: external_exports.string().optional()
|
|
16605
|
+
});
|
|
16606
|
+
var sidecarPermissionStatusParamsSchema = external_exports.object({
|
|
16607
|
+
options: sidecarRecordingOptionsSchema
|
|
16608
|
+
});
|
|
16609
|
+
var sidecarPermissionStatusResultSchema = external_exports.object({
|
|
16610
|
+
permissions: external_exports.array(sidecarPermissionItemSchema)
|
|
16611
|
+
});
|
|
16499
16612
|
var sidecarRecordingStateSchema = external_exports.enum([
|
|
16500
16613
|
"idle",
|
|
16501
16614
|
"starting",
|
|
@@ -16567,6 +16680,12 @@ var sidecarRequestSchema = external_exports.discriminatedUnion("method", [
|
|
|
16567
16680
|
method: external_exports.literal("recappi.recording.start"),
|
|
16568
16681
|
params: sidecarRecordingStartParamsSchema
|
|
16569
16682
|
}),
|
|
16683
|
+
external_exports.object({
|
|
16684
|
+
jsonrpc: external_exports.literal("2.0"),
|
|
16685
|
+
id: sidecarJsonRpcIdSchema,
|
|
16686
|
+
method: external_exports.literal("recappi.permissions.status"),
|
|
16687
|
+
params: sidecarPermissionStatusParamsSchema
|
|
16688
|
+
}),
|
|
16570
16689
|
external_exports.object({
|
|
16571
16690
|
jsonrpc: external_exports.literal("2.0"),
|
|
16572
16691
|
id: sidecarJsonRpcIdSchema,
|
|
@@ -16894,6 +17013,8 @@ var DEFAULT_EXIT_CODES = {
|
|
|
16894
17013
|
"record.helper_unavailable": 2,
|
|
16895
17014
|
"record.unsupported_platform": 2,
|
|
16896
17015
|
"record.capture_unavailable": 2,
|
|
17016
|
+
"record.permission_required": 2,
|
|
17017
|
+
"record.capture_failed": 1,
|
|
16897
17018
|
"cloud.conflict.upload_in_progress": 5,
|
|
16898
17019
|
"cloud.recording_not_ready": 5,
|
|
16899
17020
|
"cloud.job_failed": 5,
|
|
@@ -19420,6 +19541,13 @@ var MiniSidecarClient = class {
|
|
|
19420
19541
|
sidecarRecordingStartResultSchema
|
|
19421
19542
|
);
|
|
19422
19543
|
}
|
|
19544
|
+
getPermissionStatus(params) {
|
|
19545
|
+
return this.request(
|
|
19546
|
+
"recappi.permissions.status",
|
|
19547
|
+
sidecarPermissionStatusParamsSchema.parse(params),
|
|
19548
|
+
sidecarPermissionStatusResultSchema
|
|
19549
|
+
);
|
|
19550
|
+
}
|
|
19423
19551
|
stopRecording(params) {
|
|
19424
19552
|
return this.request(
|
|
19425
19553
|
"recappi.recording.stop",
|
|
@@ -19520,12 +19648,7 @@ var MiniSidecarClient = class {
|
|
|
19520
19648
|
this.pending.delete(id);
|
|
19521
19649
|
clearTimeout(pending.timer);
|
|
19522
19650
|
if ("error" in response.data) {
|
|
19523
|
-
pending.reject(
|
|
19524
|
-
cliError("internal.unexpected", response.data.error.message, {
|
|
19525
|
-
data: response.data.error,
|
|
19526
|
-
retryable: response.data.error.code >= -32099 && response.data.error.code <= -32e3
|
|
19527
|
-
})
|
|
19528
|
-
);
|
|
19651
|
+
pending.reject(sidecarErrorToCliError(response.data.error));
|
|
19529
19652
|
return;
|
|
19530
19653
|
}
|
|
19531
19654
|
pending.resolve(response.data.result);
|
|
@@ -19538,6 +19661,27 @@ var MiniSidecarClient = class {
|
|
|
19538
19661
|
}
|
|
19539
19662
|
}
|
|
19540
19663
|
};
|
|
19664
|
+
function sidecarErrorToCliError(error51) {
|
|
19665
|
+
const data = isRecord5(error51.data) ? error51.data : void 0;
|
|
19666
|
+
const maybeCode = typeof data?.cliCode === "string" ? cliErrorCodeSchema.safeParse(data.cliCode) : void 0;
|
|
19667
|
+
const hint = typeof data?.recovery === "string" ? data.recovery : void 0;
|
|
19668
|
+
const retryable = typeof data?.retryable === "boolean" ? data.retryable : error51.code >= -32099 && error51.code <= -32e3;
|
|
19669
|
+
if (maybeCode?.success) {
|
|
19670
|
+
return cliError(maybeCode.data, error51.message, {
|
|
19671
|
+
data: error51,
|
|
19672
|
+
hint,
|
|
19673
|
+
retryable
|
|
19674
|
+
});
|
|
19675
|
+
}
|
|
19676
|
+
return cliError("internal.unexpected", error51.message, {
|
|
19677
|
+
data: error51,
|
|
19678
|
+
hint,
|
|
19679
|
+
retryable
|
|
19680
|
+
});
|
|
19681
|
+
}
|
|
19682
|
+
function isRecord5(value) {
|
|
19683
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
19684
|
+
}
|
|
19541
19685
|
function spawnMiniSidecar(opts) {
|
|
19542
19686
|
const spawnProcess = opts.spawnProcess ?? spawn2;
|
|
19543
19687
|
const child = spawnProcess(opts.command, opts.args ?? [], {
|
|
@@ -19602,7 +19746,7 @@ async function recordViaSidecar(opts) {
|
|
|
19602
19746
|
}
|
|
19603
19747
|
}
|
|
19604
19748
|
async function startLiveRecordSession(opts) {
|
|
19605
|
-
const session = await startRecordSession({ ...opts, live:
|
|
19749
|
+
const session = await startRecordSession({ ...opts, live: false });
|
|
19606
19750
|
return {
|
|
19607
19751
|
source: session.source,
|
|
19608
19752
|
stop: async () => {
|
|
@@ -19658,16 +19802,19 @@ async function startRecordSession(opts) {
|
|
|
19658
19802
|
})
|
|
19659
19803
|
);
|
|
19660
19804
|
assertSidecarCapabilities(handshake, opts);
|
|
19805
|
+
const recordingOptions = {
|
|
19806
|
+
includeSystemAudio: opts.includeSystemAudio ?? true,
|
|
19807
|
+
includeMicrophone: opts.includeMicrophone ?? true,
|
|
19808
|
+
liveCaptions: opts.live === true,
|
|
19809
|
+
...opts.translationLanguage ? { translationLanguage: opts.translationLanguage } : {},
|
|
19810
|
+
...opts.transcriptionLanguage ? { transcriptionLanguage: opts.transcriptionLanguage } : {},
|
|
19811
|
+
...opts.title ? { title: opts.title } : {}
|
|
19812
|
+
};
|
|
19813
|
+
const preflight = await sidecar.client.getPermissionStatus({ options: recordingOptions });
|
|
19814
|
+
assertRecordingPermissions(preflight.permissions);
|
|
19661
19815
|
const started = await sidecar.client.startRecording({
|
|
19662
19816
|
account,
|
|
19663
|
-
options:
|
|
19664
|
-
includeSystemAudio: opts.includeSystemAudio ?? true,
|
|
19665
|
-
includeMicrophone: opts.includeMicrophone ?? true,
|
|
19666
|
-
liveCaptions: opts.live === true,
|
|
19667
|
-
...opts.translationLanguage ? { translationLanguage: opts.translationLanguage } : {},
|
|
19668
|
-
...opts.transcriptionLanguage ? { transcriptionLanguage: opts.transcriptionLanguage } : {},
|
|
19669
|
-
...opts.title ? { title: opts.title } : {}
|
|
19670
|
-
}
|
|
19817
|
+
options: recordingOptions
|
|
19671
19818
|
});
|
|
19672
19819
|
sessionId = started.sessionId;
|
|
19673
19820
|
latestState = started.state;
|
|
@@ -19709,6 +19856,24 @@ async function startRecordSession(opts) {
|
|
|
19709
19856
|
throw error51;
|
|
19710
19857
|
}
|
|
19711
19858
|
}
|
|
19859
|
+
function assertRecordingPermissions(permissions) {
|
|
19860
|
+
const blocked = permissions.find((permission) => permission.status !== "granted");
|
|
19861
|
+
if (!blocked) return;
|
|
19862
|
+
const label = blocked.name === "microphone" ? "Microphone" : blocked.name === "screen_recording" ? "Screen Recording" : "Recording";
|
|
19863
|
+
throw cliError("record.permission_required", `${label} permission is required before recording.`, {
|
|
19864
|
+
hint: blocked.hint,
|
|
19865
|
+
data: {
|
|
19866
|
+
code: -32020,
|
|
19867
|
+
message: `${label} permission is required before recording.`,
|
|
19868
|
+
data: {
|
|
19869
|
+
cliCode: "record.permission_required",
|
|
19870
|
+
permission: blocked.name,
|
|
19871
|
+
...blocked.hint ? { recovery: blocked.hint } : {},
|
|
19872
|
+
permissions
|
|
19873
|
+
}
|
|
19874
|
+
}
|
|
19875
|
+
});
|
|
19876
|
+
}
|
|
19712
19877
|
function assertSidecarCapabilities(handshake, opts) {
|
|
19713
19878
|
const capabilities = new Set(handshake.capabilities);
|
|
19714
19879
|
const missing = [];
|