recappi 0.1.76 → 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 +468 -177
- 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(
|
|
@@ -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,
|
|
@@ -2028,6 +2031,7 @@ function AppShell({
|
|
|
2028
2031
|
const [selected, setSelected] = useState8(0);
|
|
2029
2032
|
const [spinnerFrame, setSpinnerFrame] = useState8(0);
|
|
2030
2033
|
const [loadingMoreRecordings, setLoadingMoreRecordings] = useState8(false);
|
|
2034
|
+
const [revalidatingRecordings, setRevalidatingRecordings] = useState8(false);
|
|
2031
2035
|
const [loaded, setLoaded] = useState8(false);
|
|
2032
2036
|
const [loadError, setLoadError] = useState8(void 0);
|
|
2033
2037
|
const [notice, setNotice] = useState8(void 0);
|
|
@@ -2245,6 +2249,21 @@ function AppShell({
|
|
|
2245
2249
|
}, [peekTranscriptId, fetchTranscript]);
|
|
2246
2250
|
const peekSummary = peekTranscriptId ? summaryCache.get(peekTranscriptId) : void 0;
|
|
2247
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
|
+
}
|
|
2248
2267
|
const [jobsR, recR, statsR, accountR] = await Promise.allSettled([
|
|
2249
2268
|
fetchJobs(),
|
|
2250
2269
|
resetRecordings && fetchRecordings ? fetchRecordings({ limit: RECORDINGS_PAGE_SIZE }) : Promise.resolve(void 0),
|
|
@@ -2270,7 +2289,8 @@ function AppShell({
|
|
|
2270
2289
|
setAccountStatus("error");
|
|
2271
2290
|
}
|
|
2272
2291
|
setLoaded(true);
|
|
2273
|
-
|
|
2292
|
+
if (showingCachedRecordings) setRevalidatingRecordings(false);
|
|
2293
|
+
}, [fetchJobs, fetchRecordings, fetchCachedRecordings, fetchDashboardStats, fetchAccountStatus]);
|
|
2274
2294
|
const transcribeStoppedRecording = useCallback(async () => {
|
|
2275
2295
|
const current = liveRecord;
|
|
2276
2296
|
if (current?.kind !== "stopped") return;
|
|
@@ -2933,7 +2953,8 @@ function AppShell({
|
|
|
2933
2953
|
peekItem: recordings[selected],
|
|
2934
2954
|
peekSummary,
|
|
2935
2955
|
showPeek,
|
|
2936
|
-
peekWidth
|
|
2956
|
+
peekWidth,
|
|
2957
|
+
revalidating: revalidatingRecordings
|
|
2937
2958
|
}
|
|
2938
2959
|
);
|
|
2939
2960
|
} else if (screen.kind === "account") {
|
|
@@ -3051,6 +3072,7 @@ async function runDashboard(deps) {
|
|
|
3051
3072
|
fetchJobs: deps.fetchJobs,
|
|
3052
3073
|
fetchTranscript: deps.fetchTranscript,
|
|
3053
3074
|
fetchRecordings: deps.fetchRecordings,
|
|
3075
|
+
fetchCachedRecordings: deps.fetchCachedRecordings,
|
|
3054
3076
|
fetchDashboardStats: deps.fetchDashboardStats,
|
|
3055
3077
|
fetchAccountStatus: deps.fetchAccountStatus,
|
|
3056
3078
|
recordingAudio: deps.recordingAudio,
|
|
@@ -3859,10 +3881,10 @@ function mergeDefs(...defs) {
|
|
|
3859
3881
|
function cloneDef(schema) {
|
|
3860
3882
|
return mergeDefs(schema._zod.def);
|
|
3861
3883
|
}
|
|
3862
|
-
function getElementAtPath(obj,
|
|
3863
|
-
if (!
|
|
3884
|
+
function getElementAtPath(obj, path8) {
|
|
3885
|
+
if (!path8)
|
|
3864
3886
|
return obj;
|
|
3865
|
-
return
|
|
3887
|
+
return path8.reduce((acc, key) => acc?.[key], obj);
|
|
3866
3888
|
}
|
|
3867
3889
|
function promiseAllObject(promisesObj) {
|
|
3868
3890
|
const keys = Object.keys(promisesObj);
|
|
@@ -4271,11 +4293,11 @@ function explicitlyAborted(x, startIndex = 0) {
|
|
|
4271
4293
|
}
|
|
4272
4294
|
return false;
|
|
4273
4295
|
}
|
|
4274
|
-
function prefixIssues(
|
|
4296
|
+
function prefixIssues(path8, issues) {
|
|
4275
4297
|
return issues.map((iss) => {
|
|
4276
4298
|
var _a3;
|
|
4277
4299
|
(_a3 = iss).path ?? (_a3.path = []);
|
|
4278
|
-
iss.path.unshift(
|
|
4300
|
+
iss.path.unshift(path8);
|
|
4279
4301
|
return iss;
|
|
4280
4302
|
});
|
|
4281
4303
|
}
|
|
@@ -4422,16 +4444,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
|
|
|
4422
4444
|
}
|
|
4423
4445
|
function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
4424
4446
|
const fieldErrors = { _errors: [] };
|
|
4425
|
-
const processError = (error52,
|
|
4447
|
+
const processError = (error52, path8 = []) => {
|
|
4426
4448
|
for (const issue2 of error52.issues) {
|
|
4427
4449
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
4428
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
4450
|
+
issue2.errors.map((issues) => processError({ issues }, [...path8, ...issue2.path]));
|
|
4429
4451
|
} else if (issue2.code === "invalid_key") {
|
|
4430
|
-
processError({ issues: issue2.issues }, [...
|
|
4452
|
+
processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
|
|
4431
4453
|
} else if (issue2.code === "invalid_element") {
|
|
4432
|
-
processError({ issues: issue2.issues }, [...
|
|
4454
|
+
processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
|
|
4433
4455
|
} else {
|
|
4434
|
-
const fullpath = [...
|
|
4456
|
+
const fullpath = [...path8, ...issue2.path];
|
|
4435
4457
|
if (fullpath.length === 0) {
|
|
4436
4458
|
fieldErrors._errors.push(mapper(issue2));
|
|
4437
4459
|
} else {
|
|
@@ -4458,17 +4480,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
|
4458
4480
|
}
|
|
4459
4481
|
function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
4460
4482
|
const result = { errors: [] };
|
|
4461
|
-
const processError = (error52,
|
|
4483
|
+
const processError = (error52, path8 = []) => {
|
|
4462
4484
|
var _a3, _b;
|
|
4463
4485
|
for (const issue2 of error52.issues) {
|
|
4464
4486
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
4465
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
4487
|
+
issue2.errors.map((issues) => processError({ issues }, [...path8, ...issue2.path]));
|
|
4466
4488
|
} else if (issue2.code === "invalid_key") {
|
|
4467
|
-
processError({ issues: issue2.issues }, [...
|
|
4489
|
+
processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
|
|
4468
4490
|
} else if (issue2.code === "invalid_element") {
|
|
4469
|
-
processError({ issues: issue2.issues }, [...
|
|
4491
|
+
processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
|
|
4470
4492
|
} else {
|
|
4471
|
-
const fullpath = [...
|
|
4493
|
+
const fullpath = [...path8, ...issue2.path];
|
|
4472
4494
|
if (fullpath.length === 0) {
|
|
4473
4495
|
result.errors.push(mapper(issue2));
|
|
4474
4496
|
continue;
|
|
@@ -4500,8 +4522,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
|
4500
4522
|
}
|
|
4501
4523
|
function toDotPath(_path) {
|
|
4502
4524
|
const segs = [];
|
|
4503
|
-
const
|
|
4504
|
-
for (const seg of
|
|
4525
|
+
const path8 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
4526
|
+
for (const seg of path8) {
|
|
4505
4527
|
if (typeof seg === "number")
|
|
4506
4528
|
segs.push(`[${seg}]`);
|
|
4507
4529
|
else if (typeof seg === "symbol")
|
|
@@ -17193,13 +17215,13 @@ function resolveRef(ref, ctx) {
|
|
|
17193
17215
|
if (!ref.startsWith("#")) {
|
|
17194
17216
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
17195
17217
|
}
|
|
17196
|
-
const
|
|
17197
|
-
if (
|
|
17218
|
+
const path8 = ref.slice(1).split("/").filter(Boolean);
|
|
17219
|
+
if (path8.length === 0) {
|
|
17198
17220
|
return ctx.rootSchema;
|
|
17199
17221
|
}
|
|
17200
17222
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
17201
|
-
if (
|
|
17202
|
-
const key =
|
|
17223
|
+
if (path8[0] === defsKey) {
|
|
17224
|
+
const key = path8[1];
|
|
17203
17225
|
if (!key || !ctx.defs[key]) {
|
|
17204
17226
|
throw new Error(`Reference not found: ${ref}`);
|
|
17205
17227
|
}
|
|
@@ -18884,6 +18906,9 @@ function defaultStorePath(homeDir = os3.homedir(), env = process.env) {
|
|
|
18884
18906
|
const dataHome = env.XDG_DATA_HOME?.trim() || path3.join(homeDir, ".local", "share");
|
|
18885
18907
|
return path3.join(dataHome, "recappi", "cli-state.sqlite");
|
|
18886
18908
|
}
|
|
18909
|
+
function normalizeAccountStamp(input) {
|
|
18910
|
+
return parseAccountPartition(input, "lenient");
|
|
18911
|
+
}
|
|
18887
18912
|
function requireAccountPartition(input) {
|
|
18888
18913
|
const account = parseAccountPartition(input, "strict");
|
|
18889
18914
|
if (!account) {
|
|
@@ -19791,12 +19816,12 @@ var RecappiApiClient = class {
|
|
|
19791
19816
|
} : {}
|
|
19792
19817
|
};
|
|
19793
19818
|
}
|
|
19794
|
-
async getJson(
|
|
19795
|
-
const response = await this.request("GET",
|
|
19819
|
+
async getJson(path8) {
|
|
19820
|
+
const response = await this.request("GET", path8);
|
|
19796
19821
|
return await parseJson(response);
|
|
19797
19822
|
}
|
|
19798
|
-
async postJson(
|
|
19799
|
-
const response = await this.request("POST",
|
|
19823
|
+
async postJson(path8, body) {
|
|
19824
|
+
const response = await this.request("POST", path8, JSON.stringify(body), {
|
|
19800
19825
|
headers: { "content-type": "application/json" }
|
|
19801
19826
|
});
|
|
19802
19827
|
return await parseJson(response);
|
|
@@ -20187,8 +20212,11 @@ import { promises as fs4 } from "fs";
|
|
|
20187
20212
|
import path5 from "path";
|
|
20188
20213
|
function createRecordingAudioRuntime(client, deps = {}) {
|
|
20189
20214
|
const downloadRecordingAudioFile = async (recordingId, opts) => {
|
|
20190
|
-
const cached2 =
|
|
20191
|
-
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
|
+
}
|
|
20192
20220
|
const directory = opts?.directory ?? (deps.account ? defaultDownloadDirectory(deps) : void 0);
|
|
20193
20221
|
const download = await client.downloadRecordingAudio(recordingId, {
|
|
20194
20222
|
...opts,
|
|
@@ -20216,6 +20244,38 @@ function createRecordingAudioRuntime(client, deps = {}) {
|
|
|
20216
20244
|
)
|
|
20217
20245
|
};
|
|
20218
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
|
+
}
|
|
20219
20279
|
function openPath(localPath, deps = {}) {
|
|
20220
20280
|
return runMacOpen([localPath], deps);
|
|
20221
20281
|
}
|
|
@@ -20246,7 +20306,7 @@ async function rememberDownload(download, deps) {
|
|
|
20246
20306
|
resource: "recording_audio",
|
|
20247
20307
|
contentType: download.contentType,
|
|
20248
20308
|
...download.contentLength !== void 0 ? { contentLength: download.contentLength } : {},
|
|
20249
|
-
origin: download.origin
|
|
20309
|
+
...download.origin ? { origin: download.origin } : {}
|
|
20250
20310
|
}
|
|
20251
20311
|
});
|
|
20252
20312
|
return store.markLocalArtifactOpened(artifact.id);
|
|
@@ -20274,6 +20334,27 @@ async function withStore(deps, run) {
|
|
|
20274
20334
|
function defaultDownloadDirectory(deps) {
|
|
20275
20335
|
return path5.join(path5.dirname(defaultStorePath(deps.homeDir, deps.env)), "downloads");
|
|
20276
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
|
+
}
|
|
20277
20358
|
async function isReadableFile(localPath) {
|
|
20278
20359
|
try {
|
|
20279
20360
|
return (await fs4.stat(localPath)).isFile();
|
|
@@ -20553,41 +20634,170 @@ ${lines.join("\n")}
|
|
|
20553
20634
|
}
|
|
20554
20635
|
|
|
20555
20636
|
// src/export.ts
|
|
20556
|
-
import { promises as
|
|
20637
|
+
import { promises as fs6 } from "fs";
|
|
20557
20638
|
import os5 from "os";
|
|
20639
|
+
import path7 from "path";
|
|
20640
|
+
|
|
20641
|
+
// src/recordingSessionCache.ts
|
|
20642
|
+
import { promises as fs5 } from "fs";
|
|
20558
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
|
|
20559
20749
|
async function syncRecordingText(opts) {
|
|
20560
20750
|
const context = await loadRecordingBundleContext(opts);
|
|
20561
|
-
const
|
|
20751
|
+
const account = accountFromStatus(context.subscription);
|
|
20752
|
+
const sessionDir = await resolveRecordingSessionDir(context.recording, opts, account);
|
|
20562
20753
|
return writeRecordingTextFiles(context, sessionDir, {
|
|
20563
|
-
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"
|
|
20564
20760
|
});
|
|
20565
20761
|
}
|
|
20566
20762
|
async function syncRecordingAudio(opts) {
|
|
20567
20763
|
const context = await loadRecordingBundleContext(opts);
|
|
20568
|
-
const
|
|
20764
|
+
const account = accountFromStatus(context.subscription);
|
|
20765
|
+
const sessionDir = await resolveRecordingSessionDir(context.recording, opts, account);
|
|
20569
20766
|
const audio = await downloadRecordingAudioToDir(context.recording, opts.recordingAudio, sessionDir);
|
|
20570
20767
|
const text = await writeRecordingTextFiles(context, sessionDir, {
|
|
20571
20768
|
now: opts.now,
|
|
20572
|
-
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
|
|
20573
20776
|
});
|
|
20574
20777
|
return { ...text, audioPath: audio.localPath, audio: audioMetadata(audio) };
|
|
20575
20778
|
}
|
|
20576
20779
|
async function exportRecording(opts) {
|
|
20577
20780
|
const context = await loadRecordingBundleContext(opts);
|
|
20578
|
-
const
|
|
20781
|
+
const account = accountFromStatus(context.subscription);
|
|
20782
|
+
const exportDir = await resolveRecordingSessionDir(context.recording, opts, account);
|
|
20579
20783
|
const audio = await downloadRecordingAudioToDir(context.recording, opts.recordingAudio, exportDir);
|
|
20580
20784
|
const textFiles = await writeRecordingTextFiles(context, exportDir, {
|
|
20581
20785
|
now: opts.now,
|
|
20582
|
-
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
|
|
20583
20793
|
});
|
|
20584
20794
|
const { recording, subscription, transcript } = context;
|
|
20585
|
-
const subscriptionPath =
|
|
20586
|
-
const subscriptionJsonPath =
|
|
20587
|
-
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");
|
|
20588
20798
|
await writeJson(subscriptionJsonPath, subscription);
|
|
20589
|
-
const textPath =
|
|
20590
|
-
const manifestPath =
|
|
20799
|
+
const textPath = path7.join(exportDir, "handoff.md");
|
|
20800
|
+
const manifestPath = path7.join(exportDir, "manifest.json");
|
|
20591
20801
|
const data = recordingExportDataSchema.parse({
|
|
20592
20802
|
origin: recording.origin,
|
|
20593
20803
|
recordingId: recording.recordingId,
|
|
@@ -20609,7 +20819,7 @@ async function exportRecording(opts) {
|
|
|
20609
20819
|
...textFiles.summaryStatus ? { summaryStatus: textFiles.summaryStatus } : {},
|
|
20610
20820
|
audio: audioMetadata(audio)
|
|
20611
20821
|
});
|
|
20612
|
-
await
|
|
20822
|
+
await fs6.writeFile(
|
|
20613
20823
|
textPath,
|
|
20614
20824
|
renderHandoffMarkdown(recording, subscription, audio, data, transcript),
|
|
20615
20825
|
"utf8"
|
|
@@ -20619,6 +20829,33 @@ async function exportRecording(opts) {
|
|
|
20619
20829
|
command: "recordings export",
|
|
20620
20830
|
data
|
|
20621
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
|
+
);
|
|
20622
20859
|
return data;
|
|
20623
20860
|
}
|
|
20624
20861
|
async function loadRecordingBundleContext(opts) {
|
|
@@ -20641,11 +20878,11 @@ async function downloadRecordingAudioToDir(recording, recordingAudio, directory)
|
|
|
20641
20878
|
}
|
|
20642
20879
|
async function writeRecordingTextFiles(context, sessionDir, opts) {
|
|
20643
20880
|
const { recording, transcript, subscription } = context;
|
|
20644
|
-
await
|
|
20645
|
-
const recordingJsonPath =
|
|
20646
|
-
const sessionMetadataPath =
|
|
20647
|
-
const remoteManifestPath =
|
|
20648
|
-
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);
|
|
20649
20886
|
const uploadFilename = opts.uploadFilename ?? (typeof existingManifest?.uploadFilename === "string" ? existingManifest.uploadFilename : void 0);
|
|
20650
20887
|
await writeJson(recordingJsonPath, recording);
|
|
20651
20888
|
await writeJson(sessionMetadataPath, renderSessionMetadata(recording));
|
|
@@ -20660,19 +20897,23 @@ async function writeRecordingTextFiles(context, sessionDir, opts) {
|
|
|
20660
20897
|
let actionItemsPath;
|
|
20661
20898
|
let summaryStatus;
|
|
20662
20899
|
if (transcript) {
|
|
20663
|
-
transcriptPath =
|
|
20664
|
-
transcriptJsonPath =
|
|
20665
|
-
|
|
20666
|
-
summaryJsonPath = path6.join(sessionDir, "summary.json");
|
|
20667
|
-
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");
|
|
20668
20903
|
summaryStatus = transcript.summary.status;
|
|
20669
|
-
await
|
|
20904
|
+
await fs6.writeFile(transcriptPath, renderTranscriptMarkdown(transcript), "utf8");
|
|
20670
20905
|
await writeJson(transcriptJsonPath, transcript);
|
|
20671
20906
|
await writeJson(summaryJsonPath, transcript.summary);
|
|
20672
|
-
|
|
20673
|
-
|
|
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;
|
|
20674
20915
|
}
|
|
20675
|
-
|
|
20916
|
+
const data = {
|
|
20676
20917
|
recordingId: recording.recordingId,
|
|
20677
20918
|
sessionDir,
|
|
20678
20919
|
remoteManifestPath,
|
|
@@ -20686,10 +20927,56 @@ async function writeRecordingTextFiles(context, sessionDir, opts) {
|
|
|
20686
20927
|
...actionItemsPath ? { actionItemsPath } : {},
|
|
20687
20928
|
...summaryStatus ? { summaryStatus } : {}
|
|
20688
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;
|
|
20689
20954
|
}
|
|
20690
|
-
async function resolveRecordingSessionDir(recording, opts) {
|
|
20691
|
-
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;
|
|
20692
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
|
+
}
|
|
20693
20980
|
if (existing) return existing;
|
|
20694
20981
|
return createRecordingSessionDir(recording, opts.homeDir, opts.env);
|
|
20695
20982
|
}
|
|
@@ -20697,39 +20984,39 @@ async function findExistingRecordingSessionDir(recordingId, homeDir, env) {
|
|
|
20697
20984
|
const base = recordingSessionBaseDirectory(homeDir, env);
|
|
20698
20985
|
let entries;
|
|
20699
20986
|
try {
|
|
20700
|
-
entries = await
|
|
20987
|
+
entries = await fs6.readdir(base, { withFileTypes: true });
|
|
20701
20988
|
} catch {
|
|
20702
20989
|
return void 0;
|
|
20703
20990
|
}
|
|
20704
20991
|
for (const entry of entries) {
|
|
20705
20992
|
if (!entry.isDirectory()) continue;
|
|
20706
|
-
const dir =
|
|
20707
|
-
const manifest = await
|
|
20993
|
+
const dir = path7.join(base, entry.name);
|
|
20994
|
+
const manifest = await readJsonRecord2(path7.join(dir, "remote-session.json"));
|
|
20708
20995
|
if (manifest?.recordingId === recordingId) return dir;
|
|
20709
20996
|
}
|
|
20710
20997
|
return void 0;
|
|
20711
20998
|
}
|
|
20712
20999
|
async function createRecordingSessionDir(recording, homeDir, env) {
|
|
20713
21000
|
const base = recordingSessionBaseDirectory(homeDir, env);
|
|
20714
|
-
await
|
|
21001
|
+
await fs6.mkdir(base, { recursive: true });
|
|
20715
21002
|
const stem = formatSessionDirectoryDate(new Date(recording.createdAt));
|
|
20716
|
-
let candidate =
|
|
21003
|
+
let candidate = path7.join(base, stem);
|
|
20717
21004
|
let suffix = 2;
|
|
20718
21005
|
while (await pathExists(candidate)) {
|
|
20719
|
-
candidate =
|
|
21006
|
+
candidate = path7.join(base, `${stem}-cloud-${suffix}`);
|
|
20720
21007
|
suffix += 1;
|
|
20721
21008
|
}
|
|
20722
|
-
await
|
|
21009
|
+
await fs6.mkdir(candidate, { recursive: true });
|
|
20723
21010
|
return candidate;
|
|
20724
21011
|
}
|
|
20725
21012
|
function recordingSessionBaseDirectory(homeDir = os5.homedir(), env = process.env) {
|
|
20726
21013
|
const explicit = env.RECAPPI_LOCAL_SESSIONS_DIR?.trim();
|
|
20727
21014
|
if (explicit) return explicit;
|
|
20728
|
-
return
|
|
21015
|
+
return path7.join(homeDir, "Documents", "Recappi Mini");
|
|
20729
21016
|
}
|
|
20730
|
-
async function
|
|
21017
|
+
async function readJsonRecord2(filePath) {
|
|
20731
21018
|
try {
|
|
20732
|
-
const parsed = JSON.parse(await
|
|
21019
|
+
const parsed = JSON.parse(await fs6.readFile(filePath, "utf8"));
|
|
20733
21020
|
return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) ? parsed : void 0;
|
|
20734
21021
|
} catch {
|
|
20735
21022
|
return void 0;
|
|
@@ -20737,7 +21024,7 @@ async function readJsonRecord(filePath) {
|
|
|
20737
21024
|
}
|
|
20738
21025
|
async function pathExists(filePath) {
|
|
20739
21026
|
try {
|
|
20740
|
-
await
|
|
21027
|
+
await fs6.access(filePath);
|
|
20741
21028
|
return true;
|
|
20742
21029
|
} catch {
|
|
20743
21030
|
return false;
|
|
@@ -20753,15 +21040,15 @@ function formatSessionDirectoryDate(date5) {
|
|
|
20753
21040
|
return `${year}-${month}-${day}_${hour}${minute}${second}`;
|
|
20754
21041
|
}
|
|
20755
21042
|
async function writeJson(filePath, value) {
|
|
20756
|
-
await
|
|
21043
|
+
await fs6.writeFile(filePath, `${JSON.stringify(value, null, 2)}
|
|
20757
21044
|
`, "utf8");
|
|
20758
21045
|
}
|
|
20759
21046
|
async function writeOptionalText(filePath, value) {
|
|
20760
21047
|
if (value && value.trim()) {
|
|
20761
|
-
await
|
|
21048
|
+
await fs6.writeFile(filePath, value, "utf8");
|
|
20762
21049
|
return;
|
|
20763
21050
|
}
|
|
20764
|
-
await
|
|
21051
|
+
await fs6.rm(filePath, { force: true });
|
|
20765
21052
|
}
|
|
20766
21053
|
function renderHandoffMarkdown(recording, subscription, audio, data, transcript) {
|
|
20767
21054
|
const lines = [];
|
|
@@ -20797,9 +21084,12 @@ function renderHandoffMarkdown(recording, subscription, audio, data, transcript)
|
|
|
20797
21084
|
appendSubscriptionLines(lines, subscription);
|
|
20798
21085
|
lines.push("");
|
|
20799
21086
|
if (transcript) {
|
|
20800
|
-
|
|
20801
|
-
|
|
20802
|
-
|
|
21087
|
+
const summaryMarkdown = renderSummaryMarkdown(transcript);
|
|
21088
|
+
if (summaryMarkdown) {
|
|
21089
|
+
lines.push(summaryMarkdown.trimEnd());
|
|
21090
|
+
lines.push("");
|
|
21091
|
+
}
|
|
21092
|
+
lines.push(renderTimestampedTranscriptMarkdown(transcript).trimEnd());
|
|
20803
21093
|
lines.push("");
|
|
20804
21094
|
}
|
|
20805
21095
|
return `${lines.join("\n").trimEnd()}
|
|
@@ -20813,7 +21103,7 @@ function renderSubscriptionMarkdown(subscription) {
|
|
|
20813
21103
|
}
|
|
20814
21104
|
function renderSessionMetadata(recording) {
|
|
20815
21105
|
const sourceTitle = recording.title ?? recording.summaryTitle ?? "Recappi Cloud";
|
|
20816
|
-
return
|
|
21106
|
+
return stripUndefined2({
|
|
20817
21107
|
summaryTitle: recording.summaryTitle ?? recording.title ?? void 0,
|
|
20818
21108
|
sourceTitle,
|
|
20819
21109
|
sourceAppName: void 0,
|
|
@@ -20825,7 +21115,7 @@ function renderSessionMetadata(recording) {
|
|
|
20825
21115
|
});
|
|
20826
21116
|
}
|
|
20827
21117
|
function renderRemoteSessionManifest(recording, uploadFilename, transcript, subscription, now) {
|
|
20828
|
-
return
|
|
21118
|
+
return stripUndefined2({
|
|
20829
21119
|
recordingId: recording.recordingId,
|
|
20830
21120
|
jobId: transcript?.jobId,
|
|
20831
21121
|
transcriptId: transcript?.transcriptId ?? recording.activeTranscriptId ?? void 0,
|
|
@@ -20839,7 +21129,7 @@ function renderRemoteSessionManifest(recording, uploadFilename, transcript, subs
|
|
|
20839
21129
|
accountBackendOrigin: subscription.origin
|
|
20840
21130
|
});
|
|
20841
21131
|
}
|
|
20842
|
-
function
|
|
21132
|
+
function stripUndefined2(value) {
|
|
20843
21133
|
return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== void 0));
|
|
20844
21134
|
}
|
|
20845
21135
|
function appendSubscriptionLines(lines, subscription) {
|
|
@@ -20862,6 +21152,12 @@ function appendSubscriptionLines(lines, subscription) {
|
|
|
20862
21152
|
function renderTranscriptMarkdown(transcript) {
|
|
20863
21153
|
return `# Transcript
|
|
20864
21154
|
|
|
21155
|
+
${transcript.text}
|
|
21156
|
+
`;
|
|
21157
|
+
}
|
|
21158
|
+
function renderTimestampedTranscriptMarkdown(transcript) {
|
|
21159
|
+
return `# Transcript
|
|
21160
|
+
|
|
20865
21161
|
${renderTranscriptLines(transcript)}
|
|
20866
21162
|
`;
|
|
20867
21163
|
}
|
|
@@ -20873,15 +21169,10 @@ function renderTranscriptLines(transcript) {
|
|
|
20873
21169
|
if (lines.length > 0) return lines.join("\n");
|
|
20874
21170
|
return transcript.text;
|
|
20875
21171
|
}
|
|
20876
|
-
function renderSummaryMarkdown(
|
|
21172
|
+
function renderSummaryMarkdown(transcript) {
|
|
20877
21173
|
const summary = transcript.summary;
|
|
20878
21174
|
const lines = [];
|
|
20879
|
-
lines.push(
|
|
20880
|
-
lines.push("");
|
|
20881
|
-
lines.push(`- recordingId: ${recording.recordingId}`);
|
|
20882
|
-
lines.push(`- transcriptId: ${transcript.transcriptId}`);
|
|
20883
|
-
lines.push(`- summaryStatus: ${summary.status}`);
|
|
20884
|
-
if (summary.error) lines.push(`- error: ${summary.error}`);
|
|
21175
|
+
lines.push("# Summary");
|
|
20885
21176
|
lines.push("");
|
|
20886
21177
|
if (summary.tldr) {
|
|
20887
21178
|
lines.push("## TL;DR", "");
|
|
@@ -20891,8 +21182,8 @@ function renderSummaryMarkdown(recording, transcript) {
|
|
|
20891
21182
|
appendStringList(lines, "Topics", summary.topics);
|
|
20892
21183
|
appendStringList(lines, "Decisions", summary.decisions);
|
|
20893
21184
|
appendActionItems(lines, summary.actionItems);
|
|
20894
|
-
|
|
20895
|
-
|
|
21185
|
+
appendNotableQuotes(lines, summary.quotes);
|
|
21186
|
+
if (lines.length === 2) return null;
|
|
20896
21187
|
if (lines[lines.length - 1] !== "") lines.push("");
|
|
20897
21188
|
return lines.join("\n");
|
|
20898
21189
|
}
|
|
@@ -20900,7 +21191,7 @@ function renderActionItemsMarkdown(summary) {
|
|
|
20900
21191
|
if (!summary.actionItems || summary.actionItems.length === 0) return null;
|
|
20901
21192
|
const lines = ["# Action Items", ""];
|
|
20902
21193
|
for (const item of summary.actionItems) {
|
|
20903
|
-
lines.push(
|
|
21194
|
+
lines.push(actionItemLine(item));
|
|
20904
21195
|
}
|
|
20905
21196
|
lines.push("");
|
|
20906
21197
|
return lines.join("\n");
|
|
@@ -20915,27 +21206,20 @@ function appendActionItems(lines, values) {
|
|
|
20915
21206
|
if (!values || values.length === 0) return;
|
|
20916
21207
|
lines.push("## Action Items", "");
|
|
20917
21208
|
for (const item of values) {
|
|
20918
|
-
lines.push(
|
|
21209
|
+
lines.push(actionItemLine(item));
|
|
20919
21210
|
}
|
|
20920
21211
|
lines.push("");
|
|
20921
21212
|
}
|
|
20922
|
-
function
|
|
21213
|
+
function appendNotableQuotes(lines, values) {
|
|
20923
21214
|
if (!values || values.length === 0) return;
|
|
20924
|
-
lines.push("##
|
|
21215
|
+
lines.push("## Notable Quotes", "");
|
|
20925
21216
|
for (const item of values) {
|
|
20926
|
-
lines.push(
|
|
20927
|
-
`- ${formatTimestamp(item.startMs)}-${formatTimestamp(item.endMs)}: ${item.title} - ${item.summary}`
|
|
20928
|
-
);
|
|
21217
|
+
lines.push(`> ${item.speaker ? `${item.speaker}: ` : ""}${item.text}`);
|
|
20929
21218
|
}
|
|
20930
21219
|
lines.push("");
|
|
20931
21220
|
}
|
|
20932
|
-
function
|
|
20933
|
-
|
|
20934
|
-
lines.push("## Quotes", "");
|
|
20935
|
-
for (const item of values) {
|
|
20936
|
-
lines.push(`- ${item.speaker ? `${item.speaker}: ` : ""}"${item.text}"`);
|
|
20937
|
-
}
|
|
20938
|
-
lines.push("");
|
|
21221
|
+
function actionItemLine(item) {
|
|
21222
|
+
return `- ${item.who ? `${item.who}: ` : ""}${item.what}`;
|
|
20939
21223
|
}
|
|
20940
21224
|
function audioMetadata(audio) {
|
|
20941
21225
|
return {
|
|
@@ -21331,20 +21615,20 @@ function renderEnvelope(envelope, opts) {
|
|
|
21331
21615
|
`);
|
|
21332
21616
|
}
|
|
21333
21617
|
function renderHumanSuccess(command, data, opts) {
|
|
21334
|
-
if (command === "auth login" &&
|
|
21618
|
+
if (command === "auth login" && isRecord5(data)) {
|
|
21335
21619
|
opts.stdout(`Signed in${typeof data.email === "string" ? ` as ${data.email}` : ""}
|
|
21336
21620
|
`);
|
|
21337
21621
|
return;
|
|
21338
21622
|
}
|
|
21339
|
-
if (command === "auth logout" &&
|
|
21623
|
+
if (command === "auth logout" && isRecord5(data)) {
|
|
21340
21624
|
opts.stdout(data.cleared ? "Signed out of Recappi CLI\n" : "No Recappi CLI session to clear\n");
|
|
21341
21625
|
return;
|
|
21342
21626
|
}
|
|
21343
|
-
if (command === "auth import-macos" &&
|
|
21627
|
+
if (command === "auth import-macos" && isRecord5(data)) {
|
|
21344
21628
|
opts.stdout("Imported the Recappi Mini app session into Recappi CLI\n");
|
|
21345
21629
|
return;
|
|
21346
21630
|
}
|
|
21347
|
-
if (command === "auth status" &&
|
|
21631
|
+
if (command === "auth status" && isRecord5(data)) {
|
|
21348
21632
|
if (data.loggedIn) {
|
|
21349
21633
|
opts.stdout(`Signed in${typeof data.email === "string" ? ` as ${data.email}` : ""}
|
|
21350
21634
|
`);
|
|
@@ -21353,7 +21637,7 @@ function renderHumanSuccess(command, data, opts) {
|
|
|
21353
21637
|
opts.stdout("Not logged in\n");
|
|
21354
21638
|
return;
|
|
21355
21639
|
}
|
|
21356
|
-
if (command === "account status" &&
|
|
21640
|
+
if (command === "account status" && isRecord5(data)) {
|
|
21357
21641
|
if (!data.loggedIn) {
|
|
21358
21642
|
opts.stdout("Not logged in\n");
|
|
21359
21643
|
return;
|
|
@@ -21364,7 +21648,7 @@ function renderHumanSuccess(command, data, opts) {
|
|
|
21364
21648
|
`);
|
|
21365
21649
|
if (typeof data.userId === "string") opts.stdout(` userId: ${data.userId}
|
|
21366
21650
|
`);
|
|
21367
|
-
const billing =
|
|
21651
|
+
const billing = isRecord5(data.billing) ? data.billing : {};
|
|
21368
21652
|
if (typeof billing.tier === "string") opts.stdout(` plan: ${billing.tier}
|
|
21369
21653
|
`);
|
|
21370
21654
|
if (typeof billing.minutesUsed === "number") {
|
|
@@ -21377,7 +21661,7 @@ function renderHumanSuccess(command, data, opts) {
|
|
|
21377
21661
|
opts.stdout(` storage: ${formatBytes2(billing.storageBytes)} / ${cap}
|
|
21378
21662
|
`);
|
|
21379
21663
|
}
|
|
21380
|
-
const localStore =
|
|
21664
|
+
const localStore = isRecord5(data.localStore) ? data.localStore : {};
|
|
21381
21665
|
if (typeof localStore.path === "string") opts.stdout(` localStore: ${localStore.path}
|
|
21382
21666
|
`);
|
|
21383
21667
|
opts.stdout(
|
|
@@ -21386,17 +21670,17 @@ function renderHumanSuccess(command, data, opts) {
|
|
|
21386
21670
|
);
|
|
21387
21671
|
return;
|
|
21388
21672
|
}
|
|
21389
|
-
if (command === "version" &&
|
|
21673
|
+
if (command === "version" && isRecord5(data) && typeof data.version === "string") {
|
|
21390
21674
|
opts.stdout(`${data.version}
|
|
21391
21675
|
`);
|
|
21392
21676
|
return;
|
|
21393
21677
|
}
|
|
21394
|
-
if (command === "doctor" &&
|
|
21678
|
+
if (command === "doctor" && isRecord5(data) && Array.isArray(data.checks)) {
|
|
21395
21679
|
const status = typeof data.status === "string" ? data.status : "unknown";
|
|
21396
21680
|
opts.stdout(`Doctor: ${status}
|
|
21397
21681
|
`);
|
|
21398
21682
|
for (const check2 of data.checks) {
|
|
21399
|
-
if (!
|
|
21683
|
+
if (!isRecord5(check2)) continue;
|
|
21400
21684
|
const checkStatus = typeof check2.status === "string" ? check2.status : "unknown";
|
|
21401
21685
|
const name = typeof check2.name === "string" ? check2.name : "check";
|
|
21402
21686
|
const message = typeof check2.message === "string" ? ` \u2014 ${check2.message}` : "";
|
|
@@ -21407,14 +21691,14 @@ function renderHumanSuccess(command, data, opts) {
|
|
|
21407
21691
|
}
|
|
21408
21692
|
return;
|
|
21409
21693
|
}
|
|
21410
|
-
if (command === "transcript get" &&
|
|
21694
|
+
if (command === "transcript get" && isRecord5(data)) {
|
|
21411
21695
|
renderTranscriptHuman(data, opts);
|
|
21412
21696
|
return;
|
|
21413
21697
|
}
|
|
21414
|
-
if (command === "recordings list" &&
|
|
21698
|
+
if (command === "recordings list" && isRecord5(data) && Array.isArray(data.items)) {
|
|
21415
21699
|
opts.stdout("Recordings:\n");
|
|
21416
21700
|
for (const item of data.items) {
|
|
21417
|
-
if (!
|
|
21701
|
+
if (!isRecord5(item)) continue;
|
|
21418
21702
|
opts.stdout(` ${recordingLabel(item)}
|
|
21419
21703
|
`);
|
|
21420
21704
|
}
|
|
@@ -21426,7 +21710,7 @@ Next cursor: ${data.nextCursor}
|
|
|
21426
21710
|
}
|
|
21427
21711
|
return;
|
|
21428
21712
|
}
|
|
21429
|
-
if (command === "recordings get" &&
|
|
21713
|
+
if (command === "recordings get" && isRecord5(data)) {
|
|
21430
21714
|
opts.stdout(`${recordingTitle(data)}
|
|
21431
21715
|
`);
|
|
21432
21716
|
opts.stdout(` recordingId: ${String(data.recordingId)}
|
|
@@ -21448,7 +21732,7 @@ Next:
|
|
|
21448
21732
|
}
|
|
21449
21733
|
return;
|
|
21450
21734
|
}
|
|
21451
|
-
if (command === "recordings export" &&
|
|
21735
|
+
if (command === "recordings export" && isRecord5(data)) {
|
|
21452
21736
|
opts.stdout("Recording export ready\n");
|
|
21453
21737
|
printStringField(opts, data, "recordingId");
|
|
21454
21738
|
printStringField(opts, data, "exportDir");
|
|
@@ -21470,7 +21754,7 @@ Next:
|
|
|
21470
21754
|
}
|
|
21471
21755
|
return;
|
|
21472
21756
|
}
|
|
21473
|
-
if (command === "recordings retranscribe" &&
|
|
21757
|
+
if (command === "recordings retranscribe" && isRecord5(data)) {
|
|
21474
21758
|
opts.stdout("Transcription started\n");
|
|
21475
21759
|
if (typeof data.recordingId === "string") opts.stdout(` recordingId: ${data.recordingId}
|
|
21476
21760
|
`);
|
|
@@ -21493,7 +21777,7 @@ Next:
|
|
|
21493
21777
|
}
|
|
21494
21778
|
return;
|
|
21495
21779
|
}
|
|
21496
|
-
if (command === "recordings resummarize" &&
|
|
21780
|
+
if (command === "recordings resummarize" && isRecord5(data)) {
|
|
21497
21781
|
opts.stdout("Summary queued\n");
|
|
21498
21782
|
if (typeof data.recordingId === "string") opts.stdout(` recordingId: ${data.recordingId}
|
|
21499
21783
|
`);
|
|
@@ -21511,9 +21795,9 @@ Next:
|
|
|
21511
21795
|
}
|
|
21512
21796
|
return;
|
|
21513
21797
|
}
|
|
21514
|
-
if (command === "dashboard stats" &&
|
|
21515
|
-
const recordings =
|
|
21516
|
-
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 : {};
|
|
21517
21801
|
opts.stdout(
|
|
21518
21802
|
`Recordings: ${numberText(recordings.total)} total, ${numberText(recordings.ready)} ready
|
|
21519
21803
|
`
|
|
@@ -21556,7 +21840,7 @@ Next:
|
|
|
21556
21840
|
}
|
|
21557
21841
|
return;
|
|
21558
21842
|
}
|
|
21559
|
-
if (command === "record" &&
|
|
21843
|
+
if (command === "record" && isRecord5(data)) {
|
|
21560
21844
|
opts.stdout("Recording complete\n");
|
|
21561
21845
|
if (typeof data.recordingId === "string") opts.stdout(` recordingId: ${data.recordingId}
|
|
21562
21846
|
`);
|
|
@@ -21575,14 +21859,14 @@ Next:
|
|
|
21575
21859
|
if (Array.isArray(data.artifacts) && data.artifacts.length > 0) {
|
|
21576
21860
|
opts.stdout(" artifacts:\n");
|
|
21577
21861
|
for (const artifact of data.artifacts) {
|
|
21578
|
-
if (!
|
|
21862
|
+
if (!isRecord5(artifact)) continue;
|
|
21579
21863
|
const kind = typeof artifact.kind === "string" ? artifact.kind : "artifact";
|
|
21580
21864
|
const localPath = typeof artifact.localPath === "string" ? artifact.localPath : "";
|
|
21581
21865
|
opts.stdout(` - ${kind}: ${localPath}
|
|
21582
21866
|
`);
|
|
21583
21867
|
}
|
|
21584
21868
|
}
|
|
21585
|
-
const cloudHandoffError =
|
|
21869
|
+
const cloudHandoffError = isRecord5(data.cloudHandoffError) ? data.cloudHandoffError : void 0;
|
|
21586
21870
|
if (cloudHandoffError && typeof cloudHandoffError.message === "string") {
|
|
21587
21871
|
opts.stderr(`Cloud handoff failed: ${cloudHandoffError.message}
|
|
21588
21872
|
`);
|
|
@@ -21607,7 +21891,7 @@ Next:
|
|
|
21607
21891
|
}
|
|
21608
21892
|
return;
|
|
21609
21893
|
}
|
|
21610
|
-
if (command === "audio" &&
|
|
21894
|
+
if (command === "audio" && isRecord5(data)) {
|
|
21611
21895
|
const action = typeof data.action === "string" ? data.action : "download";
|
|
21612
21896
|
opts.stdout(
|
|
21613
21897
|
action === "open" ? "Audio opened\n" : action === "reveal" ? "Audio revealed\n" : "Audio ready\n"
|
|
@@ -21622,7 +21906,7 @@ Next:
|
|
|
21622
21906
|
}
|
|
21623
21907
|
return;
|
|
21624
21908
|
}
|
|
21625
|
-
if ((command === "jobs wait" || command === "upload") &&
|
|
21909
|
+
if ((command === "jobs wait" || command === "upload") && isRecord5(data)) {
|
|
21626
21910
|
if (typeof data.transcriptId === "string") {
|
|
21627
21911
|
opts.stdout("Transcript ready\n");
|
|
21628
21912
|
if (typeof data.recordingId === "string" && typeof data.origin === "string") {
|
|
@@ -21647,10 +21931,10 @@ Next:
|
|
|
21647
21931
|
}
|
|
21648
21932
|
return;
|
|
21649
21933
|
}
|
|
21650
|
-
if (command === "schema" &&
|
|
21934
|
+
if (command === "schema" && isRecord5(data) && Array.isArray(data.commands)) {
|
|
21651
21935
|
opts.stdout("Commands:\n");
|
|
21652
21936
|
for (const entry of data.commands) {
|
|
21653
|
-
if (!
|
|
21937
|
+
if (!isRecord5(entry) || typeof entry.name !== "string") continue;
|
|
21654
21938
|
const summary = typeof entry.summary === "string" ? ` \u2014 ${entry.summary}` : "";
|
|
21655
21939
|
opts.stdout(` ${entry.name}${summary}
|
|
21656
21940
|
`);
|
|
@@ -21660,9 +21944,9 @@ Next:
|
|
|
21660
21944
|
}
|
|
21661
21945
|
if (Array.isArray(entry.examples) && entry.examples.length > 0) {
|
|
21662
21946
|
const first = entry.examples.find(
|
|
21663
|
-
(example) =>
|
|
21947
|
+
(example) => isRecord5(example) && typeof example.command === "string"
|
|
21664
21948
|
);
|
|
21665
|
-
if (
|
|
21949
|
+
if (isRecord5(first) && typeof first.command === "string") {
|
|
21666
21950
|
opts.stdout(` example: ${first.command}
|
|
21667
21951
|
`);
|
|
21668
21952
|
}
|
|
@@ -21794,7 +22078,7 @@ function renderTranscriptHuman(data, opts) {
|
|
|
21794
22078
|
const segments = Array.isArray(data.segments) ? data.segments : [];
|
|
21795
22079
|
let printedBody = false;
|
|
21796
22080
|
for (const segment of segments) {
|
|
21797
|
-
if (!
|
|
22081
|
+
if (!isRecord5(segment) || typeof segment.text !== "string") continue;
|
|
21798
22082
|
const clock = typeof segment.startMs === "number" ? `[${formatClock(segment.startMs / 1e3)}] ` : "";
|
|
21799
22083
|
const speaker = typeof segment.speaker === "string" ? `${segment.speaker}: ` : "";
|
|
21800
22084
|
opts.stdout(`${clock}${speaker}${segment.text}
|
|
@@ -21806,7 +22090,7 @@ function renderTranscriptHuman(data, opts) {
|
|
|
21806
22090
|
`);
|
|
21807
22091
|
printedBody = true;
|
|
21808
22092
|
}
|
|
21809
|
-
const summary =
|
|
22093
|
+
const summary = isRecord5(data.summary) ? data.summary : void 0;
|
|
21810
22094
|
if (!summary || summary.status !== "succeeded") return;
|
|
21811
22095
|
if (typeof summary.tldr === "string" && summary.tldr.length > 0) {
|
|
21812
22096
|
opts.stdout(`
|
|
@@ -21824,7 +22108,7 @@ Summary:
|
|
|
21824
22108
|
if (Array.isArray(summary.actionItems) && summary.actionItems.length > 0) {
|
|
21825
22109
|
opts.stdout("\nAction items:\n");
|
|
21826
22110
|
for (const item of summary.actionItems) {
|
|
21827
|
-
if (!
|
|
22111
|
+
if (!isRecord5(item) || typeof item.what !== "string") continue;
|
|
21828
22112
|
const who = typeof item.who === "string" ? `${item.who}: ` : "";
|
|
21829
22113
|
opts.stdout(` - ${who}${item.what}
|
|
21830
22114
|
`);
|
|
@@ -21899,7 +22183,7 @@ function applyFields(command, data, fields, compact) {
|
|
|
21899
22183
|
};
|
|
21900
22184
|
return compact ? compactData(filtered2) : filtered2;
|
|
21901
22185
|
}
|
|
21902
|
-
if (!
|
|
22186
|
+
if (!isRecord5(data)) return data;
|
|
21903
22187
|
const allowed = new Set(Object.keys(data));
|
|
21904
22188
|
assertKnownFields(fields, allowed);
|
|
21905
22189
|
const filtered = pickFields(data, fields);
|
|
@@ -21924,7 +22208,7 @@ function compactData(value) {
|
|
|
21924
22208
|
if (Array.isArray(value)) {
|
|
21925
22209
|
return value.map(compactData).filter((item) => item !== void 0);
|
|
21926
22210
|
}
|
|
21927
|
-
if (
|
|
22211
|
+
if (isRecord5(value)) {
|
|
21928
22212
|
const out = {};
|
|
21929
22213
|
for (const [key, child] of Object.entries(value)) {
|
|
21930
22214
|
const compacted = compactData(child);
|
|
@@ -21942,16 +22226,16 @@ function stableStringify(value, compact) {
|
|
|
21942
22226
|
}
|
|
21943
22227
|
function sortKeys(value) {
|
|
21944
22228
|
if (Array.isArray(value)) return value.map(sortKeys);
|
|
21945
|
-
if (!
|
|
22229
|
+
if (!isRecord5(value)) return value;
|
|
21946
22230
|
return Object.fromEntries(
|
|
21947
22231
|
Object.keys(value).sort().map((key) => [key, sortKeys(value[key])])
|
|
21948
22232
|
);
|
|
21949
22233
|
}
|
|
21950
|
-
function
|
|
22234
|
+
function isRecord5(value) {
|
|
21951
22235
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
21952
22236
|
}
|
|
21953
22237
|
function isUploadBatch(value) {
|
|
21954
|
-
return
|
|
22238
|
+
return isRecord5(value) && Array.isArray(value.successes) && Array.isArray(value.failures);
|
|
21955
22239
|
}
|
|
21956
22240
|
|
|
21957
22241
|
// src/schema.ts
|
|
@@ -22006,11 +22290,11 @@ function buildSchemaDocument(program) {
|
|
|
22006
22290
|
event: toJsonSchema(operationEventSchema)
|
|
22007
22291
|
};
|
|
22008
22292
|
}
|
|
22009
|
-
function walkCommands(command,
|
|
22293
|
+
function walkCommands(command, path8, out) {
|
|
22010
22294
|
for (const sub of subcommandsOf(command)) {
|
|
22011
22295
|
const name = sub.name();
|
|
22012
22296
|
if (name === "help") continue;
|
|
22013
|
-
const fullPath = [...
|
|
22297
|
+
const fullPath = [...path8, name];
|
|
22014
22298
|
const children = subcommandsOf(sub).filter((child) => child.name() !== "help");
|
|
22015
22299
|
if (children.length === 0) {
|
|
22016
22300
|
out.push(leafCommandDoc(sub, fullPath.join(" ")));
|
|
@@ -22288,7 +22572,7 @@ var MiniSidecarClient = class {
|
|
|
22288
22572
|
}
|
|
22289
22573
|
};
|
|
22290
22574
|
function sidecarErrorToCliError(error51) {
|
|
22291
|
-
const data =
|
|
22575
|
+
const data = isRecord7(error51.data) ? error51.data : void 0;
|
|
22292
22576
|
const maybeCode = typeof data?.cliCode === "string" ? cliErrorCodeSchema.safeParse(data.cliCode) : void 0;
|
|
22293
22577
|
const hint = typeof data?.recovery === "string" ? data.recovery : void 0;
|
|
22294
22578
|
const retryable = typeof data?.retryable === "boolean" ? data.retryable : error51.code >= -32099 && error51.code <= -32e3;
|
|
@@ -22305,7 +22589,7 @@ function sidecarErrorToCliError(error51) {
|
|
|
22305
22589
|
retryable
|
|
22306
22590
|
});
|
|
22307
22591
|
}
|
|
22308
|
-
function
|
|
22592
|
+
function isRecord7(value) {
|
|
22309
22593
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
22310
22594
|
}
|
|
22311
22595
|
function spawnMiniSidecar(opts) {
|
|
@@ -22412,8 +22696,8 @@ function requestLaunchServicesSidecarShutdown(input) {
|
|
|
22412
22696
|
} catch {
|
|
22413
22697
|
}
|
|
22414
22698
|
}
|
|
22415
|
-
function createFifo(
|
|
22416
|
-
const result = spawnSync("mkfifo", [
|
|
22699
|
+
function createFifo(path8) {
|
|
22700
|
+
const result = spawnSync("mkfifo", [path8], { encoding: "utf8" });
|
|
22417
22701
|
if (result.status !== 0) {
|
|
22418
22702
|
throw cliError("record.helper_unavailable", "Recappi recording helper could not start.", {
|
|
22419
22703
|
hint: result.stderr || "Could not create the local recorder pipes. Try again."
|
|
@@ -22949,14 +23233,14 @@ async function startRecordSessionOnce(opts) {
|
|
|
22949
23233
|
}
|
|
22950
23234
|
}
|
|
22951
23235
|
function isPermissionRestartRequiredError(error51, permissionName) {
|
|
22952
|
-
const root =
|
|
22953
|
-
const descriptor =
|
|
23236
|
+
const root = isRecord8(error51) ? error51 : void 0;
|
|
23237
|
+
const descriptor = isRecord8(root?.descriptor) ? root.descriptor : void 0;
|
|
22954
23238
|
if (descriptor?.code !== "record.permission_required") return false;
|
|
22955
|
-
const sidecarError =
|
|
22956
|
-
const sidecarData =
|
|
23239
|
+
const sidecarError = isRecord8(root?.data) ? root.data : void 0;
|
|
23240
|
+
const sidecarData = isRecord8(sidecarError?.data) ? sidecarError.data : void 0;
|
|
22957
23241
|
return sidecarData?.permission === permissionName && (sidecarData.requiresProcessRestart === true || sidecarData.requiresProcessRestart === "true");
|
|
22958
23242
|
}
|
|
22959
|
-
function
|
|
23243
|
+
function isRecord8(value) {
|
|
22960
23244
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
22961
23245
|
}
|
|
22962
23246
|
function normalizeSidecarSources(sources) {
|
|
@@ -23037,9 +23321,9 @@ function resolveSidecarCommand(opts) {
|
|
|
23037
23321
|
hint: `No bundled helper is registered for ${platform}. Set ${SIDECAR_COMMAND_ENV} to a compatible helper when one is available.`
|
|
23038
23322
|
});
|
|
23039
23323
|
}
|
|
23040
|
-
function ensureBundledHelperExecutable(
|
|
23041
|
-
if (process.platform === "darwin" &&
|
|
23042
|
-
const stableApp = ensureStableDarwinHelperApp(
|
|
23324
|
+
function ensureBundledHelperExecutable(path8, opts = {}) {
|
|
23325
|
+
if (process.platform === "darwin" && path8.endsWith(".app")) {
|
|
23326
|
+
const stableApp = ensureStableDarwinHelperApp(path8, opts);
|
|
23043
23327
|
const executable = darwinAppExecutablePath(stableApp);
|
|
23044
23328
|
if (!existsSync(executable)) {
|
|
23045
23329
|
throw cliError("record.helper_unavailable", "Recappi recording helper is not available.", {
|
|
@@ -23049,19 +23333,19 @@ function ensureBundledHelperExecutable(path7, opts = {}) {
|
|
|
23049
23333
|
ensureExecutableMode(executable);
|
|
23050
23334
|
return stableApp;
|
|
23051
23335
|
}
|
|
23052
|
-
if (process.platform === "win32") return
|
|
23053
|
-
ensureExecutableMode(
|
|
23054
|
-
return
|
|
23336
|
+
if (process.platform === "win32") return path8;
|
|
23337
|
+
ensureExecutableMode(path8);
|
|
23338
|
+
return path8;
|
|
23055
23339
|
}
|
|
23056
|
-
function ensureExecutableMode(
|
|
23057
|
-
const mode = statSync(
|
|
23340
|
+
function ensureExecutableMode(path8) {
|
|
23341
|
+
const mode = statSync(path8).mode;
|
|
23058
23342
|
if ((mode & 73) !== 0) return;
|
|
23059
23343
|
try {
|
|
23060
|
-
chmodSync(
|
|
23344
|
+
chmodSync(path8, mode | 493);
|
|
23061
23345
|
} catch (error51) {
|
|
23062
23346
|
const message = error51 instanceof Error ? error51.message : String(error51);
|
|
23063
23347
|
throw cliError("record.helper_unavailable", "Recappi recording helper is not executable.", {
|
|
23064
|
-
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.`
|
|
23065
23349
|
});
|
|
23066
23350
|
}
|
|
23067
23351
|
}
|
|
@@ -23106,14 +23390,14 @@ function helperSourceSignature(sourceApp) {
|
|
|
23106
23390
|
codeSignature: existsSync(signaturePath) ? fileDigest(signaturePath) : null
|
|
23107
23391
|
});
|
|
23108
23392
|
}
|
|
23109
|
-
function fileDigest(
|
|
23393
|
+
function fileDigest(path8) {
|
|
23110
23394
|
const hash2 = createHash("sha256");
|
|
23111
|
-
hash2.update(readFileSync2(
|
|
23395
|
+
hash2.update(readFileSync2(path8));
|
|
23112
23396
|
return hash2.digest("hex");
|
|
23113
23397
|
}
|
|
23114
|
-
function readTextIfExists(
|
|
23398
|
+
function readTextIfExists(path8) {
|
|
23115
23399
|
try {
|
|
23116
|
-
return readFileSync2(
|
|
23400
|
+
return readFileSync2(path8, "utf8");
|
|
23117
23401
|
} catch {
|
|
23118
23402
|
return null;
|
|
23119
23403
|
}
|
|
@@ -23407,6 +23691,13 @@ async function runCli(deps = {}) {
|
|
|
23407
23691
|
await runDashboard2({
|
|
23408
23692
|
fetchJobs: () => client.listJobs({ status: "active", limit: 20 }),
|
|
23409
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,
|
|
23410
23701
|
fetchDashboardStats: () => client.dashboardStats(),
|
|
23411
23702
|
fetchAccountStatus: () => client.accountStatus(),
|
|
23412
23703
|
fetchTranscript: (transcriptId) => client.getTranscript(transcriptId),
|