recappi 0.1.33 → 0.1.35
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 +489 -422
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -594,32 +594,151 @@ var init_LiveCaptionsScreen = __esm({
|
|
|
594
594
|
}
|
|
595
595
|
});
|
|
596
596
|
|
|
597
|
-
// src/tui/
|
|
597
|
+
// src/tui/RecordingHeroScreen.tsx
|
|
598
|
+
import { useEffect as useEffect2, useState as useState3 } from "react";
|
|
598
599
|
import { Box as Box2, Text as Text2 } from "ink";
|
|
599
|
-
import {
|
|
600
|
+
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
601
|
+
function waveform(samples, width) {
|
|
602
|
+
if (width <= 0) return "";
|
|
603
|
+
const tail = samples.slice(-width);
|
|
604
|
+
const pad = width - tail.length;
|
|
605
|
+
const cells = tail.map((v) => {
|
|
606
|
+
const i = Math.max(0, Math.min(BLOCKS.length - 1, Math.round(Math.max(0, Math.min(1, v)) * (BLOCKS.length - 1))));
|
|
607
|
+
return BLOCKS[i];
|
|
608
|
+
});
|
|
609
|
+
return "\u2581".repeat(Math.max(0, pad)) + cells.join("");
|
|
610
|
+
}
|
|
611
|
+
function RecordingHeroScreen({
|
|
612
|
+
telemetry,
|
|
613
|
+
artifact,
|
|
614
|
+
canTranscribe = false,
|
|
615
|
+
canPause = false,
|
|
616
|
+
now = () => Date.now()
|
|
617
|
+
}) {
|
|
618
|
+
const size = useTerminalSize();
|
|
619
|
+
const [tick, setTick] = useState3(() => now());
|
|
620
|
+
const [wave, setWave] = useState3([]);
|
|
621
|
+
useEffect2(() => {
|
|
622
|
+
if (telemetry.level == null) return;
|
|
623
|
+
const lvl = Math.max(telemetry.level.system ?? 0, telemetry.level.mic ?? 0);
|
|
624
|
+
setWave((w) => [...w.slice(-512), lvl]);
|
|
625
|
+
}, [telemetry.level]);
|
|
626
|
+
useEffect2(() => {
|
|
627
|
+
const id = setInterval(() => setTick(now()), 1e3);
|
|
628
|
+
return () => clearInterval(id);
|
|
629
|
+
}, []);
|
|
630
|
+
const elapsed = telemetry.startedAtMs != null ? formatClockMs(Math.max(0, tick - telemetry.startedAtMs)) : "00:00";
|
|
631
|
+
const innerWidth = Math.max(10, size.columns - 4);
|
|
632
|
+
if (telemetry.status === "stopped") {
|
|
633
|
+
const handoff = stoppedHandoffCopy(artifact, canTranscribe);
|
|
634
|
+
const meta3 = [
|
|
635
|
+
telemetry.durationMs != null ? formatClockMs(telemetry.durationMs) : null,
|
|
636
|
+
formatBytes2(telemetry.sizeBytes) || null
|
|
637
|
+
].filter(Boolean).join(" \xB7 ");
|
|
638
|
+
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", paddingX: 1, children: [
|
|
639
|
+
/* @__PURE__ */ jsx3(Text2, { dimColor: true, children: "recappi \xB7 Recording" }),
|
|
640
|
+
/* @__PURE__ */ jsxs2(Box2, { marginTop: 1, flexDirection: "column", children: [
|
|
641
|
+
/* @__PURE__ */ jsx3(Text2, { color: "green", children: "\u2713 Saved to your Mac" }),
|
|
642
|
+
meta3 ? /* @__PURE__ */ jsx3(Text2, { dimColor: true, children: meta3 }) : null,
|
|
643
|
+
telemetry.savedPath ? /* @__PURE__ */ jsx3(Text2, { dimColor: true, wrap: "truncate-middle", children: telemetry.savedPath }) : null
|
|
644
|
+
] }),
|
|
645
|
+
/* @__PURE__ */ jsxs2(Box2, { marginTop: 1, flexDirection: "column", children: [
|
|
646
|
+
/* @__PURE__ */ jsx3(Text2, { color: handoff.tone === "red" ? "red" : handoff.tone === "green" ? "green" : void 0, dimColor: handoff.tone === "dim", children: handoff.text }),
|
|
647
|
+
artifact?.error ? /* @__PURE__ */ jsx3(Text2, { color: "red", wrap: "truncate-end", children: artifact.error }) : null
|
|
648
|
+
] })
|
|
649
|
+
] });
|
|
650
|
+
}
|
|
651
|
+
if (telemetry.status === "error") {
|
|
652
|
+
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", paddingX: 1, children: [
|
|
653
|
+
/* @__PURE__ */ jsx3(Text2, { dimColor: true, children: "recappi \xB7 Recording" }),
|
|
654
|
+
/* @__PURE__ */ jsx3(Box2, { marginTop: 1, children: /* @__PURE__ */ jsx3(Text2, { color: "red", children: telemetry.error ? `Recording error: ${telemetry.error}` : "Recording error" }) }),
|
|
655
|
+
/* @__PURE__ */ jsx3(Box2, { marginTop: 1, children: /* @__PURE__ */ jsx3(Text2, { dimColor: true, children: "esc back" }) })
|
|
656
|
+
] });
|
|
657
|
+
}
|
|
658
|
+
const paused = telemetry.status === "paused";
|
|
659
|
+
const starting = telemetry.status === "starting" || telemetry.status === "stopping";
|
|
660
|
+
const badge = paused ? "\u23F8 PAUSED" : starting ? "\u2026" : "\u23FA REC";
|
|
661
|
+
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", paddingX: 1, height: size.rows, children: [
|
|
662
|
+
/* @__PURE__ */ jsxs2(Text2, { children: [
|
|
663
|
+
/* @__PURE__ */ jsx3(Text2, { bold: true, color: "green", children: "recappi" }),
|
|
664
|
+
/* @__PURE__ */ jsx3(Text2, { dimColor: true, children: " \xB7 Recording" })
|
|
665
|
+
] }),
|
|
666
|
+
/* @__PURE__ */ jsxs2(Box2, { flexGrow: 1, flexDirection: "column", justifyContent: "center", alignItems: "center", children: [
|
|
667
|
+
/* @__PURE__ */ jsx3(Text2, { bold: true, color: paused ? "yellow" : "red", children: badge }),
|
|
668
|
+
/* @__PURE__ */ jsx3(Text2, { bold: true, children: elapsed }),
|
|
669
|
+
/* @__PURE__ */ jsx3(Box2, { marginTop: 1, children: telemetry.level == null ? (
|
|
670
|
+
// No level telemetry yet — show honest activity, not a flat meter that
|
|
671
|
+
// looks like silence (the elapsed timer above proves it's live).
|
|
672
|
+
/* @__PURE__ */ jsx3(Text2, { dimColor: true, children: paused ? "Paused" : `Capturing audio${".".repeat(Math.floor(tick / 1e3) % 3 + 1)}` })
|
|
673
|
+
) : /* @__PURE__ */ jsx3(Text2, { color: paused ? "gray" : "red", children: waveform(wave, innerWidth) }) }),
|
|
674
|
+
/* @__PURE__ */ jsx3(Box2, { marginTop: 1, children: /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
|
|
675
|
+
telemetry.sourceLabel,
|
|
676
|
+
telemetry.micEnabled ? " + Microphone" : ""
|
|
677
|
+
] }) })
|
|
678
|
+
] }),
|
|
679
|
+
/* @__PURE__ */ jsx3(Box2, { children: /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
|
|
680
|
+
"q stop & save",
|
|
681
|
+
canPause ? ` \xB7 p ${paused ? "resume" : "pause"}` : ""
|
|
682
|
+
] }) })
|
|
683
|
+
] });
|
|
684
|
+
}
|
|
685
|
+
function stoppedHandoffCopy(artifact, canTranscribe) {
|
|
686
|
+
if (artifact?.uploadStatus === "uploading") {
|
|
687
|
+
return { text: "Uploading\u2026", tone: "normal" };
|
|
688
|
+
}
|
|
689
|
+
if (artifact?.transcriptionStatus === "processing") {
|
|
690
|
+
return { text: "Transcribing\u2026", tone: "normal" };
|
|
691
|
+
}
|
|
692
|
+
if (artifact?.transcriptionStatus === "queued") {
|
|
693
|
+
return { text: "Transcription queued \xB7 \u23CE open recording \xB7 n not now", tone: "green" };
|
|
694
|
+
}
|
|
695
|
+
if (artifact?.transcriptionStatus === "ready") {
|
|
696
|
+
return { text: "Transcription ready \xB7 \u23CE open recording \xB7 n not now", tone: "green" };
|
|
697
|
+
}
|
|
698
|
+
if (artifact?.uploadStatus === "failed" || artifact?.transcriptionStatus === "failed") {
|
|
699
|
+
return { text: "Transcription failed \xB7 \u23CE retry \xB7 n not now", tone: "red" };
|
|
700
|
+
}
|
|
701
|
+
if (!canTranscribe || !artifact?.audioPath) {
|
|
702
|
+
return { text: "Saved locally \xB7 n back", tone: "dim" };
|
|
703
|
+
}
|
|
704
|
+
return { text: "Transcribe now? \u23CE yes \xB7 n not now", tone: "normal" };
|
|
705
|
+
}
|
|
706
|
+
var BLOCKS;
|
|
707
|
+
var init_RecordingHeroScreen = __esm({
|
|
708
|
+
"src/tui/RecordingHeroScreen.tsx"() {
|
|
709
|
+
"use strict";
|
|
710
|
+
init_format();
|
|
711
|
+
init_terminal();
|
|
712
|
+
BLOCKS = " \u2581\u2582\u2583\u2584\u2585\u2586\u2587\u2588";
|
|
713
|
+
}
|
|
714
|
+
});
|
|
715
|
+
|
|
716
|
+
// src/tui/AccountView.tsx
|
|
717
|
+
import { Box as Box3, Text as Text3 } from "ink";
|
|
718
|
+
import { Fragment, jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
600
719
|
function AccountView({ status }) {
|
|
601
|
-
return /* @__PURE__ */
|
|
602
|
-
/* @__PURE__ */
|
|
603
|
-
status === "loading" || status === void 0 ? /* @__PURE__ */
|
|
604
|
-
/* @__PURE__ */
|
|
605
|
-
/* @__PURE__ */
|
|
606
|
-
/* @__PURE__ */
|
|
607
|
-
] }) : /* @__PURE__ */
|
|
608
|
-
/* @__PURE__ */
|
|
720
|
+
return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", paddingX: 1, children: [
|
|
721
|
+
/* @__PURE__ */ jsx5(Text3, { dimColor: true, children: "\u2039 Account" }),
|
|
722
|
+
status === "loading" || status === void 0 ? /* @__PURE__ */ jsx5(Box3, { marginTop: 1, children: /* @__PURE__ */ jsx5(Text3, { dimColor: true, children: "Loading account\u2026" }) }) : status === "error" ? /* @__PURE__ */ jsx5(Box3, { marginTop: 1, children: /* @__PURE__ */ jsx5(Text3, { color: "red", children: "Couldn't load account status" }) }) : !status.loggedIn ? /* @__PURE__ */ jsxs3(Box3, { marginTop: 1, flexDirection: "column", children: [
|
|
723
|
+
/* @__PURE__ */ jsx5(Text3, { color: "yellow", children: "Not signed in" }),
|
|
724
|
+
/* @__PURE__ */ jsx5(Text3, { dimColor: true, children: `origin ${status.origin}` }),
|
|
725
|
+
/* @__PURE__ */ jsx5(Text3, { dimColor: true, children: "Run `recappi auth login` to sign in." })
|
|
726
|
+
] }) : /* @__PURE__ */ jsx5(AccountBody, { status }),
|
|
727
|
+
/* @__PURE__ */ jsx5(Box3, { marginTop: 1, children: /* @__PURE__ */ jsx5(Text3, { dimColor: true, children: "r refresh \xB7 esc back \xB7 q quit" }) })
|
|
609
728
|
] });
|
|
610
729
|
}
|
|
611
730
|
function AccountBody({ status }) {
|
|
612
|
-
return /* @__PURE__ */
|
|
613
|
-
/* @__PURE__ */
|
|
614
|
-
/* @__PURE__ */
|
|
615
|
-
status.email && status.userId ? /* @__PURE__ */
|
|
616
|
-
/* @__PURE__ */
|
|
731
|
+
return /* @__PURE__ */ jsxs3(Fragment, { children: [
|
|
732
|
+
/* @__PURE__ */ jsxs3(Box3, { marginTop: 1, flexDirection: "column", children: [
|
|
733
|
+
/* @__PURE__ */ jsx5(Text3, { bold: true, color: "green", children: status.email ?? status.userId ?? "Signed in" }),
|
|
734
|
+
status.email && status.userId ? /* @__PURE__ */ jsx5(Text3, { dimColor: true, children: status.userId }) : null,
|
|
735
|
+
/* @__PURE__ */ jsx5(Text3, { dimColor: true, children: `origin ${status.origin}` })
|
|
617
736
|
] }),
|
|
618
|
-
status.billing ? /* @__PURE__ */
|
|
619
|
-
/* @__PURE__ */
|
|
620
|
-
/* @__PURE__ */
|
|
621
|
-
/* @__PURE__ */
|
|
622
|
-
/* @__PURE__ */
|
|
737
|
+
status.billing ? /* @__PURE__ */ jsx5(Usage, { billing: status.billing }) : null,
|
|
738
|
+
/* @__PURE__ */ jsxs3(Box3, { marginTop: 1, flexDirection: "column", children: [
|
|
739
|
+
/* @__PURE__ */ jsx5(Text3, { bold: true, children: "Local store" }),
|
|
740
|
+
/* @__PURE__ */ jsx5(Text3, { dimColor: true, wrap: "truncate-middle", children: status.localStore.path }),
|
|
741
|
+
/* @__PURE__ */ jsxs3(Text3, { dimColor: true, children: [
|
|
623
742
|
`${status.localStore.accountScopedArtifacts} artifact${status.localStore.accountScopedArtifacts === 1 ? "" : "s"} for this account`,
|
|
624
743
|
status.localStore.unattributedArtifacts > 0 ? ` \xB7 ${status.localStore.unattributedArtifacts} unattributed` : ""
|
|
625
744
|
] })
|
|
@@ -630,29 +749,29 @@ function Usage({ billing }) {
|
|
|
630
749
|
const minutesCap = billing.minutesCap;
|
|
631
750
|
const minutesUsed = billing.minutesUsed;
|
|
632
751
|
const storageCap = billing.storageCapBytes;
|
|
633
|
-
return /* @__PURE__ */
|
|
634
|
-
/* @__PURE__ */
|
|
635
|
-
/* @__PURE__ */
|
|
636
|
-
/* @__PURE__ */
|
|
752
|
+
return /* @__PURE__ */ jsxs3(Box3, { marginTop: 1, flexDirection: "column", children: [
|
|
753
|
+
/* @__PURE__ */ jsxs3(Text3, { children: [
|
|
754
|
+
/* @__PURE__ */ jsx5(Text3, { dimColor: true, children: "Plan " }),
|
|
755
|
+
/* @__PURE__ */ jsx5(Text3, { bold: true, children: billing.tier })
|
|
637
756
|
] }),
|
|
638
|
-
/* @__PURE__ */
|
|
639
|
-
/* @__PURE__ */
|
|
640
|
-
minutesCap != null ? /* @__PURE__ */
|
|
641
|
-
/* @__PURE__ */
|
|
642
|
-
/* @__PURE__ */
|
|
643
|
-
/* @__PURE__ */
|
|
757
|
+
/* @__PURE__ */ jsxs3(Text3, { children: [
|
|
758
|
+
/* @__PURE__ */ jsx5(Text3, { dimColor: true, children: "Minutes " }),
|
|
759
|
+
minutesCap != null ? /* @__PURE__ */ jsx5(Text3, { color: billing.isOverMinutes ? "red" : "cyan", children: `${progressBar(minutesUsed / Math.max(1, minutesCap), 12)} ` }) : null,
|
|
760
|
+
/* @__PURE__ */ jsx5(Text3, { color: billing.isOverMinutes ? "red" : void 0, children: `${Math.round(minutesUsed)}` }),
|
|
761
|
+
/* @__PURE__ */ jsx5(Text3, { dimColor: true, children: ` / ${minutesCap != null ? Math.round(minutesCap) : "\u221E"} min` }),
|
|
762
|
+
/* @__PURE__ */ jsx5(Text3, { dimColor: true, children: ` (batch ${Math.round(billing.batchMinutesUsed)} \xB7 live ${Math.round(billing.realtimeMinutesUsed)})` })
|
|
644
763
|
] }),
|
|
645
|
-
/* @__PURE__ */
|
|
646
|
-
/* @__PURE__ */
|
|
647
|
-
storageCap != null ? /* @__PURE__ */
|
|
648
|
-
/* @__PURE__ */
|
|
649
|
-
/* @__PURE__ */
|
|
764
|
+
/* @__PURE__ */ jsxs3(Text3, { children: [
|
|
765
|
+
/* @__PURE__ */ jsx5(Text3, { dimColor: true, children: "Storage " }),
|
|
766
|
+
storageCap != null ? /* @__PURE__ */ jsx5(Text3, { color: billing.isOverStorage ? "red" : "cyan", children: `${progressBar(billing.storageBytes / Math.max(1, storageCap), 12)} ` }) : null,
|
|
767
|
+
/* @__PURE__ */ jsx5(Text3, { color: billing.isOverStorage ? "red" : void 0, children: formatBytes2(billing.storageBytes) }),
|
|
768
|
+
/* @__PURE__ */ jsx5(Text3, { dimColor: true, children: ` / ${storageCap != null ? formatBytes2(storageCap) : "\u221E"}` })
|
|
650
769
|
] }),
|
|
651
|
-
billing.isOverMinutes || billing.isOverStorage ? /* @__PURE__ */
|
|
770
|
+
billing.isOverMinutes || billing.isOverStorage ? /* @__PURE__ */ jsxs3(Text3, { color: "red", children: [
|
|
652
771
|
billing.isOverMinutes ? "Over minutes limit. " : "",
|
|
653
772
|
billing.isOverStorage ? "Over storage limit." : ""
|
|
654
773
|
] }) : null,
|
|
655
|
-
/* @__PURE__ */
|
|
774
|
+
/* @__PURE__ */ jsx5(Text3, { dimColor: true, children: `Period ${periodText(billing)}` })
|
|
656
775
|
] });
|
|
657
776
|
}
|
|
658
777
|
function periodText(billing) {
|
|
@@ -673,17 +792,17 @@ var init_AccountView = __esm({
|
|
|
673
792
|
});
|
|
674
793
|
|
|
675
794
|
// src/tui/chrome.tsx
|
|
676
|
-
import { Box as
|
|
677
|
-
import { jsx as
|
|
795
|
+
import { Box as Box4, Text as Text4 } from "ink";
|
|
796
|
+
import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
678
797
|
function Header({ active }) {
|
|
679
|
-
return /* @__PURE__ */
|
|
680
|
-
/* @__PURE__ */
|
|
798
|
+
return /* @__PURE__ */ jsxs4(Box4, { children: [
|
|
799
|
+
/* @__PURE__ */ jsxs4(Text4, { bold: true, color: "green", children: [
|
|
681
800
|
"\u25CF Recappi",
|
|
682
801
|
" "
|
|
683
802
|
] }),
|
|
684
|
-
/* @__PURE__ */
|
|
685
|
-
/* @__PURE__ */
|
|
686
|
-
/* @__PURE__ */
|
|
803
|
+
/* @__PURE__ */ jsx6(Tab, { num: "1", label: "Overview", active: active === "overview" }),
|
|
804
|
+
/* @__PURE__ */ jsx6(Tab, { num: "2", label: "Jobs", active: active === "jobs" }),
|
|
805
|
+
/* @__PURE__ */ jsx6(Tab, { num: "3", label: "Account", active: active === "account" })
|
|
687
806
|
] });
|
|
688
807
|
}
|
|
689
808
|
function Tab({
|
|
@@ -692,24 +811,24 @@ function Tab({
|
|
|
692
811
|
active
|
|
693
812
|
}) {
|
|
694
813
|
if (active) {
|
|
695
|
-
return /* @__PURE__ */
|
|
814
|
+
return /* @__PURE__ */ jsx6(Text4, { bold: true, inverse: true, color: "cyan", children: ` ${num} ${label} ` });
|
|
696
815
|
}
|
|
697
|
-
return /* @__PURE__ */
|
|
816
|
+
return /* @__PURE__ */ jsxs4(Text4, { dimColor: true, children: [
|
|
698
817
|
" ",
|
|
699
|
-
/* @__PURE__ */
|
|
818
|
+
/* @__PURE__ */ jsx6(Text4, { color: "cyan", children: num }),
|
|
700
819
|
` ${label} `
|
|
701
820
|
] });
|
|
702
821
|
}
|
|
703
822
|
function Footer({ keys }) {
|
|
704
823
|
const segments = keys.split(" \xB7 ");
|
|
705
|
-
return /* @__PURE__ */
|
|
824
|
+
return /* @__PURE__ */ jsx6(Box4, { marginTop: 1, children: /* @__PURE__ */ jsx6(Text4, { children: segments.map((segment, i) => {
|
|
706
825
|
const space = segment.indexOf(" ");
|
|
707
826
|
const key = space === -1 ? segment : segment.slice(0, space);
|
|
708
827
|
const desc = space === -1 ? "" : segment.slice(space);
|
|
709
|
-
return /* @__PURE__ */
|
|
710
|
-
i > 0 ? /* @__PURE__ */
|
|
711
|
-
/* @__PURE__ */
|
|
712
|
-
/* @__PURE__ */
|
|
828
|
+
return /* @__PURE__ */ jsxs4(Text4, { children: [
|
|
829
|
+
i > 0 ? /* @__PURE__ */ jsx6(Text4, { dimColor: true, children: " \xB7 " }) : null,
|
|
830
|
+
/* @__PURE__ */ jsx6(Text4, { color: "cyan", children: key }),
|
|
831
|
+
/* @__PURE__ */ jsx6(Text4, { dimColor: true, children: desc })
|
|
713
832
|
] }, `${segment}-${i}`);
|
|
714
833
|
}) }) });
|
|
715
834
|
}
|
|
@@ -720,8 +839,8 @@ var init_chrome = __esm({
|
|
|
720
839
|
});
|
|
721
840
|
|
|
722
841
|
// src/tui/JobRow.tsx
|
|
723
|
-
import { Box as
|
|
724
|
-
import { jsx as
|
|
842
|
+
import { Box as Box5, Text as Text5 } from "ink";
|
|
843
|
+
import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
725
844
|
function JobRow({
|
|
726
845
|
item,
|
|
727
846
|
selected,
|
|
@@ -730,11 +849,11 @@ function JobRow({
|
|
|
730
849
|
const style = statusStyle(item.status);
|
|
731
850
|
const glyph = statusGlyph(item.status, spinnerFrame);
|
|
732
851
|
const title = item.recording?.title ?? item.recordingId;
|
|
733
|
-
return /* @__PURE__ */
|
|
734
|
-
/* @__PURE__ */
|
|
735
|
-
/* @__PURE__ */
|
|
736
|
-
/* @__PURE__ */
|
|
737
|
-
/* @__PURE__ */
|
|
852
|
+
return /* @__PURE__ */ jsxs5(Box5, { children: [
|
|
853
|
+
/* @__PURE__ */ jsx7(Text5, { color: "cyan", children: selected ? "\u25B8 " : " " }),
|
|
854
|
+
/* @__PURE__ */ jsx7(Text5, { color: style.color, children: `${glyph} ${padCell(style.label, 13)}` }),
|
|
855
|
+
/* @__PURE__ */ jsx7(Text5, { bold: selected, children: padCell(title, 24) }),
|
|
856
|
+
/* @__PURE__ */ jsx7(Text5, { dimColor: !selected, children: jobDetail(item) })
|
|
738
857
|
] });
|
|
739
858
|
}
|
|
740
859
|
var init_JobRow = __esm({
|
|
@@ -745,17 +864,17 @@ var init_JobRow = __esm({
|
|
|
745
864
|
});
|
|
746
865
|
|
|
747
866
|
// src/tui/JobsView.tsx
|
|
748
|
-
import { Box as
|
|
749
|
-
import { jsx as
|
|
867
|
+
import { Box as Box6, Text as Text6 } from "ink";
|
|
868
|
+
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
750
869
|
function JobsView({
|
|
751
870
|
items,
|
|
752
871
|
selectedIndex,
|
|
753
872
|
spinnerFrame
|
|
754
873
|
}) {
|
|
755
874
|
if (items.length === 0) {
|
|
756
|
-
return /* @__PURE__ */
|
|
875
|
+
return /* @__PURE__ */ jsx8(Box6, { marginTop: 1, children: /* @__PURE__ */ jsx8(Text6, { dimColor: true, children: "No transcription jobs yet \u2014 run: recappi upload <file> --transcribe" }) });
|
|
757
876
|
}
|
|
758
|
-
return /* @__PURE__ */
|
|
877
|
+
return /* @__PURE__ */ jsx8(Box6, { marginTop: 1, flexDirection: "column", children: items.map((item, index) => /* @__PURE__ */ jsx8(
|
|
759
878
|
JobRow,
|
|
760
879
|
{
|
|
761
880
|
item,
|
|
@@ -773,8 +892,8 @@ var init_JobsView = __esm({
|
|
|
773
892
|
});
|
|
774
893
|
|
|
775
894
|
// src/tui/RecordingRow.tsx
|
|
776
|
-
import { Box as
|
|
777
|
-
import { jsx as
|
|
895
|
+
import { Box as Box7, Text as Text7 } from "ink";
|
|
896
|
+
import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
778
897
|
function recordingTitle2(item) {
|
|
779
898
|
const named = (item.title || item.summaryTitle || "").trim();
|
|
780
899
|
if (named && !UUID_RE.test(named)) return named;
|
|
@@ -810,22 +929,22 @@ function RecordingRow({
|
|
|
810
929
|
const { title, showWhen } = recordingLayout(columns);
|
|
811
930
|
const { glyph, color } = recordingProcessingState(item, jobStatus, spinnerFrame);
|
|
812
931
|
const duration3 = item.durationMs ? formatClockMs(item.durationMs) : "\u2014";
|
|
813
|
-
return /* @__PURE__ */
|
|
814
|
-
/* @__PURE__ */
|
|
815
|
-
/* @__PURE__ */
|
|
816
|
-
/* @__PURE__ */
|
|
817
|
-
/* @__PURE__ */
|
|
818
|
-
showWhen ? /* @__PURE__ */
|
|
819
|
-
/* @__PURE__ */
|
|
932
|
+
return /* @__PURE__ */ jsxs6(Box7, { children: [
|
|
933
|
+
/* @__PURE__ */ jsx9(Text7, { color: "cyan", children: selected ? "\u25B8 " : " " }),
|
|
934
|
+
/* @__PURE__ */ jsx9(Text7, { color, children: `${glyph} ` }),
|
|
935
|
+
/* @__PURE__ */ jsx9(Text7, { bold: selected, children: padDisplay(recordingTitle2(item), title) }),
|
|
936
|
+
/* @__PURE__ */ jsx9(Text7, { dimColor: true, children: padDisplay(duration3, LENGTH_W) }),
|
|
937
|
+
showWhen ? /* @__PURE__ */ jsx9(Text7, { dimColor: true, children: padDisplay(formatAge(item.createdAt, nowMs), WHEN_W) }) : null,
|
|
938
|
+
/* @__PURE__ */ jsx9(Text7, { color: "green", children: downloaded ? " \u2913" : " " })
|
|
820
939
|
] });
|
|
821
940
|
}
|
|
822
941
|
function RecordingHeader({ columns }) {
|
|
823
942
|
const { title, showWhen } = recordingLayout(columns);
|
|
824
|
-
return /* @__PURE__ */
|
|
825
|
-
/* @__PURE__ */
|
|
826
|
-
/* @__PURE__ */
|
|
827
|
-
/* @__PURE__ */
|
|
828
|
-
showWhen ? /* @__PURE__ */
|
|
943
|
+
return /* @__PURE__ */ jsxs6(Box7, { children: [
|
|
944
|
+
/* @__PURE__ */ jsx9(Text7, { dimColor: true, children: padDisplay("", MARKER_W + GLYPH_W) }),
|
|
945
|
+
/* @__PURE__ */ jsx9(Text7, { dimColor: true, children: padDisplay("TITLE", title) }),
|
|
946
|
+
/* @__PURE__ */ jsx9(Text7, { dimColor: true, children: padDisplay("LENGTH", LENGTH_W) }),
|
|
947
|
+
showWhen ? /* @__PURE__ */ jsx9(Text7, { dimColor: true, children: "WHEN" }) : null
|
|
829
948
|
] });
|
|
830
949
|
}
|
|
831
950
|
var UUID_RE, MARKER_W, GLYPH_W, LENGTH_W, WHEN_W;
|
|
@@ -842,9 +961,9 @@ var init_RecordingRow = __esm({
|
|
|
842
961
|
});
|
|
843
962
|
|
|
844
963
|
// src/tui/RecordingsView.tsx
|
|
845
|
-
import
|
|
846
|
-
import { Box as
|
|
847
|
-
import { jsx as
|
|
964
|
+
import React5 from "react";
|
|
965
|
+
import { Box as Box8, Text as Text8 } from "ink";
|
|
966
|
+
import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
848
967
|
function RecordingsView({
|
|
849
968
|
items,
|
|
850
969
|
selectedIndex,
|
|
@@ -855,16 +974,16 @@ function RecordingsView({
|
|
|
855
974
|
spinnerFrame = 0
|
|
856
975
|
}) {
|
|
857
976
|
if (items.length === 0) {
|
|
858
|
-
return /* @__PURE__ */
|
|
977
|
+
return /* @__PURE__ */ jsx10(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx10(Text8, { dimColor: true, children: "No recordings yet \u2014 run: recappi upload <file>" }) });
|
|
859
978
|
}
|
|
860
|
-
return /* @__PURE__ */
|
|
861
|
-
/* @__PURE__ */
|
|
979
|
+
return /* @__PURE__ */ jsxs7(Box8, { marginTop: 1, flexDirection: "column", children: [
|
|
980
|
+
/* @__PURE__ */ jsx10(RecordingHeader, { columns }),
|
|
862
981
|
items.map((item, index) => {
|
|
863
982
|
const bucket = dateBucket(item.createdAt, nowMs);
|
|
864
983
|
const showHeader = index === 0 || bucket !== dateBucket(items[index - 1].createdAt, nowMs);
|
|
865
|
-
return /* @__PURE__ */
|
|
866
|
-
showHeader ? /* @__PURE__ */
|
|
867
|
-
/* @__PURE__ */
|
|
984
|
+
return /* @__PURE__ */ jsxs7(React5.Fragment, { children: [
|
|
985
|
+
showHeader ? /* @__PURE__ */ jsx10(Box8, { marginTop: index === 0 ? 0 : 1, children: /* @__PURE__ */ jsx10(Text8, { bold: true, color: "blue", children: bucket }) }) : null,
|
|
986
|
+
/* @__PURE__ */ jsx10(
|
|
868
987
|
RecordingRow,
|
|
869
988
|
{
|
|
870
989
|
item,
|
|
@@ -889,15 +1008,15 @@ var init_RecordingsView = __esm({
|
|
|
889
1008
|
});
|
|
890
1009
|
|
|
891
1010
|
// src/tui/RecordingPeek.tsx
|
|
892
|
-
import { Box as
|
|
893
|
-
import { Fragment as Fragment2, jsx as
|
|
1011
|
+
import { Box as Box9, Text as Text9 } from "ink";
|
|
1012
|
+
import { Fragment as Fragment2, jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
894
1013
|
function RecordingPeek({
|
|
895
1014
|
item,
|
|
896
1015
|
summary,
|
|
897
1016
|
nowMs,
|
|
898
1017
|
width
|
|
899
1018
|
}) {
|
|
900
|
-
return /* @__PURE__ */
|
|
1019
|
+
return /* @__PURE__ */ jsx11(Box9, { width, borderStyle: "round", borderColor: "gray", paddingX: 1, flexDirection: "column", children: !item ? /* @__PURE__ */ jsx11(Text9, { dimColor: true, children: "No selection" }) : /* @__PURE__ */ jsx11(PeekBody, { item, summary, nowMs }) });
|
|
901
1020
|
}
|
|
902
1021
|
function PeekBody({
|
|
903
1022
|
item,
|
|
@@ -910,30 +1029,30 @@ function PeekBody({
|
|
|
910
1029
|
formatBytes2(item.sizeBytes) || null,
|
|
911
1030
|
item.contentType || null
|
|
912
1031
|
].filter(Boolean).join(" \xB7 ");
|
|
913
|
-
return /* @__PURE__ */
|
|
914
|
-
/* @__PURE__ */
|
|
915
|
-
/* @__PURE__ */
|
|
916
|
-
meta3 ? /* @__PURE__ */
|
|
917
|
-
/* @__PURE__ */
|
|
918
|
-
/* @__PURE__ */
|
|
919
|
-
/* @__PURE__ */
|
|
1032
|
+
return /* @__PURE__ */ jsxs8(Fragment2, { children: [
|
|
1033
|
+
/* @__PURE__ */ jsx11(Text9, { bold: true, color: "green", wrap: "truncate-end", children: recordingTitle2(item) }),
|
|
1034
|
+
/* @__PURE__ */ jsx11(Text9, { color: style.color, children: `${style.glyph} ${style.label}` }),
|
|
1035
|
+
meta3 ? /* @__PURE__ */ jsx11(Text9, { dimColor: true, children: meta3 }) : null,
|
|
1036
|
+
/* @__PURE__ */ jsx11(Text9, { dimColor: true, children: formatAge(item.createdAt, nowMs) }),
|
|
1037
|
+
/* @__PURE__ */ jsx11(Box9, { marginTop: 1, flexDirection: "column", children: /* @__PURE__ */ jsx11(SummarySection, { item, summary }) }),
|
|
1038
|
+
/* @__PURE__ */ jsx11(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx11(Text9, { dimColor: true, children: "\u23CE open \xB7 t transcript \xB7 o web" }) })
|
|
920
1039
|
] });
|
|
921
1040
|
}
|
|
922
1041
|
function SummarySection({
|
|
923
1042
|
item,
|
|
924
1043
|
summary
|
|
925
1044
|
}) {
|
|
926
|
-
if (!item.activeTranscriptId) return /* @__PURE__ */
|
|
927
|
-
if (summary === "loading" || summary === void 0) return /* @__PURE__ */
|
|
928
|
-
if (summary === "error") return /* @__PURE__ */
|
|
1045
|
+
if (!item.activeTranscriptId) return /* @__PURE__ */ jsx11(Text9, { dimColor: true, children: "No transcript yet" });
|
|
1046
|
+
if (summary === "loading" || summary === void 0) return /* @__PURE__ */ jsx11(Text9, { dimColor: true, children: "Loading summary\u2026" });
|
|
1047
|
+
if (summary === "error") return /* @__PURE__ */ jsx11(Text9, { dimColor: true, children: "(summary unavailable)" });
|
|
929
1048
|
if (summary.status !== "succeeded" || !summary.tldr) {
|
|
930
|
-
return /* @__PURE__ */
|
|
1049
|
+
return /* @__PURE__ */ jsx11(Text9, { dimColor: true, children: `Summary ${summary.status}` });
|
|
931
1050
|
}
|
|
932
1051
|
const points = (summary.keyPoints ?? []).slice(0, 3);
|
|
933
|
-
return /* @__PURE__ */
|
|
934
|
-
/* @__PURE__ */
|
|
935
|
-
/* @__PURE__ */
|
|
936
|
-
points.length > 0 ? /* @__PURE__ */
|
|
1052
|
+
return /* @__PURE__ */ jsxs8(Fragment2, { children: [
|
|
1053
|
+
/* @__PURE__ */ jsx11(Text9, { bold: true, children: "Summary" }),
|
|
1054
|
+
/* @__PURE__ */ jsx11(Text9, { children: summary.tldr }),
|
|
1055
|
+
points.length > 0 ? /* @__PURE__ */ jsx11(Box9, { marginTop: 1, flexDirection: "column", children: points.map((point, i) => /* @__PURE__ */ jsx11(Text9, { dimColor: true, wrap: "truncate-end", children: `\u2022 ${point}` }, i)) }) : null
|
|
937
1056
|
] });
|
|
938
1057
|
}
|
|
939
1058
|
var init_RecordingPeek = __esm({
|
|
@@ -945,8 +1064,8 @@ var init_RecordingPeek = __esm({
|
|
|
945
1064
|
});
|
|
946
1065
|
|
|
947
1066
|
// src/tui/OverviewView.tsx
|
|
948
|
-
import { Box as
|
|
949
|
-
import { jsx as
|
|
1067
|
+
import { Box as Box10, Text as Text10 } from "ink";
|
|
1068
|
+
import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
950
1069
|
function OverviewView({
|
|
951
1070
|
recordings,
|
|
952
1071
|
jobs,
|
|
@@ -965,17 +1084,17 @@ function OverviewView({
|
|
|
965
1084
|
const jobCounts = countJobs(jobs);
|
|
966
1085
|
const running = stats?.jobs.running ?? jobCounts.running;
|
|
967
1086
|
const queued = stats?.jobs.queued ?? jobCounts.queued;
|
|
968
|
-
return /* @__PURE__ */
|
|
969
|
-
/* @__PURE__ */
|
|
970
|
-
/* @__PURE__ */
|
|
971
|
-
/* @__PURE__ */
|
|
972
|
-
stats?.recordings.ready != null ? /* @__PURE__ */
|
|
973
|
-
stats?.recordings.totalDurationMs != null ? /* @__PURE__ */
|
|
974
|
-
running > 0 ? /* @__PURE__ */
|
|
975
|
-
queued > 0 ? /* @__PURE__ */
|
|
1087
|
+
return /* @__PURE__ */ jsxs9(Box10, { flexDirection: "column", children: [
|
|
1088
|
+
/* @__PURE__ */ jsxs9(Box10, { children: [
|
|
1089
|
+
/* @__PURE__ */ jsx12(Text10, { dimColor: true, children: "Recordings " }),
|
|
1090
|
+
/* @__PURE__ */ jsx12(Text10, { bold: true, children: stats?.recordings.total ?? recordings.length }),
|
|
1091
|
+
stats?.recordings.ready != null ? /* @__PURE__ */ jsx12(Text10, { dimColor: true, children: ` \xB7 ${stats.recordings.ready} ready` }) : null,
|
|
1092
|
+
stats?.recordings.totalDurationMs != null ? /* @__PURE__ */ jsx12(Text10, { dimColor: true, children: ` \xB7 ${formatClockMs(stats.recordings.totalDurationMs)} transcribed` }) : null,
|
|
1093
|
+
running > 0 ? /* @__PURE__ */ jsx12(Text10, { color: "cyan", children: ` \xB7 ${running} transcribing` }) : null,
|
|
1094
|
+
queued > 0 ? /* @__PURE__ */ jsx12(Text10, { color: "yellow", children: ` \xB7 ${queued} queued` }) : null
|
|
976
1095
|
] }),
|
|
977
|
-
/* @__PURE__ */
|
|
978
|
-
/* @__PURE__ */
|
|
1096
|
+
/* @__PURE__ */ jsxs9(Box10, { flexDirection: "row", alignItems: "flex-start", children: [
|
|
1097
|
+
/* @__PURE__ */ jsx12(Box10, { flexGrow: 1, flexDirection: "column", children: /* @__PURE__ */ jsx12(
|
|
979
1098
|
RecordingsView,
|
|
980
1099
|
{
|
|
981
1100
|
items: recordings,
|
|
@@ -987,7 +1106,7 @@ function OverviewView({
|
|
|
987
1106
|
spinnerFrame
|
|
988
1107
|
}
|
|
989
1108
|
) }),
|
|
990
|
-
showPeek ? /* @__PURE__ */
|
|
1109
|
+
showPeek ? /* @__PURE__ */ jsx12(Box10, { marginLeft: 1, marginTop: 1, children: /* @__PURE__ */ jsx12(RecordingPeek, { item: peekItem, summary: peekSummary, nowMs, width: peekWidth }) }) : null
|
|
991
1110
|
] })
|
|
992
1111
|
] });
|
|
993
1112
|
}
|
|
@@ -1001,8 +1120,8 @@ var init_OverviewView = __esm({
|
|
|
1001
1120
|
});
|
|
1002
1121
|
|
|
1003
1122
|
// src/tui/JobDetailView.tsx
|
|
1004
|
-
import { Box as
|
|
1005
|
-
import { jsx as
|
|
1123
|
+
import { Box as Box11, Text as Text11 } from "ink";
|
|
1124
|
+
import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1006
1125
|
function JobDetailView({
|
|
1007
1126
|
item,
|
|
1008
1127
|
origin,
|
|
@@ -1012,13 +1131,13 @@ function JobDetailView({
|
|
|
1012
1131
|
const style = statusStyle(item.status);
|
|
1013
1132
|
const links = resolveJobLinks(item, origin);
|
|
1014
1133
|
const title = item.recording?.title ?? item.recordingId;
|
|
1015
|
-
return /* @__PURE__ */
|
|
1016
|
-
/* @__PURE__ */
|
|
1134
|
+
return /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", paddingX: 1, children: [
|
|
1135
|
+
/* @__PURE__ */ jsxs10(Text11, { dimColor: true, children: [
|
|
1017
1136
|
"\u2039 Jobs / ",
|
|
1018
1137
|
title
|
|
1019
1138
|
] }),
|
|
1020
|
-
/* @__PURE__ */
|
|
1021
|
-
|
|
1139
|
+
/* @__PURE__ */ jsxs10(
|
|
1140
|
+
Box11,
|
|
1022
1141
|
{
|
|
1023
1142
|
marginTop: 1,
|
|
1024
1143
|
borderStyle: "round",
|
|
@@ -1026,17 +1145,17 @@ function JobDetailView({
|
|
|
1026
1145
|
paddingX: 1,
|
|
1027
1146
|
flexDirection: "column",
|
|
1028
1147
|
children: [
|
|
1029
|
-
/* @__PURE__ */
|
|
1148
|
+
/* @__PURE__ */ jsxs10(Text11, { color: style.color, bold: true, children: [
|
|
1030
1149
|
style.label,
|
|
1031
|
-
item.provider ? /* @__PURE__ */
|
|
1150
|
+
item.provider ? /* @__PURE__ */ jsx13(Text11, { dimColor: true, children: ` ${item.provider}` }) : null
|
|
1032
1151
|
] }),
|
|
1033
|
-
/* @__PURE__ */
|
|
1152
|
+
/* @__PURE__ */ jsx13(StatusLine, { item, spinnerFrame, nowMs })
|
|
1034
1153
|
]
|
|
1035
1154
|
}
|
|
1036
1155
|
),
|
|
1037
|
-
/* @__PURE__ */
|
|
1038
|
-
/* @__PURE__ */
|
|
1039
|
-
/* @__PURE__ */
|
|
1156
|
+
/* @__PURE__ */ jsxs10(Box11, { marginTop: 1, flexDirection: "column", children: [
|
|
1157
|
+
/* @__PURE__ */ jsx13(Text11, { bold: true, children: "Timeline" }),
|
|
1158
|
+
/* @__PURE__ */ jsx13(
|
|
1040
1159
|
TimelineRow,
|
|
1041
1160
|
{
|
|
1042
1161
|
label: "Enqueued",
|
|
@@ -1045,7 +1164,7 @@ function JobDetailView({
|
|
|
1045
1164
|
nowMs
|
|
1046
1165
|
}
|
|
1047
1166
|
),
|
|
1048
|
-
/* @__PURE__ */
|
|
1167
|
+
/* @__PURE__ */ jsx13(
|
|
1049
1168
|
TimelineRow,
|
|
1050
1169
|
{
|
|
1051
1170
|
label: "Started",
|
|
@@ -1054,7 +1173,7 @@ function JobDetailView({
|
|
|
1054
1173
|
nowMs
|
|
1055
1174
|
}
|
|
1056
1175
|
),
|
|
1057
|
-
/* @__PURE__ */
|
|
1176
|
+
/* @__PURE__ */ jsx13(
|
|
1058
1177
|
TimelineRow,
|
|
1059
1178
|
{
|
|
1060
1179
|
label: item.status === "failed" ? "Failed" : item.status === "running" ? "Transcribing" : "Finished",
|
|
@@ -1066,21 +1185,21 @@ function JobDetailView({
|
|
|
1066
1185
|
}
|
|
1067
1186
|
)
|
|
1068
1187
|
] }),
|
|
1069
|
-
/* @__PURE__ */
|
|
1070
|
-
/* @__PURE__ */
|
|
1188
|
+
/* @__PURE__ */ jsx13(Box11, { marginTop: 1, children: /* @__PURE__ */ jsxs10(Text11, { children: [
|
|
1189
|
+
/* @__PURE__ */ jsx13(Text11, { dimColor: true, children: "Recording " }),
|
|
1071
1190
|
title,
|
|
1072
|
-
item.recording?.durationMs ? /* @__PURE__ */
|
|
1191
|
+
item.recording?.durationMs ? /* @__PURE__ */ jsx13(Text11, { dimColor: true, children: ` \xB7 ${formatClockMs(item.recording.durationMs)}` }) : null
|
|
1073
1192
|
] }) }),
|
|
1074
|
-
/* @__PURE__ */
|
|
1075
|
-
/* @__PURE__ */
|
|
1076
|
-
/* @__PURE__ */
|
|
1077
|
-
/* @__PURE__ */
|
|
1078
|
-
/* @__PURE__ */
|
|
1079
|
-
/* @__PURE__ */
|
|
1080
|
-
/* @__PURE__ */
|
|
1081
|
-
/* @__PURE__ */
|
|
1193
|
+
/* @__PURE__ */ jsx13(Box11, { marginTop: 1, borderStyle: "round", borderColor: "gray", paddingX: 1, children: /* @__PURE__ */ jsxs10(Text11, { children: [
|
|
1194
|
+
/* @__PURE__ */ jsx13(Text11, { color: links.webUrl ? "cyan" : "gray", children: "o open" }),
|
|
1195
|
+
/* @__PURE__ */ jsx13(Text11, { dimColor: true, children: " \xB7 " }),
|
|
1196
|
+
/* @__PURE__ */ jsx13(Text11, { color: links.webUrl ? "cyan" : "gray", children: "w web" }),
|
|
1197
|
+
/* @__PURE__ */ jsx13(Text11, { dimColor: true, children: " \xB7 " }),
|
|
1198
|
+
/* @__PURE__ */ jsx13(Text11, { dimColor: true, children: "m mac app (soon)" }),
|
|
1199
|
+
/* @__PURE__ */ jsx13(Text11, { dimColor: true, children: " \xB7 " }),
|
|
1200
|
+
/* @__PURE__ */ jsx13(Text11, { color: links.webUrl ? "cyan" : "gray", children: "c copy" })
|
|
1082
1201
|
] }) }),
|
|
1083
|
-
/* @__PURE__ */
|
|
1202
|
+
/* @__PURE__ */ jsx13(Box11, { marginTop: 1, children: /* @__PURE__ */ jsxs10(Text11, { dimColor: true, children: [
|
|
1084
1203
|
"esc back \xB7 t transcript",
|
|
1085
1204
|
item.transcriptId ? "" : " (when ready)",
|
|
1086
1205
|
" \xB7 q quit"
|
|
@@ -1097,24 +1216,24 @@ function StatusLine({
|
|
|
1097
1216
|
const elapsed = item.startedAt ? ` \xB7 ${formatClockMs(nowMs - item.startedAt)} elapsed` : "";
|
|
1098
1217
|
if (fraction != null) {
|
|
1099
1218
|
const pct = Math.round(fraction * 100);
|
|
1100
|
-
return /* @__PURE__ */
|
|
1219
|
+
return /* @__PURE__ */ jsxs10(Text11, { children: [
|
|
1101
1220
|
`${progressBar(fraction)} ${pct}% ${formatClockMs(item.processedDurationMs)} / ${formatClockMs(
|
|
1102
1221
|
item.recording?.durationMs
|
|
1103
1222
|
)}`,
|
|
1104
|
-
/* @__PURE__ */
|
|
1223
|
+
/* @__PURE__ */ jsx13(Text11, { dimColor: true, children: elapsed })
|
|
1105
1224
|
] });
|
|
1106
1225
|
}
|
|
1107
1226
|
const spinner = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"][spinnerFrame % 10];
|
|
1108
|
-
return /* @__PURE__ */
|
|
1227
|
+
return /* @__PURE__ */ jsxs10(Text11, { children: [
|
|
1109
1228
|
`${spinner} transcribing\u2026`,
|
|
1110
|
-
/* @__PURE__ */
|
|
1229
|
+
/* @__PURE__ */ jsx13(Text11, { dimColor: true, children: elapsed })
|
|
1111
1230
|
] });
|
|
1112
1231
|
}
|
|
1113
1232
|
if (item.status === "succeeded")
|
|
1114
|
-
return /* @__PURE__ */
|
|
1115
|
-
if (item.status === "queued") return /* @__PURE__ */
|
|
1116
|
-
if (item.status === "failed") return /* @__PURE__ */
|
|
1117
|
-
return /* @__PURE__ */
|
|
1233
|
+
return /* @__PURE__ */ jsx13(Text11, { children: item.transcriptId ? "transcript ready" : "done" });
|
|
1234
|
+
if (item.status === "queued") return /* @__PURE__ */ jsx13(Text11, { dimColor: true, children: "waiting to start\u2026" });
|
|
1235
|
+
if (item.status === "failed") return /* @__PURE__ */ jsx13(Text11, { color: "red", children: "transcription failed" });
|
|
1236
|
+
return /* @__PURE__ */ jsx13(Text11, { dimColor: true, children: item.status });
|
|
1118
1237
|
}
|
|
1119
1238
|
function TimelineRow({
|
|
1120
1239
|
label,
|
|
@@ -1127,10 +1246,10 @@ function TimelineRow({
|
|
|
1127
1246
|
const glyph = failed ? "\u2717" : done ? "\u2713" : running ? "\u280B" : "\u25CB";
|
|
1128
1247
|
const color = failed ? "red" : done ? "green" : running ? "cyan" : "gray";
|
|
1129
1248
|
const age = at ? formatAge(at, nowMs) : running ? "now" : "";
|
|
1130
|
-
return /* @__PURE__ */
|
|
1131
|
-
/* @__PURE__ */
|
|
1132
|
-
/* @__PURE__ */
|
|
1133
|
-
age ? /* @__PURE__ */
|
|
1249
|
+
return /* @__PURE__ */ jsxs10(Box11, { children: [
|
|
1250
|
+
/* @__PURE__ */ jsx13(Text11, { color, children: ` ${glyph} ` }),
|
|
1251
|
+
/* @__PURE__ */ jsx13(Text11, { dimColor: !done && !running, children: label }),
|
|
1252
|
+
age ? /* @__PURE__ */ jsx13(Text11, { dimColor: true, children: ` ${age}` }) : null
|
|
1134
1253
|
] });
|
|
1135
1254
|
}
|
|
1136
1255
|
var init_JobDetailView = __esm({
|
|
@@ -1141,9 +1260,9 @@ var init_JobDetailView = __esm({
|
|
|
1141
1260
|
});
|
|
1142
1261
|
|
|
1143
1262
|
// src/tui/RecordingDetailView.tsx
|
|
1144
|
-
import
|
|
1145
|
-
import { Box as
|
|
1146
|
-
import { Fragment as Fragment3, jsx as
|
|
1263
|
+
import React6, { useMemo as useMemo2, useState as useState4 } from "react";
|
|
1264
|
+
import { Box as Box12, Text as Text12, useInput as useInput3 } from "ink";
|
|
1265
|
+
import { Fragment as Fragment3, jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1147
1266
|
function RecordingDetailView({
|
|
1148
1267
|
item,
|
|
1149
1268
|
nowMs,
|
|
@@ -1151,9 +1270,9 @@ function RecordingDetailView({
|
|
|
1151
1270
|
audio
|
|
1152
1271
|
}) {
|
|
1153
1272
|
const size = useTerminalSize();
|
|
1154
|
-
const [tab, setTab] =
|
|
1155
|
-
const [scroll, setScroll] =
|
|
1156
|
-
const [chapterSel, setChapterSel] =
|
|
1273
|
+
const [tab, setTab] = useState4("summary");
|
|
1274
|
+
const [scroll, setScroll] = useState4(0);
|
|
1275
|
+
const [chapterSel, setChapterSel] = useState4(0);
|
|
1157
1276
|
const style = recordingStatusStyle(item.status);
|
|
1158
1277
|
const links = resolveRecordingLinks(item.recordingId, item.origin);
|
|
1159
1278
|
const title = recordingTitle2(item);
|
|
@@ -1206,20 +1325,20 @@ function RecordingDetailView({
|
|
|
1206
1325
|
else if (input === "g") setScroll(0);
|
|
1207
1326
|
else if (input === "G") setScroll(segWin.maxScroll);
|
|
1208
1327
|
});
|
|
1209
|
-
return /* @__PURE__ */
|
|
1210
|
-
/* @__PURE__ */
|
|
1211
|
-
/* @__PURE__ */
|
|
1212
|
-
/* @__PURE__ */
|
|
1213
|
-
/* @__PURE__ */
|
|
1214
|
-
/* @__PURE__ */
|
|
1328
|
+
return /* @__PURE__ */ jsxs11(Box12, { flexDirection: "column", paddingX: 1, children: [
|
|
1329
|
+
/* @__PURE__ */ jsx14(Text12, { dimColor: true, children: "\u2039 Recordings" }),
|
|
1330
|
+
/* @__PURE__ */ jsx14(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx14(Text12, { bold: true, color: "green", children: title }) }),
|
|
1331
|
+
/* @__PURE__ */ jsxs11(Text12, { children: [
|
|
1332
|
+
/* @__PURE__ */ jsx14(Text12, { color: style.color, children: `${style.glyph} ${style.label}` }),
|
|
1333
|
+
/* @__PURE__ */ jsx14(Text12, { dimColor: true, children: ` ${formatAge(item.createdAt, nowMs) || "\u2014"}` })
|
|
1215
1334
|
] }),
|
|
1216
|
-
meta3 ? /* @__PURE__ */
|
|
1217
|
-
/* @__PURE__ */
|
|
1218
|
-
!item.activeTranscriptId ? /* @__PURE__ */
|
|
1219
|
-
/* @__PURE__ */
|
|
1220
|
-
/* @__PURE__ */
|
|
1335
|
+
meta3 ? /* @__PURE__ */ jsx14(Text12, { dimColor: true, children: meta3 }) : null,
|
|
1336
|
+
/* @__PURE__ */ jsx14(AudioActionRow, { item, audio }),
|
|
1337
|
+
!item.activeTranscriptId ? /* @__PURE__ */ jsx14(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx14(Text12, { dimColor: true, children: "Transcript not available yet" }) }) : transcript === "loading" || transcript === void 0 ? /* @__PURE__ */ jsx14(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx14(Text12, { dimColor: true, children: "Loading\u2026" }) }) : transcript === "error" ? /* @__PURE__ */ jsx14(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx14(Text12, { dimColor: true, children: "(transcript unavailable)" }) }) : /* @__PURE__ */ jsxs11(Fragment3, { children: [
|
|
1338
|
+
/* @__PURE__ */ jsx14(TabBar, { active: tab }),
|
|
1339
|
+
/* @__PURE__ */ jsx14(Box12, { marginTop: 1, flexDirection: "column", children: tab === "summary" ? /* @__PURE__ */ jsx14(SummaryPane, { summary, budget: paneBudget }) : tab === "chapters" ? /* @__PURE__ */ jsx14(ChaptersPane, { chapters, win: chapWin, selectedIndex: chapterSel }) : /* @__PURE__ */ jsx14(TranscriptPane, { segments, win: segWin }) })
|
|
1221
1340
|
] }),
|
|
1222
|
-
/* @__PURE__ */
|
|
1341
|
+
/* @__PURE__ */ jsx14(Box12, { marginTop: 1, children: /* @__PURE__ */ jsxs11(Text12, { dimColor: true, children: [
|
|
1223
1342
|
ready ? "tab switch" : "",
|
|
1224
1343
|
ready && tab === "chapters" ? " \xB7 \u2191\u2193 select \xB7 \u23CE jump" : "",
|
|
1225
1344
|
scrollable ? " \xB7 \u2191\u2193 scroll" : "",
|
|
@@ -1232,9 +1351,9 @@ function RecordingDetailView({
|
|
|
1232
1351
|
] });
|
|
1233
1352
|
}
|
|
1234
1353
|
function TabBar({ active }) {
|
|
1235
|
-
return /* @__PURE__ */
|
|
1236
|
-
i > 0 ? /* @__PURE__ */
|
|
1237
|
-
tab === active ? /* @__PURE__ */
|
|
1354
|
+
return /* @__PURE__ */ jsx14(Box12, { marginTop: 1, children: TAB_ORDER.map((tab, i) => /* @__PURE__ */ jsxs11(React6.Fragment, { children: [
|
|
1355
|
+
i > 0 ? /* @__PURE__ */ jsx14(Text12, { dimColor: true, children: " " }) : null,
|
|
1356
|
+
tab === active ? /* @__PURE__ */ jsx14(Text12, { inverse: true, bold: true, children: ` ${TAB_LABEL[tab]} ` }) : /* @__PURE__ */ jsx14(Text12, { dimColor: true, children: ` ${TAB_LABEL[tab]} ` })
|
|
1238
1357
|
] }, tab)) });
|
|
1239
1358
|
}
|
|
1240
1359
|
function AudioActionRow({
|
|
@@ -1245,30 +1364,30 @@ function AudioActionRow({
|
|
|
1245
1364
|
const status = audio?.status ?? "idle";
|
|
1246
1365
|
let line;
|
|
1247
1366
|
if (!ready) {
|
|
1248
|
-
line = /* @__PURE__ */
|
|
1367
|
+
line = /* @__PURE__ */ jsx14(Text12, { dimColor: true, children: "Audio available once the recording is ready" });
|
|
1249
1368
|
} else if (status === "downloading") {
|
|
1250
|
-
line = /* @__PURE__ */
|
|
1369
|
+
line = /* @__PURE__ */ jsx14(Text12, { color: "cyan", children: "Downloading audio\u2026" });
|
|
1251
1370
|
} else if (status === "opening") {
|
|
1252
|
-
line = /* @__PURE__ */
|
|
1371
|
+
line = /* @__PURE__ */ jsx14(Text12, { color: "cyan", children: "Opening\u2026" });
|
|
1253
1372
|
} else if (status === "error") {
|
|
1254
|
-
line = /* @__PURE__ */
|
|
1373
|
+
line = /* @__PURE__ */ jsx14(Text12, { color: "red", children: audio?.error ? `Audio failed: ${audio.error}` : "Audio failed" });
|
|
1255
1374
|
} else if (status === "ready" && audio?.localPath) {
|
|
1256
|
-
line = /* @__PURE__ */
|
|
1257
|
-
/* @__PURE__ */
|
|
1258
|
-
/* @__PURE__ */
|
|
1375
|
+
line = /* @__PURE__ */ jsxs11(Text12, { children: [
|
|
1376
|
+
/* @__PURE__ */ jsx14(Text12, { color: "green", children: "\u2713 Downloaded " }),
|
|
1377
|
+
/* @__PURE__ */ jsx14(Text12, { dimColor: true, wrap: "truncate-middle", children: audio.localPath })
|
|
1259
1378
|
] });
|
|
1260
1379
|
} else {
|
|
1261
|
-
line = /* @__PURE__ */
|
|
1262
|
-
/* @__PURE__ */
|
|
1263
|
-
/* @__PURE__ */
|
|
1264
|
-
/* @__PURE__ */
|
|
1265
|
-
/* @__PURE__ */
|
|
1266
|
-
/* @__PURE__ */
|
|
1267
|
-
/* @__PURE__ */
|
|
1380
|
+
line = /* @__PURE__ */ jsxs11(Text12, { children: [
|
|
1381
|
+
/* @__PURE__ */ jsx14(Text12, { color: "cyan", children: "o" }),
|
|
1382
|
+
/* @__PURE__ */ jsx14(Text12, { dimColor: true, children: " open in player \xB7 " }),
|
|
1383
|
+
/* @__PURE__ */ jsx14(Text12, { color: "cyan", children: "d" }),
|
|
1384
|
+
/* @__PURE__ */ jsx14(Text12, { dimColor: true, children: " download \xB7 " }),
|
|
1385
|
+
/* @__PURE__ */ jsx14(Text12, { color: "cyan", children: "f" }),
|
|
1386
|
+
/* @__PURE__ */ jsx14(Text12, { dimColor: true, children: " reveal in Finder" })
|
|
1268
1387
|
] });
|
|
1269
1388
|
}
|
|
1270
|
-
return /* @__PURE__ */
|
|
1271
|
-
/* @__PURE__ */
|
|
1389
|
+
return /* @__PURE__ */ jsxs11(Box12, { marginTop: 1, borderStyle: "round", borderColor: "gray", paddingX: 1, children: [
|
|
1390
|
+
/* @__PURE__ */ jsx14(Text12, { color: ready ? "cyan" : "gray", children: "\u266A " }),
|
|
1272
1391
|
line
|
|
1273
1392
|
] });
|
|
1274
1393
|
}
|
|
@@ -1277,12 +1396,12 @@ function SummaryPane({
|
|
|
1277
1396
|
budget
|
|
1278
1397
|
}) {
|
|
1279
1398
|
if (!summary || summary.status !== "succeeded" || !summary.tldr) {
|
|
1280
|
-
return /* @__PURE__ */
|
|
1399
|
+
return /* @__PURE__ */ jsx14(Text12, { dimColor: true, children: `Summary ${summary?.status ?? "unavailable"}` });
|
|
1281
1400
|
}
|
|
1282
1401
|
const points = (summary.keyPoints ?? []).slice(0, Math.max(1, budget - 4));
|
|
1283
|
-
return /* @__PURE__ */
|
|
1284
|
-
/* @__PURE__ */
|
|
1285
|
-
points.length > 0 ? /* @__PURE__ */
|
|
1402
|
+
return /* @__PURE__ */ jsxs11(Fragment3, { children: [
|
|
1403
|
+
/* @__PURE__ */ jsx14(Text12, { children: summary.tldr }),
|
|
1404
|
+
points.length > 0 ? /* @__PURE__ */ jsx14(Box12, { marginTop: 1, flexDirection: "column", children: points.map((point, i) => /* @__PURE__ */ jsx14(Text12, { dimColor: true, children: `\u2022 ${point}` }, i)) }) : null
|
|
1286
1405
|
] });
|
|
1287
1406
|
}
|
|
1288
1407
|
function ChaptersPane({
|
|
@@ -1290,32 +1409,32 @@ function ChaptersPane({
|
|
|
1290
1409
|
win,
|
|
1291
1410
|
selectedIndex
|
|
1292
1411
|
}) {
|
|
1293
|
-
if (chapters.length === 0) return /* @__PURE__ */
|
|
1294
|
-
return /* @__PURE__ */
|
|
1412
|
+
if (chapters.length === 0) return /* @__PURE__ */ jsx14(Text12, { dimColor: true, children: "No chapters" });
|
|
1413
|
+
return /* @__PURE__ */ jsxs11(Fragment3, { children: [
|
|
1295
1414
|
chapters.slice(win.start, win.end).map((chapter, i) => {
|
|
1296
1415
|
const index = win.start + i;
|
|
1297
1416
|
const selected = index === selectedIndex;
|
|
1298
|
-
return /* @__PURE__ */
|
|
1299
|
-
/* @__PURE__ */
|
|
1300
|
-
/* @__PURE__ */
|
|
1301
|
-
/* @__PURE__ */
|
|
1417
|
+
return /* @__PURE__ */ jsxs11(Text12, { wrap: "truncate-end", children: [
|
|
1418
|
+
/* @__PURE__ */ jsx14(Text12, { color: "cyan", children: selected ? "\u25B8 " : " " }),
|
|
1419
|
+
/* @__PURE__ */ jsx14(Text12, { color: "blue", children: `[${formatClockMs(chapter.startMs)}] ` }),
|
|
1420
|
+
/* @__PURE__ */ jsx14(Text12, { bold: selected, children: chapter.title })
|
|
1302
1421
|
] }, index);
|
|
1303
1422
|
}),
|
|
1304
|
-
win.end < chapters.length || win.start > 0 ? /* @__PURE__ */
|
|
1423
|
+
win.end < chapters.length || win.start > 0 ? /* @__PURE__ */ jsx14(Text12, { dimColor: true, children: ` ${selectedIndex + 1} / ${chapters.length}` }) : null
|
|
1305
1424
|
] });
|
|
1306
1425
|
}
|
|
1307
1426
|
function TranscriptPane({
|
|
1308
1427
|
segments,
|
|
1309
1428
|
win
|
|
1310
1429
|
}) {
|
|
1311
|
-
if (segments.length === 0) return /* @__PURE__ */
|
|
1312
|
-
return /* @__PURE__ */
|
|
1313
|
-
segments.slice(win.start, win.end).map((seg, i) => /* @__PURE__ */
|
|
1314
|
-
/* @__PURE__ */
|
|
1315
|
-
seg.speaker ? /* @__PURE__ */
|
|
1316
|
-
/* @__PURE__ */
|
|
1430
|
+
if (segments.length === 0) return /* @__PURE__ */ jsx14(Text12, { dimColor: true, children: "(no segments)" });
|
|
1431
|
+
return /* @__PURE__ */ jsxs11(Fragment3, { children: [
|
|
1432
|
+
segments.slice(win.start, win.end).map((seg, i) => /* @__PURE__ */ jsxs11(Text12, { children: [
|
|
1433
|
+
/* @__PURE__ */ jsx14(Text12, { color: "blue", children: `[${formatClockMs(seg.startMs)}] ` }),
|
|
1434
|
+
seg.speaker ? /* @__PURE__ */ jsx14(Text12, { dimColor: true, children: `${seg.speaker} ` }) : null,
|
|
1435
|
+
/* @__PURE__ */ jsx14(Text12, { children: seg.text })
|
|
1317
1436
|
] }, win.start + i)),
|
|
1318
|
-
win.maxScroll > 0 ? /* @__PURE__ */
|
|
1437
|
+
win.maxScroll > 0 ? /* @__PURE__ */ jsx14(Text12, { dimColor: true, children: ` ${win.start + 1}\u2013${win.end} / ${segments.length}` }) : null
|
|
1319
1438
|
] });
|
|
1320
1439
|
}
|
|
1321
1440
|
var TAB_ORDER, TAB_LABEL;
|
|
@@ -1335,12 +1454,12 @@ var init_RecordingDetailView = __esm({
|
|
|
1335
1454
|
});
|
|
1336
1455
|
|
|
1337
1456
|
// src/tui/TranscriptView.tsx
|
|
1338
|
-
import { useMemo as useMemo3, useState as
|
|
1339
|
-
import { Box as
|
|
1340
|
-
import { jsx as
|
|
1457
|
+
import { useMemo as useMemo3, useState as useState5 } from "react";
|
|
1458
|
+
import { Box as Box13, Text as Text13, useInput as useInput4 } from "ink";
|
|
1459
|
+
import { jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1341
1460
|
function TranscriptView({ loading, data, error: error51 }) {
|
|
1342
1461
|
const size = useTerminalSize();
|
|
1343
|
-
const [scroll, setScroll] =
|
|
1462
|
+
const [scroll, setScroll] = useState5(0);
|
|
1344
1463
|
const segments = data?.segments ?? [];
|
|
1345
1464
|
const innerWidth = Math.max(10, size.columns - 2);
|
|
1346
1465
|
const heights = useMemo3(
|
|
@@ -1362,42 +1481,42 @@ function TranscriptView({ loading, data, error: error51 }) {
|
|
|
1362
1481
|
else if (input === "G") setScroll(win.maxScroll);
|
|
1363
1482
|
});
|
|
1364
1483
|
if (loading) {
|
|
1365
|
-
return /* @__PURE__ */
|
|
1484
|
+
return /* @__PURE__ */ jsx15(Box13, { paddingX: 1, children: /* @__PURE__ */ jsx15(Text13, { dimColor: true, children: "Loading transcript\u2026" }) });
|
|
1366
1485
|
}
|
|
1367
1486
|
if (error51) {
|
|
1368
|
-
return /* @__PURE__ */
|
|
1369
|
-
/* @__PURE__ */
|
|
1487
|
+
return /* @__PURE__ */ jsxs12(Box13, { flexDirection: "column", paddingX: 1, children: [
|
|
1488
|
+
/* @__PURE__ */ jsxs12(Text13, { color: "red", children: [
|
|
1370
1489
|
"! ",
|
|
1371
1490
|
error51
|
|
1372
1491
|
] }),
|
|
1373
|
-
/* @__PURE__ */
|
|
1492
|
+
/* @__PURE__ */ jsx15(Text13, { dimColor: true, children: "q / esc / \u2190 back" })
|
|
1374
1493
|
] });
|
|
1375
1494
|
}
|
|
1376
1495
|
if (!data) {
|
|
1377
|
-
return /* @__PURE__ */
|
|
1496
|
+
return /* @__PURE__ */ jsx15(Box13, { paddingX: 1, children: /* @__PURE__ */ jsx15(Text13, { dimColor: true, children: "No transcript." }) });
|
|
1378
1497
|
}
|
|
1379
1498
|
const title = data.summary?.title ?? "Transcript";
|
|
1380
1499
|
const total = segments.length;
|
|
1381
1500
|
const more = win.maxScroll > 0;
|
|
1382
1501
|
const position = total === 0 ? "" : `${win.start + 1}\u2013${win.end} / ${total}`;
|
|
1383
|
-
return /* @__PURE__ */
|
|
1384
|
-
/* @__PURE__ */
|
|
1502
|
+
return /* @__PURE__ */ jsxs12(Box13, { flexDirection: "column", paddingX: 1, children: [
|
|
1503
|
+
/* @__PURE__ */ jsxs12(Text13, { bold: true, color: "green", children: [
|
|
1385
1504
|
title,
|
|
1386
|
-
more ? /* @__PURE__ */
|
|
1505
|
+
more ? /* @__PURE__ */ jsx15(Text13, { dimColor: true, children: ` ${position}` }) : null
|
|
1387
1506
|
] }),
|
|
1388
|
-
/* @__PURE__ */
|
|
1389
|
-
/* @__PURE__ */
|
|
1507
|
+
/* @__PURE__ */ jsx15(Box13, { marginTop: 1, flexDirection: "column", children: total === 0 ? /* @__PURE__ */ jsx15(Text13, { children: data.text }) : segments.slice(win.start, win.end).map((segment, index) => /* @__PURE__ */ jsxs12(Text13, { children: [
|
|
1508
|
+
/* @__PURE__ */ jsxs12(Text13, { dimColor: true, children: [
|
|
1390
1509
|
"[",
|
|
1391
1510
|
formatClockMs(segment.startMs),
|
|
1392
1511
|
"] "
|
|
1393
1512
|
] }),
|
|
1394
|
-
segment.speaker ? /* @__PURE__ */
|
|
1513
|
+
segment.speaker ? /* @__PURE__ */ jsxs12(Text13, { color: "cyan", children: [
|
|
1395
1514
|
segment.speaker,
|
|
1396
1515
|
": "
|
|
1397
1516
|
] }) : null,
|
|
1398
1517
|
segment.text
|
|
1399
1518
|
] }, win.start + index)) }),
|
|
1400
|
-
/* @__PURE__ */
|
|
1519
|
+
/* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsxs12(Text13, { dimColor: true, children: [
|
|
1401
1520
|
more ? "\u2191\u2193 scroll \xB7 PgUp/PgDn \xB7 g/G top/bottom \xB7 " : "",
|
|
1402
1521
|
"q / esc / \u2190 back"
|
|
1403
1522
|
] }) })
|
|
@@ -1412,8 +1531,8 @@ var init_TranscriptView = __esm({
|
|
|
1412
1531
|
});
|
|
1413
1532
|
|
|
1414
1533
|
// src/tui/PermissionPreflightView.tsx
|
|
1415
|
-
import { Box as
|
|
1416
|
-
import { jsx as
|
|
1534
|
+
import { Box as Box14, Text as Text14 } from "ink";
|
|
1535
|
+
import { jsx as jsx16, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1417
1536
|
function statusGlyph2(status) {
|
|
1418
1537
|
switch (status) {
|
|
1419
1538
|
case "granted":
|
|
@@ -1429,41 +1548,41 @@ function PermissionPreflightView({
|
|
|
1429
1548
|
}) {
|
|
1430
1549
|
const allGranted = items.length > 0 && items.every((item) => item.status === "granted" && !item.requiresProcessRestart);
|
|
1431
1550
|
const hasRestartRequired = items.some((item) => item.requiresProcessRestart);
|
|
1432
|
-
return /* @__PURE__ */
|
|
1433
|
-
/* @__PURE__ */
|
|
1434
|
-
/* @__PURE__ */
|
|
1435
|
-
/* @__PURE__ */
|
|
1551
|
+
return /* @__PURE__ */ jsxs13(Box14, { flexDirection: "column", paddingX: 1, children: [
|
|
1552
|
+
/* @__PURE__ */ jsxs13(Text14, { children: [
|
|
1553
|
+
/* @__PURE__ */ jsx16(Text14, { dimColor: true, children: "\u2039 " }),
|
|
1554
|
+
/* @__PURE__ */ jsx16(Text14, { bold: true, color: "cyan", children: "Recording permissions" })
|
|
1436
1555
|
] }),
|
|
1437
|
-
/* @__PURE__ */
|
|
1556
|
+
/* @__PURE__ */ jsx16(Box14, { marginTop: 1, flexDirection: "column", children: items.length === 0 ? /* @__PURE__ */ jsx16(Text14, { dimColor: true, children: "Checking permissions\u2026" }) : items.map((item) => {
|
|
1438
1557
|
const status = statusGlyph2(item.status);
|
|
1439
1558
|
const restart = item.requiresProcessRestart === true;
|
|
1440
1559
|
const color = restart ? "yellow" : status.color;
|
|
1441
1560
|
const hint = restart ? item.hint ?? `${item.name} enabled. Run recappi record again to start.` : item.status === "granted" ? void 0 : item.hint ?? DEFAULT_HINTS[item.name];
|
|
1442
|
-
return /* @__PURE__ */
|
|
1443
|
-
/* @__PURE__ */
|
|
1444
|
-
/* @__PURE__ */
|
|
1445
|
-
/* @__PURE__ */
|
|
1446
|
-
/* @__PURE__ */
|
|
1561
|
+
return /* @__PURE__ */ jsxs13(Box14, { flexDirection: "column", children: [
|
|
1562
|
+
/* @__PURE__ */ jsxs13(Text14, { children: [
|
|
1563
|
+
/* @__PURE__ */ jsx16(Text14, { bold: true, color, children: status.glyph }),
|
|
1564
|
+
/* @__PURE__ */ jsx16(Text14, { bold: true, children: ` ${item.name}` }),
|
|
1565
|
+
/* @__PURE__ */ jsx16(Text14, { color, children: ` ${status.label}` })
|
|
1447
1566
|
] }),
|
|
1448
|
-
hint ? /* @__PURE__ */
|
|
1567
|
+
hint ? /* @__PURE__ */ jsx16(Text14, { dimColor: true, children: ` ${hint}` }) : null
|
|
1449
1568
|
] }, item.name);
|
|
1450
1569
|
}) }),
|
|
1451
|
-
/* @__PURE__ */
|
|
1452
|
-
/* @__PURE__ */
|
|
1453
|
-
/* @__PURE__ */
|
|
1454
|
-
/* @__PURE__ */
|
|
1455
|
-
] }) : /* @__PURE__ */
|
|
1456
|
-
/* @__PURE__ */
|
|
1457
|
-
/* @__PURE__ */
|
|
1458
|
-
/* @__PURE__ */
|
|
1570
|
+
/* @__PURE__ */ jsx16(Box14, { marginTop: 1, children: allGranted ? /* @__PURE__ */ jsx16(Text14, { bold: true, color: "green", children: "\u2713 All set \u2014 ready to record." }) : hasRestartRequired ? /* @__PURE__ */ jsxs13(Text14, { children: [
|
|
1571
|
+
/* @__PURE__ */ jsx16(Text14, { dimColor: true, children: "Run recappi record again to start, or press " }),
|
|
1572
|
+
/* @__PURE__ */ jsx16(Text14, { bold: true, color: "cyan", children: "r" }),
|
|
1573
|
+
/* @__PURE__ */ jsx16(Text14, { dimColor: true, children: " to retry." })
|
|
1574
|
+
] }) : /* @__PURE__ */ jsxs13(Text14, { children: [
|
|
1575
|
+
/* @__PURE__ */ jsx16(Text14, { dimColor: true, children: "Grant the permissions above, then press " }),
|
|
1576
|
+
/* @__PURE__ */ jsx16(Text14, { bold: true, color: "cyan", children: "r" }),
|
|
1577
|
+
/* @__PURE__ */ jsx16(Text14, { dimColor: true, children: " to recheck." })
|
|
1459
1578
|
] }) }),
|
|
1460
|
-
/* @__PURE__ */
|
|
1461
|
-
/* @__PURE__ */
|
|
1462
|
-
/* @__PURE__ */
|
|
1463
|
-
/* @__PURE__ */
|
|
1464
|
-
/* @__PURE__ */
|
|
1465
|
-
/* @__PURE__ */
|
|
1466
|
-
/* @__PURE__ */
|
|
1579
|
+
/* @__PURE__ */ jsx16(Box14, { marginTop: 1, children: /* @__PURE__ */ jsxs13(Text14, { children: [
|
|
1580
|
+
/* @__PURE__ */ jsx16(Text14, { color: "cyan", children: "r" }),
|
|
1581
|
+
/* @__PURE__ */ jsx16(Text14, { dimColor: true, children: " recheck \xB7 " }),
|
|
1582
|
+
/* @__PURE__ */ jsx16(Text14, { color: "cyan", children: "o" }),
|
|
1583
|
+
/* @__PURE__ */ jsx16(Text14, { dimColor: true, children: " open System Settings \xB7 " }),
|
|
1584
|
+
/* @__PURE__ */ jsx16(Text14, { color: "cyan", children: "esc" }),
|
|
1585
|
+
/* @__PURE__ */ jsx16(Text14, { dimColor: true, children: " back" })
|
|
1467
1586
|
] }) })
|
|
1468
1587
|
] });
|
|
1469
1588
|
}
|
|
@@ -1479,21 +1598,21 @@ var init_PermissionPreflightView = __esm({
|
|
|
1479
1598
|
});
|
|
1480
1599
|
|
|
1481
1600
|
// src/tui/RecordSetupView.tsx
|
|
1482
|
-
import { useState as
|
|
1483
|
-
import { Box as
|
|
1484
|
-
import { jsx as
|
|
1601
|
+
import { useState as useState6 } from "react";
|
|
1602
|
+
import { Box as Box15, Text as Text15, useInput as useInput5 } from "ink";
|
|
1603
|
+
import { jsx as jsx17, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1485
1604
|
function RecordSetupView({
|
|
1486
1605
|
model,
|
|
1487
1606
|
onStart,
|
|
1488
1607
|
onCancel
|
|
1489
1608
|
}) {
|
|
1490
1609
|
const size = useTerminalSize();
|
|
1491
|
-
const [srcIdx, setSrcIdx] =
|
|
1492
|
-
const [includeMic, setIncludeMic] =
|
|
1493
|
-
const [micIdx, setMicIdx] =
|
|
1610
|
+
const [srcIdx, setSrcIdx] = useState6(0);
|
|
1611
|
+
const [includeMic, setIncludeMic] = useState6(true);
|
|
1612
|
+
const [micIdx, setMicIdx] = useState6(
|
|
1494
1613
|
() => Math.max(0, model.microphones?.findIndex((device) => device.isDefault) ?? 0)
|
|
1495
1614
|
);
|
|
1496
|
-
const [sceneIdx, setSceneIdx] =
|
|
1615
|
+
const [sceneIdx, setSceneIdx] = useState6(0);
|
|
1497
1616
|
const sources = model.sources;
|
|
1498
1617
|
const microphones = model.microphones ?? [];
|
|
1499
1618
|
const selected = sources[Math.min(srcIdx, Math.max(0, sources.length - 1))];
|
|
@@ -1518,21 +1637,21 @@ function RecordSetupView({
|
|
|
1518
1637
|
});
|
|
1519
1638
|
} else if (key.escape) onCancel();
|
|
1520
1639
|
});
|
|
1521
|
-
const sourceList = /* @__PURE__ */
|
|
1522
|
-
/* @__PURE__ */
|
|
1640
|
+
const sourceList = /* @__PURE__ */ jsxs14(Box15, { flexDirection: "column", children: [
|
|
1641
|
+
/* @__PURE__ */ jsx17(Text15, { dimColor: true, children: "SOURCE" }),
|
|
1523
1642
|
sources.map((s, i) => {
|
|
1524
1643
|
const on = i === srcIdx;
|
|
1525
|
-
return /* @__PURE__ */
|
|
1644
|
+
return /* @__PURE__ */ jsxs14(Text15, { color: on ? "cyan" : void 0, wrap: "truncate-end", children: [
|
|
1526
1645
|
on ? "\u25B8 \u25CF " : " \u25CB ",
|
|
1527
1646
|
s.label
|
|
1528
1647
|
] }, s.id);
|
|
1529
1648
|
}),
|
|
1530
|
-
!hasAppSource ? /* @__PURE__ */
|
|
1649
|
+
!hasAppSource ? /* @__PURE__ */ jsx17(Text15, { dimColor: true, children: "No app-specific sources available right now" }) : null
|
|
1531
1650
|
] });
|
|
1532
|
-
const capturePlan = /* @__PURE__ */
|
|
1533
|
-
/* @__PURE__ */
|
|
1534
|
-
/* @__PURE__ */
|
|
1535
|
-
/* @__PURE__ */
|
|
1651
|
+
const capturePlan = /* @__PURE__ */ jsxs14(Box15, { flexDirection: "column", children: [
|
|
1652
|
+
/* @__PURE__ */ jsx17(Text15, { dimColor: true, children: "CAPTURE PLAN" }),
|
|
1653
|
+
/* @__PURE__ */ jsx17(Text15, { children: includeMic ? `${selected?.label ?? "System audio"} + microphone` : `${selected?.label ?? "System audio"} only` }),
|
|
1654
|
+
/* @__PURE__ */ jsx17(Text15, { dimColor: true, children: includeMic ? "Mic is mixed into the recording" : "Mic stays muted" })
|
|
1536
1655
|
] });
|
|
1537
1656
|
const shortcuts = [
|
|
1538
1657
|
hasMultipleSources ? "\u2191\u2193 source" : void 0,
|
|
@@ -1542,31 +1661,31 @@ function RecordSetupView({
|
|
|
1542
1661
|
"\u23CE start recording",
|
|
1543
1662
|
"esc cancel"
|
|
1544
1663
|
].filter(Boolean).join(" \xB7 ");
|
|
1545
|
-
return /* @__PURE__ */
|
|
1546
|
-
/* @__PURE__ */
|
|
1547
|
-
/* @__PURE__ */
|
|
1548
|
-
/* @__PURE__ */
|
|
1549
|
-
/* @__PURE__ */
|
|
1664
|
+
return /* @__PURE__ */ jsxs14(Box15, { flexDirection: "column", paddingX: 1, children: [
|
|
1665
|
+
/* @__PURE__ */ jsx17(Text15, { bold: true, color: "green", children: "New recording" }),
|
|
1666
|
+
/* @__PURE__ */ jsxs14(Box15, { marginTop: 1, flexDirection: wide ? "row" : "column", children: [
|
|
1667
|
+
/* @__PURE__ */ jsx17(Box15, { flexGrow: 1, flexDirection: "column", children: sourceList }),
|
|
1668
|
+
/* @__PURE__ */ jsx17(Box15, { marginLeft: wide ? 4 : 0, marginTop: wide ? 0 : 1, children: capturePlan })
|
|
1550
1669
|
] }),
|
|
1551
|
-
/* @__PURE__ */
|
|
1552
|
-
/* @__PURE__ */
|
|
1553
|
-
/* @__PURE__ */
|
|
1554
|
-
/* @__PURE__ */
|
|
1555
|
-
/* @__PURE__ */
|
|
1670
|
+
/* @__PURE__ */ jsxs14(Box15, { marginTop: 1, flexDirection: "column", children: [
|
|
1671
|
+
/* @__PURE__ */ jsxs14(Text15, { children: [
|
|
1672
|
+
/* @__PURE__ */ jsx17(Text15, { dimColor: true, children: "Microphone " }),
|
|
1673
|
+
/* @__PURE__ */ jsx17(Text15, { color: includeMic ? "green" : "gray", children: includeMic ? "[x] include mic" : "[ ] include mic" }),
|
|
1674
|
+
/* @__PURE__ */ jsx17(Text15, { dimColor: true, children: " (space)" })
|
|
1556
1675
|
] }),
|
|
1557
|
-
selectedMic ? /* @__PURE__ */
|
|
1558
|
-
/* @__PURE__ */
|
|
1559
|
-
/* @__PURE__ */
|
|
1560
|
-
selectedMic.isDefault ? /* @__PURE__ */
|
|
1561
|
-
includeMic && hasMultipleMicrophones ? /* @__PURE__ */
|
|
1676
|
+
selectedMic ? /* @__PURE__ */ jsxs14(Text15, { dimColor: !includeMic, children: [
|
|
1677
|
+
/* @__PURE__ */ jsx17(Text15, { dimColor: true, children: "Mic device " }),
|
|
1678
|
+
/* @__PURE__ */ jsx17(Text15, { children: selectedMic.label }),
|
|
1679
|
+
selectedMic.isDefault ? /* @__PURE__ */ jsx17(Text15, { dimColor: true, children: " \xB7 default" }) : null,
|
|
1680
|
+
includeMic && hasMultipleMicrophones ? /* @__PURE__ */ jsx17(Text15, { dimColor: true, children: " (m to change)" }) : null
|
|
1562
1681
|
] }) : null,
|
|
1563
|
-
model.scenes.length > 0 ? /* @__PURE__ */
|
|
1564
|
-
/* @__PURE__ */
|
|
1565
|
-
/* @__PURE__ */
|
|
1566
|
-
model.scenes.length > 1 ? /* @__PURE__ */
|
|
1682
|
+
model.scenes.length > 0 ? /* @__PURE__ */ jsxs14(Text15, { children: [
|
|
1683
|
+
/* @__PURE__ */ jsx17(Text15, { dimColor: true, children: "Scene " }),
|
|
1684
|
+
/* @__PURE__ */ jsx17(Text15, { children: model.scenes[sceneIdx]?.label ?? "Default" }),
|
|
1685
|
+
model.scenes.length > 1 ? /* @__PURE__ */ jsx17(Text15, { dimColor: true, children: " (s to change)" }) : null
|
|
1567
1686
|
] }) : null
|
|
1568
1687
|
] }),
|
|
1569
|
-
/* @__PURE__ */
|
|
1688
|
+
/* @__PURE__ */ jsx17(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx17(Text15, { dimColor: true, children: shortcuts }) })
|
|
1570
1689
|
] });
|
|
1571
1690
|
}
|
|
1572
1691
|
var init_RecordSetupView = __esm({
|
|
@@ -1576,125 +1695,6 @@ var init_RecordSetupView = __esm({
|
|
|
1576
1695
|
}
|
|
1577
1696
|
});
|
|
1578
1697
|
|
|
1579
|
-
// src/tui/RecordingHeroScreen.tsx
|
|
1580
|
-
import { useEffect as useEffect2, useState as useState6 } from "react";
|
|
1581
|
-
import { Box as Box15, Text as Text15 } from "ink";
|
|
1582
|
-
import { jsx as jsx17, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1583
|
-
function waveform(samples, width) {
|
|
1584
|
-
if (width <= 0) return "";
|
|
1585
|
-
const tail = samples.slice(-width);
|
|
1586
|
-
const pad = width - tail.length;
|
|
1587
|
-
const cells = tail.map((v) => {
|
|
1588
|
-
const i = Math.max(0, Math.min(BLOCKS.length - 1, Math.round(Math.max(0, Math.min(1, v)) * (BLOCKS.length - 1))));
|
|
1589
|
-
return BLOCKS[i];
|
|
1590
|
-
});
|
|
1591
|
-
return "\u2581".repeat(Math.max(0, pad)) + cells.join("");
|
|
1592
|
-
}
|
|
1593
|
-
function RecordingHeroScreen({
|
|
1594
|
-
telemetry,
|
|
1595
|
-
artifact,
|
|
1596
|
-
canTranscribe = false,
|
|
1597
|
-
canPause = false,
|
|
1598
|
-
now = () => Date.now()
|
|
1599
|
-
}) {
|
|
1600
|
-
const size = useTerminalSize();
|
|
1601
|
-
const [tick, setTick] = useState6(() => now());
|
|
1602
|
-
const [wave, setWave] = useState6([]);
|
|
1603
|
-
useEffect2(() => {
|
|
1604
|
-
if (telemetry.level == null) return;
|
|
1605
|
-
const lvl = Math.max(telemetry.level.system ?? 0, telemetry.level.mic ?? 0);
|
|
1606
|
-
setWave((w) => [...w.slice(-512), lvl]);
|
|
1607
|
-
}, [telemetry.level]);
|
|
1608
|
-
useEffect2(() => {
|
|
1609
|
-
const id = setInterval(() => setTick(now()), 1e3);
|
|
1610
|
-
return () => clearInterval(id);
|
|
1611
|
-
}, []);
|
|
1612
|
-
const elapsed = telemetry.startedAtMs != null ? formatClockMs(Math.max(0, tick - telemetry.startedAtMs)) : "00:00";
|
|
1613
|
-
const innerWidth = Math.max(10, size.columns - 4);
|
|
1614
|
-
if (telemetry.status === "stopped") {
|
|
1615
|
-
const handoff = stoppedHandoffCopy(artifact, canTranscribe);
|
|
1616
|
-
const meta3 = [
|
|
1617
|
-
telemetry.durationMs != null ? formatClockMs(telemetry.durationMs) : null,
|
|
1618
|
-
formatBytes2(telemetry.sizeBytes) || null
|
|
1619
|
-
].filter(Boolean).join(" \xB7 ");
|
|
1620
|
-
return /* @__PURE__ */ jsxs14(Box15, { flexDirection: "column", paddingX: 1, children: [
|
|
1621
|
-
/* @__PURE__ */ jsx17(Text15, { dimColor: true, children: "recappi \xB7 Recording" }),
|
|
1622
|
-
/* @__PURE__ */ jsxs14(Box15, { marginTop: 1, flexDirection: "column", children: [
|
|
1623
|
-
/* @__PURE__ */ jsx17(Text15, { color: "green", children: "\u2713 Saved to your Mac" }),
|
|
1624
|
-
meta3 ? /* @__PURE__ */ jsx17(Text15, { dimColor: true, children: meta3 }) : null,
|
|
1625
|
-
telemetry.savedPath ? /* @__PURE__ */ jsx17(Text15, { dimColor: true, wrap: "truncate-middle", children: telemetry.savedPath }) : null
|
|
1626
|
-
] }),
|
|
1627
|
-
/* @__PURE__ */ jsxs14(Box15, { marginTop: 1, flexDirection: "column", children: [
|
|
1628
|
-
/* @__PURE__ */ jsx17(Text15, { color: handoff.tone === "red" ? "red" : handoff.tone === "green" ? "green" : void 0, dimColor: handoff.tone === "dim", children: handoff.text }),
|
|
1629
|
-
artifact?.error ? /* @__PURE__ */ jsx17(Text15, { color: "red", wrap: "truncate-end", children: artifact.error }) : null
|
|
1630
|
-
] })
|
|
1631
|
-
] });
|
|
1632
|
-
}
|
|
1633
|
-
if (telemetry.status === "error") {
|
|
1634
|
-
return /* @__PURE__ */ jsxs14(Box15, { flexDirection: "column", paddingX: 1, children: [
|
|
1635
|
-
/* @__PURE__ */ jsx17(Text15, { dimColor: true, children: "recappi \xB7 Recording" }),
|
|
1636
|
-
/* @__PURE__ */ jsx17(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx17(Text15, { color: "red", children: telemetry.error ? `Recording error: ${telemetry.error}` : "Recording error" }) }),
|
|
1637
|
-
/* @__PURE__ */ jsx17(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx17(Text15, { dimColor: true, children: "esc back" }) })
|
|
1638
|
-
] });
|
|
1639
|
-
}
|
|
1640
|
-
const paused = telemetry.status === "paused";
|
|
1641
|
-
const starting = telemetry.status === "starting" || telemetry.status === "stopping";
|
|
1642
|
-
const badge = paused ? "\u23F8 PAUSED" : starting ? "\u2026" : "\u23FA REC";
|
|
1643
|
-
return /* @__PURE__ */ jsxs14(Box15, { flexDirection: "column", paddingX: 1, height: size.rows, children: [
|
|
1644
|
-
/* @__PURE__ */ jsxs14(Text15, { children: [
|
|
1645
|
-
/* @__PURE__ */ jsx17(Text15, { bold: true, color: "green", children: "recappi" }),
|
|
1646
|
-
/* @__PURE__ */ jsx17(Text15, { dimColor: true, children: " \xB7 Recording" })
|
|
1647
|
-
] }),
|
|
1648
|
-
/* @__PURE__ */ jsxs14(Box15, { flexGrow: 1, flexDirection: "column", justifyContent: "center", alignItems: "center", children: [
|
|
1649
|
-
/* @__PURE__ */ jsx17(Text15, { bold: true, color: paused ? "yellow" : "red", children: badge }),
|
|
1650
|
-
/* @__PURE__ */ jsx17(Text15, { bold: true, children: elapsed }),
|
|
1651
|
-
/* @__PURE__ */ jsx17(Box15, { marginTop: 1, children: telemetry.level == null ? (
|
|
1652
|
-
// No level telemetry yet — show honest activity, not a flat meter that
|
|
1653
|
-
// looks like silence (the elapsed timer above proves it's live).
|
|
1654
|
-
/* @__PURE__ */ jsx17(Text15, { dimColor: true, children: paused ? "Paused" : `Capturing audio${".".repeat(Math.floor(tick / 1e3) % 3 + 1)}` })
|
|
1655
|
-
) : /* @__PURE__ */ jsx17(Text15, { color: paused ? "gray" : "red", children: waveform(wave, innerWidth) }) }),
|
|
1656
|
-
/* @__PURE__ */ jsx17(Box15, { marginTop: 1, children: /* @__PURE__ */ jsxs14(Text15, { dimColor: true, children: [
|
|
1657
|
-
telemetry.sourceLabel,
|
|
1658
|
-
telemetry.micEnabled ? " + Microphone" : ""
|
|
1659
|
-
] }) })
|
|
1660
|
-
] }),
|
|
1661
|
-
/* @__PURE__ */ jsx17(Box15, { children: /* @__PURE__ */ jsxs14(Text15, { dimColor: true, children: [
|
|
1662
|
-
"q stop & save",
|
|
1663
|
-
canPause ? ` \xB7 p ${paused ? "resume" : "pause"}` : ""
|
|
1664
|
-
] }) })
|
|
1665
|
-
] });
|
|
1666
|
-
}
|
|
1667
|
-
function stoppedHandoffCopy(artifact, canTranscribe) {
|
|
1668
|
-
if (artifact?.uploadStatus === "uploading") {
|
|
1669
|
-
return { text: "Uploading\u2026", tone: "normal" };
|
|
1670
|
-
}
|
|
1671
|
-
if (artifact?.transcriptionStatus === "processing") {
|
|
1672
|
-
return { text: "Transcribing\u2026", tone: "normal" };
|
|
1673
|
-
}
|
|
1674
|
-
if (artifact?.transcriptionStatus === "queued") {
|
|
1675
|
-
return { text: "Transcription queued \xB7 \u23CE open recording \xB7 n not now", tone: "green" };
|
|
1676
|
-
}
|
|
1677
|
-
if (artifact?.transcriptionStatus === "ready") {
|
|
1678
|
-
return { text: "Transcription ready \xB7 \u23CE open recording \xB7 n not now", tone: "green" };
|
|
1679
|
-
}
|
|
1680
|
-
if (artifact?.uploadStatus === "failed" || artifact?.transcriptionStatus === "failed") {
|
|
1681
|
-
return { text: "Transcription failed \xB7 \u23CE retry \xB7 n not now", tone: "red" };
|
|
1682
|
-
}
|
|
1683
|
-
if (!canTranscribe || !artifact?.audioPath) {
|
|
1684
|
-
return { text: "Saved locally \xB7 n back", tone: "dim" };
|
|
1685
|
-
}
|
|
1686
|
-
return { text: "Transcribe now? \u23CE yes \xB7 n not now", tone: "normal" };
|
|
1687
|
-
}
|
|
1688
|
-
var BLOCKS;
|
|
1689
|
-
var init_RecordingHeroScreen = __esm({
|
|
1690
|
-
"src/tui/RecordingHeroScreen.tsx"() {
|
|
1691
|
-
"use strict";
|
|
1692
|
-
init_format();
|
|
1693
|
-
init_terminal();
|
|
1694
|
-
BLOCKS = " \u2581\u2582\u2583\u2584\u2585\u2586\u2587\u2588";
|
|
1695
|
-
}
|
|
1696
|
-
});
|
|
1697
|
-
|
|
1698
1698
|
// src/tui/AppShell.tsx
|
|
1699
1699
|
import { useCallback, useEffect as useEffect3, useState as useState7 } from "react";
|
|
1700
1700
|
import { Box as Box16, Text as Text16, useApp, useInput as useInput6 } from "ink";
|
|
@@ -2449,7 +2449,7 @@ __export(tui_exports, {
|
|
|
2449
2449
|
runDashboard: () => runDashboard,
|
|
2450
2450
|
useTerminalSize: () => useTerminalSize
|
|
2451
2451
|
});
|
|
2452
|
-
import
|
|
2452
|
+
import React10 from "react";
|
|
2453
2453
|
import { render as render2 } from "ink";
|
|
2454
2454
|
import { spawn as spawn3 } from "child_process";
|
|
2455
2455
|
function openUrl(url2) {
|
|
@@ -2470,7 +2470,7 @@ function copyText(text) {
|
|
|
2470
2470
|
async function runDashboard(deps) {
|
|
2471
2471
|
const renderApp = deps.renderApp ?? render2;
|
|
2472
2472
|
const app = renderApp(
|
|
2473
|
-
|
|
2473
|
+
React10.createElement(AppShell, {
|
|
2474
2474
|
fetchJobs: deps.fetchJobs,
|
|
2475
2475
|
fetchTranscript: deps.fetchTranscript,
|
|
2476
2476
|
fetchRecordings: deps.fetchRecordings,
|
|
@@ -20091,6 +20091,7 @@ function readCliVersion() {
|
|
|
20091
20091
|
var CLI_VERSION = readCliVersion();
|
|
20092
20092
|
|
|
20093
20093
|
// src/record.tsx
|
|
20094
|
+
import React4 from "react";
|
|
20094
20095
|
import {
|
|
20095
20096
|
chmodSync,
|
|
20096
20097
|
cpSync,
|
|
@@ -20102,6 +20103,7 @@ import {
|
|
|
20102
20103
|
statSync,
|
|
20103
20104
|
writeFileSync
|
|
20104
20105
|
} from "fs";
|
|
20106
|
+
import { createHash } from "crypto";
|
|
20105
20107
|
import { createRequire as createRequire2 } from "module";
|
|
20106
20108
|
import { homedir } from "os";
|
|
20107
20109
|
import { dirname, join as join2 } from "path";
|
|
@@ -20420,7 +20422,8 @@ function createFifo(path6) {
|
|
|
20420
20422
|
|
|
20421
20423
|
// src/record.tsx
|
|
20422
20424
|
init_LiveCaptionsScreen();
|
|
20423
|
-
|
|
20425
|
+
init_RecordingHeroScreen();
|
|
20426
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
20424
20427
|
var SIDECAR_COMMAND_ENV = "RECAPPI_MINI_SIDECAR";
|
|
20425
20428
|
var SIDECAR_HELPER_NAME = "RecappiMiniSidecar";
|
|
20426
20429
|
var SIDECAR_APP_BUNDLE_NAME = "Recappi Recorder.app";
|
|
@@ -20436,6 +20439,14 @@ async function recordViaSidecar(opts) {
|
|
|
20436
20439
|
renderApp: opts.runtime?.renderApp,
|
|
20437
20440
|
now: opts.runtime?.now
|
|
20438
20441
|
});
|
|
20442
|
+
} else if (opts.renderHero) {
|
|
20443
|
+
liveRenderer = opts.runtime?.createHeroRenderer?.(session.source) ?? createInkRecordingHeroRenderer({
|
|
20444
|
+
source: session.source,
|
|
20445
|
+
sourceLabel: opts.includeSystemAudio === false ? "Microphone" : "System audio \xB7 all apps",
|
|
20446
|
+
micEnabled: opts.includeMicrophone !== false,
|
|
20447
|
+
renderApp: opts.runtime?.renderApp,
|
|
20448
|
+
now: opts.runtime?.now
|
|
20449
|
+
});
|
|
20439
20450
|
}
|
|
20440
20451
|
if (liveRenderer) {
|
|
20441
20452
|
await liveRenderer.waitUntilStop();
|
|
@@ -20767,16 +20778,21 @@ function stableDarwinHelperAppPath(opts = {}) {
|
|
|
20767
20778
|
return join2(base, SIDECAR_APP_BUNDLE_NAME);
|
|
20768
20779
|
}
|
|
20769
20780
|
function helperSourceSignature(sourceApp) {
|
|
20770
|
-
const
|
|
20771
|
-
const
|
|
20781
|
+
const executablePath = darwinAppExecutablePath(sourceApp);
|
|
20782
|
+
const infoPath = join2(sourceApp, "Contents", "Info.plist");
|
|
20783
|
+
const signaturePath = join2(sourceApp, "Contents", "_CodeSignature", "CodeResources");
|
|
20772
20784
|
return JSON.stringify({
|
|
20773
20785
|
app: SIDECAR_APP_BUNDLE_NAME,
|
|
20774
|
-
|
|
20775
|
-
|
|
20776
|
-
|
|
20777
|
-
infoMtimeMs: info.mtimeMs
|
|
20786
|
+
executable: fileDigest(executablePath),
|
|
20787
|
+
info: fileDigest(infoPath),
|
|
20788
|
+
codeSignature: existsSync(signaturePath) ? fileDigest(signaturePath) : null
|
|
20778
20789
|
});
|
|
20779
20790
|
}
|
|
20791
|
+
function fileDigest(path6) {
|
|
20792
|
+
const hash2 = createHash("sha256");
|
|
20793
|
+
hash2.update(readFileSync2(path6));
|
|
20794
|
+
return hash2.digest("hex");
|
|
20795
|
+
}
|
|
20780
20796
|
function readTextIfExists(path6) {
|
|
20781
20797
|
try {
|
|
20782
20798
|
return readFileSync2(path6, "utf8");
|
|
@@ -20860,7 +20876,7 @@ function createInkLiveRenderer(opts) {
|
|
|
20860
20876
|
});
|
|
20861
20877
|
const renderApp = opts.renderApp ?? render;
|
|
20862
20878
|
const app = renderApp(
|
|
20863
|
-
/* @__PURE__ */
|
|
20879
|
+
/* @__PURE__ */ jsx4(
|
|
20864
20880
|
RecordLiveScreen,
|
|
20865
20881
|
{
|
|
20866
20882
|
source: opts.source,
|
|
@@ -20883,7 +20899,60 @@ function RecordLiveScreen({
|
|
|
20883
20899
|
useInput2((input, key) => {
|
|
20884
20900
|
if (input === "q" || key.escape || key.leftArrow) onStop();
|
|
20885
20901
|
});
|
|
20886
|
-
return /* @__PURE__ */
|
|
20902
|
+
return /* @__PURE__ */ jsx4(LiveCaptionsScreen, { source, now });
|
|
20903
|
+
}
|
|
20904
|
+
function createInkRecordingHeroRenderer(opts) {
|
|
20905
|
+
let resolveStop;
|
|
20906
|
+
const stopped = new Promise((resolve) => {
|
|
20907
|
+
resolveStop = resolve;
|
|
20908
|
+
});
|
|
20909
|
+
const onStop = () => resolveStop?.();
|
|
20910
|
+
const onSigint = () => onStop();
|
|
20911
|
+
process.once("SIGINT", onSigint);
|
|
20912
|
+
const renderApp = opts.renderApp ?? render;
|
|
20913
|
+
const app = renderApp(
|
|
20914
|
+
/* @__PURE__ */ jsx4(
|
|
20915
|
+
RecordingHeroLive,
|
|
20916
|
+
{
|
|
20917
|
+
source: opts.source,
|
|
20918
|
+
sourceLabel: opts.sourceLabel,
|
|
20919
|
+
micEnabled: opts.micEnabled,
|
|
20920
|
+
onStop,
|
|
20921
|
+
now: opts.now ?? Date.now
|
|
20922
|
+
}
|
|
20923
|
+
),
|
|
20924
|
+
{ alternateScreen: true, interactive: true }
|
|
20925
|
+
);
|
|
20926
|
+
return {
|
|
20927
|
+
waitUntilStop: () => stopped,
|
|
20928
|
+
close: () => {
|
|
20929
|
+
process.removeListener("SIGINT", onSigint);
|
|
20930
|
+
app.unmount();
|
|
20931
|
+
}
|
|
20932
|
+
};
|
|
20933
|
+
}
|
|
20934
|
+
function RecordingHeroLive({
|
|
20935
|
+
source,
|
|
20936
|
+
sourceLabel,
|
|
20937
|
+
micEnabled,
|
|
20938
|
+
onStop,
|
|
20939
|
+
now
|
|
20940
|
+
}) {
|
|
20941
|
+
const [telemetry, setTelemetry] = React4.useState(() => ({
|
|
20942
|
+
status: "recording",
|
|
20943
|
+
startedAtMs: now(),
|
|
20944
|
+
sourceLabel,
|
|
20945
|
+
micEnabled
|
|
20946
|
+
}));
|
|
20947
|
+
React4.useEffect(() => {
|
|
20948
|
+
return source.onEvent((event) => {
|
|
20949
|
+
setTelemetry((prev) => applyRecordingEventToTelemetry(prev, event));
|
|
20950
|
+
});
|
|
20951
|
+
}, [source]);
|
|
20952
|
+
useInput2((input, key) => {
|
|
20953
|
+
if (input === "q" || key.escape) onStop();
|
|
20954
|
+
});
|
|
20955
|
+
return /* @__PURE__ */ jsx4(RecordingHeroScreen, { telemetry, now });
|
|
20887
20956
|
}
|
|
20888
20957
|
|
|
20889
20958
|
// src/cli.ts
|
|
@@ -21088,9 +21157,6 @@ async function runCli(deps = {}) {
|
|
|
21088
21157
|
hint: "Run recappi auth login, or import the Recappi Mini session with recappi auth import-macos."
|
|
21089
21158
|
});
|
|
21090
21159
|
}
|
|
21091
|
-
if (mode === "human" && isTTY && !parsed.live) {
|
|
21092
|
-
stderr("Recording\u2026 press Ctrl-C to stop.\n");
|
|
21093
|
-
}
|
|
21094
21160
|
const data = await recordViaSidecar({
|
|
21095
21161
|
account: {
|
|
21096
21162
|
backendOrigin: auth.origin,
|
|
@@ -21108,6 +21174,7 @@ async function runCli(deps = {}) {
|
|
|
21108
21174
|
transcriptionLanguage: parsed.transcriptionLanguage,
|
|
21109
21175
|
sidecarCommand: parsed.sidecarCommand,
|
|
21110
21176
|
renderLive: parsed.live === true && mode === "human" && isTTY,
|
|
21177
|
+
renderHero: parsed.live !== true && mode === "human" && isTTY,
|
|
21111
21178
|
runtime: deps.recordRuntime
|
|
21112
21179
|
});
|
|
21113
21180
|
renderSuccess("record", data, render3);
|