recappi 0.1.76 → 0.1.78

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -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 = isRecord5(artifact?.metadata) ? artifact.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 isRecord5(value) {
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 ${"\u280B\u2819\u2839\u2838\u283C\u2834\u2826\u2827\u2807\u280F"[spinnerFrame % 10]} 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 = isRecord8(error51) && isRecord8(error51.descriptor) ? error51.descriptor : void 0;
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: isRecord8(error51) ? error51.data : void 0,
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 && isRecord8(error51) && isRecord8(error51.descriptor) ? error51.descriptor : void 0;
1893
- const code = typeof descriptor?.code === "string" ? descriptor.code : isRecord8(error51) && typeof error51.code === "string" ? error51.code : void 0;
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 = isRecord8(data) ? data : void 0;
1968
- const sidecarData = isRecord8(sidecarError?.data) ? sidecarError.data : void 0;
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 = isRecord8(data) ? data : void 0;
1984
- const sidecarData = isRecord8(sidecarError?.data) ? sidecarError.data : void 0;
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 isRecord8(value) {
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);
@@ -2067,6 +2071,12 @@ function AppShell({
2067
2071
  void refreshDownloadedIds();
2068
2072
  }, [refreshDownloadedIds]);
2069
2073
  const screen = stack[stack.length - 1];
2074
+ const recordingsRef = useRef3(recordings);
2075
+ recordingsRef.current = recordings;
2076
+ const selectedRef = useRef3(selected);
2077
+ selectedRef.current = selected;
2078
+ const screenRef = useRef3(screen);
2079
+ screenRef.current = screen;
2070
2080
  useEffect4(() => {
2071
2081
  if (screen.kind !== "recordSetup" || !startRecordSetupPreview) return;
2072
2082
  let cancelled = false;
@@ -2245,6 +2255,21 @@ function AppShell({
2245
2255
  }, [peekTranscriptId, fetchTranscript]);
2246
2256
  const peekSummary = peekTranscriptId ? summaryCache.get(peekTranscriptId) : void 0;
2247
2257
  const refresh = useCallback(async ({ resetRecordings = false } = {}) => {
2258
+ let showingCachedRecordings = false;
2259
+ if (resetRecordings && fetchCachedRecordings) {
2260
+ try {
2261
+ const cached2 = await fetchCachedRecordings({ limit: RECORDINGS_PAGE_SIZE });
2262
+ if (cached2.items.length > 0) {
2263
+ showingCachedRecordings = true;
2264
+ setRecordings(cached2.items);
2265
+ setRecordingsNextCursor(cached2.nextCursor ?? null);
2266
+ setRecordingsTotalCount(cached2.totalCount);
2267
+ setLoaded(true);
2268
+ setRevalidatingRecordings(Boolean(fetchRecordings));
2269
+ }
2270
+ } catch {
2271
+ }
2272
+ }
2248
2273
  const [jobsR, recR, statsR, accountR] = await Promise.allSettled([
2249
2274
  fetchJobs(),
2250
2275
  resetRecordings && fetchRecordings ? fetchRecordings({ limit: RECORDINGS_PAGE_SIZE }) : Promise.resolve(void 0),
@@ -2259,9 +2284,15 @@ function AppShell({
2259
2284
  setLoadError(jobsR.reason instanceof Error ? jobsR.reason.message : String(jobsR.reason));
2260
2285
  }
2261
2286
  if (recR.status === "fulfilled" && recR.value) {
2262
- setRecordings(recR.value.items);
2287
+ const prevSelectedId = screenRef.current.kind === "overview" ? recordingsRef.current[selectedRef.current]?.recordingId : void 0;
2288
+ const freshItems = recR.value.items;
2289
+ setRecordings(freshItems);
2263
2290
  setRecordingsNextCursor(recR.value.nextCursor ?? null);
2264
2291
  setRecordingsTotalCount(recR.value.totalCount);
2292
+ if (prevSelectedId) {
2293
+ const idx = freshItems.findIndex((r) => r.recordingId === prevSelectedId);
2294
+ setSelected((s) => idx >= 0 ? idx : Math.min(s, Math.max(0, freshItems.length - 1)));
2295
+ }
2265
2296
  }
2266
2297
  if (statsR.status === "fulfilled" && statsR.value) setStats(statsR.value);
2267
2298
  if (accountR.status === "fulfilled") {
@@ -2270,7 +2301,8 @@ function AppShell({
2270
2301
  setAccountStatus("error");
2271
2302
  }
2272
2303
  setLoaded(true);
2273
- }, [fetchJobs, fetchRecordings, fetchDashboardStats, fetchAccountStatus]);
2304
+ if (showingCachedRecordings) setRevalidatingRecordings(false);
2305
+ }, [fetchJobs, fetchRecordings, fetchCachedRecordings, fetchDashboardStats, fetchAccountStatus]);
2274
2306
  const transcribeStoppedRecording = useCallback(async () => {
2275
2307
  const current = liveRecord;
2276
2308
  if (current?.kind !== "stopped") return;
@@ -2933,7 +2965,8 @@ function AppShell({
2933
2965
  peekItem: recordings[selected],
2934
2966
  peekSummary,
2935
2967
  showPeek,
2936
- peekWidth
2968
+ peekWidth,
2969
+ revalidating: revalidatingRecordings
2937
2970
  }
2938
2971
  );
2939
2972
  } else if (screen.kind === "account") {
@@ -3051,6 +3084,7 @@ async function runDashboard(deps) {
3051
3084
  fetchJobs: deps.fetchJobs,
3052
3085
  fetchTranscript: deps.fetchTranscript,
3053
3086
  fetchRecordings: deps.fetchRecordings,
3087
+ fetchCachedRecordings: deps.fetchCachedRecordings,
3054
3088
  fetchDashboardStats: deps.fetchDashboardStats,
3055
3089
  fetchAccountStatus: deps.fetchAccountStatus,
3056
3090
  recordingAudio: deps.recordingAudio,
@@ -3859,10 +3893,10 @@ function mergeDefs(...defs) {
3859
3893
  function cloneDef(schema) {
3860
3894
  return mergeDefs(schema._zod.def);
3861
3895
  }
3862
- function getElementAtPath(obj, path7) {
3863
- if (!path7)
3896
+ function getElementAtPath(obj, path8) {
3897
+ if (!path8)
3864
3898
  return obj;
3865
- return path7.reduce((acc, key) => acc?.[key], obj);
3899
+ return path8.reduce((acc, key) => acc?.[key], obj);
3866
3900
  }
3867
3901
  function promiseAllObject(promisesObj) {
3868
3902
  const keys = Object.keys(promisesObj);
@@ -4271,11 +4305,11 @@ function explicitlyAborted(x, startIndex = 0) {
4271
4305
  }
4272
4306
  return false;
4273
4307
  }
4274
- function prefixIssues(path7, issues) {
4308
+ function prefixIssues(path8, issues) {
4275
4309
  return issues.map((iss) => {
4276
4310
  var _a3;
4277
4311
  (_a3 = iss).path ?? (_a3.path = []);
4278
- iss.path.unshift(path7);
4312
+ iss.path.unshift(path8);
4279
4313
  return iss;
4280
4314
  });
4281
4315
  }
@@ -4422,16 +4456,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
4422
4456
  }
4423
4457
  function formatError(error51, mapper = (issue2) => issue2.message) {
4424
4458
  const fieldErrors = { _errors: [] };
4425
- const processError = (error52, path7 = []) => {
4459
+ const processError = (error52, path8 = []) => {
4426
4460
  for (const issue2 of error52.issues) {
4427
4461
  if (issue2.code === "invalid_union" && issue2.errors.length) {
4428
- issue2.errors.map((issues) => processError({ issues }, [...path7, ...issue2.path]));
4462
+ issue2.errors.map((issues) => processError({ issues }, [...path8, ...issue2.path]));
4429
4463
  } else if (issue2.code === "invalid_key") {
4430
- processError({ issues: issue2.issues }, [...path7, ...issue2.path]);
4464
+ processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
4431
4465
  } else if (issue2.code === "invalid_element") {
4432
- processError({ issues: issue2.issues }, [...path7, ...issue2.path]);
4466
+ processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
4433
4467
  } else {
4434
- const fullpath = [...path7, ...issue2.path];
4468
+ const fullpath = [...path8, ...issue2.path];
4435
4469
  if (fullpath.length === 0) {
4436
4470
  fieldErrors._errors.push(mapper(issue2));
4437
4471
  } else {
@@ -4458,17 +4492,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
4458
4492
  }
4459
4493
  function treeifyError(error51, mapper = (issue2) => issue2.message) {
4460
4494
  const result = { errors: [] };
4461
- const processError = (error52, path7 = []) => {
4495
+ const processError = (error52, path8 = []) => {
4462
4496
  var _a3, _b;
4463
4497
  for (const issue2 of error52.issues) {
4464
4498
  if (issue2.code === "invalid_union" && issue2.errors.length) {
4465
- issue2.errors.map((issues) => processError({ issues }, [...path7, ...issue2.path]));
4499
+ issue2.errors.map((issues) => processError({ issues }, [...path8, ...issue2.path]));
4466
4500
  } else if (issue2.code === "invalid_key") {
4467
- processError({ issues: issue2.issues }, [...path7, ...issue2.path]);
4501
+ processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
4468
4502
  } else if (issue2.code === "invalid_element") {
4469
- processError({ issues: issue2.issues }, [...path7, ...issue2.path]);
4503
+ processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
4470
4504
  } else {
4471
- const fullpath = [...path7, ...issue2.path];
4505
+ const fullpath = [...path8, ...issue2.path];
4472
4506
  if (fullpath.length === 0) {
4473
4507
  result.errors.push(mapper(issue2));
4474
4508
  continue;
@@ -4500,8 +4534,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
4500
4534
  }
4501
4535
  function toDotPath(_path) {
4502
4536
  const segs = [];
4503
- const path7 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
4504
- for (const seg of path7) {
4537
+ const path8 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
4538
+ for (const seg of path8) {
4505
4539
  if (typeof seg === "number")
4506
4540
  segs.push(`[${seg}]`);
4507
4541
  else if (typeof seg === "symbol")
@@ -17193,13 +17227,13 @@ function resolveRef(ref, ctx) {
17193
17227
  if (!ref.startsWith("#")) {
17194
17228
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
17195
17229
  }
17196
- const path7 = ref.slice(1).split("/").filter(Boolean);
17197
- if (path7.length === 0) {
17230
+ const path8 = ref.slice(1).split("/").filter(Boolean);
17231
+ if (path8.length === 0) {
17198
17232
  return ctx.rootSchema;
17199
17233
  }
17200
17234
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
17201
- if (path7[0] === defsKey) {
17202
- const key = path7[1];
17235
+ if (path8[0] === defsKey) {
17236
+ const key = path8[1];
17203
17237
  if (!key || !ctx.defs[key]) {
17204
17238
  throw new Error(`Reference not found: ${ref}`);
17205
17239
  }
@@ -18884,6 +18918,9 @@ function defaultStorePath(homeDir = os3.homedir(), env = process.env) {
18884
18918
  const dataHome = env.XDG_DATA_HOME?.trim() || path3.join(homeDir, ".local", "share");
18885
18919
  return path3.join(dataHome, "recappi", "cli-state.sqlite");
18886
18920
  }
18921
+ function normalizeAccountStamp(input) {
18922
+ return parseAccountPartition(input, "lenient");
18923
+ }
18887
18924
  function requireAccountPartition(input) {
18888
18925
  const account = parseAccountPartition(input, "strict");
18889
18926
  if (!account) {
@@ -18900,6 +18937,30 @@ function requireAccountPartition(input) {
18900
18937
  function openCliStore(opts = {}) {
18901
18938
  return new CliLocalStore(opts);
18902
18939
  }
18940
+ function isLocalStoreUnavailableError(error51) {
18941
+ return typeof error51 === "object" && error51 !== null && error51.localStoreUnavailable === true;
18942
+ }
18943
+ var warnedLocalStoreUnavailable = false;
18944
+ function tryOpenCliStore(opts = {}) {
18945
+ const { onUnavailable, open = openCliStore, ...storeOpts } = opts;
18946
+ try {
18947
+ return open(storeOpts);
18948
+ } catch (error51) {
18949
+ if (isLocalStoreUnavailableError(error51)) {
18950
+ if (!warnedLocalStoreUnavailable) {
18951
+ warnedLocalStoreUnavailable = true;
18952
+ (onUnavailable ?? defaultWarnLocalStoreUnavailable)();
18953
+ }
18954
+ return null;
18955
+ }
18956
+ throw error51;
18957
+ }
18958
+ }
18959
+ function defaultWarnLocalStoreUnavailable() {
18960
+ process.stderr.write(
18961
+ "Local cache unavailable (needs Node.js 22+ for node:sqlite). Cloud commands work normally.\n"
18962
+ );
18963
+ }
18903
18964
  var CliLocalStore = class {
18904
18965
  db;
18905
18966
  now;
@@ -19195,9 +19256,11 @@ function suppressNodeSqliteWarning(run) {
19195
19256
  return run();
19196
19257
  } catch (error51) {
19197
19258
  if (isMissingNodeSqlite(error51)) {
19198
- throw cliError("internal.unexpected", "Local SQLite store requires Node.js 22 or newer.", {
19259
+ const err = cliError("internal.unexpected", "Local SQLite store requires Node.js 22 or newer.", {
19199
19260
  hint: "Upgrade Node.js, then retry. Cloud-only commands that do not touch local state can still run."
19200
19261
  });
19262
+ err.localStoreUnavailable = true;
19263
+ throw err;
19201
19264
  }
19202
19265
  throw error51;
19203
19266
  } finally {
@@ -19524,21 +19587,23 @@ var RecappiApiClient = class {
19524
19587
  let accountScopedArtifacts = 0;
19525
19588
  let unattributedArtifacts = 0;
19526
19589
  if (status.loggedIn && status.userId) {
19527
- const store = openCliStore({
19590
+ const store = tryOpenCliStore({
19528
19591
  dbPath: storePath,
19529
19592
  env: this.env,
19530
19593
  homeDir: this.homeDir
19531
19594
  });
19532
- try {
19533
- const account = requireAccountPartition({
19534
- backendOrigin: this.auth.origin,
19535
- userId: status.userId
19536
- });
19537
- store.recordAccountSeen(account, status.email);
19538
- accountScopedArtifacts = store.listLocalArtifactsForAccount(account).length;
19539
- unattributedArtifacts = store.listUnattributedLocalArtifacts().length;
19540
- } finally {
19541
- store.close();
19595
+ if (store) {
19596
+ try {
19597
+ const account = requireAccountPartition({
19598
+ backendOrigin: this.auth.origin,
19599
+ userId: status.userId
19600
+ });
19601
+ store.recordAccountSeen(account, status.email);
19602
+ accountScopedArtifacts = store.listLocalArtifactsForAccount(account).length;
19603
+ unattributedArtifacts = store.listUnattributedLocalArtifacts().length;
19604
+ } finally {
19605
+ store.close();
19606
+ }
19542
19607
  }
19543
19608
  }
19544
19609
  const billing = status.loggedIn ? await this.billingStatus() : void 0;
@@ -19791,12 +19856,12 @@ var RecappiApiClient = class {
19791
19856
  } : {}
19792
19857
  };
19793
19858
  }
19794
- async getJson(path7) {
19795
- const response = await this.request("GET", path7);
19859
+ async getJson(path8) {
19860
+ const response = await this.request("GET", path8);
19796
19861
  return await parseJson(response);
19797
19862
  }
19798
- async postJson(path7, body) {
19799
- const response = await this.request("POST", path7, JSON.stringify(body), {
19863
+ async postJson(path8, body) {
19864
+ const response = await this.request("POST", path8, JSON.stringify(body), {
19800
19865
  headers: { "content-type": "application/json" }
19801
19866
  });
19802
19867
  return await parseJson(response);
@@ -20187,8 +20252,11 @@ import { promises as fs4 } from "fs";
20187
20252
  import path5 from "path";
20188
20253
  function createRecordingAudioRuntime(client, deps = {}) {
20189
20254
  const downloadRecordingAudioFile = async (recordingId, opts) => {
20190
- const cached2 = opts?.directory ? null : await findReusableDownload(recordingId, deps);
20191
- if (cached2) return cached2;
20255
+ const cached2 = await findReusableDownload(recordingId, deps);
20256
+ if (cached2) {
20257
+ if (!opts?.directory) return cached2;
20258
+ return materializeCachedDownload(recordingId, cached2, opts, deps);
20259
+ }
20192
20260
  const directory = opts?.directory ?? (deps.account ? defaultDownloadDirectory(deps) : void 0);
20193
20261
  const download = await client.downloadRecordingAudio(recordingId, {
20194
20262
  ...opts,
@@ -20216,6 +20284,38 @@ function createRecordingAudioRuntime(client, deps = {}) {
20216
20284
  )
20217
20285
  };
20218
20286
  }
20287
+ async function materializeCachedDownload(recordingId, cached2, opts, deps) {
20288
+ if (!opts.directory) return cached2;
20289
+ await fs4.mkdir(opts.directory, { recursive: true });
20290
+ const contentType = cached2.contentType ?? contentTypeForAudioPath(cached2.localPath);
20291
+ const targetPath = path5.join(
20292
+ opts.directory,
20293
+ recordingAudioFileName(recordingId, opts.title, contentType, opts.filenameStem)
20294
+ );
20295
+ if (path5.resolve(cached2.localPath) !== path5.resolve(targetPath)) {
20296
+ await fs4.copyFile(cached2.localPath, targetPath);
20297
+ }
20298
+ const contentLength = cached2.contentLength ?? (await fs4.stat(targetPath)).size;
20299
+ const artifact = await rememberDownload(
20300
+ {
20301
+ recordingId,
20302
+ localPath: targetPath,
20303
+ contentType,
20304
+ contentLength,
20305
+ origin: cached2.origin ?? ""
20306
+ },
20307
+ deps
20308
+ );
20309
+ return {
20310
+ recordingId,
20311
+ localPath: targetPath,
20312
+ reused: true,
20313
+ ...artifact ? { artifactId: artifact.id } : {},
20314
+ contentType,
20315
+ contentLength,
20316
+ ...cached2.origin ? { origin: cached2.origin } : {}
20317
+ };
20318
+ }
20219
20319
  function openPath(localPath, deps = {}) {
20220
20320
  return runMacOpen([localPath], deps);
20221
20321
  }
@@ -20232,7 +20332,7 @@ async function findReusableDownload(recordingId, deps) {
20232
20332
  if (!artifact || !await isReadableFile(artifact.localPath)) return null;
20233
20333
  const opened = store.markLocalArtifactOpened(artifact.id);
20234
20334
  return artifactToDownload(opened, recordingId);
20235
- });
20335
+ }, null);
20236
20336
  }
20237
20337
  async function rememberDownload(download, deps) {
20238
20338
  return withStore(deps, (store, account) => {
@@ -20246,16 +20346,17 @@ async function rememberDownload(download, deps) {
20246
20346
  resource: "recording_audio",
20247
20347
  contentType: download.contentType,
20248
20348
  ...download.contentLength !== void 0 ? { contentLength: download.contentLength } : {},
20249
- origin: download.origin
20349
+ ...download.origin ? { origin: download.origin } : {}
20250
20350
  }
20251
20351
  });
20252
20352
  return store.markLocalArtifactOpened(artifact.id);
20253
- });
20353
+ }, null);
20254
20354
  }
20255
20355
  async function listExistingDownloads(deps) {
20256
20356
  const artifacts = await withStore(
20257
20357
  deps,
20258
- (store, account) => account ? store.listLocalArtifactsForAccount(account, { kind: "download" }) : []
20358
+ (store, account) => account ? store.listLocalArtifactsForAccount(account, { kind: "download" }) : [],
20359
+ []
20259
20360
  );
20260
20361
  const existing = [];
20261
20362
  for (const artifact of artifacts) {
@@ -20263,8 +20364,9 @@ async function listExistingDownloads(deps) {
20263
20364
  }
20264
20365
  return existing;
20265
20366
  }
20266
- async function withStore(deps, run) {
20267
- const store = deps.store ?? openCliStore({ homeDir: deps.homeDir, env: deps.env });
20367
+ async function withStore(deps, run, fallback) {
20368
+ const store = deps.store ?? tryOpenCliStore({ homeDir: deps.homeDir, env: deps.env });
20369
+ if (!store) return fallback;
20268
20370
  try {
20269
20371
  return await run(store, deps.account ?? null);
20270
20372
  } finally {
@@ -20274,6 +20376,27 @@ async function withStore(deps, run) {
20274
20376
  function defaultDownloadDirectory(deps) {
20275
20377
  return path5.join(path5.dirname(defaultStorePath(deps.homeDir, deps.env)), "downloads");
20276
20378
  }
20379
+ function contentTypeForAudioPath(localPath) {
20380
+ switch (path5.extname(localPath).toLowerCase()) {
20381
+ case ".mp3":
20382
+ return "audio/mpeg";
20383
+ case ".m4a":
20384
+ case ".mp4":
20385
+ return "audio/m4a";
20386
+ case ".ogg":
20387
+ return "audio/ogg";
20388
+ case ".flac":
20389
+ return "audio/flac";
20390
+ case ".webm":
20391
+ return "audio/webm";
20392
+ case ".aiff":
20393
+ case ".aif":
20394
+ return "audio/aiff";
20395
+ case ".wav":
20396
+ default:
20397
+ return "audio/wav";
20398
+ }
20399
+ }
20277
20400
  async function isReadableFile(localPath) {
20278
20401
  try {
20279
20402
  return (await fs4.stat(localPath)).isFile();
@@ -20553,41 +20676,171 @@ ${lines.join("\n")}
20553
20676
  }
20554
20677
 
20555
20678
  // src/export.ts
20556
- import { promises as fs5 } from "fs";
20679
+ import { promises as fs6 } from "fs";
20557
20680
  import os5 from "os";
20681
+ import path7 from "path";
20682
+
20683
+ // src/recordingSessionCache.ts
20684
+ import { promises as fs5 } from "fs";
20558
20685
  import path6 from "path";
20686
+ function accountFromStatus(status) {
20687
+ if (!status.loggedIn || !status.userId) return null;
20688
+ return normalizeAccountStamp({ backendOrigin: status.origin, userId: status.userId });
20689
+ }
20690
+ async function findIndexedRecordingSessionDir(recordingId, deps) {
20691
+ return withSessionStore(deps, async (store, account) => {
20692
+ if (!account) return void 0;
20693
+ const artifact = store.findLocalArtifactForAccount(account, {
20694
+ kind: "recording_session",
20695
+ remoteId: recordingId
20696
+ });
20697
+ if (!artifact) return void 0;
20698
+ if (!await isReadableDirectory(artifact.localPath)) return void 0;
20699
+ const manifest = await readJsonRecord(path6.join(artifact.localPath, "remote-session.json"));
20700
+ if (manifest?.recordingId && manifest.recordingId !== recordingId) return void 0;
20701
+ return artifact.localPath;
20702
+ }, void 0);
20703
+ }
20704
+ async function rememberRecordingSession(input, deps) {
20705
+ return withSessionStore(deps, (store, account) => {
20706
+ if (!account) return null;
20707
+ return store.upsertLocalArtifact({
20708
+ kind: "recording_session",
20709
+ account,
20710
+ remoteId: input.recording.recordingId,
20711
+ localPath: input.sessionDir,
20712
+ metadata: stripUndefined({
20713
+ resource: "recording_session",
20714
+ source: input.source,
20715
+ sessionDir: input.sessionDir,
20716
+ recording: input.recording,
20717
+ files: stripUndefined({ ...input.files }),
20718
+ transcriptId: input.transcriptId,
20719
+ summaryStatus: input.summaryStatus,
20720
+ uploadFilename: input.uploadFilename,
20721
+ origin: input.recording.origin,
20722
+ indexedAt: (input.now ?? (() => /* @__PURE__ */ new Date()))().toISOString()
20723
+ })
20724
+ });
20725
+ }, null);
20726
+ }
20727
+ async function listCachedRecordingSessions(deps) {
20728
+ const limit = deps.limit ?? 50;
20729
+ const items = await withSessionStore(deps, async (store, account) => {
20730
+ if (!account) return [];
20731
+ const artifacts = store.listLocalArtifactsForAccount(account, { kind: "recording_session" });
20732
+ const recordings = [];
20733
+ const seen = /* @__PURE__ */ new Set();
20734
+ for (const artifact of artifacts) {
20735
+ if (recordings.length >= limit) break;
20736
+ const recording = await recordingFromArtifact(artifact);
20737
+ if (!recording || seen.has(recording.recordingId)) continue;
20738
+ if (!await isReadableDirectory(artifact.localPath)) continue;
20739
+ seen.add(recording.recordingId);
20740
+ recordings.push(recording);
20741
+ }
20742
+ return recordings.sort((a, b) => b.createdAt - a.createdAt || b.updatedAt - a.updatedAt);
20743
+ }, []);
20744
+ return recordingListDataSchema.parse({
20745
+ items,
20746
+ limit,
20747
+ nextCursor: null,
20748
+ totalCount: items.length,
20749
+ origin: deps.origin
20750
+ });
20751
+ }
20752
+ async function recordingFromArtifact(artifact) {
20753
+ const metadata = isRecord4(artifact.metadata) ? artifact.metadata : {};
20754
+ const cached2 = recordingDataSchema.safeParse(metadata.recording);
20755
+ if (cached2.success) return cached2.data;
20756
+ const fromFile = await readJsonRecord(path6.join(artifact.localPath, "recording.json"));
20757
+ const parsed = recordingDataSchema.safeParse(fromFile);
20758
+ return parsed.success ? parsed.data : null;
20759
+ }
20760
+ async function withSessionStore(deps, run, fallback) {
20761
+ const store = deps.store ?? tryOpenCliStore({ homeDir: deps.homeDir, env: deps.env });
20762
+ if (!store) return fallback;
20763
+ try {
20764
+ return await run(store, deps.account ?? null);
20765
+ } finally {
20766
+ if (!deps.store) store.close();
20767
+ }
20768
+ }
20769
+ async function readJsonRecord(filePath) {
20770
+ try {
20771
+ const parsed = JSON.parse(await fs5.readFile(filePath, "utf8"));
20772
+ return isRecord4(parsed) ? parsed : void 0;
20773
+ } catch {
20774
+ return void 0;
20775
+ }
20776
+ }
20777
+ async function isReadableDirectory(localPath) {
20778
+ try {
20779
+ return (await fs5.stat(localPath)).isDirectory();
20780
+ } catch {
20781
+ return false;
20782
+ }
20783
+ }
20784
+ function stripUndefined(value) {
20785
+ return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== void 0));
20786
+ }
20787
+ function isRecord4(value) {
20788
+ return typeof value === "object" && value !== null && !Array.isArray(value);
20789
+ }
20790
+
20791
+ // src/export.ts
20559
20792
  async function syncRecordingText(opts) {
20560
20793
  const context = await loadRecordingBundleContext(opts);
20561
- const sessionDir = await resolveRecordingSessionDir(context.recording, opts);
20794
+ const account = accountFromStatus(context.subscription);
20795
+ const sessionDir = await resolveRecordingSessionDir(context.recording, opts, account);
20562
20796
  return writeRecordingTextFiles(context, sessionDir, {
20563
- now: opts.now
20797
+ now: opts.now,
20798
+ store: opts.store,
20799
+ env: opts.env,
20800
+ homeDir: opts.homeDir,
20801
+ account,
20802
+ source: "text_sync"
20564
20803
  });
20565
20804
  }
20566
20805
  async function syncRecordingAudio(opts) {
20567
20806
  const context = await loadRecordingBundleContext(opts);
20568
- const sessionDir = await resolveRecordingSessionDir(context.recording, opts);
20807
+ const account = accountFromStatus(context.subscription);
20808
+ const sessionDir = await resolveRecordingSessionDir(context.recording, opts, account);
20569
20809
  const audio = await downloadRecordingAudioToDir(context.recording, opts.recordingAudio, sessionDir);
20570
20810
  const text = await writeRecordingTextFiles(context, sessionDir, {
20571
20811
  now: opts.now,
20572
- uploadFilename: path6.basename(audio.localPath)
20812
+ uploadFilename: path7.basename(audio.localPath),
20813
+ store: opts.store,
20814
+ env: opts.env,
20815
+ homeDir: opts.homeDir,
20816
+ account,
20817
+ source: "audio_sync",
20818
+ audioPath: audio.localPath
20573
20819
  });
20574
20820
  return { ...text, audioPath: audio.localPath, audio: audioMetadata(audio) };
20575
20821
  }
20576
20822
  async function exportRecording(opts) {
20577
20823
  const context = await loadRecordingBundleContext(opts);
20578
- const exportDir = await resolveRecordingSessionDir(context.recording, opts);
20824
+ const account = accountFromStatus(context.subscription);
20825
+ const exportDir = await resolveRecordingSessionDir(context.recording, opts, account);
20579
20826
  const audio = await downloadRecordingAudioToDir(context.recording, opts.recordingAudio, exportDir);
20580
20827
  const textFiles = await writeRecordingTextFiles(context, exportDir, {
20581
20828
  now: opts.now,
20582
- uploadFilename: path6.basename(audio.localPath)
20829
+ uploadFilename: path7.basename(audio.localPath),
20830
+ store: opts.store,
20831
+ env: opts.env,
20832
+ homeDir: opts.homeDir,
20833
+ account,
20834
+ source: "export",
20835
+ audioPath: audio.localPath
20583
20836
  });
20584
20837
  const { recording, subscription, transcript } = context;
20585
- const subscriptionPath = path6.join(exportDir, "subscription.md");
20586
- const subscriptionJsonPath = path6.join(exportDir, "subscription.json");
20587
- await fs5.writeFile(subscriptionPath, renderSubscriptionMarkdown(subscription), "utf8");
20838
+ const subscriptionPath = path7.join(exportDir, "subscription.md");
20839
+ const subscriptionJsonPath = path7.join(exportDir, "subscription.json");
20840
+ await fs6.writeFile(subscriptionPath, renderSubscriptionMarkdown(subscription), "utf8");
20588
20841
  await writeJson(subscriptionJsonPath, subscription);
20589
- const textPath = path6.join(exportDir, "handoff.md");
20590
- const manifestPath = path6.join(exportDir, "manifest.json");
20842
+ const textPath = path7.join(exportDir, "handoff.md");
20843
+ const manifestPath = path7.join(exportDir, "manifest.json");
20591
20844
  const data = recordingExportDataSchema.parse({
20592
20845
  origin: recording.origin,
20593
20846
  recordingId: recording.recordingId,
@@ -20609,7 +20862,7 @@ async function exportRecording(opts) {
20609
20862
  ...textFiles.summaryStatus ? { summaryStatus: textFiles.summaryStatus } : {},
20610
20863
  audio: audioMetadata(audio)
20611
20864
  });
20612
- await fs5.writeFile(
20865
+ await fs6.writeFile(
20613
20866
  textPath,
20614
20867
  renderHandoffMarkdown(recording, subscription, audio, data, transcript),
20615
20868
  "utf8"
@@ -20619,6 +20872,33 @@ async function exportRecording(opts) {
20619
20872
  command: "recordings export",
20620
20873
  data
20621
20874
  });
20875
+ await rememberRecordingSession(
20876
+ {
20877
+ recording,
20878
+ sessionDir: exportDir,
20879
+ files: {
20880
+ remoteManifestPath: data.remoteManifestPath,
20881
+ sessionMetadataPath: data.sessionMetadataPath,
20882
+ recordingJsonPath: data.recordingJsonPath,
20883
+ ...data.transcriptPath ? { transcriptPath: data.transcriptPath } : {},
20884
+ ...data.transcriptJsonPath ? { transcriptJsonPath: data.transcriptJsonPath } : {},
20885
+ ...data.summaryPath ? { summaryPath: data.summaryPath } : {},
20886
+ ...data.summaryJsonPath ? { summaryJsonPath: data.summaryJsonPath } : {},
20887
+ ...data.actionItemsPath ? { actionItemsPath: data.actionItemsPath } : {},
20888
+ audioPath: data.audioPath,
20889
+ subscriptionPath: data.subscriptionPath,
20890
+ subscriptionJsonPath: data.subscriptionJsonPath,
20891
+ textPath: data.textPath,
20892
+ manifestPath: data.manifestPath
20893
+ },
20894
+ ...data.transcriptId !== void 0 ? { transcriptId: data.transcriptId } : {},
20895
+ ...data.summaryStatus ? { summaryStatus: data.summaryStatus } : {},
20896
+ uploadFilename: path7.basename(audio.localPath),
20897
+ source: "export",
20898
+ now: opts.now
20899
+ },
20900
+ { account, store: opts.store, env: opts.env, homeDir: opts.homeDir }
20901
+ );
20622
20902
  return data;
20623
20903
  }
20624
20904
  async function loadRecordingBundleContext(opts) {
@@ -20641,11 +20921,11 @@ async function downloadRecordingAudioToDir(recording, recordingAudio, directory)
20641
20921
  }
20642
20922
  async function writeRecordingTextFiles(context, sessionDir, opts) {
20643
20923
  const { recording, transcript, subscription } = context;
20644
- await fs5.mkdir(sessionDir, { recursive: true });
20645
- const recordingJsonPath = path6.join(sessionDir, "recording.json");
20646
- const sessionMetadataPath = path6.join(sessionDir, "session-metadata.json");
20647
- const remoteManifestPath = path6.join(sessionDir, "remote-session.json");
20648
- const existingManifest = await readJsonRecord(remoteManifestPath);
20924
+ await fs6.mkdir(sessionDir, { recursive: true });
20925
+ const recordingJsonPath = path7.join(sessionDir, "recording.json");
20926
+ const sessionMetadataPath = path7.join(sessionDir, "session-metadata.json");
20927
+ const remoteManifestPath = path7.join(sessionDir, "remote-session.json");
20928
+ const existingManifest = await readJsonRecord2(remoteManifestPath);
20649
20929
  const uploadFilename = opts.uploadFilename ?? (typeof existingManifest?.uploadFilename === "string" ? existingManifest.uploadFilename : void 0);
20650
20930
  await writeJson(recordingJsonPath, recording);
20651
20931
  await writeJson(sessionMetadataPath, renderSessionMetadata(recording));
@@ -20660,19 +20940,23 @@ async function writeRecordingTextFiles(context, sessionDir, opts) {
20660
20940
  let actionItemsPath;
20661
20941
  let summaryStatus;
20662
20942
  if (transcript) {
20663
- transcriptPath = path6.join(sessionDir, "transcript.md");
20664
- transcriptJsonPath = path6.join(sessionDir, "transcript.json");
20665
- summaryPath = path6.join(sessionDir, "summary.md");
20666
- summaryJsonPath = path6.join(sessionDir, "summary.json");
20667
- actionItemsPath = path6.join(sessionDir, "action-items.md");
20943
+ transcriptPath = path7.join(sessionDir, "transcript.md");
20944
+ transcriptJsonPath = path7.join(sessionDir, "transcript.json");
20945
+ summaryJsonPath = path7.join(sessionDir, "summary.json");
20668
20946
  summaryStatus = transcript.summary.status;
20669
- await fs5.writeFile(transcriptPath, renderTranscriptMarkdown(transcript), "utf8");
20947
+ await fs6.writeFile(transcriptPath, renderTranscriptMarkdown(transcript), "utf8");
20670
20948
  await writeJson(transcriptJsonPath, transcript);
20671
20949
  await writeJson(summaryJsonPath, transcript.summary);
20672
- await fs5.writeFile(summaryPath, renderSummaryMarkdown(recording, transcript), "utf8");
20673
- await writeOptionalText(actionItemsPath, renderActionItemsMarkdown(transcript.summary));
20950
+ const summaryFilePath = path7.join(sessionDir, "summary.md");
20951
+ const summaryMarkdown = renderSummaryMarkdown(transcript);
20952
+ await writeOptionalText(summaryFilePath, summaryMarkdown);
20953
+ if (summaryMarkdown) summaryPath = summaryFilePath;
20954
+ const actionItemsFilePath = path7.join(sessionDir, "action-items.md");
20955
+ const actionItemsMarkdown = renderActionItemsMarkdown(transcript.summary);
20956
+ await writeOptionalText(actionItemsFilePath, actionItemsMarkdown);
20957
+ if (actionItemsMarkdown) actionItemsPath = actionItemsFilePath;
20674
20958
  }
20675
- return {
20959
+ const data = {
20676
20960
  recordingId: recording.recordingId,
20677
20961
  sessionDir,
20678
20962
  remoteManifestPath,
@@ -20686,10 +20970,56 @@ async function writeRecordingTextFiles(context, sessionDir, opts) {
20686
20970
  ...actionItemsPath ? { actionItemsPath } : {},
20687
20971
  ...summaryStatus ? { summaryStatus } : {}
20688
20972
  };
20973
+ await rememberRecordingSession(
20974
+ {
20975
+ recording,
20976
+ sessionDir,
20977
+ files: {
20978
+ remoteManifestPath,
20979
+ sessionMetadataPath,
20980
+ recordingJsonPath,
20981
+ ...transcriptPath ? { transcriptPath } : {},
20982
+ ...transcriptJsonPath ? { transcriptJsonPath } : {},
20983
+ ...summaryPath ? { summaryPath } : {},
20984
+ ...summaryJsonPath ? { summaryJsonPath } : {},
20985
+ ...actionItemsPath ? { actionItemsPath } : {},
20986
+ ...opts.audioPath ? { audioPath: opts.audioPath } : {}
20987
+ },
20988
+ ...context.transcriptId !== void 0 ? { transcriptId: context.transcriptId } : {},
20989
+ ...summaryStatus ? { summaryStatus } : {},
20990
+ ...uploadFilename ? { uploadFilename } : {},
20991
+ source: opts.source,
20992
+ now: opts.now
20993
+ },
20994
+ { account: opts.account ?? null, store: opts.store, env: opts.env, homeDir: opts.homeDir }
20995
+ );
20996
+ return data;
20689
20997
  }
20690
- async function resolveRecordingSessionDir(recording, opts) {
20691
- if (opts.directory) return path6.resolve(opts.directory);
20998
+ async function resolveRecordingSessionDir(recording, opts, account) {
20999
+ if (opts.directory) return path7.resolve(opts.directory);
21000
+ const indexed = await findIndexedRecordingSessionDir(recording.recordingId, {
21001
+ account,
21002
+ store: opts.store,
21003
+ homeDir: opts.homeDir,
21004
+ env: opts.env
21005
+ });
21006
+ if (indexed) return indexed;
20692
21007
  const existing = await findExistingRecordingSessionDir(recording.recordingId, opts.homeDir, opts.env);
21008
+ if (existing) {
21009
+ await rememberRecordingSession(
21010
+ {
21011
+ recording,
21012
+ sessionDir: existing,
21013
+ files: {
21014
+ remoteManifestPath: path7.join(existing, "remote-session.json"),
21015
+ sessionMetadataPath: path7.join(existing, "session-metadata.json"),
21016
+ recordingJsonPath: path7.join(existing, "recording.json")
21017
+ },
21018
+ source: "manifest_scan"
21019
+ },
21020
+ { account, store: opts.store, env: opts.env, homeDir: opts.homeDir }
21021
+ );
21022
+ }
20693
21023
  if (existing) return existing;
20694
21024
  return createRecordingSessionDir(recording, opts.homeDir, opts.env);
20695
21025
  }
@@ -20697,39 +21027,39 @@ async function findExistingRecordingSessionDir(recordingId, homeDir, env) {
20697
21027
  const base = recordingSessionBaseDirectory(homeDir, env);
20698
21028
  let entries;
20699
21029
  try {
20700
- entries = await fs5.readdir(base, { withFileTypes: true });
21030
+ entries = await fs6.readdir(base, { withFileTypes: true });
20701
21031
  } catch {
20702
21032
  return void 0;
20703
21033
  }
20704
21034
  for (const entry of entries) {
20705
21035
  if (!entry.isDirectory()) continue;
20706
- const dir = path6.join(base, entry.name);
20707
- const manifest = await readJsonRecord(path6.join(dir, "remote-session.json"));
21036
+ const dir = path7.join(base, entry.name);
21037
+ const manifest = await readJsonRecord2(path7.join(dir, "remote-session.json"));
20708
21038
  if (manifest?.recordingId === recordingId) return dir;
20709
21039
  }
20710
21040
  return void 0;
20711
21041
  }
20712
21042
  async function createRecordingSessionDir(recording, homeDir, env) {
20713
21043
  const base = recordingSessionBaseDirectory(homeDir, env);
20714
- await fs5.mkdir(base, { recursive: true });
21044
+ await fs6.mkdir(base, { recursive: true });
20715
21045
  const stem = formatSessionDirectoryDate(new Date(recording.createdAt));
20716
- let candidate = path6.join(base, stem);
21046
+ let candidate = path7.join(base, stem);
20717
21047
  let suffix = 2;
20718
21048
  while (await pathExists(candidate)) {
20719
- candidate = path6.join(base, `${stem}-cloud-${suffix}`);
21049
+ candidate = path7.join(base, `${stem}-cloud-${suffix}`);
20720
21050
  suffix += 1;
20721
21051
  }
20722
- await fs5.mkdir(candidate, { recursive: true });
21052
+ await fs6.mkdir(candidate, { recursive: true });
20723
21053
  return candidate;
20724
21054
  }
20725
21055
  function recordingSessionBaseDirectory(homeDir = os5.homedir(), env = process.env) {
20726
21056
  const explicit = env.RECAPPI_LOCAL_SESSIONS_DIR?.trim();
20727
21057
  if (explicit) return explicit;
20728
- return path6.join(homeDir, "Documents", "Recappi Mini");
21058
+ return path7.join(homeDir, "Documents", "Recappi Mini");
20729
21059
  }
20730
- async function readJsonRecord(filePath) {
21060
+ async function readJsonRecord2(filePath) {
20731
21061
  try {
20732
- const parsed = JSON.parse(await fs5.readFile(filePath, "utf8"));
21062
+ const parsed = JSON.parse(await fs6.readFile(filePath, "utf8"));
20733
21063
  return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) ? parsed : void 0;
20734
21064
  } catch {
20735
21065
  return void 0;
@@ -20737,7 +21067,7 @@ async function readJsonRecord(filePath) {
20737
21067
  }
20738
21068
  async function pathExists(filePath) {
20739
21069
  try {
20740
- await fs5.access(filePath);
21070
+ await fs6.access(filePath);
20741
21071
  return true;
20742
21072
  } catch {
20743
21073
  return false;
@@ -20753,15 +21083,15 @@ function formatSessionDirectoryDate(date5) {
20753
21083
  return `${year}-${month}-${day}_${hour}${minute}${second}`;
20754
21084
  }
20755
21085
  async function writeJson(filePath, value) {
20756
- await fs5.writeFile(filePath, `${JSON.stringify(value, null, 2)}
21086
+ await fs6.writeFile(filePath, `${JSON.stringify(value, null, 2)}
20757
21087
  `, "utf8");
20758
21088
  }
20759
21089
  async function writeOptionalText(filePath, value) {
20760
21090
  if (value && value.trim()) {
20761
- await fs5.writeFile(filePath, value, "utf8");
21091
+ await fs6.writeFile(filePath, value, "utf8");
20762
21092
  return;
20763
21093
  }
20764
- await fs5.rm(filePath, { force: true });
21094
+ await fs6.rm(filePath, { force: true });
20765
21095
  }
20766
21096
  function renderHandoffMarkdown(recording, subscription, audio, data, transcript) {
20767
21097
  const lines = [];
@@ -20797,9 +21127,12 @@ function renderHandoffMarkdown(recording, subscription, audio, data, transcript)
20797
21127
  appendSubscriptionLines(lines, subscription);
20798
21128
  lines.push("");
20799
21129
  if (transcript) {
20800
- lines.push(renderSummaryMarkdown(recording, transcript).trimEnd());
20801
- lines.push("");
20802
- lines.push(renderTranscriptMarkdown(transcript).trimEnd());
21130
+ const summaryMarkdown = renderSummaryMarkdown(transcript);
21131
+ if (summaryMarkdown) {
21132
+ lines.push(summaryMarkdown.trimEnd());
21133
+ lines.push("");
21134
+ }
21135
+ lines.push(renderTimestampedTranscriptMarkdown(transcript).trimEnd());
20803
21136
  lines.push("");
20804
21137
  }
20805
21138
  return `${lines.join("\n").trimEnd()}
@@ -20813,7 +21146,7 @@ function renderSubscriptionMarkdown(subscription) {
20813
21146
  }
20814
21147
  function renderSessionMetadata(recording) {
20815
21148
  const sourceTitle = recording.title ?? recording.summaryTitle ?? "Recappi Cloud";
20816
- return stripUndefined({
21149
+ return stripUndefined2({
20817
21150
  summaryTitle: recording.summaryTitle ?? recording.title ?? void 0,
20818
21151
  sourceTitle,
20819
21152
  sourceAppName: void 0,
@@ -20825,7 +21158,7 @@ function renderSessionMetadata(recording) {
20825
21158
  });
20826
21159
  }
20827
21160
  function renderRemoteSessionManifest(recording, uploadFilename, transcript, subscription, now) {
20828
- return stripUndefined({
21161
+ return stripUndefined2({
20829
21162
  recordingId: recording.recordingId,
20830
21163
  jobId: transcript?.jobId,
20831
21164
  transcriptId: transcript?.transcriptId ?? recording.activeTranscriptId ?? void 0,
@@ -20839,7 +21172,7 @@ function renderRemoteSessionManifest(recording, uploadFilename, transcript, subs
20839
21172
  accountBackendOrigin: subscription.origin
20840
21173
  });
20841
21174
  }
20842
- function stripUndefined(value) {
21175
+ function stripUndefined2(value) {
20843
21176
  return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== void 0));
20844
21177
  }
20845
21178
  function appendSubscriptionLines(lines, subscription) {
@@ -20862,6 +21195,12 @@ function appendSubscriptionLines(lines, subscription) {
20862
21195
  function renderTranscriptMarkdown(transcript) {
20863
21196
  return `# Transcript
20864
21197
 
21198
+ ${transcript.text}
21199
+ `;
21200
+ }
21201
+ function renderTimestampedTranscriptMarkdown(transcript) {
21202
+ return `# Transcript
21203
+
20865
21204
  ${renderTranscriptLines(transcript)}
20866
21205
  `;
20867
21206
  }
@@ -20873,15 +21212,10 @@ function renderTranscriptLines(transcript) {
20873
21212
  if (lines.length > 0) return lines.join("\n");
20874
21213
  return transcript.text;
20875
21214
  }
20876
- function renderSummaryMarkdown(recording, transcript) {
21215
+ function renderSummaryMarkdown(transcript) {
20877
21216
  const summary = transcript.summary;
20878
21217
  const lines = [];
20879
- lines.push(`# ${summary.title ?? recording.title ?? recording.summaryTitle ?? "Summary"}`);
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}`);
21218
+ lines.push("# Summary");
20885
21219
  lines.push("");
20886
21220
  if (summary.tldr) {
20887
21221
  lines.push("## TL;DR", "");
@@ -20891,8 +21225,8 @@ function renderSummaryMarkdown(recording, transcript) {
20891
21225
  appendStringList(lines, "Topics", summary.topics);
20892
21226
  appendStringList(lines, "Decisions", summary.decisions);
20893
21227
  appendActionItems(lines, summary.actionItems);
20894
- appendTimeline(lines, summary.timeline);
20895
- appendQuotes(lines, summary.quotes);
21228
+ appendNotableQuotes(lines, summary.quotes);
21229
+ if (lines.length === 2) return null;
20896
21230
  if (lines[lines.length - 1] !== "") lines.push("");
20897
21231
  return lines.join("\n");
20898
21232
  }
@@ -20900,7 +21234,7 @@ function renderActionItemsMarkdown(summary) {
20900
21234
  if (!summary.actionItems || summary.actionItems.length === 0) return null;
20901
21235
  const lines = ["# Action Items", ""];
20902
21236
  for (const item of summary.actionItems) {
20903
- lines.push(`- ${item.who ? `${item.who} - ` : ""}${item.what}`);
21237
+ lines.push(actionItemLine(item));
20904
21238
  }
20905
21239
  lines.push("");
20906
21240
  return lines.join("\n");
@@ -20915,27 +21249,20 @@ function appendActionItems(lines, values) {
20915
21249
  if (!values || values.length === 0) return;
20916
21250
  lines.push("## Action Items", "");
20917
21251
  for (const item of values) {
20918
- lines.push(`- ${item.who ? `${item.who}: ` : ""}${item.what}`);
21252
+ lines.push(actionItemLine(item));
20919
21253
  }
20920
21254
  lines.push("");
20921
21255
  }
20922
- function appendTimeline(lines, values) {
21256
+ function appendNotableQuotes(lines, values) {
20923
21257
  if (!values || values.length === 0) return;
20924
- lines.push("## Timeline", "");
21258
+ lines.push("## Notable Quotes", "");
20925
21259
  for (const item of values) {
20926
- lines.push(
20927
- `- ${formatTimestamp(item.startMs)}-${formatTimestamp(item.endMs)}: ${item.title} - ${item.summary}`
20928
- );
21260
+ lines.push(`> ${item.speaker ? `${item.speaker}: ` : ""}${item.text}`);
20929
21261
  }
20930
21262
  lines.push("");
20931
21263
  }
20932
- function appendQuotes(lines, values) {
20933
- if (!values || values.length === 0) return;
20934
- lines.push("## Quotes", "");
20935
- for (const item of values) {
20936
- lines.push(`- ${item.speaker ? `${item.speaker}: ` : ""}"${item.text}"`);
20937
- }
20938
- lines.push("");
21264
+ function actionItemLine(item) {
21265
+ return `- ${item.who ? `${item.who}: ` : ""}${item.what}`;
20939
21266
  }
20940
21267
  function audioMetadata(audio) {
20941
21268
  return {
@@ -21331,20 +21658,20 @@ function renderEnvelope(envelope, opts) {
21331
21658
  `);
21332
21659
  }
21333
21660
  function renderHumanSuccess(command, data, opts) {
21334
- if (command === "auth login" && isRecord4(data)) {
21661
+ if (command === "auth login" && isRecord5(data)) {
21335
21662
  opts.stdout(`Signed in${typeof data.email === "string" ? ` as ${data.email}` : ""}
21336
21663
  `);
21337
21664
  return;
21338
21665
  }
21339
- if (command === "auth logout" && isRecord4(data)) {
21666
+ if (command === "auth logout" && isRecord5(data)) {
21340
21667
  opts.stdout(data.cleared ? "Signed out of Recappi CLI\n" : "No Recappi CLI session to clear\n");
21341
21668
  return;
21342
21669
  }
21343
- if (command === "auth import-macos" && isRecord4(data)) {
21670
+ if (command === "auth import-macos" && isRecord5(data)) {
21344
21671
  opts.stdout("Imported the Recappi Mini app session into Recappi CLI\n");
21345
21672
  return;
21346
21673
  }
21347
- if (command === "auth status" && isRecord4(data)) {
21674
+ if (command === "auth status" && isRecord5(data)) {
21348
21675
  if (data.loggedIn) {
21349
21676
  opts.stdout(`Signed in${typeof data.email === "string" ? ` as ${data.email}` : ""}
21350
21677
  `);
@@ -21353,7 +21680,7 @@ function renderHumanSuccess(command, data, opts) {
21353
21680
  opts.stdout("Not logged in\n");
21354
21681
  return;
21355
21682
  }
21356
- if (command === "account status" && isRecord4(data)) {
21683
+ if (command === "account status" && isRecord5(data)) {
21357
21684
  if (!data.loggedIn) {
21358
21685
  opts.stdout("Not logged in\n");
21359
21686
  return;
@@ -21364,7 +21691,7 @@ function renderHumanSuccess(command, data, opts) {
21364
21691
  `);
21365
21692
  if (typeof data.userId === "string") opts.stdout(` userId: ${data.userId}
21366
21693
  `);
21367
- const billing = isRecord4(data.billing) ? data.billing : {};
21694
+ const billing = isRecord5(data.billing) ? data.billing : {};
21368
21695
  if (typeof billing.tier === "string") opts.stdout(` plan: ${billing.tier}
21369
21696
  `);
21370
21697
  if (typeof billing.minutesUsed === "number") {
@@ -21377,7 +21704,7 @@ function renderHumanSuccess(command, data, opts) {
21377
21704
  opts.stdout(` storage: ${formatBytes2(billing.storageBytes)} / ${cap}
21378
21705
  `);
21379
21706
  }
21380
- const localStore = isRecord4(data.localStore) ? data.localStore : {};
21707
+ const localStore = isRecord5(data.localStore) ? data.localStore : {};
21381
21708
  if (typeof localStore.path === "string") opts.stdout(` localStore: ${localStore.path}
21382
21709
  `);
21383
21710
  opts.stdout(
@@ -21386,17 +21713,17 @@ function renderHumanSuccess(command, data, opts) {
21386
21713
  );
21387
21714
  return;
21388
21715
  }
21389
- if (command === "version" && isRecord4(data) && typeof data.version === "string") {
21716
+ if (command === "version" && isRecord5(data) && typeof data.version === "string") {
21390
21717
  opts.stdout(`${data.version}
21391
21718
  `);
21392
21719
  return;
21393
21720
  }
21394
- if (command === "doctor" && isRecord4(data) && Array.isArray(data.checks)) {
21721
+ if (command === "doctor" && isRecord5(data) && Array.isArray(data.checks)) {
21395
21722
  const status = typeof data.status === "string" ? data.status : "unknown";
21396
21723
  opts.stdout(`Doctor: ${status}
21397
21724
  `);
21398
21725
  for (const check2 of data.checks) {
21399
- if (!isRecord4(check2)) continue;
21726
+ if (!isRecord5(check2)) continue;
21400
21727
  const checkStatus = typeof check2.status === "string" ? check2.status : "unknown";
21401
21728
  const name = typeof check2.name === "string" ? check2.name : "check";
21402
21729
  const message = typeof check2.message === "string" ? ` \u2014 ${check2.message}` : "";
@@ -21407,14 +21734,14 @@ function renderHumanSuccess(command, data, opts) {
21407
21734
  }
21408
21735
  return;
21409
21736
  }
21410
- if (command === "transcript get" && isRecord4(data)) {
21737
+ if (command === "transcript get" && isRecord5(data)) {
21411
21738
  renderTranscriptHuman(data, opts);
21412
21739
  return;
21413
21740
  }
21414
- if (command === "recordings list" && isRecord4(data) && Array.isArray(data.items)) {
21741
+ if (command === "recordings list" && isRecord5(data) && Array.isArray(data.items)) {
21415
21742
  opts.stdout("Recordings:\n");
21416
21743
  for (const item of data.items) {
21417
- if (!isRecord4(item)) continue;
21744
+ if (!isRecord5(item)) continue;
21418
21745
  opts.stdout(` ${recordingLabel(item)}
21419
21746
  `);
21420
21747
  }
@@ -21426,7 +21753,7 @@ Next cursor: ${data.nextCursor}
21426
21753
  }
21427
21754
  return;
21428
21755
  }
21429
- if (command === "recordings get" && isRecord4(data)) {
21756
+ if (command === "recordings get" && isRecord5(data)) {
21430
21757
  opts.stdout(`${recordingTitle(data)}
21431
21758
  `);
21432
21759
  opts.stdout(` recordingId: ${String(data.recordingId)}
@@ -21448,7 +21775,7 @@ Next:
21448
21775
  }
21449
21776
  return;
21450
21777
  }
21451
- if (command === "recordings export" && isRecord4(data)) {
21778
+ if (command === "recordings export" && isRecord5(data)) {
21452
21779
  opts.stdout("Recording export ready\n");
21453
21780
  printStringField(opts, data, "recordingId");
21454
21781
  printStringField(opts, data, "exportDir");
@@ -21470,7 +21797,7 @@ Next:
21470
21797
  }
21471
21798
  return;
21472
21799
  }
21473
- if (command === "recordings retranscribe" && isRecord4(data)) {
21800
+ if (command === "recordings retranscribe" && isRecord5(data)) {
21474
21801
  opts.stdout("Transcription started\n");
21475
21802
  if (typeof data.recordingId === "string") opts.stdout(` recordingId: ${data.recordingId}
21476
21803
  `);
@@ -21493,7 +21820,7 @@ Next:
21493
21820
  }
21494
21821
  return;
21495
21822
  }
21496
- if (command === "recordings resummarize" && isRecord4(data)) {
21823
+ if (command === "recordings resummarize" && isRecord5(data)) {
21497
21824
  opts.stdout("Summary queued\n");
21498
21825
  if (typeof data.recordingId === "string") opts.stdout(` recordingId: ${data.recordingId}
21499
21826
  `);
@@ -21511,9 +21838,9 @@ Next:
21511
21838
  }
21512
21839
  return;
21513
21840
  }
21514
- if (command === "dashboard stats" && isRecord4(data)) {
21515
- const recordings = isRecord4(data.recordings) ? data.recordings : {};
21516
- const jobs = isRecord4(data.jobs) ? data.jobs : {};
21841
+ if (command === "dashboard stats" && isRecord5(data)) {
21842
+ const recordings = isRecord5(data.recordings) ? data.recordings : {};
21843
+ const jobs = isRecord5(data.jobs) ? data.jobs : {};
21517
21844
  opts.stdout(
21518
21845
  `Recordings: ${numberText(recordings.total)} total, ${numberText(recordings.ready)} ready
21519
21846
  `
@@ -21556,7 +21883,7 @@ Next:
21556
21883
  }
21557
21884
  return;
21558
21885
  }
21559
- if (command === "record" && isRecord4(data)) {
21886
+ if (command === "record" && isRecord5(data)) {
21560
21887
  opts.stdout("Recording complete\n");
21561
21888
  if (typeof data.recordingId === "string") opts.stdout(` recordingId: ${data.recordingId}
21562
21889
  `);
@@ -21575,14 +21902,14 @@ Next:
21575
21902
  if (Array.isArray(data.artifacts) && data.artifacts.length > 0) {
21576
21903
  opts.stdout(" artifacts:\n");
21577
21904
  for (const artifact of data.artifacts) {
21578
- if (!isRecord4(artifact)) continue;
21905
+ if (!isRecord5(artifact)) continue;
21579
21906
  const kind = typeof artifact.kind === "string" ? artifact.kind : "artifact";
21580
21907
  const localPath = typeof artifact.localPath === "string" ? artifact.localPath : "";
21581
21908
  opts.stdout(` - ${kind}: ${localPath}
21582
21909
  `);
21583
21910
  }
21584
21911
  }
21585
- const cloudHandoffError = isRecord4(data.cloudHandoffError) ? data.cloudHandoffError : void 0;
21912
+ const cloudHandoffError = isRecord5(data.cloudHandoffError) ? data.cloudHandoffError : void 0;
21586
21913
  if (cloudHandoffError && typeof cloudHandoffError.message === "string") {
21587
21914
  opts.stderr(`Cloud handoff failed: ${cloudHandoffError.message}
21588
21915
  `);
@@ -21607,7 +21934,7 @@ Next:
21607
21934
  }
21608
21935
  return;
21609
21936
  }
21610
- if (command === "audio" && isRecord4(data)) {
21937
+ if (command === "audio" && isRecord5(data)) {
21611
21938
  const action = typeof data.action === "string" ? data.action : "download";
21612
21939
  opts.stdout(
21613
21940
  action === "open" ? "Audio opened\n" : action === "reveal" ? "Audio revealed\n" : "Audio ready\n"
@@ -21622,7 +21949,7 @@ Next:
21622
21949
  }
21623
21950
  return;
21624
21951
  }
21625
- if ((command === "jobs wait" || command === "upload") && isRecord4(data)) {
21952
+ if ((command === "jobs wait" || command === "upload") && isRecord5(data)) {
21626
21953
  if (typeof data.transcriptId === "string") {
21627
21954
  opts.stdout("Transcript ready\n");
21628
21955
  if (typeof data.recordingId === "string" && typeof data.origin === "string") {
@@ -21647,10 +21974,10 @@ Next:
21647
21974
  }
21648
21975
  return;
21649
21976
  }
21650
- if (command === "schema" && isRecord4(data) && Array.isArray(data.commands)) {
21977
+ if (command === "schema" && isRecord5(data) && Array.isArray(data.commands)) {
21651
21978
  opts.stdout("Commands:\n");
21652
21979
  for (const entry of data.commands) {
21653
- if (!isRecord4(entry) || typeof entry.name !== "string") continue;
21980
+ if (!isRecord5(entry) || typeof entry.name !== "string") continue;
21654
21981
  const summary = typeof entry.summary === "string" ? ` \u2014 ${entry.summary}` : "";
21655
21982
  opts.stdout(` ${entry.name}${summary}
21656
21983
  `);
@@ -21660,9 +21987,9 @@ Next:
21660
21987
  }
21661
21988
  if (Array.isArray(entry.examples) && entry.examples.length > 0) {
21662
21989
  const first = entry.examples.find(
21663
- (example) => isRecord4(example) && typeof example.command === "string"
21990
+ (example) => isRecord5(example) && typeof example.command === "string"
21664
21991
  );
21665
- if (isRecord4(first) && typeof first.command === "string") {
21992
+ if (isRecord5(first) && typeof first.command === "string") {
21666
21993
  opts.stdout(` example: ${first.command}
21667
21994
  `);
21668
21995
  }
@@ -21794,7 +22121,7 @@ function renderTranscriptHuman(data, opts) {
21794
22121
  const segments = Array.isArray(data.segments) ? data.segments : [];
21795
22122
  let printedBody = false;
21796
22123
  for (const segment of segments) {
21797
- if (!isRecord4(segment) || typeof segment.text !== "string") continue;
22124
+ if (!isRecord5(segment) || typeof segment.text !== "string") continue;
21798
22125
  const clock = typeof segment.startMs === "number" ? `[${formatClock(segment.startMs / 1e3)}] ` : "";
21799
22126
  const speaker = typeof segment.speaker === "string" ? `${segment.speaker}: ` : "";
21800
22127
  opts.stdout(`${clock}${speaker}${segment.text}
@@ -21806,7 +22133,7 @@ function renderTranscriptHuman(data, opts) {
21806
22133
  `);
21807
22134
  printedBody = true;
21808
22135
  }
21809
- const summary = isRecord4(data.summary) ? data.summary : void 0;
22136
+ const summary = isRecord5(data.summary) ? data.summary : void 0;
21810
22137
  if (!summary || summary.status !== "succeeded") return;
21811
22138
  if (typeof summary.tldr === "string" && summary.tldr.length > 0) {
21812
22139
  opts.stdout(`
@@ -21824,7 +22151,7 @@ Summary:
21824
22151
  if (Array.isArray(summary.actionItems) && summary.actionItems.length > 0) {
21825
22152
  opts.stdout("\nAction items:\n");
21826
22153
  for (const item of summary.actionItems) {
21827
- if (!isRecord4(item) || typeof item.what !== "string") continue;
22154
+ if (!isRecord5(item) || typeof item.what !== "string") continue;
21828
22155
  const who = typeof item.who === "string" ? `${item.who}: ` : "";
21829
22156
  opts.stdout(` - ${who}${item.what}
21830
22157
  `);
@@ -21899,7 +22226,7 @@ function applyFields(command, data, fields, compact) {
21899
22226
  };
21900
22227
  return compact ? compactData(filtered2) : filtered2;
21901
22228
  }
21902
- if (!isRecord4(data)) return data;
22229
+ if (!isRecord5(data)) return data;
21903
22230
  const allowed = new Set(Object.keys(data));
21904
22231
  assertKnownFields(fields, allowed);
21905
22232
  const filtered = pickFields(data, fields);
@@ -21924,7 +22251,7 @@ function compactData(value) {
21924
22251
  if (Array.isArray(value)) {
21925
22252
  return value.map(compactData).filter((item) => item !== void 0);
21926
22253
  }
21927
- if (isRecord4(value)) {
22254
+ if (isRecord5(value)) {
21928
22255
  const out = {};
21929
22256
  for (const [key, child] of Object.entries(value)) {
21930
22257
  const compacted = compactData(child);
@@ -21942,16 +22269,16 @@ function stableStringify(value, compact) {
21942
22269
  }
21943
22270
  function sortKeys(value) {
21944
22271
  if (Array.isArray(value)) return value.map(sortKeys);
21945
- if (!isRecord4(value)) return value;
22272
+ if (!isRecord5(value)) return value;
21946
22273
  return Object.fromEntries(
21947
22274
  Object.keys(value).sort().map((key) => [key, sortKeys(value[key])])
21948
22275
  );
21949
22276
  }
21950
- function isRecord4(value) {
22277
+ function isRecord5(value) {
21951
22278
  return typeof value === "object" && value !== null && !Array.isArray(value);
21952
22279
  }
21953
22280
  function isUploadBatch(value) {
21954
- return isRecord4(value) && Array.isArray(value.successes) && Array.isArray(value.failures);
22281
+ return isRecord5(value) && Array.isArray(value.successes) && Array.isArray(value.failures);
21955
22282
  }
21956
22283
 
21957
22284
  // src/schema.ts
@@ -22006,11 +22333,11 @@ function buildSchemaDocument(program) {
22006
22333
  event: toJsonSchema(operationEventSchema)
22007
22334
  };
22008
22335
  }
22009
- function walkCommands(command, path7, out) {
22336
+ function walkCommands(command, path8, out) {
22010
22337
  for (const sub of subcommandsOf(command)) {
22011
22338
  const name = sub.name();
22012
22339
  if (name === "help") continue;
22013
- const fullPath = [...path7, name];
22340
+ const fullPath = [...path8, name];
22014
22341
  const children = subcommandsOf(sub).filter((child) => child.name() !== "help");
22015
22342
  if (children.length === 0) {
22016
22343
  out.push(leafCommandDoc(sub, fullPath.join(" ")));
@@ -22288,7 +22615,7 @@ var MiniSidecarClient = class {
22288
22615
  }
22289
22616
  };
22290
22617
  function sidecarErrorToCliError(error51) {
22291
- const data = isRecord6(error51.data) ? error51.data : void 0;
22618
+ const data = isRecord7(error51.data) ? error51.data : void 0;
22292
22619
  const maybeCode = typeof data?.cliCode === "string" ? cliErrorCodeSchema.safeParse(data.cliCode) : void 0;
22293
22620
  const hint = typeof data?.recovery === "string" ? data.recovery : void 0;
22294
22621
  const retryable = typeof data?.retryable === "boolean" ? data.retryable : error51.code >= -32099 && error51.code <= -32e3;
@@ -22305,7 +22632,7 @@ function sidecarErrorToCliError(error51) {
22305
22632
  retryable
22306
22633
  });
22307
22634
  }
22308
- function isRecord6(value) {
22635
+ function isRecord7(value) {
22309
22636
  return typeof value === "object" && value !== null && !Array.isArray(value);
22310
22637
  }
22311
22638
  function spawnMiniSidecar(opts) {
@@ -22412,8 +22739,8 @@ function requestLaunchServicesSidecarShutdown(input) {
22412
22739
  } catch {
22413
22740
  }
22414
22741
  }
22415
- function createFifo(path7) {
22416
- const result = spawnSync("mkfifo", [path7], { encoding: "utf8" });
22742
+ function createFifo(path8) {
22743
+ const result = spawnSync("mkfifo", [path8], { encoding: "utf8" });
22417
22744
  if (result.status !== 0) {
22418
22745
  throw cliError("record.helper_unavailable", "Recappi recording helper could not start.", {
22419
22746
  hint: result.stderr || "Could not create the local recorder pipes. Try again."
@@ -22949,14 +23276,14 @@ async function startRecordSessionOnce(opts) {
22949
23276
  }
22950
23277
  }
22951
23278
  function isPermissionRestartRequiredError(error51, permissionName) {
22952
- const root = isRecord7(error51) ? error51 : void 0;
22953
- const descriptor = isRecord7(root?.descriptor) ? root.descriptor : void 0;
23279
+ const root = isRecord8(error51) ? error51 : void 0;
23280
+ const descriptor = isRecord8(root?.descriptor) ? root.descriptor : void 0;
22954
23281
  if (descriptor?.code !== "record.permission_required") return false;
22955
- const sidecarError = isRecord7(root?.data) ? root.data : void 0;
22956
- const sidecarData = isRecord7(sidecarError?.data) ? sidecarError.data : void 0;
23282
+ const sidecarError = isRecord8(root?.data) ? root.data : void 0;
23283
+ const sidecarData = isRecord8(sidecarError?.data) ? sidecarError.data : void 0;
22957
23284
  return sidecarData?.permission === permissionName && (sidecarData.requiresProcessRestart === true || sidecarData.requiresProcessRestart === "true");
22958
23285
  }
22959
- function isRecord7(value) {
23286
+ function isRecord8(value) {
22960
23287
  return typeof value === "object" && value !== null && !Array.isArray(value);
22961
23288
  }
22962
23289
  function normalizeSidecarSources(sources) {
@@ -23037,9 +23364,9 @@ function resolveSidecarCommand(opts) {
23037
23364
  hint: `No bundled helper is registered for ${platform}. Set ${SIDECAR_COMMAND_ENV} to a compatible helper when one is available.`
23038
23365
  });
23039
23366
  }
23040
- function ensureBundledHelperExecutable(path7, opts = {}) {
23041
- if (process.platform === "darwin" && path7.endsWith(".app")) {
23042
- const stableApp = ensureStableDarwinHelperApp(path7, opts);
23367
+ function ensureBundledHelperExecutable(path8, opts = {}) {
23368
+ if (process.platform === "darwin" && path8.endsWith(".app")) {
23369
+ const stableApp = ensureStableDarwinHelperApp(path8, opts);
23043
23370
  const executable = darwinAppExecutablePath(stableApp);
23044
23371
  if (!existsSync(executable)) {
23045
23372
  throw cliError("record.helper_unavailable", "Recappi recording helper is not available.", {
@@ -23049,19 +23376,19 @@ function ensureBundledHelperExecutable(path7, opts = {}) {
23049
23376
  ensureExecutableMode(executable);
23050
23377
  return stableApp;
23051
23378
  }
23052
- if (process.platform === "win32") return path7;
23053
- ensureExecutableMode(path7);
23054
- return path7;
23379
+ if (process.platform === "win32") return path8;
23380
+ ensureExecutableMode(path8);
23381
+ return path8;
23055
23382
  }
23056
- function ensureExecutableMode(path7) {
23057
- const mode = statSync(path7).mode;
23383
+ function ensureExecutableMode(path8) {
23384
+ const mode = statSync(path8).mode;
23058
23385
  if ((mode & 73) !== 0) return;
23059
23386
  try {
23060
- chmodSync(path7, mode | 493);
23387
+ chmodSync(path8, mode | 493);
23061
23388
  } catch (error51) {
23062
23389
  const message = error51 instanceof Error ? error51.message : String(error51);
23063
23390
  throw cliError("record.helper_unavailable", "Recappi recording helper is not executable.", {
23064
- hint: `Could not make bundled helper executable at ${path7}: ${message}. Reinstall recappi, or set ${SIDECAR_COMMAND_ENV} to a compatible helper.`
23391
+ hint: `Could not make bundled helper executable at ${path8}: ${message}. Reinstall recappi, or set ${SIDECAR_COMMAND_ENV} to a compatible helper.`
23065
23392
  });
23066
23393
  }
23067
23394
  }
@@ -23106,14 +23433,14 @@ function helperSourceSignature(sourceApp) {
23106
23433
  codeSignature: existsSync(signaturePath) ? fileDigest(signaturePath) : null
23107
23434
  });
23108
23435
  }
23109
- function fileDigest(path7) {
23436
+ function fileDigest(path8) {
23110
23437
  const hash2 = createHash("sha256");
23111
- hash2.update(readFileSync2(path7));
23438
+ hash2.update(readFileSync2(path8));
23112
23439
  return hash2.digest("hex");
23113
23440
  }
23114
- function readTextIfExists(path7) {
23441
+ function readTextIfExists(path8) {
23115
23442
  try {
23116
- return readFileSync2(path7, "utf8");
23443
+ return readFileSync2(path8, "utf8");
23117
23444
  } catch {
23118
23445
  return null;
23119
23446
  }
@@ -23407,6 +23734,13 @@ async function runCli(deps = {}) {
23407
23734
  await runDashboard2({
23408
23735
  fetchJobs: () => client.listJobs({ status: "active", limit: 20 }),
23409
23736
  fetchRecordings: ({ cursor, limit = DASHBOARD_RECORDINGS_PAGE_SIZE } = {}) => client.listRecordings({ limit, cursor }),
23737
+ fetchCachedRecordings: account ? ({ limit = DASHBOARD_RECORDINGS_PAGE_SIZE } = {}) => listCachedRecordingSessions({
23738
+ account,
23739
+ origin: auth.origin,
23740
+ limit,
23741
+ env: deps.env,
23742
+ homeDir: deps.homeDir
23743
+ }) : void 0,
23410
23744
  fetchDashboardStats: () => client.dashboardStats(),
23411
23745
  fetchAccountStatus: () => client.accountStatus(),
23412
23746
  fetchTranscript: (transcriptId) => client.getTranscript(transcriptId),