recappi 0.1.75 → 0.1.77

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