recappi 0.1.75 → 0.1.77
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 +531 -180
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -84,7 +84,7 @@ function isLiveCaptionSidecarError(code) {
|
|
|
84
84
|
}
|
|
85
85
|
function recordingArtifactFromRecordData(data) {
|
|
86
86
|
const artifact = data.artifacts.find((item) => item.kind === "recording_session") ?? data.artifacts[0];
|
|
87
|
-
const metadata =
|
|
87
|
+
const metadata = isRecord6(artifact?.metadata) ? artifact.metadata : {};
|
|
88
88
|
const audioPath = typeof metadata.audioPath === "string" ? metadata.audioPath : typeof artifact?.localPath === "string" ? artifact.localPath : void 0;
|
|
89
89
|
const durationMs = typeof metadata.durationMs === "number" && Number.isFinite(metadata.durationMs) ? metadata.durationMs : void 0;
|
|
90
90
|
const sizeBytes = typeof metadata.sizeBytes === "number" && Number.isFinite(metadata.sizeBytes) ? metadata.sizeBytes : void 0;
|
|
@@ -104,7 +104,7 @@ function artifactTelemetryPatch(artifact) {
|
|
|
104
104
|
sizeBytes: artifact.sizeBytes
|
|
105
105
|
};
|
|
106
106
|
}
|
|
107
|
-
function
|
|
107
|
+
function isRecord6(value) {
|
|
108
108
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
109
109
|
}
|
|
110
110
|
var DEFAULT_RECORDING_SOURCES, DEFAULT_RECORDING_SCENES, DEFAULT_RECORDING_SELECTION;
|
|
@@ -977,7 +977,8 @@ function OverviewView({
|
|
|
977
977
|
peekItem,
|
|
978
978
|
peekSummary,
|
|
979
979
|
showPeek = false,
|
|
980
|
-
peekWidth = 0
|
|
980
|
+
peekWidth = 0,
|
|
981
|
+
revalidating = false
|
|
981
982
|
}) {
|
|
982
983
|
const jobCounts = countJobs(jobs);
|
|
983
984
|
const running = stats?.jobs.running ?? jobCounts.running;
|
|
@@ -998,7 +999,8 @@ function OverviewView({
|
|
|
998
999
|
/* @__PURE__ */ jsx12(Text10, { dimColor: true, children: " \xB7 " }),
|
|
999
1000
|
/* @__PURE__ */ jsx12(Text10, { color: "yellow", children: `${queued} queued` })
|
|
1000
1001
|
] }) : null,
|
|
1001
|
-
stats?.recordings.totalDurationMs != null ? /* @__PURE__ */ jsx12(Text10, { dimColor: true, children: ` \xB7 ${formatClockMs(stats.recordings.totalDurationMs)} transcribed` }) : null
|
|
1002
|
+
stats?.recordings.totalDurationMs != null ? /* @__PURE__ */ jsx12(Text10, { dimColor: true, children: ` \xB7 ${formatClockMs(stats.recordings.totalDurationMs)} transcribed` }) : null,
|
|
1003
|
+
revalidating ? /* @__PURE__ */ jsx12(Text10, { dimColor: true, children: " \xB7 syncing" }) : null
|
|
1002
1004
|
] }),
|
|
1003
1005
|
/* @__PURE__ */ jsxs9(Box10, { flexDirection: "row", alignItems: "flex-start", children: [
|
|
1004
1006
|
/* @__PURE__ */ jsx12(Box10, { flexGrow: 1, flexDirection: "column", children: /* @__PURE__ */ jsx12(
|
|
@@ -1252,7 +1254,7 @@ function RecordingDetailView({
|
|
|
1252
1254
|
scrollable ? " \xB7 \u2191\u2193 scroll" : "",
|
|
1253
1255
|
ready ? " \xB7 " : "",
|
|
1254
1256
|
`o open \xB7 d download \xB7 f finder`,
|
|
1255
|
-
" \xB7 T re-transcribe \xB7 s re-summarize",
|
|
1257
|
+
" \xB7 T re-transcribe \xB7 s re-summarize \xB7 e export",
|
|
1256
1258
|
item.activeTranscriptId ? " \xB7 t full" : "",
|
|
1257
1259
|
links.webUrl ? " \xB7 w web" : "",
|
|
1258
1260
|
" \xB7 r refresh \xB7 esc back"
|
|
@@ -1877,20 +1879,20 @@ function recordErrorCopy(code, message) {
|
|
|
1877
1879
|
}
|
|
1878
1880
|
function recordErrorState(error51, selection) {
|
|
1879
1881
|
if (error51 instanceof Error) {
|
|
1880
|
-
const descriptor =
|
|
1882
|
+
const descriptor = isRecord9(error51) && isRecord9(error51.descriptor) ? error51.descriptor : void 0;
|
|
1881
1883
|
return {
|
|
1882
1884
|
kind: "error",
|
|
1883
1885
|
message: error51.message,
|
|
1884
1886
|
code: typeof descriptor?.code === "string" ? descriptor.code : "code" in error51 && typeof error51.code === "string" ? error51.code : void 0,
|
|
1885
|
-
data:
|
|
1887
|
+
data: isRecord9(error51) ? error51.data : void 0,
|
|
1886
1888
|
...selection ? { selection } : {}
|
|
1887
1889
|
};
|
|
1888
1890
|
}
|
|
1889
1891
|
return { kind: "error", message: String(error51), ...selection ? { selection } : {} };
|
|
1890
1892
|
}
|
|
1891
1893
|
function transcribeHandoffErrorCopy(error51) {
|
|
1892
|
-
const descriptor = error51 instanceof Error &&
|
|
1893
|
-
const code = typeof descriptor?.code === "string" ? descriptor.code :
|
|
1894
|
+
const descriptor = error51 instanceof Error && isRecord9(error51) && isRecord9(error51.descriptor) ? error51.descriptor : void 0;
|
|
1895
|
+
const code = typeof descriptor?.code === "string" ? descriptor.code : isRecord9(error51) && typeof error51.code === "string" ? error51.code : void 0;
|
|
1894
1896
|
switch (code) {
|
|
1895
1897
|
case "auth.not_logged_in":
|
|
1896
1898
|
return "Sign in to Recappi before transcribing this recording.";
|
|
@@ -1964,8 +1966,8 @@ function recordFrameTitle(recordings, recordingId) {
|
|
|
1964
1966
|
return recording ? recordingTitle2(recording) : "New recording";
|
|
1965
1967
|
}
|
|
1966
1968
|
function permissionItemsFromRecordError(data) {
|
|
1967
|
-
const sidecarError =
|
|
1968
|
-
const sidecarData =
|
|
1969
|
+
const sidecarError = isRecord9(data) ? data : void 0;
|
|
1970
|
+
const sidecarData = isRecord9(sidecarError?.data) ? sidecarError.data : void 0;
|
|
1969
1971
|
const permission = typeof sidecarData?.permission === "string" ? sidecarData.permission : "";
|
|
1970
1972
|
const hint = typeof sidecarData?.recovery === "string" ? sidecarData.recovery : void 0;
|
|
1971
1973
|
const requiresProcessRestart = sidecarData?.requiresProcessRestart === true || sidecarData?.requiresProcessRestart === "true";
|
|
@@ -1980,21 +1982,22 @@ function permissionItemsFromRecordError(data) {
|
|
|
1980
1982
|
];
|
|
1981
1983
|
}
|
|
1982
1984
|
function settingsUrlFromRecordError(data) {
|
|
1983
|
-
const sidecarError =
|
|
1984
|
-
const sidecarData =
|
|
1985
|
+
const sidecarError = isRecord9(data) ? data : void 0;
|
|
1986
|
+
const sidecarData = isRecord9(sidecarError?.data) ? sidecarError.data : void 0;
|
|
1985
1987
|
const permission = typeof sidecarData?.permission === "string" ? sidecarData.permission : "";
|
|
1986
1988
|
if (permission === "microphone") {
|
|
1987
1989
|
return "x-apple.systempreferences:com.apple.preference.security?Privacy_Microphone";
|
|
1988
1990
|
}
|
|
1989
1991
|
return "x-apple.systempreferences:com.apple.preference.security?Privacy_ScreenCapture";
|
|
1990
1992
|
}
|
|
1991
|
-
function
|
|
1993
|
+
function isRecord9(value) {
|
|
1992
1994
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1993
1995
|
}
|
|
1994
1996
|
function AppShell({
|
|
1995
1997
|
fetchJobs,
|
|
1996
1998
|
fetchTranscript,
|
|
1997
1999
|
fetchRecordings,
|
|
2000
|
+
fetchCachedRecordings,
|
|
1998
2001
|
fetchDashboardStats,
|
|
1999
2002
|
fetchAccountStatus,
|
|
2000
2003
|
recordingAudio,
|
|
@@ -2005,6 +2008,9 @@ function AppShell({
|
|
|
2005
2008
|
transcribeRecordingArtifact,
|
|
2006
2009
|
onRetranscribe,
|
|
2007
2010
|
onResummarize,
|
|
2011
|
+
onSyncRecordingText,
|
|
2012
|
+
onSyncRecordingAudio,
|
|
2013
|
+
onExportRecording,
|
|
2008
2014
|
initialView = "overview",
|
|
2009
2015
|
openUrl: openUrl2,
|
|
2010
2016
|
copyText: copyText2,
|
|
@@ -2025,6 +2031,7 @@ function AppShell({
|
|
|
2025
2031
|
const [selected, setSelected] = useState8(0);
|
|
2026
2032
|
const [spinnerFrame, setSpinnerFrame] = useState8(0);
|
|
2027
2033
|
const [loadingMoreRecordings, setLoadingMoreRecordings] = useState8(false);
|
|
2034
|
+
const [revalidatingRecordings, setRevalidatingRecordings] = useState8(false);
|
|
2028
2035
|
const [loaded, setLoaded] = useState8(false);
|
|
2029
2036
|
const [loadError, setLoadError] = useState8(void 0);
|
|
2030
2037
|
const [notice, setNotice] = useState8(void 0);
|
|
@@ -2242,6 +2249,21 @@ function AppShell({
|
|
|
2242
2249
|
}, [peekTranscriptId, fetchTranscript]);
|
|
2243
2250
|
const peekSummary = peekTranscriptId ? summaryCache.get(peekTranscriptId) : void 0;
|
|
2244
2251
|
const refresh = useCallback(async ({ resetRecordings = false } = {}) => {
|
|
2252
|
+
let showingCachedRecordings = false;
|
|
2253
|
+
if (resetRecordings && fetchCachedRecordings) {
|
|
2254
|
+
try {
|
|
2255
|
+
const cached2 = await fetchCachedRecordings({ limit: RECORDINGS_PAGE_SIZE });
|
|
2256
|
+
if (cached2.items.length > 0) {
|
|
2257
|
+
showingCachedRecordings = true;
|
|
2258
|
+
setRecordings(cached2.items);
|
|
2259
|
+
setRecordingsNextCursor(cached2.nextCursor ?? null);
|
|
2260
|
+
setRecordingsTotalCount(cached2.totalCount);
|
|
2261
|
+
setLoaded(true);
|
|
2262
|
+
setRevalidatingRecordings(Boolean(fetchRecordings));
|
|
2263
|
+
}
|
|
2264
|
+
} catch {
|
|
2265
|
+
}
|
|
2266
|
+
}
|
|
2245
2267
|
const [jobsR, recR, statsR, accountR] = await Promise.allSettled([
|
|
2246
2268
|
fetchJobs(),
|
|
2247
2269
|
resetRecordings && fetchRecordings ? fetchRecordings({ limit: RECORDINGS_PAGE_SIZE }) : Promise.resolve(void 0),
|
|
@@ -2267,7 +2289,8 @@ function AppShell({
|
|
|
2267
2289
|
setAccountStatus("error");
|
|
2268
2290
|
}
|
|
2269
2291
|
setLoaded(true);
|
|
2270
|
-
|
|
2292
|
+
if (showingCachedRecordings) setRevalidatingRecordings(false);
|
|
2293
|
+
}, [fetchJobs, fetchRecordings, fetchCachedRecordings, fetchDashboardStats, fetchAccountStatus]);
|
|
2271
2294
|
const transcribeStoppedRecording = useCallback(async () => {
|
|
2272
2295
|
const current = liveRecord;
|
|
2273
2296
|
if (current?.kind !== "stopped") return;
|
|
@@ -2458,6 +2481,54 @@ function AppShell({
|
|
|
2458
2481
|
},
|
|
2459
2482
|
[onResummarize, refresh, recordings, now, refetchTranscript]
|
|
2460
2483
|
);
|
|
2484
|
+
const syncedTextRef = useRef3(/* @__PURE__ */ new Set());
|
|
2485
|
+
const syncRecordingText2 = useCallback(
|
|
2486
|
+
async (recordingId, opts = {}) => {
|
|
2487
|
+
if (!onSyncRecordingText) return;
|
|
2488
|
+
if (opts.manual) setNotice("Syncing text locally\u2026");
|
|
2489
|
+
try {
|
|
2490
|
+
const data = await onSyncRecordingText(recordingId);
|
|
2491
|
+
syncedTextRef.current.add(recordingId);
|
|
2492
|
+
if (opts.manual) setNotice(`Text synced \xB7 ${data.sessionDir}`);
|
|
2493
|
+
} catch (error51) {
|
|
2494
|
+
if (opts.manual) setNotice(transcribeHandoffErrorCopy(error51));
|
|
2495
|
+
}
|
|
2496
|
+
},
|
|
2497
|
+
[onSyncRecordingText]
|
|
2498
|
+
);
|
|
2499
|
+
const syncRecordingAudio2 = useCallback(
|
|
2500
|
+
async (recordingId) => {
|
|
2501
|
+
if (!onSyncRecordingAudio) {
|
|
2502
|
+
setNotice("Audio sync is not available in this CLI session.");
|
|
2503
|
+
return;
|
|
2504
|
+
}
|
|
2505
|
+
setNotice("Downloading audio\u2026");
|
|
2506
|
+
try {
|
|
2507
|
+
const data = await onSyncRecordingAudio(recordingId);
|
|
2508
|
+
setNotice(`Audio saved \xB7 ${data.audioPath}`);
|
|
2509
|
+
} catch (error51) {
|
|
2510
|
+
setNotice(transcribeHandoffErrorCopy(error51));
|
|
2511
|
+
}
|
|
2512
|
+
},
|
|
2513
|
+
[onSyncRecordingAudio]
|
|
2514
|
+
);
|
|
2515
|
+
const exportRecordingForAgent = useCallback(
|
|
2516
|
+
async (recordingId) => {
|
|
2517
|
+
if (!onExportRecording) {
|
|
2518
|
+
setNotice("Export is not available in this CLI session.");
|
|
2519
|
+
return;
|
|
2520
|
+
}
|
|
2521
|
+
setNotice("Exporting\u2026");
|
|
2522
|
+
try {
|
|
2523
|
+
const data = await onExportRecording(recordingId);
|
|
2524
|
+
copyText2?.(data.textPath);
|
|
2525
|
+
setNotice(`Exported \xB7 ${data.textPath} (path copied)`);
|
|
2526
|
+
} catch (error51) {
|
|
2527
|
+
setNotice(transcribeHandoffErrorCopy(error51));
|
|
2528
|
+
}
|
|
2529
|
+
},
|
|
2530
|
+
[onExportRecording, copyText2]
|
|
2531
|
+
);
|
|
2461
2532
|
useEffect4(() => {
|
|
2462
2533
|
if (liveRecord?.kind !== "stopped") return;
|
|
2463
2534
|
const artifact = liveRecord.artifact;
|
|
@@ -2602,6 +2673,11 @@ function AppShell({
|
|
|
2602
2673
|
cancelled = true;
|
|
2603
2674
|
};
|
|
2604
2675
|
}, [detailTranscriptId, fetchTranscript]);
|
|
2676
|
+
const detailRecordingId = screen.kind === "recordingDetail" ? screen.recordingId : void 0;
|
|
2677
|
+
useEffect4(() => {
|
|
2678
|
+
if (!detailRecordingId || syncedTextRef.current.has(detailRecordingId)) return;
|
|
2679
|
+
void syncRecordingText2(detailRecordingId);
|
|
2680
|
+
}, [detailRecordingId, syncRecordingText2]);
|
|
2605
2681
|
const setAudio = (recordingId, action) => setAudioCache((m) => new Map(m).set(recordingId, action));
|
|
2606
2682
|
const runAudio = useCallback(
|
|
2607
2683
|
async (recordingId, mode) => {
|
|
@@ -2708,6 +2784,7 @@ function AppShell({
|
|
|
2708
2784
|
if (screen.kind === "recordingDetail") {
|
|
2709
2785
|
const detailRec = recordings.find((r) => r.recordingId === screen.recordingId);
|
|
2710
2786
|
if (detailRec?.activeTranscriptId) refetchTranscript(detailRec.activeTranscriptId);
|
|
2787
|
+
void syncRecordingText2(screen.recordingId, { manual: true });
|
|
2711
2788
|
}
|
|
2712
2789
|
return;
|
|
2713
2790
|
}
|
|
@@ -2750,10 +2827,13 @@ function AppShell({
|
|
|
2750
2827
|
const links = rec ? resolveRecordingLinks(rec.recordingId, rec.origin) : {};
|
|
2751
2828
|
if (input === "T" && rec) void retranscribeExistingRecording(rec.recordingId);
|
|
2752
2829
|
else if ((input === "s" || input === "S") && rec) void resummarizeExistingRecording(rec.recordingId);
|
|
2830
|
+
else if (input === "e" && rec) void exportRecordingForAgent(rec.recordingId);
|
|
2753
2831
|
else if (input === "t" && rec?.activeTranscriptId) void openTranscript(rec.activeTranscriptId);
|
|
2754
2832
|
else if (input === "o" && rec) void runAudio(rec.recordingId, "open");
|
|
2755
|
-
else if (input === "d" && rec)
|
|
2756
|
-
|
|
2833
|
+
else if (input === "d" && rec) {
|
|
2834
|
+
if (onSyncRecordingAudio) void syncRecordingAudio2(rec.recordingId);
|
|
2835
|
+
else void runAudio(rec.recordingId, "download");
|
|
2836
|
+
} else if (input === "f" && rec) void runAudio(rec.recordingId, "finder");
|
|
2757
2837
|
else if (input === "w" && links.webUrl) openUrl2?.(links.webUrl);
|
|
2758
2838
|
else if (input === "c" && links.webUrl) {
|
|
2759
2839
|
copyText2?.(links.webUrl);
|
|
@@ -2873,7 +2953,8 @@ function AppShell({
|
|
|
2873
2953
|
peekItem: recordings[selected],
|
|
2874
2954
|
peekSummary,
|
|
2875
2955
|
showPeek,
|
|
2876
|
-
peekWidth
|
|
2956
|
+
peekWidth,
|
|
2957
|
+
revalidating: revalidatingRecordings
|
|
2877
2958
|
}
|
|
2878
2959
|
);
|
|
2879
2960
|
} else if (screen.kind === "account") {
|
|
@@ -2991,6 +3072,7 @@ async function runDashboard(deps) {
|
|
|
2991
3072
|
fetchJobs: deps.fetchJobs,
|
|
2992
3073
|
fetchTranscript: deps.fetchTranscript,
|
|
2993
3074
|
fetchRecordings: deps.fetchRecordings,
|
|
3075
|
+
fetchCachedRecordings: deps.fetchCachedRecordings,
|
|
2994
3076
|
fetchDashboardStats: deps.fetchDashboardStats,
|
|
2995
3077
|
fetchAccountStatus: deps.fetchAccountStatus,
|
|
2996
3078
|
recordingAudio: deps.recordingAudio,
|
|
@@ -3799,10 +3881,10 @@ function mergeDefs(...defs) {
|
|
|
3799
3881
|
function cloneDef(schema) {
|
|
3800
3882
|
return mergeDefs(schema._zod.def);
|
|
3801
3883
|
}
|
|
3802
|
-
function getElementAtPath(obj,
|
|
3803
|
-
if (!
|
|
3884
|
+
function getElementAtPath(obj, path8) {
|
|
3885
|
+
if (!path8)
|
|
3804
3886
|
return obj;
|
|
3805
|
-
return
|
|
3887
|
+
return path8.reduce((acc, key) => acc?.[key], obj);
|
|
3806
3888
|
}
|
|
3807
3889
|
function promiseAllObject(promisesObj) {
|
|
3808
3890
|
const keys = Object.keys(promisesObj);
|
|
@@ -4211,11 +4293,11 @@ function explicitlyAborted(x, startIndex = 0) {
|
|
|
4211
4293
|
}
|
|
4212
4294
|
return false;
|
|
4213
4295
|
}
|
|
4214
|
-
function prefixIssues(
|
|
4296
|
+
function prefixIssues(path8, issues) {
|
|
4215
4297
|
return issues.map((iss) => {
|
|
4216
4298
|
var _a3;
|
|
4217
4299
|
(_a3 = iss).path ?? (_a3.path = []);
|
|
4218
|
-
iss.path.unshift(
|
|
4300
|
+
iss.path.unshift(path8);
|
|
4219
4301
|
return iss;
|
|
4220
4302
|
});
|
|
4221
4303
|
}
|
|
@@ -4362,16 +4444,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
|
|
|
4362
4444
|
}
|
|
4363
4445
|
function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
4364
4446
|
const fieldErrors = { _errors: [] };
|
|
4365
|
-
const processError = (error52,
|
|
4447
|
+
const processError = (error52, path8 = []) => {
|
|
4366
4448
|
for (const issue2 of error52.issues) {
|
|
4367
4449
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
4368
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
4450
|
+
issue2.errors.map((issues) => processError({ issues }, [...path8, ...issue2.path]));
|
|
4369
4451
|
} else if (issue2.code === "invalid_key") {
|
|
4370
|
-
processError({ issues: issue2.issues }, [...
|
|
4452
|
+
processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
|
|
4371
4453
|
} else if (issue2.code === "invalid_element") {
|
|
4372
|
-
processError({ issues: issue2.issues }, [...
|
|
4454
|
+
processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
|
|
4373
4455
|
} else {
|
|
4374
|
-
const fullpath = [...
|
|
4456
|
+
const fullpath = [...path8, ...issue2.path];
|
|
4375
4457
|
if (fullpath.length === 0) {
|
|
4376
4458
|
fieldErrors._errors.push(mapper(issue2));
|
|
4377
4459
|
} else {
|
|
@@ -4398,17 +4480,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
|
4398
4480
|
}
|
|
4399
4481
|
function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
4400
4482
|
const result = { errors: [] };
|
|
4401
|
-
const processError = (error52,
|
|
4483
|
+
const processError = (error52, path8 = []) => {
|
|
4402
4484
|
var _a3, _b;
|
|
4403
4485
|
for (const issue2 of error52.issues) {
|
|
4404
4486
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
4405
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
4487
|
+
issue2.errors.map((issues) => processError({ issues }, [...path8, ...issue2.path]));
|
|
4406
4488
|
} else if (issue2.code === "invalid_key") {
|
|
4407
|
-
processError({ issues: issue2.issues }, [...
|
|
4489
|
+
processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
|
|
4408
4490
|
} else if (issue2.code === "invalid_element") {
|
|
4409
|
-
processError({ issues: issue2.issues }, [...
|
|
4491
|
+
processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
|
|
4410
4492
|
} else {
|
|
4411
|
-
const fullpath = [...
|
|
4493
|
+
const fullpath = [...path8, ...issue2.path];
|
|
4412
4494
|
if (fullpath.length === 0) {
|
|
4413
4495
|
result.errors.push(mapper(issue2));
|
|
4414
4496
|
continue;
|
|
@@ -4440,8 +4522,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
|
4440
4522
|
}
|
|
4441
4523
|
function toDotPath(_path) {
|
|
4442
4524
|
const segs = [];
|
|
4443
|
-
const
|
|
4444
|
-
for (const seg of
|
|
4525
|
+
const path8 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
4526
|
+
for (const seg of path8) {
|
|
4445
4527
|
if (typeof seg === "number")
|
|
4446
4528
|
segs.push(`[${seg}]`);
|
|
4447
4529
|
else if (typeof seg === "symbol")
|
|
@@ -17133,13 +17215,13 @@ function resolveRef(ref, ctx) {
|
|
|
17133
17215
|
if (!ref.startsWith("#")) {
|
|
17134
17216
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
17135
17217
|
}
|
|
17136
|
-
const
|
|
17137
|
-
if (
|
|
17218
|
+
const path8 = ref.slice(1).split("/").filter(Boolean);
|
|
17219
|
+
if (path8.length === 0) {
|
|
17138
17220
|
return ctx.rootSchema;
|
|
17139
17221
|
}
|
|
17140
17222
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
17141
|
-
if (
|
|
17142
|
-
const key =
|
|
17223
|
+
if (path8[0] === defsKey) {
|
|
17224
|
+
const key = path8[1];
|
|
17143
17225
|
if (!key || !ctx.defs[key]) {
|
|
17144
17226
|
throw new Error(`Reference not found: ${ref}`);
|
|
17145
17227
|
}
|
|
@@ -18824,6 +18906,9 @@ function defaultStorePath(homeDir = os3.homedir(), env = process.env) {
|
|
|
18824
18906
|
const dataHome = env.XDG_DATA_HOME?.trim() || path3.join(homeDir, ".local", "share");
|
|
18825
18907
|
return path3.join(dataHome, "recappi", "cli-state.sqlite");
|
|
18826
18908
|
}
|
|
18909
|
+
function normalizeAccountStamp(input) {
|
|
18910
|
+
return parseAccountPartition(input, "lenient");
|
|
18911
|
+
}
|
|
18827
18912
|
function requireAccountPartition(input) {
|
|
18828
18913
|
const account = parseAccountPartition(input, "strict");
|
|
18829
18914
|
if (!account) {
|
|
@@ -19731,12 +19816,12 @@ var RecappiApiClient = class {
|
|
|
19731
19816
|
} : {}
|
|
19732
19817
|
};
|
|
19733
19818
|
}
|
|
19734
|
-
async getJson(
|
|
19735
|
-
const response = await this.request("GET",
|
|
19819
|
+
async getJson(path8) {
|
|
19820
|
+
const response = await this.request("GET", path8);
|
|
19736
19821
|
return await parseJson(response);
|
|
19737
19822
|
}
|
|
19738
|
-
async postJson(
|
|
19739
|
-
const response = await this.request("POST",
|
|
19823
|
+
async postJson(path8, body) {
|
|
19824
|
+
const response = await this.request("POST", path8, JSON.stringify(body), {
|
|
19740
19825
|
headers: { "content-type": "application/json" }
|
|
19741
19826
|
});
|
|
19742
19827
|
return await parseJson(response);
|
|
@@ -20127,8 +20212,11 @@ import { promises as fs4 } from "fs";
|
|
|
20127
20212
|
import path5 from "path";
|
|
20128
20213
|
function createRecordingAudioRuntime(client, deps = {}) {
|
|
20129
20214
|
const downloadRecordingAudioFile = async (recordingId, opts) => {
|
|
20130
|
-
const cached2 =
|
|
20131
|
-
if (cached2)
|
|
20215
|
+
const cached2 = await findReusableDownload(recordingId, deps);
|
|
20216
|
+
if (cached2) {
|
|
20217
|
+
if (!opts?.directory) return cached2;
|
|
20218
|
+
return materializeCachedDownload(recordingId, cached2, opts, deps);
|
|
20219
|
+
}
|
|
20132
20220
|
const directory = opts?.directory ?? (deps.account ? defaultDownloadDirectory(deps) : void 0);
|
|
20133
20221
|
const download = await client.downloadRecordingAudio(recordingId, {
|
|
20134
20222
|
...opts,
|
|
@@ -20156,6 +20244,38 @@ function createRecordingAudioRuntime(client, deps = {}) {
|
|
|
20156
20244
|
)
|
|
20157
20245
|
};
|
|
20158
20246
|
}
|
|
20247
|
+
async function materializeCachedDownload(recordingId, cached2, opts, deps) {
|
|
20248
|
+
if (!opts.directory) return cached2;
|
|
20249
|
+
await fs4.mkdir(opts.directory, { recursive: true });
|
|
20250
|
+
const contentType = cached2.contentType ?? contentTypeForAudioPath(cached2.localPath);
|
|
20251
|
+
const targetPath = path5.join(
|
|
20252
|
+
opts.directory,
|
|
20253
|
+
recordingAudioFileName(recordingId, opts.title, contentType, opts.filenameStem)
|
|
20254
|
+
);
|
|
20255
|
+
if (path5.resolve(cached2.localPath) !== path5.resolve(targetPath)) {
|
|
20256
|
+
await fs4.copyFile(cached2.localPath, targetPath);
|
|
20257
|
+
}
|
|
20258
|
+
const contentLength = cached2.contentLength ?? (await fs4.stat(targetPath)).size;
|
|
20259
|
+
const artifact = await rememberDownload(
|
|
20260
|
+
{
|
|
20261
|
+
recordingId,
|
|
20262
|
+
localPath: targetPath,
|
|
20263
|
+
contentType,
|
|
20264
|
+
contentLength,
|
|
20265
|
+
origin: cached2.origin ?? ""
|
|
20266
|
+
},
|
|
20267
|
+
deps
|
|
20268
|
+
);
|
|
20269
|
+
return {
|
|
20270
|
+
recordingId,
|
|
20271
|
+
localPath: targetPath,
|
|
20272
|
+
reused: true,
|
|
20273
|
+
...artifact ? { artifactId: artifact.id } : {},
|
|
20274
|
+
contentType,
|
|
20275
|
+
contentLength,
|
|
20276
|
+
...cached2.origin ? { origin: cached2.origin } : {}
|
|
20277
|
+
};
|
|
20278
|
+
}
|
|
20159
20279
|
function openPath(localPath, deps = {}) {
|
|
20160
20280
|
return runMacOpen([localPath], deps);
|
|
20161
20281
|
}
|
|
@@ -20186,7 +20306,7 @@ async function rememberDownload(download, deps) {
|
|
|
20186
20306
|
resource: "recording_audio",
|
|
20187
20307
|
contentType: download.contentType,
|
|
20188
20308
|
...download.contentLength !== void 0 ? { contentLength: download.contentLength } : {},
|
|
20189
|
-
origin: download.origin
|
|
20309
|
+
...download.origin ? { origin: download.origin } : {}
|
|
20190
20310
|
}
|
|
20191
20311
|
});
|
|
20192
20312
|
return store.markLocalArtifactOpened(artifact.id);
|
|
@@ -20214,6 +20334,27 @@ async function withStore(deps, run) {
|
|
|
20214
20334
|
function defaultDownloadDirectory(deps) {
|
|
20215
20335
|
return path5.join(path5.dirname(defaultStorePath(deps.homeDir, deps.env)), "downloads");
|
|
20216
20336
|
}
|
|
20337
|
+
function contentTypeForAudioPath(localPath) {
|
|
20338
|
+
switch (path5.extname(localPath).toLowerCase()) {
|
|
20339
|
+
case ".mp3":
|
|
20340
|
+
return "audio/mpeg";
|
|
20341
|
+
case ".m4a":
|
|
20342
|
+
case ".mp4":
|
|
20343
|
+
return "audio/m4a";
|
|
20344
|
+
case ".ogg":
|
|
20345
|
+
return "audio/ogg";
|
|
20346
|
+
case ".flac":
|
|
20347
|
+
return "audio/flac";
|
|
20348
|
+
case ".webm":
|
|
20349
|
+
return "audio/webm";
|
|
20350
|
+
case ".aiff":
|
|
20351
|
+
case ".aif":
|
|
20352
|
+
return "audio/aiff";
|
|
20353
|
+
case ".wav":
|
|
20354
|
+
default:
|
|
20355
|
+
return "audio/wav";
|
|
20356
|
+
}
|
|
20357
|
+
}
|
|
20217
20358
|
async function isReadableFile(localPath) {
|
|
20218
20359
|
try {
|
|
20219
20360
|
return (await fs4.stat(localPath)).isFile();
|
|
@@ -20493,41 +20634,170 @@ ${lines.join("\n")}
|
|
|
20493
20634
|
}
|
|
20494
20635
|
|
|
20495
20636
|
// src/export.ts
|
|
20496
|
-
import { promises as
|
|
20637
|
+
import { promises as fs6 } from "fs";
|
|
20497
20638
|
import os5 from "os";
|
|
20639
|
+
import path7 from "path";
|
|
20640
|
+
|
|
20641
|
+
// src/recordingSessionCache.ts
|
|
20642
|
+
import { promises as fs5 } from "fs";
|
|
20498
20643
|
import path6 from "path";
|
|
20644
|
+
function accountFromStatus(status) {
|
|
20645
|
+
if (!status.loggedIn || !status.userId) return null;
|
|
20646
|
+
return normalizeAccountStamp({ backendOrigin: status.origin, userId: status.userId });
|
|
20647
|
+
}
|
|
20648
|
+
async function findIndexedRecordingSessionDir(recordingId, deps) {
|
|
20649
|
+
return withSessionStore(deps, async (store, account) => {
|
|
20650
|
+
if (!account) return void 0;
|
|
20651
|
+
const artifact = store.findLocalArtifactForAccount(account, {
|
|
20652
|
+
kind: "recording_session",
|
|
20653
|
+
remoteId: recordingId
|
|
20654
|
+
});
|
|
20655
|
+
if (!artifact) return void 0;
|
|
20656
|
+
if (!await isReadableDirectory(artifact.localPath)) return void 0;
|
|
20657
|
+
const manifest = await readJsonRecord(path6.join(artifact.localPath, "remote-session.json"));
|
|
20658
|
+
if (manifest?.recordingId && manifest.recordingId !== recordingId) return void 0;
|
|
20659
|
+
return artifact.localPath;
|
|
20660
|
+
});
|
|
20661
|
+
}
|
|
20662
|
+
async function rememberRecordingSession(input, deps) {
|
|
20663
|
+
return withSessionStore(deps, (store, account) => {
|
|
20664
|
+
if (!account) return null;
|
|
20665
|
+
return store.upsertLocalArtifact({
|
|
20666
|
+
kind: "recording_session",
|
|
20667
|
+
account,
|
|
20668
|
+
remoteId: input.recording.recordingId,
|
|
20669
|
+
localPath: input.sessionDir,
|
|
20670
|
+
metadata: stripUndefined({
|
|
20671
|
+
resource: "recording_session",
|
|
20672
|
+
source: input.source,
|
|
20673
|
+
sessionDir: input.sessionDir,
|
|
20674
|
+
recording: input.recording,
|
|
20675
|
+
files: stripUndefined({ ...input.files }),
|
|
20676
|
+
transcriptId: input.transcriptId,
|
|
20677
|
+
summaryStatus: input.summaryStatus,
|
|
20678
|
+
uploadFilename: input.uploadFilename,
|
|
20679
|
+
origin: input.recording.origin,
|
|
20680
|
+
indexedAt: (input.now ?? (() => /* @__PURE__ */ new Date()))().toISOString()
|
|
20681
|
+
})
|
|
20682
|
+
});
|
|
20683
|
+
});
|
|
20684
|
+
}
|
|
20685
|
+
async function listCachedRecordingSessions(deps) {
|
|
20686
|
+
const limit = deps.limit ?? 50;
|
|
20687
|
+
const items = await withSessionStore(deps, async (store, account) => {
|
|
20688
|
+
if (!account) return [];
|
|
20689
|
+
const artifacts = store.listLocalArtifactsForAccount(account, { kind: "recording_session" });
|
|
20690
|
+
const recordings = [];
|
|
20691
|
+
const seen = /* @__PURE__ */ new Set();
|
|
20692
|
+
for (const artifact of artifacts) {
|
|
20693
|
+
if (recordings.length >= limit) break;
|
|
20694
|
+
const recording = await recordingFromArtifact(artifact);
|
|
20695
|
+
if (!recording || seen.has(recording.recordingId)) continue;
|
|
20696
|
+
if (!await isReadableDirectory(artifact.localPath)) continue;
|
|
20697
|
+
seen.add(recording.recordingId);
|
|
20698
|
+
recordings.push(recording);
|
|
20699
|
+
}
|
|
20700
|
+
return recordings.sort((a, b) => b.createdAt - a.createdAt || b.updatedAt - a.updatedAt);
|
|
20701
|
+
});
|
|
20702
|
+
return recordingListDataSchema.parse({
|
|
20703
|
+
items,
|
|
20704
|
+
limit,
|
|
20705
|
+
nextCursor: null,
|
|
20706
|
+
totalCount: items.length,
|
|
20707
|
+
origin: deps.origin
|
|
20708
|
+
});
|
|
20709
|
+
}
|
|
20710
|
+
async function recordingFromArtifact(artifact) {
|
|
20711
|
+
const metadata = isRecord4(artifact.metadata) ? artifact.metadata : {};
|
|
20712
|
+
const cached2 = recordingDataSchema.safeParse(metadata.recording);
|
|
20713
|
+
if (cached2.success) return cached2.data;
|
|
20714
|
+
const fromFile = await readJsonRecord(path6.join(artifact.localPath, "recording.json"));
|
|
20715
|
+
const parsed = recordingDataSchema.safeParse(fromFile);
|
|
20716
|
+
return parsed.success ? parsed.data : null;
|
|
20717
|
+
}
|
|
20718
|
+
async function withSessionStore(deps, run) {
|
|
20719
|
+
const store = deps.store ?? openCliStore({ homeDir: deps.homeDir, env: deps.env });
|
|
20720
|
+
try {
|
|
20721
|
+
return await run(store, deps.account ?? null);
|
|
20722
|
+
} finally {
|
|
20723
|
+
if (!deps.store) store.close();
|
|
20724
|
+
}
|
|
20725
|
+
}
|
|
20726
|
+
async function readJsonRecord(filePath) {
|
|
20727
|
+
try {
|
|
20728
|
+
const parsed = JSON.parse(await fs5.readFile(filePath, "utf8"));
|
|
20729
|
+
return isRecord4(parsed) ? parsed : void 0;
|
|
20730
|
+
} catch {
|
|
20731
|
+
return void 0;
|
|
20732
|
+
}
|
|
20733
|
+
}
|
|
20734
|
+
async function isReadableDirectory(localPath) {
|
|
20735
|
+
try {
|
|
20736
|
+
return (await fs5.stat(localPath)).isDirectory();
|
|
20737
|
+
} catch {
|
|
20738
|
+
return false;
|
|
20739
|
+
}
|
|
20740
|
+
}
|
|
20741
|
+
function stripUndefined(value) {
|
|
20742
|
+
return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== void 0));
|
|
20743
|
+
}
|
|
20744
|
+
function isRecord4(value) {
|
|
20745
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
20746
|
+
}
|
|
20747
|
+
|
|
20748
|
+
// src/export.ts
|
|
20499
20749
|
async function syncRecordingText(opts) {
|
|
20500
20750
|
const context = await loadRecordingBundleContext(opts);
|
|
20501
|
-
const
|
|
20751
|
+
const account = accountFromStatus(context.subscription);
|
|
20752
|
+
const sessionDir = await resolveRecordingSessionDir(context.recording, opts, account);
|
|
20502
20753
|
return writeRecordingTextFiles(context, sessionDir, {
|
|
20503
|
-
now: opts.now
|
|
20754
|
+
now: opts.now,
|
|
20755
|
+
store: opts.store,
|
|
20756
|
+
env: opts.env,
|
|
20757
|
+
homeDir: opts.homeDir,
|
|
20758
|
+
account,
|
|
20759
|
+
source: "text_sync"
|
|
20504
20760
|
});
|
|
20505
20761
|
}
|
|
20506
20762
|
async function syncRecordingAudio(opts) {
|
|
20507
20763
|
const context = await loadRecordingBundleContext(opts);
|
|
20508
|
-
const
|
|
20764
|
+
const account = accountFromStatus(context.subscription);
|
|
20765
|
+
const sessionDir = await resolveRecordingSessionDir(context.recording, opts, account);
|
|
20509
20766
|
const audio = await downloadRecordingAudioToDir(context.recording, opts.recordingAudio, sessionDir);
|
|
20510
20767
|
const text = await writeRecordingTextFiles(context, sessionDir, {
|
|
20511
20768
|
now: opts.now,
|
|
20512
|
-
uploadFilename:
|
|
20769
|
+
uploadFilename: path7.basename(audio.localPath),
|
|
20770
|
+
store: opts.store,
|
|
20771
|
+
env: opts.env,
|
|
20772
|
+
homeDir: opts.homeDir,
|
|
20773
|
+
account,
|
|
20774
|
+
source: "audio_sync",
|
|
20775
|
+
audioPath: audio.localPath
|
|
20513
20776
|
});
|
|
20514
20777
|
return { ...text, audioPath: audio.localPath, audio: audioMetadata(audio) };
|
|
20515
20778
|
}
|
|
20516
20779
|
async function exportRecording(opts) {
|
|
20517
20780
|
const context = await loadRecordingBundleContext(opts);
|
|
20518
|
-
const
|
|
20781
|
+
const account = accountFromStatus(context.subscription);
|
|
20782
|
+
const exportDir = await resolveRecordingSessionDir(context.recording, opts, account);
|
|
20519
20783
|
const audio = await downloadRecordingAudioToDir(context.recording, opts.recordingAudio, exportDir);
|
|
20520
20784
|
const textFiles = await writeRecordingTextFiles(context, exportDir, {
|
|
20521
20785
|
now: opts.now,
|
|
20522
|
-
uploadFilename:
|
|
20786
|
+
uploadFilename: path7.basename(audio.localPath),
|
|
20787
|
+
store: opts.store,
|
|
20788
|
+
env: opts.env,
|
|
20789
|
+
homeDir: opts.homeDir,
|
|
20790
|
+
account,
|
|
20791
|
+
source: "export",
|
|
20792
|
+
audioPath: audio.localPath
|
|
20523
20793
|
});
|
|
20524
20794
|
const { recording, subscription, transcript } = context;
|
|
20525
|
-
const subscriptionPath =
|
|
20526
|
-
const subscriptionJsonPath =
|
|
20527
|
-
await
|
|
20795
|
+
const subscriptionPath = path7.join(exportDir, "subscription.md");
|
|
20796
|
+
const subscriptionJsonPath = path7.join(exportDir, "subscription.json");
|
|
20797
|
+
await fs6.writeFile(subscriptionPath, renderSubscriptionMarkdown(subscription), "utf8");
|
|
20528
20798
|
await writeJson(subscriptionJsonPath, subscription);
|
|
20529
|
-
const textPath =
|
|
20530
|
-
const manifestPath =
|
|
20799
|
+
const textPath = path7.join(exportDir, "handoff.md");
|
|
20800
|
+
const manifestPath = path7.join(exportDir, "manifest.json");
|
|
20531
20801
|
const data = recordingExportDataSchema.parse({
|
|
20532
20802
|
origin: recording.origin,
|
|
20533
20803
|
recordingId: recording.recordingId,
|
|
@@ -20549,7 +20819,7 @@ async function exportRecording(opts) {
|
|
|
20549
20819
|
...textFiles.summaryStatus ? { summaryStatus: textFiles.summaryStatus } : {},
|
|
20550
20820
|
audio: audioMetadata(audio)
|
|
20551
20821
|
});
|
|
20552
|
-
await
|
|
20822
|
+
await fs6.writeFile(
|
|
20553
20823
|
textPath,
|
|
20554
20824
|
renderHandoffMarkdown(recording, subscription, audio, data, transcript),
|
|
20555
20825
|
"utf8"
|
|
@@ -20559,6 +20829,33 @@ async function exportRecording(opts) {
|
|
|
20559
20829
|
command: "recordings export",
|
|
20560
20830
|
data
|
|
20561
20831
|
});
|
|
20832
|
+
await rememberRecordingSession(
|
|
20833
|
+
{
|
|
20834
|
+
recording,
|
|
20835
|
+
sessionDir: exportDir,
|
|
20836
|
+
files: {
|
|
20837
|
+
remoteManifestPath: data.remoteManifestPath,
|
|
20838
|
+
sessionMetadataPath: data.sessionMetadataPath,
|
|
20839
|
+
recordingJsonPath: data.recordingJsonPath,
|
|
20840
|
+
...data.transcriptPath ? { transcriptPath: data.transcriptPath } : {},
|
|
20841
|
+
...data.transcriptJsonPath ? { transcriptJsonPath: data.transcriptJsonPath } : {},
|
|
20842
|
+
...data.summaryPath ? { summaryPath: data.summaryPath } : {},
|
|
20843
|
+
...data.summaryJsonPath ? { summaryJsonPath: data.summaryJsonPath } : {},
|
|
20844
|
+
...data.actionItemsPath ? { actionItemsPath: data.actionItemsPath } : {},
|
|
20845
|
+
audioPath: data.audioPath,
|
|
20846
|
+
subscriptionPath: data.subscriptionPath,
|
|
20847
|
+
subscriptionJsonPath: data.subscriptionJsonPath,
|
|
20848
|
+
textPath: data.textPath,
|
|
20849
|
+
manifestPath: data.manifestPath
|
|
20850
|
+
},
|
|
20851
|
+
...data.transcriptId !== void 0 ? { transcriptId: data.transcriptId } : {},
|
|
20852
|
+
...data.summaryStatus ? { summaryStatus: data.summaryStatus } : {},
|
|
20853
|
+
uploadFilename: path7.basename(audio.localPath),
|
|
20854
|
+
source: "export",
|
|
20855
|
+
now: opts.now
|
|
20856
|
+
},
|
|
20857
|
+
{ account, store: opts.store, env: opts.env, homeDir: opts.homeDir }
|
|
20858
|
+
);
|
|
20562
20859
|
return data;
|
|
20563
20860
|
}
|
|
20564
20861
|
async function loadRecordingBundleContext(opts) {
|
|
@@ -20581,11 +20878,11 @@ async function downloadRecordingAudioToDir(recording, recordingAudio, directory)
|
|
|
20581
20878
|
}
|
|
20582
20879
|
async function writeRecordingTextFiles(context, sessionDir, opts) {
|
|
20583
20880
|
const { recording, transcript, subscription } = context;
|
|
20584
|
-
await
|
|
20585
|
-
const recordingJsonPath =
|
|
20586
|
-
const sessionMetadataPath =
|
|
20587
|
-
const remoteManifestPath =
|
|
20588
|
-
const existingManifest = await
|
|
20881
|
+
await fs6.mkdir(sessionDir, { recursive: true });
|
|
20882
|
+
const recordingJsonPath = path7.join(sessionDir, "recording.json");
|
|
20883
|
+
const sessionMetadataPath = path7.join(sessionDir, "session-metadata.json");
|
|
20884
|
+
const remoteManifestPath = path7.join(sessionDir, "remote-session.json");
|
|
20885
|
+
const existingManifest = await readJsonRecord2(remoteManifestPath);
|
|
20589
20886
|
const uploadFilename = opts.uploadFilename ?? (typeof existingManifest?.uploadFilename === "string" ? existingManifest.uploadFilename : void 0);
|
|
20590
20887
|
await writeJson(recordingJsonPath, recording);
|
|
20591
20888
|
await writeJson(sessionMetadataPath, renderSessionMetadata(recording));
|
|
@@ -20600,19 +20897,23 @@ async function writeRecordingTextFiles(context, sessionDir, opts) {
|
|
|
20600
20897
|
let actionItemsPath;
|
|
20601
20898
|
let summaryStatus;
|
|
20602
20899
|
if (transcript) {
|
|
20603
|
-
transcriptPath =
|
|
20604
|
-
transcriptJsonPath =
|
|
20605
|
-
|
|
20606
|
-
summaryJsonPath = path6.join(sessionDir, "summary.json");
|
|
20607
|
-
actionItemsPath = path6.join(sessionDir, "action-items.md");
|
|
20900
|
+
transcriptPath = path7.join(sessionDir, "transcript.md");
|
|
20901
|
+
transcriptJsonPath = path7.join(sessionDir, "transcript.json");
|
|
20902
|
+
summaryJsonPath = path7.join(sessionDir, "summary.json");
|
|
20608
20903
|
summaryStatus = transcript.summary.status;
|
|
20609
|
-
await
|
|
20904
|
+
await fs6.writeFile(transcriptPath, renderTranscriptMarkdown(transcript), "utf8");
|
|
20610
20905
|
await writeJson(transcriptJsonPath, transcript);
|
|
20611
20906
|
await writeJson(summaryJsonPath, transcript.summary);
|
|
20612
|
-
|
|
20613
|
-
|
|
20907
|
+
const summaryFilePath = path7.join(sessionDir, "summary.md");
|
|
20908
|
+
const summaryMarkdown = renderSummaryMarkdown(transcript);
|
|
20909
|
+
await writeOptionalText(summaryFilePath, summaryMarkdown);
|
|
20910
|
+
if (summaryMarkdown) summaryPath = summaryFilePath;
|
|
20911
|
+
const actionItemsFilePath = path7.join(sessionDir, "action-items.md");
|
|
20912
|
+
const actionItemsMarkdown = renderActionItemsMarkdown(transcript.summary);
|
|
20913
|
+
await writeOptionalText(actionItemsFilePath, actionItemsMarkdown);
|
|
20914
|
+
if (actionItemsMarkdown) actionItemsPath = actionItemsFilePath;
|
|
20614
20915
|
}
|
|
20615
|
-
|
|
20916
|
+
const data = {
|
|
20616
20917
|
recordingId: recording.recordingId,
|
|
20617
20918
|
sessionDir,
|
|
20618
20919
|
remoteManifestPath,
|
|
@@ -20626,10 +20927,56 @@ async function writeRecordingTextFiles(context, sessionDir, opts) {
|
|
|
20626
20927
|
...actionItemsPath ? { actionItemsPath } : {},
|
|
20627
20928
|
...summaryStatus ? { summaryStatus } : {}
|
|
20628
20929
|
};
|
|
20930
|
+
await rememberRecordingSession(
|
|
20931
|
+
{
|
|
20932
|
+
recording,
|
|
20933
|
+
sessionDir,
|
|
20934
|
+
files: {
|
|
20935
|
+
remoteManifestPath,
|
|
20936
|
+
sessionMetadataPath,
|
|
20937
|
+
recordingJsonPath,
|
|
20938
|
+
...transcriptPath ? { transcriptPath } : {},
|
|
20939
|
+
...transcriptJsonPath ? { transcriptJsonPath } : {},
|
|
20940
|
+
...summaryPath ? { summaryPath } : {},
|
|
20941
|
+
...summaryJsonPath ? { summaryJsonPath } : {},
|
|
20942
|
+
...actionItemsPath ? { actionItemsPath } : {},
|
|
20943
|
+
...opts.audioPath ? { audioPath: opts.audioPath } : {}
|
|
20944
|
+
},
|
|
20945
|
+
...context.transcriptId !== void 0 ? { transcriptId: context.transcriptId } : {},
|
|
20946
|
+
...summaryStatus ? { summaryStatus } : {},
|
|
20947
|
+
...uploadFilename ? { uploadFilename } : {},
|
|
20948
|
+
source: opts.source,
|
|
20949
|
+
now: opts.now
|
|
20950
|
+
},
|
|
20951
|
+
{ account: opts.account ?? null, store: opts.store, env: opts.env, homeDir: opts.homeDir }
|
|
20952
|
+
);
|
|
20953
|
+
return data;
|
|
20629
20954
|
}
|
|
20630
|
-
async function resolveRecordingSessionDir(recording, opts) {
|
|
20631
|
-
if (opts.directory) return
|
|
20955
|
+
async function resolveRecordingSessionDir(recording, opts, account) {
|
|
20956
|
+
if (opts.directory) return path7.resolve(opts.directory);
|
|
20957
|
+
const indexed = await findIndexedRecordingSessionDir(recording.recordingId, {
|
|
20958
|
+
account,
|
|
20959
|
+
store: opts.store,
|
|
20960
|
+
homeDir: opts.homeDir,
|
|
20961
|
+
env: opts.env
|
|
20962
|
+
});
|
|
20963
|
+
if (indexed) return indexed;
|
|
20632
20964
|
const existing = await findExistingRecordingSessionDir(recording.recordingId, opts.homeDir, opts.env);
|
|
20965
|
+
if (existing) {
|
|
20966
|
+
await rememberRecordingSession(
|
|
20967
|
+
{
|
|
20968
|
+
recording,
|
|
20969
|
+
sessionDir: existing,
|
|
20970
|
+
files: {
|
|
20971
|
+
remoteManifestPath: path7.join(existing, "remote-session.json"),
|
|
20972
|
+
sessionMetadataPath: path7.join(existing, "session-metadata.json"),
|
|
20973
|
+
recordingJsonPath: path7.join(existing, "recording.json")
|
|
20974
|
+
},
|
|
20975
|
+
source: "manifest_scan"
|
|
20976
|
+
},
|
|
20977
|
+
{ account, store: opts.store, env: opts.env, homeDir: opts.homeDir }
|
|
20978
|
+
);
|
|
20979
|
+
}
|
|
20633
20980
|
if (existing) return existing;
|
|
20634
20981
|
return createRecordingSessionDir(recording, opts.homeDir, opts.env);
|
|
20635
20982
|
}
|
|
@@ -20637,39 +20984,39 @@ async function findExistingRecordingSessionDir(recordingId, homeDir, env) {
|
|
|
20637
20984
|
const base = recordingSessionBaseDirectory(homeDir, env);
|
|
20638
20985
|
let entries;
|
|
20639
20986
|
try {
|
|
20640
|
-
entries = await
|
|
20987
|
+
entries = await fs6.readdir(base, { withFileTypes: true });
|
|
20641
20988
|
} catch {
|
|
20642
20989
|
return void 0;
|
|
20643
20990
|
}
|
|
20644
20991
|
for (const entry of entries) {
|
|
20645
20992
|
if (!entry.isDirectory()) continue;
|
|
20646
|
-
const dir =
|
|
20647
|
-
const manifest = await
|
|
20993
|
+
const dir = path7.join(base, entry.name);
|
|
20994
|
+
const manifest = await readJsonRecord2(path7.join(dir, "remote-session.json"));
|
|
20648
20995
|
if (manifest?.recordingId === recordingId) return dir;
|
|
20649
20996
|
}
|
|
20650
20997
|
return void 0;
|
|
20651
20998
|
}
|
|
20652
20999
|
async function createRecordingSessionDir(recording, homeDir, env) {
|
|
20653
21000
|
const base = recordingSessionBaseDirectory(homeDir, env);
|
|
20654
|
-
await
|
|
21001
|
+
await fs6.mkdir(base, { recursive: true });
|
|
20655
21002
|
const stem = formatSessionDirectoryDate(new Date(recording.createdAt));
|
|
20656
|
-
let candidate =
|
|
21003
|
+
let candidate = path7.join(base, stem);
|
|
20657
21004
|
let suffix = 2;
|
|
20658
21005
|
while (await pathExists(candidate)) {
|
|
20659
|
-
candidate =
|
|
21006
|
+
candidate = path7.join(base, `${stem}-cloud-${suffix}`);
|
|
20660
21007
|
suffix += 1;
|
|
20661
21008
|
}
|
|
20662
|
-
await
|
|
21009
|
+
await fs6.mkdir(candidate, { recursive: true });
|
|
20663
21010
|
return candidate;
|
|
20664
21011
|
}
|
|
20665
21012
|
function recordingSessionBaseDirectory(homeDir = os5.homedir(), env = process.env) {
|
|
20666
21013
|
const explicit = env.RECAPPI_LOCAL_SESSIONS_DIR?.trim();
|
|
20667
21014
|
if (explicit) return explicit;
|
|
20668
|
-
return
|
|
21015
|
+
return path7.join(homeDir, "Documents", "Recappi Mini");
|
|
20669
21016
|
}
|
|
20670
|
-
async function
|
|
21017
|
+
async function readJsonRecord2(filePath) {
|
|
20671
21018
|
try {
|
|
20672
|
-
const parsed = JSON.parse(await
|
|
21019
|
+
const parsed = JSON.parse(await fs6.readFile(filePath, "utf8"));
|
|
20673
21020
|
return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) ? parsed : void 0;
|
|
20674
21021
|
} catch {
|
|
20675
21022
|
return void 0;
|
|
@@ -20677,7 +21024,7 @@ async function readJsonRecord(filePath) {
|
|
|
20677
21024
|
}
|
|
20678
21025
|
async function pathExists(filePath) {
|
|
20679
21026
|
try {
|
|
20680
|
-
await
|
|
21027
|
+
await fs6.access(filePath);
|
|
20681
21028
|
return true;
|
|
20682
21029
|
} catch {
|
|
20683
21030
|
return false;
|
|
@@ -20693,15 +21040,15 @@ function formatSessionDirectoryDate(date5) {
|
|
|
20693
21040
|
return `${year}-${month}-${day}_${hour}${minute}${second}`;
|
|
20694
21041
|
}
|
|
20695
21042
|
async function writeJson(filePath, value) {
|
|
20696
|
-
await
|
|
21043
|
+
await fs6.writeFile(filePath, `${JSON.stringify(value, null, 2)}
|
|
20697
21044
|
`, "utf8");
|
|
20698
21045
|
}
|
|
20699
21046
|
async function writeOptionalText(filePath, value) {
|
|
20700
21047
|
if (value && value.trim()) {
|
|
20701
|
-
await
|
|
21048
|
+
await fs6.writeFile(filePath, value, "utf8");
|
|
20702
21049
|
return;
|
|
20703
21050
|
}
|
|
20704
|
-
await
|
|
21051
|
+
await fs6.rm(filePath, { force: true });
|
|
20705
21052
|
}
|
|
20706
21053
|
function renderHandoffMarkdown(recording, subscription, audio, data, transcript) {
|
|
20707
21054
|
const lines = [];
|
|
@@ -20737,9 +21084,12 @@ function renderHandoffMarkdown(recording, subscription, audio, data, transcript)
|
|
|
20737
21084
|
appendSubscriptionLines(lines, subscription);
|
|
20738
21085
|
lines.push("");
|
|
20739
21086
|
if (transcript) {
|
|
20740
|
-
|
|
20741
|
-
|
|
20742
|
-
|
|
21087
|
+
const summaryMarkdown = renderSummaryMarkdown(transcript);
|
|
21088
|
+
if (summaryMarkdown) {
|
|
21089
|
+
lines.push(summaryMarkdown.trimEnd());
|
|
21090
|
+
lines.push("");
|
|
21091
|
+
}
|
|
21092
|
+
lines.push(renderTimestampedTranscriptMarkdown(transcript).trimEnd());
|
|
20743
21093
|
lines.push("");
|
|
20744
21094
|
}
|
|
20745
21095
|
return `${lines.join("\n").trimEnd()}
|
|
@@ -20753,7 +21103,7 @@ function renderSubscriptionMarkdown(subscription) {
|
|
|
20753
21103
|
}
|
|
20754
21104
|
function renderSessionMetadata(recording) {
|
|
20755
21105
|
const sourceTitle = recording.title ?? recording.summaryTitle ?? "Recappi Cloud";
|
|
20756
|
-
return
|
|
21106
|
+
return stripUndefined2({
|
|
20757
21107
|
summaryTitle: recording.summaryTitle ?? recording.title ?? void 0,
|
|
20758
21108
|
sourceTitle,
|
|
20759
21109
|
sourceAppName: void 0,
|
|
@@ -20765,7 +21115,7 @@ function renderSessionMetadata(recording) {
|
|
|
20765
21115
|
});
|
|
20766
21116
|
}
|
|
20767
21117
|
function renderRemoteSessionManifest(recording, uploadFilename, transcript, subscription, now) {
|
|
20768
|
-
return
|
|
21118
|
+
return stripUndefined2({
|
|
20769
21119
|
recordingId: recording.recordingId,
|
|
20770
21120
|
jobId: transcript?.jobId,
|
|
20771
21121
|
transcriptId: transcript?.transcriptId ?? recording.activeTranscriptId ?? void 0,
|
|
@@ -20779,7 +21129,7 @@ function renderRemoteSessionManifest(recording, uploadFilename, transcript, subs
|
|
|
20779
21129
|
accountBackendOrigin: subscription.origin
|
|
20780
21130
|
});
|
|
20781
21131
|
}
|
|
20782
|
-
function
|
|
21132
|
+
function stripUndefined2(value) {
|
|
20783
21133
|
return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== void 0));
|
|
20784
21134
|
}
|
|
20785
21135
|
function appendSubscriptionLines(lines, subscription) {
|
|
@@ -20802,6 +21152,12 @@ function appendSubscriptionLines(lines, subscription) {
|
|
|
20802
21152
|
function renderTranscriptMarkdown(transcript) {
|
|
20803
21153
|
return `# Transcript
|
|
20804
21154
|
|
|
21155
|
+
${transcript.text}
|
|
21156
|
+
`;
|
|
21157
|
+
}
|
|
21158
|
+
function renderTimestampedTranscriptMarkdown(transcript) {
|
|
21159
|
+
return `# Transcript
|
|
21160
|
+
|
|
20805
21161
|
${renderTranscriptLines(transcript)}
|
|
20806
21162
|
`;
|
|
20807
21163
|
}
|
|
@@ -20813,15 +21169,10 @@ function renderTranscriptLines(transcript) {
|
|
|
20813
21169
|
if (lines.length > 0) return lines.join("\n");
|
|
20814
21170
|
return transcript.text;
|
|
20815
21171
|
}
|
|
20816
|
-
function renderSummaryMarkdown(
|
|
21172
|
+
function renderSummaryMarkdown(transcript) {
|
|
20817
21173
|
const summary = transcript.summary;
|
|
20818
21174
|
const lines = [];
|
|
20819
|
-
lines.push(
|
|
20820
|
-
lines.push("");
|
|
20821
|
-
lines.push(`- recordingId: ${recording.recordingId}`);
|
|
20822
|
-
lines.push(`- transcriptId: ${transcript.transcriptId}`);
|
|
20823
|
-
lines.push(`- summaryStatus: ${summary.status}`);
|
|
20824
|
-
if (summary.error) lines.push(`- error: ${summary.error}`);
|
|
21175
|
+
lines.push("# Summary");
|
|
20825
21176
|
lines.push("");
|
|
20826
21177
|
if (summary.tldr) {
|
|
20827
21178
|
lines.push("## TL;DR", "");
|
|
@@ -20831,8 +21182,8 @@ function renderSummaryMarkdown(recording, transcript) {
|
|
|
20831
21182
|
appendStringList(lines, "Topics", summary.topics);
|
|
20832
21183
|
appendStringList(lines, "Decisions", summary.decisions);
|
|
20833
21184
|
appendActionItems(lines, summary.actionItems);
|
|
20834
|
-
|
|
20835
|
-
|
|
21185
|
+
appendNotableQuotes(lines, summary.quotes);
|
|
21186
|
+
if (lines.length === 2) return null;
|
|
20836
21187
|
if (lines[lines.length - 1] !== "") lines.push("");
|
|
20837
21188
|
return lines.join("\n");
|
|
20838
21189
|
}
|
|
@@ -20840,7 +21191,7 @@ function renderActionItemsMarkdown(summary) {
|
|
|
20840
21191
|
if (!summary.actionItems || summary.actionItems.length === 0) return null;
|
|
20841
21192
|
const lines = ["# Action Items", ""];
|
|
20842
21193
|
for (const item of summary.actionItems) {
|
|
20843
|
-
lines.push(
|
|
21194
|
+
lines.push(actionItemLine(item));
|
|
20844
21195
|
}
|
|
20845
21196
|
lines.push("");
|
|
20846
21197
|
return lines.join("\n");
|
|
@@ -20855,27 +21206,20 @@ function appendActionItems(lines, values) {
|
|
|
20855
21206
|
if (!values || values.length === 0) return;
|
|
20856
21207
|
lines.push("## Action Items", "");
|
|
20857
21208
|
for (const item of values) {
|
|
20858
|
-
lines.push(
|
|
21209
|
+
lines.push(actionItemLine(item));
|
|
20859
21210
|
}
|
|
20860
21211
|
lines.push("");
|
|
20861
21212
|
}
|
|
20862
|
-
function
|
|
21213
|
+
function appendNotableQuotes(lines, values) {
|
|
20863
21214
|
if (!values || values.length === 0) return;
|
|
20864
|
-
lines.push("##
|
|
21215
|
+
lines.push("## Notable Quotes", "");
|
|
20865
21216
|
for (const item of values) {
|
|
20866
|
-
lines.push(
|
|
20867
|
-
`- ${formatTimestamp(item.startMs)}-${formatTimestamp(item.endMs)}: ${item.title} - ${item.summary}`
|
|
20868
|
-
);
|
|
21217
|
+
lines.push(`> ${item.speaker ? `${item.speaker}: ` : ""}${item.text}`);
|
|
20869
21218
|
}
|
|
20870
21219
|
lines.push("");
|
|
20871
21220
|
}
|
|
20872
|
-
function
|
|
20873
|
-
|
|
20874
|
-
lines.push("## Quotes", "");
|
|
20875
|
-
for (const item of values) {
|
|
20876
|
-
lines.push(`- ${item.speaker ? `${item.speaker}: ` : ""}"${item.text}"`);
|
|
20877
|
-
}
|
|
20878
|
-
lines.push("");
|
|
21221
|
+
function actionItemLine(item) {
|
|
21222
|
+
return `- ${item.who ? `${item.who}: ` : ""}${item.what}`;
|
|
20879
21223
|
}
|
|
20880
21224
|
function audioMetadata(audio) {
|
|
20881
21225
|
return {
|
|
@@ -21271,20 +21615,20 @@ function renderEnvelope(envelope, opts) {
|
|
|
21271
21615
|
`);
|
|
21272
21616
|
}
|
|
21273
21617
|
function renderHumanSuccess(command, data, opts) {
|
|
21274
|
-
if (command === "auth login" &&
|
|
21618
|
+
if (command === "auth login" && isRecord5(data)) {
|
|
21275
21619
|
opts.stdout(`Signed in${typeof data.email === "string" ? ` as ${data.email}` : ""}
|
|
21276
21620
|
`);
|
|
21277
21621
|
return;
|
|
21278
21622
|
}
|
|
21279
|
-
if (command === "auth logout" &&
|
|
21623
|
+
if (command === "auth logout" && isRecord5(data)) {
|
|
21280
21624
|
opts.stdout(data.cleared ? "Signed out of Recappi CLI\n" : "No Recappi CLI session to clear\n");
|
|
21281
21625
|
return;
|
|
21282
21626
|
}
|
|
21283
|
-
if (command === "auth import-macos" &&
|
|
21627
|
+
if (command === "auth import-macos" && isRecord5(data)) {
|
|
21284
21628
|
opts.stdout("Imported the Recappi Mini app session into Recappi CLI\n");
|
|
21285
21629
|
return;
|
|
21286
21630
|
}
|
|
21287
|
-
if (command === "auth status" &&
|
|
21631
|
+
if (command === "auth status" && isRecord5(data)) {
|
|
21288
21632
|
if (data.loggedIn) {
|
|
21289
21633
|
opts.stdout(`Signed in${typeof data.email === "string" ? ` as ${data.email}` : ""}
|
|
21290
21634
|
`);
|
|
@@ -21293,7 +21637,7 @@ function renderHumanSuccess(command, data, opts) {
|
|
|
21293
21637
|
opts.stdout("Not logged in\n");
|
|
21294
21638
|
return;
|
|
21295
21639
|
}
|
|
21296
|
-
if (command === "account status" &&
|
|
21640
|
+
if (command === "account status" && isRecord5(data)) {
|
|
21297
21641
|
if (!data.loggedIn) {
|
|
21298
21642
|
opts.stdout("Not logged in\n");
|
|
21299
21643
|
return;
|
|
@@ -21304,7 +21648,7 @@ function renderHumanSuccess(command, data, opts) {
|
|
|
21304
21648
|
`);
|
|
21305
21649
|
if (typeof data.userId === "string") opts.stdout(` userId: ${data.userId}
|
|
21306
21650
|
`);
|
|
21307
|
-
const billing =
|
|
21651
|
+
const billing = isRecord5(data.billing) ? data.billing : {};
|
|
21308
21652
|
if (typeof billing.tier === "string") opts.stdout(` plan: ${billing.tier}
|
|
21309
21653
|
`);
|
|
21310
21654
|
if (typeof billing.minutesUsed === "number") {
|
|
@@ -21317,7 +21661,7 @@ function renderHumanSuccess(command, data, opts) {
|
|
|
21317
21661
|
opts.stdout(` storage: ${formatBytes2(billing.storageBytes)} / ${cap}
|
|
21318
21662
|
`);
|
|
21319
21663
|
}
|
|
21320
|
-
const localStore =
|
|
21664
|
+
const localStore = isRecord5(data.localStore) ? data.localStore : {};
|
|
21321
21665
|
if (typeof localStore.path === "string") opts.stdout(` localStore: ${localStore.path}
|
|
21322
21666
|
`);
|
|
21323
21667
|
opts.stdout(
|
|
@@ -21326,17 +21670,17 @@ function renderHumanSuccess(command, data, opts) {
|
|
|
21326
21670
|
);
|
|
21327
21671
|
return;
|
|
21328
21672
|
}
|
|
21329
|
-
if (command === "version" &&
|
|
21673
|
+
if (command === "version" && isRecord5(data) && typeof data.version === "string") {
|
|
21330
21674
|
opts.stdout(`${data.version}
|
|
21331
21675
|
`);
|
|
21332
21676
|
return;
|
|
21333
21677
|
}
|
|
21334
|
-
if (command === "doctor" &&
|
|
21678
|
+
if (command === "doctor" && isRecord5(data) && Array.isArray(data.checks)) {
|
|
21335
21679
|
const status = typeof data.status === "string" ? data.status : "unknown";
|
|
21336
21680
|
opts.stdout(`Doctor: ${status}
|
|
21337
21681
|
`);
|
|
21338
21682
|
for (const check2 of data.checks) {
|
|
21339
|
-
if (!
|
|
21683
|
+
if (!isRecord5(check2)) continue;
|
|
21340
21684
|
const checkStatus = typeof check2.status === "string" ? check2.status : "unknown";
|
|
21341
21685
|
const name = typeof check2.name === "string" ? check2.name : "check";
|
|
21342
21686
|
const message = typeof check2.message === "string" ? ` \u2014 ${check2.message}` : "";
|
|
@@ -21347,14 +21691,14 @@ function renderHumanSuccess(command, data, opts) {
|
|
|
21347
21691
|
}
|
|
21348
21692
|
return;
|
|
21349
21693
|
}
|
|
21350
|
-
if (command === "transcript get" &&
|
|
21694
|
+
if (command === "transcript get" && isRecord5(data)) {
|
|
21351
21695
|
renderTranscriptHuman(data, opts);
|
|
21352
21696
|
return;
|
|
21353
21697
|
}
|
|
21354
|
-
if (command === "recordings list" &&
|
|
21698
|
+
if (command === "recordings list" && isRecord5(data) && Array.isArray(data.items)) {
|
|
21355
21699
|
opts.stdout("Recordings:\n");
|
|
21356
21700
|
for (const item of data.items) {
|
|
21357
|
-
if (!
|
|
21701
|
+
if (!isRecord5(item)) continue;
|
|
21358
21702
|
opts.stdout(` ${recordingLabel(item)}
|
|
21359
21703
|
`);
|
|
21360
21704
|
}
|
|
@@ -21366,7 +21710,7 @@ Next cursor: ${data.nextCursor}
|
|
|
21366
21710
|
}
|
|
21367
21711
|
return;
|
|
21368
21712
|
}
|
|
21369
|
-
if (command === "recordings get" &&
|
|
21713
|
+
if (command === "recordings get" && isRecord5(data)) {
|
|
21370
21714
|
opts.stdout(`${recordingTitle(data)}
|
|
21371
21715
|
`);
|
|
21372
21716
|
opts.stdout(` recordingId: ${String(data.recordingId)}
|
|
@@ -21388,7 +21732,7 @@ Next:
|
|
|
21388
21732
|
}
|
|
21389
21733
|
return;
|
|
21390
21734
|
}
|
|
21391
|
-
if (command === "recordings export" &&
|
|
21735
|
+
if (command === "recordings export" && isRecord5(data)) {
|
|
21392
21736
|
opts.stdout("Recording export ready\n");
|
|
21393
21737
|
printStringField(opts, data, "recordingId");
|
|
21394
21738
|
printStringField(opts, data, "exportDir");
|
|
@@ -21410,7 +21754,7 @@ Next:
|
|
|
21410
21754
|
}
|
|
21411
21755
|
return;
|
|
21412
21756
|
}
|
|
21413
|
-
if (command === "recordings retranscribe" &&
|
|
21757
|
+
if (command === "recordings retranscribe" && isRecord5(data)) {
|
|
21414
21758
|
opts.stdout("Transcription started\n");
|
|
21415
21759
|
if (typeof data.recordingId === "string") opts.stdout(` recordingId: ${data.recordingId}
|
|
21416
21760
|
`);
|
|
@@ -21433,7 +21777,7 @@ Next:
|
|
|
21433
21777
|
}
|
|
21434
21778
|
return;
|
|
21435
21779
|
}
|
|
21436
|
-
if (command === "recordings resummarize" &&
|
|
21780
|
+
if (command === "recordings resummarize" && isRecord5(data)) {
|
|
21437
21781
|
opts.stdout("Summary queued\n");
|
|
21438
21782
|
if (typeof data.recordingId === "string") opts.stdout(` recordingId: ${data.recordingId}
|
|
21439
21783
|
`);
|
|
@@ -21451,9 +21795,9 @@ Next:
|
|
|
21451
21795
|
}
|
|
21452
21796
|
return;
|
|
21453
21797
|
}
|
|
21454
|
-
if (command === "dashboard stats" &&
|
|
21455
|
-
const recordings =
|
|
21456
|
-
const jobs =
|
|
21798
|
+
if (command === "dashboard stats" && isRecord5(data)) {
|
|
21799
|
+
const recordings = isRecord5(data.recordings) ? data.recordings : {};
|
|
21800
|
+
const jobs = isRecord5(data.jobs) ? data.jobs : {};
|
|
21457
21801
|
opts.stdout(
|
|
21458
21802
|
`Recordings: ${numberText(recordings.total)} total, ${numberText(recordings.ready)} ready
|
|
21459
21803
|
`
|
|
@@ -21496,7 +21840,7 @@ Next:
|
|
|
21496
21840
|
}
|
|
21497
21841
|
return;
|
|
21498
21842
|
}
|
|
21499
|
-
if (command === "record" &&
|
|
21843
|
+
if (command === "record" && isRecord5(data)) {
|
|
21500
21844
|
opts.stdout("Recording complete\n");
|
|
21501
21845
|
if (typeof data.recordingId === "string") opts.stdout(` recordingId: ${data.recordingId}
|
|
21502
21846
|
`);
|
|
@@ -21515,14 +21859,14 @@ Next:
|
|
|
21515
21859
|
if (Array.isArray(data.artifacts) && data.artifacts.length > 0) {
|
|
21516
21860
|
opts.stdout(" artifacts:\n");
|
|
21517
21861
|
for (const artifact of data.artifacts) {
|
|
21518
|
-
if (!
|
|
21862
|
+
if (!isRecord5(artifact)) continue;
|
|
21519
21863
|
const kind = typeof artifact.kind === "string" ? artifact.kind : "artifact";
|
|
21520
21864
|
const localPath = typeof artifact.localPath === "string" ? artifact.localPath : "";
|
|
21521
21865
|
opts.stdout(` - ${kind}: ${localPath}
|
|
21522
21866
|
`);
|
|
21523
21867
|
}
|
|
21524
21868
|
}
|
|
21525
|
-
const cloudHandoffError =
|
|
21869
|
+
const cloudHandoffError = isRecord5(data.cloudHandoffError) ? data.cloudHandoffError : void 0;
|
|
21526
21870
|
if (cloudHandoffError && typeof cloudHandoffError.message === "string") {
|
|
21527
21871
|
opts.stderr(`Cloud handoff failed: ${cloudHandoffError.message}
|
|
21528
21872
|
`);
|
|
@@ -21547,7 +21891,7 @@ Next:
|
|
|
21547
21891
|
}
|
|
21548
21892
|
return;
|
|
21549
21893
|
}
|
|
21550
|
-
if (command === "audio" &&
|
|
21894
|
+
if (command === "audio" && isRecord5(data)) {
|
|
21551
21895
|
const action = typeof data.action === "string" ? data.action : "download";
|
|
21552
21896
|
opts.stdout(
|
|
21553
21897
|
action === "open" ? "Audio opened\n" : action === "reveal" ? "Audio revealed\n" : "Audio ready\n"
|
|
@@ -21562,7 +21906,7 @@ Next:
|
|
|
21562
21906
|
}
|
|
21563
21907
|
return;
|
|
21564
21908
|
}
|
|
21565
|
-
if ((command === "jobs wait" || command === "upload") &&
|
|
21909
|
+
if ((command === "jobs wait" || command === "upload") && isRecord5(data)) {
|
|
21566
21910
|
if (typeof data.transcriptId === "string") {
|
|
21567
21911
|
opts.stdout("Transcript ready\n");
|
|
21568
21912
|
if (typeof data.recordingId === "string" && typeof data.origin === "string") {
|
|
@@ -21587,10 +21931,10 @@ Next:
|
|
|
21587
21931
|
}
|
|
21588
21932
|
return;
|
|
21589
21933
|
}
|
|
21590
|
-
if (command === "schema" &&
|
|
21934
|
+
if (command === "schema" && isRecord5(data) && Array.isArray(data.commands)) {
|
|
21591
21935
|
opts.stdout("Commands:\n");
|
|
21592
21936
|
for (const entry of data.commands) {
|
|
21593
|
-
if (!
|
|
21937
|
+
if (!isRecord5(entry) || typeof entry.name !== "string") continue;
|
|
21594
21938
|
const summary = typeof entry.summary === "string" ? ` \u2014 ${entry.summary}` : "";
|
|
21595
21939
|
opts.stdout(` ${entry.name}${summary}
|
|
21596
21940
|
`);
|
|
@@ -21600,9 +21944,9 @@ Next:
|
|
|
21600
21944
|
}
|
|
21601
21945
|
if (Array.isArray(entry.examples) && entry.examples.length > 0) {
|
|
21602
21946
|
const first = entry.examples.find(
|
|
21603
|
-
(example) =>
|
|
21947
|
+
(example) => isRecord5(example) && typeof example.command === "string"
|
|
21604
21948
|
);
|
|
21605
|
-
if (
|
|
21949
|
+
if (isRecord5(first) && typeof first.command === "string") {
|
|
21606
21950
|
opts.stdout(` example: ${first.command}
|
|
21607
21951
|
`);
|
|
21608
21952
|
}
|
|
@@ -21734,7 +22078,7 @@ function renderTranscriptHuman(data, opts) {
|
|
|
21734
22078
|
const segments = Array.isArray(data.segments) ? data.segments : [];
|
|
21735
22079
|
let printedBody = false;
|
|
21736
22080
|
for (const segment of segments) {
|
|
21737
|
-
if (!
|
|
22081
|
+
if (!isRecord5(segment) || typeof segment.text !== "string") continue;
|
|
21738
22082
|
const clock = typeof segment.startMs === "number" ? `[${formatClock(segment.startMs / 1e3)}] ` : "";
|
|
21739
22083
|
const speaker = typeof segment.speaker === "string" ? `${segment.speaker}: ` : "";
|
|
21740
22084
|
opts.stdout(`${clock}${speaker}${segment.text}
|
|
@@ -21746,7 +22090,7 @@ function renderTranscriptHuman(data, opts) {
|
|
|
21746
22090
|
`);
|
|
21747
22091
|
printedBody = true;
|
|
21748
22092
|
}
|
|
21749
|
-
const summary =
|
|
22093
|
+
const summary = isRecord5(data.summary) ? data.summary : void 0;
|
|
21750
22094
|
if (!summary || summary.status !== "succeeded") return;
|
|
21751
22095
|
if (typeof summary.tldr === "string" && summary.tldr.length > 0) {
|
|
21752
22096
|
opts.stdout(`
|
|
@@ -21764,7 +22108,7 @@ Summary:
|
|
|
21764
22108
|
if (Array.isArray(summary.actionItems) && summary.actionItems.length > 0) {
|
|
21765
22109
|
opts.stdout("\nAction items:\n");
|
|
21766
22110
|
for (const item of summary.actionItems) {
|
|
21767
|
-
if (!
|
|
22111
|
+
if (!isRecord5(item) || typeof item.what !== "string") continue;
|
|
21768
22112
|
const who = typeof item.who === "string" ? `${item.who}: ` : "";
|
|
21769
22113
|
opts.stdout(` - ${who}${item.what}
|
|
21770
22114
|
`);
|
|
@@ -21839,7 +22183,7 @@ function applyFields(command, data, fields, compact) {
|
|
|
21839
22183
|
};
|
|
21840
22184
|
return compact ? compactData(filtered2) : filtered2;
|
|
21841
22185
|
}
|
|
21842
|
-
if (!
|
|
22186
|
+
if (!isRecord5(data)) return data;
|
|
21843
22187
|
const allowed = new Set(Object.keys(data));
|
|
21844
22188
|
assertKnownFields(fields, allowed);
|
|
21845
22189
|
const filtered = pickFields(data, fields);
|
|
@@ -21864,7 +22208,7 @@ function compactData(value) {
|
|
|
21864
22208
|
if (Array.isArray(value)) {
|
|
21865
22209
|
return value.map(compactData).filter((item) => item !== void 0);
|
|
21866
22210
|
}
|
|
21867
|
-
if (
|
|
22211
|
+
if (isRecord5(value)) {
|
|
21868
22212
|
const out = {};
|
|
21869
22213
|
for (const [key, child] of Object.entries(value)) {
|
|
21870
22214
|
const compacted = compactData(child);
|
|
@@ -21882,16 +22226,16 @@ function stableStringify(value, compact) {
|
|
|
21882
22226
|
}
|
|
21883
22227
|
function sortKeys(value) {
|
|
21884
22228
|
if (Array.isArray(value)) return value.map(sortKeys);
|
|
21885
|
-
if (!
|
|
22229
|
+
if (!isRecord5(value)) return value;
|
|
21886
22230
|
return Object.fromEntries(
|
|
21887
22231
|
Object.keys(value).sort().map((key) => [key, sortKeys(value[key])])
|
|
21888
22232
|
);
|
|
21889
22233
|
}
|
|
21890
|
-
function
|
|
22234
|
+
function isRecord5(value) {
|
|
21891
22235
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
21892
22236
|
}
|
|
21893
22237
|
function isUploadBatch(value) {
|
|
21894
|
-
return
|
|
22238
|
+
return isRecord5(value) && Array.isArray(value.successes) && Array.isArray(value.failures);
|
|
21895
22239
|
}
|
|
21896
22240
|
|
|
21897
22241
|
// src/schema.ts
|
|
@@ -21946,11 +22290,11 @@ function buildSchemaDocument(program) {
|
|
|
21946
22290
|
event: toJsonSchema(operationEventSchema)
|
|
21947
22291
|
};
|
|
21948
22292
|
}
|
|
21949
|
-
function walkCommands(command,
|
|
22293
|
+
function walkCommands(command, path8, out) {
|
|
21950
22294
|
for (const sub of subcommandsOf(command)) {
|
|
21951
22295
|
const name = sub.name();
|
|
21952
22296
|
if (name === "help") continue;
|
|
21953
|
-
const fullPath = [...
|
|
22297
|
+
const fullPath = [...path8, name];
|
|
21954
22298
|
const children = subcommandsOf(sub).filter((child) => child.name() !== "help");
|
|
21955
22299
|
if (children.length === 0) {
|
|
21956
22300
|
out.push(leafCommandDoc(sub, fullPath.join(" ")));
|
|
@@ -22228,7 +22572,7 @@ var MiniSidecarClient = class {
|
|
|
22228
22572
|
}
|
|
22229
22573
|
};
|
|
22230
22574
|
function sidecarErrorToCliError(error51) {
|
|
22231
|
-
const data =
|
|
22575
|
+
const data = isRecord7(error51.data) ? error51.data : void 0;
|
|
22232
22576
|
const maybeCode = typeof data?.cliCode === "string" ? cliErrorCodeSchema.safeParse(data.cliCode) : void 0;
|
|
22233
22577
|
const hint = typeof data?.recovery === "string" ? data.recovery : void 0;
|
|
22234
22578
|
const retryable = typeof data?.retryable === "boolean" ? data.retryable : error51.code >= -32099 && error51.code <= -32e3;
|
|
@@ -22245,7 +22589,7 @@ function sidecarErrorToCliError(error51) {
|
|
|
22245
22589
|
retryable
|
|
22246
22590
|
});
|
|
22247
22591
|
}
|
|
22248
|
-
function
|
|
22592
|
+
function isRecord7(value) {
|
|
22249
22593
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
22250
22594
|
}
|
|
22251
22595
|
function spawnMiniSidecar(opts) {
|
|
@@ -22352,8 +22696,8 @@ function requestLaunchServicesSidecarShutdown(input) {
|
|
|
22352
22696
|
} catch {
|
|
22353
22697
|
}
|
|
22354
22698
|
}
|
|
22355
|
-
function createFifo(
|
|
22356
|
-
const result = spawnSync("mkfifo", [
|
|
22699
|
+
function createFifo(path8) {
|
|
22700
|
+
const result = spawnSync("mkfifo", [path8], { encoding: "utf8" });
|
|
22357
22701
|
if (result.status !== 0) {
|
|
22358
22702
|
throw cliError("record.helper_unavailable", "Recappi recording helper could not start.", {
|
|
22359
22703
|
hint: result.stderr || "Could not create the local recorder pipes. Try again."
|
|
@@ -22889,14 +23233,14 @@ async function startRecordSessionOnce(opts) {
|
|
|
22889
23233
|
}
|
|
22890
23234
|
}
|
|
22891
23235
|
function isPermissionRestartRequiredError(error51, permissionName) {
|
|
22892
|
-
const root =
|
|
22893
|
-
const descriptor =
|
|
23236
|
+
const root = isRecord8(error51) ? error51 : void 0;
|
|
23237
|
+
const descriptor = isRecord8(root?.descriptor) ? root.descriptor : void 0;
|
|
22894
23238
|
if (descriptor?.code !== "record.permission_required") return false;
|
|
22895
|
-
const sidecarError =
|
|
22896
|
-
const sidecarData =
|
|
23239
|
+
const sidecarError = isRecord8(root?.data) ? root.data : void 0;
|
|
23240
|
+
const sidecarData = isRecord8(sidecarError?.data) ? sidecarError.data : void 0;
|
|
22897
23241
|
return sidecarData?.permission === permissionName && (sidecarData.requiresProcessRestart === true || sidecarData.requiresProcessRestart === "true");
|
|
22898
23242
|
}
|
|
22899
|
-
function
|
|
23243
|
+
function isRecord8(value) {
|
|
22900
23244
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
22901
23245
|
}
|
|
22902
23246
|
function normalizeSidecarSources(sources) {
|
|
@@ -22977,9 +23321,9 @@ function resolveSidecarCommand(opts) {
|
|
|
22977
23321
|
hint: `No bundled helper is registered for ${platform}. Set ${SIDECAR_COMMAND_ENV} to a compatible helper when one is available.`
|
|
22978
23322
|
});
|
|
22979
23323
|
}
|
|
22980
|
-
function ensureBundledHelperExecutable(
|
|
22981
|
-
if (process.platform === "darwin" &&
|
|
22982
|
-
const stableApp = ensureStableDarwinHelperApp(
|
|
23324
|
+
function ensureBundledHelperExecutable(path8, opts = {}) {
|
|
23325
|
+
if (process.platform === "darwin" && path8.endsWith(".app")) {
|
|
23326
|
+
const stableApp = ensureStableDarwinHelperApp(path8, opts);
|
|
22983
23327
|
const executable = darwinAppExecutablePath(stableApp);
|
|
22984
23328
|
if (!existsSync(executable)) {
|
|
22985
23329
|
throw cliError("record.helper_unavailable", "Recappi recording helper is not available.", {
|
|
@@ -22989,19 +23333,19 @@ function ensureBundledHelperExecutable(path7, opts = {}) {
|
|
|
22989
23333
|
ensureExecutableMode(executable);
|
|
22990
23334
|
return stableApp;
|
|
22991
23335
|
}
|
|
22992
|
-
if (process.platform === "win32") return
|
|
22993
|
-
ensureExecutableMode(
|
|
22994
|
-
return
|
|
23336
|
+
if (process.platform === "win32") return path8;
|
|
23337
|
+
ensureExecutableMode(path8);
|
|
23338
|
+
return path8;
|
|
22995
23339
|
}
|
|
22996
|
-
function ensureExecutableMode(
|
|
22997
|
-
const mode = statSync(
|
|
23340
|
+
function ensureExecutableMode(path8) {
|
|
23341
|
+
const mode = statSync(path8).mode;
|
|
22998
23342
|
if ((mode & 73) !== 0) return;
|
|
22999
23343
|
try {
|
|
23000
|
-
chmodSync(
|
|
23344
|
+
chmodSync(path8, mode | 493);
|
|
23001
23345
|
} catch (error51) {
|
|
23002
23346
|
const message = error51 instanceof Error ? error51.message : String(error51);
|
|
23003
23347
|
throw cliError("record.helper_unavailable", "Recappi recording helper is not executable.", {
|
|
23004
|
-
hint: `Could not make bundled helper executable at ${
|
|
23348
|
+
hint: `Could not make bundled helper executable at ${path8}: ${message}. Reinstall recappi, or set ${SIDECAR_COMMAND_ENV} to a compatible helper.`
|
|
23005
23349
|
});
|
|
23006
23350
|
}
|
|
23007
23351
|
}
|
|
@@ -23046,14 +23390,14 @@ function helperSourceSignature(sourceApp) {
|
|
|
23046
23390
|
codeSignature: existsSync(signaturePath) ? fileDigest(signaturePath) : null
|
|
23047
23391
|
});
|
|
23048
23392
|
}
|
|
23049
|
-
function fileDigest(
|
|
23393
|
+
function fileDigest(path8) {
|
|
23050
23394
|
const hash2 = createHash("sha256");
|
|
23051
|
-
hash2.update(readFileSync2(
|
|
23395
|
+
hash2.update(readFileSync2(path8));
|
|
23052
23396
|
return hash2.digest("hex");
|
|
23053
23397
|
}
|
|
23054
|
-
function readTextIfExists(
|
|
23398
|
+
function readTextIfExists(path8) {
|
|
23055
23399
|
try {
|
|
23056
|
-
return readFileSync2(
|
|
23400
|
+
return readFileSync2(path8, "utf8");
|
|
23057
23401
|
} catch {
|
|
23058
23402
|
return null;
|
|
23059
23403
|
}
|
|
@@ -23347,6 +23691,13 @@ async function runCli(deps = {}) {
|
|
|
23347
23691
|
await runDashboard2({
|
|
23348
23692
|
fetchJobs: () => client.listJobs({ status: "active", limit: 20 }),
|
|
23349
23693
|
fetchRecordings: ({ cursor, limit = DASHBOARD_RECORDINGS_PAGE_SIZE } = {}) => client.listRecordings({ limit, cursor }),
|
|
23694
|
+
fetchCachedRecordings: account ? ({ limit = DASHBOARD_RECORDINGS_PAGE_SIZE } = {}) => listCachedRecordingSessions({
|
|
23695
|
+
account,
|
|
23696
|
+
origin: auth.origin,
|
|
23697
|
+
limit,
|
|
23698
|
+
env: deps.env,
|
|
23699
|
+
homeDir: deps.homeDir
|
|
23700
|
+
}) : void 0,
|
|
23350
23701
|
fetchDashboardStats: () => client.dashboardStats(),
|
|
23351
23702
|
fetchAccountStatus: () => client.accountStatus(),
|
|
23352
23703
|
fetchTranscript: (transcriptId) => client.getTranscript(transcriptId),
|