@plaud-ai/cli 0.3.7 → 0.3.9
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 +117 -31
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -20379,7 +20379,7 @@ function isNewer(current, latest) {
|
|
|
20379
20379
|
return false;
|
|
20380
20380
|
}
|
|
20381
20381
|
var updateCommand = new Command("update").description("Check npm for the latest Plaud CLI and print the upgrade command").action(async () => {
|
|
20382
|
-
const current = "0.3.
|
|
20382
|
+
const current = "0.3.9";
|
|
20383
20383
|
const spinner = ora("Checking npm for latest version...").start();
|
|
20384
20384
|
const latest = await fetchLatestVersion();
|
|
20385
20385
|
spinner.stop();
|
|
@@ -20434,10 +20434,10 @@ async function checkForUpdate(current) {
|
|
|
20434
20434
|
return isNewer(current, latest) ? latest : null;
|
|
20435
20435
|
}
|
|
20436
20436
|
var versionCommand = new Command2("version").description("Show CLI version information").action(async () => {
|
|
20437
|
-
const current = "0.3.
|
|
20437
|
+
const current = "0.3.9";
|
|
20438
20438
|
console.log(`plaud ${current}`);
|
|
20439
|
-
if ("
|
|
20440
|
-
if ("2026-08-
|
|
20439
|
+
if ("e0fb5d6") console.log(`commit ${"e0fb5d6"}`);
|
|
20440
|
+
if ("2026-08-18T03:07:34.503Z") console.log(`built ${"2026-08-18T03:07:34.503Z"}`);
|
|
20441
20441
|
if (current === "unknown") return;
|
|
20442
20442
|
const newer = await checkForUpdate(current);
|
|
20443
20443
|
if (newer) {
|
|
@@ -20902,6 +20902,49 @@ async function loadBlockContent(block) {
|
|
|
20902
20902
|
return "";
|
|
20903
20903
|
}
|
|
20904
20904
|
|
|
20905
|
+
// ../shared/dist/time.js
|
|
20906
|
+
var HAS_TIMEZONE = /(?:[Zz]|[+-]\d{2}(?::?\d{2})?)$/;
|
|
20907
|
+
var HAS_TIME = /\d{2}:\d{2}/;
|
|
20908
|
+
var DATE_ONLY = /^(\d{4})-(\d{2})-(\d{2})$/;
|
|
20909
|
+
function parseApiTimestamp(value) {
|
|
20910
|
+
if (!value)
|
|
20911
|
+
return null;
|
|
20912
|
+
const trimmed = value.trim();
|
|
20913
|
+
if (!trimmed)
|
|
20914
|
+
return null;
|
|
20915
|
+
const normalised = HAS_TIME.test(trimmed) && !HAS_TIMEZONE.test(trimmed) ? `${trimmed}Z` : trimmed;
|
|
20916
|
+
const ms = new Date(normalised).getTime();
|
|
20917
|
+
return Number.isNaN(ms) ? null : ms;
|
|
20918
|
+
}
|
|
20919
|
+
function localDayStart(value) {
|
|
20920
|
+
const parts = parseDateOnly(value);
|
|
20921
|
+
if (!parts)
|
|
20922
|
+
return null;
|
|
20923
|
+
const [y, m, d] = parts;
|
|
20924
|
+
return new Date(y, m - 1, d, 0, 0, 0, 0).getTime();
|
|
20925
|
+
}
|
|
20926
|
+
function localDayEnd(value) {
|
|
20927
|
+
const parts = parseDateOnly(value);
|
|
20928
|
+
if (!parts)
|
|
20929
|
+
return null;
|
|
20930
|
+
const [y, m, d] = parts;
|
|
20931
|
+
return new Date(y, m - 1, d + 1, 0, 0, 0, 0).getTime() - 1;
|
|
20932
|
+
}
|
|
20933
|
+
function parseDateOnly(value) {
|
|
20934
|
+
if (!value)
|
|
20935
|
+
return null;
|
|
20936
|
+
const match = DATE_ONLY.exec(value.trim());
|
|
20937
|
+
if (!match)
|
|
20938
|
+
return null;
|
|
20939
|
+
const y = Number(match[1]);
|
|
20940
|
+
const m = Number(match[2]);
|
|
20941
|
+
const d = Number(match[3]);
|
|
20942
|
+
const probe = new Date(y, m - 1, d);
|
|
20943
|
+
if (probe.getFullYear() !== y || probe.getMonth() !== m - 1 || probe.getDate() !== d)
|
|
20944
|
+
return null;
|
|
20945
|
+
return [y, m, d];
|
|
20946
|
+
}
|
|
20947
|
+
|
|
20905
20948
|
// src/config.ts
|
|
20906
20949
|
import { readFileSync, existsSync } from "fs";
|
|
20907
20950
|
import { homedir as homedir4 } from "os";
|
|
@@ -21138,8 +21181,9 @@ function formatDuration(ms) {
|
|
|
21138
21181
|
}
|
|
21139
21182
|
function formatDate(iso) {
|
|
21140
21183
|
if (!iso) return "-";
|
|
21141
|
-
const
|
|
21142
|
-
if (
|
|
21184
|
+
const ms = parseApiTimestamp(iso);
|
|
21185
|
+
if (ms === null) return iso;
|
|
21186
|
+
const d = new Date(ms);
|
|
21143
21187
|
const y = d.getFullYear();
|
|
21144
21188
|
const m = String(d.getMonth() + 1).padStart(2, "0");
|
|
21145
21189
|
const day = String(d.getDate()).padStart(2, "0");
|
|
@@ -21231,7 +21275,8 @@ var getFileCommand = new Command7("file").description("Get details of a specific
|
|
|
21231
21275
|
console.log(` ${chalk8.cyan("start_at")}: ${file.start_at ?? "-"}`);
|
|
21232
21276
|
console.log(` ${chalk8.cyan("duration")}: ${formatDuration(file.duration)}`);
|
|
21233
21277
|
console.log(` ${chalk8.cyan("serial_number")}: ${file.serial_number ?? "-"}`);
|
|
21234
|
-
|
|
21278
|
+
const audioState = file.presigned_url ? chalk8.green("available") : chalk8.gray("unknown (run `plaud audio` to check)");
|
|
21279
|
+
console.log(` ${chalk8.cyan("audio")}: ${audioState}`);
|
|
21235
21280
|
console.log(` ${chalk8.cyan("transcript")}: ${hasTranscript ? chalk8.green("available") : chalk8.gray("unavailable")}`);
|
|
21236
21281
|
console.log(` ${chalk8.cyan("summary")}: ${hasSummary ? chalk8.green("available") : chalk8.gray("unavailable")}`);
|
|
21237
21282
|
console.log();
|
|
@@ -21378,27 +21423,74 @@ import { Command as Command10 } from "commander";
|
|
|
21378
21423
|
import chalk11 from "chalk";
|
|
21379
21424
|
import ora8 from "ora";
|
|
21380
21425
|
import { writeFile as writeFile5 } from "fs/promises";
|
|
21381
|
-
var
|
|
21426
|
+
var SUMMARY_TYPE = "auto_sum_note";
|
|
21427
|
+
async function noteContent(note) {
|
|
21428
|
+
try {
|
|
21429
|
+
return await loadBlockContent(note);
|
|
21430
|
+
} catch {
|
|
21431
|
+
return "";
|
|
21432
|
+
}
|
|
21433
|
+
}
|
|
21434
|
+
var summaryCommand = new Command10("summary").description("Get the AI summary for a Plaud recording").argument("<file_id>", "The file ID to retrieve summary for").option("-o, --output <file>", "Save summary to a file").option("--all", "Print every note on the recording, not just the first summary").option("--json", "Print note_list verbatim as JSON (same payload as the MCP get_note tool)").action(async (fileId, opts) => {
|
|
21382
21435
|
const client2 = getClient2();
|
|
21383
21436
|
const spinner = ora8("Fetching summary...").start();
|
|
21384
21437
|
try {
|
|
21385
21438
|
const file = await client2.getFile(fileId);
|
|
21386
21439
|
spinner.stop();
|
|
21387
21440
|
const noteList = file.note_list ?? [];
|
|
21388
|
-
|
|
21389
|
-
|
|
21390
|
-
|
|
21441
|
+
if (opts.json) {
|
|
21442
|
+
const payload = JSON.stringify(noteList, null, 2);
|
|
21443
|
+
if (opts.output) {
|
|
21444
|
+
await writeFile5(opts.output, payload, "utf-8");
|
|
21445
|
+
console.log(chalk11.green(`Notes saved to ${opts.output}`));
|
|
21446
|
+
} else {
|
|
21447
|
+
console.log(payload);
|
|
21448
|
+
}
|
|
21449
|
+
return;
|
|
21450
|
+
}
|
|
21451
|
+
const summaries = noteList.filter((n) => n.data_type === SUMMARY_TYPE);
|
|
21452
|
+
if (summaries.length === 0) {
|
|
21453
|
+
if (noteList.length === 0) {
|
|
21454
|
+
console.log(chalk11.yellow("Summary not available for this recording."));
|
|
21455
|
+
} else {
|
|
21456
|
+
const available = noteList.map((n) => n.data_type).filter(Boolean).join(", ") || "(none)";
|
|
21457
|
+
console.log(
|
|
21458
|
+
chalk11.yellow(
|
|
21459
|
+
`No "${SUMMARY_TYPE}" note for this recording. Available: ${available}.`
|
|
21460
|
+
)
|
|
21461
|
+
);
|
|
21462
|
+
}
|
|
21391
21463
|
return;
|
|
21392
21464
|
}
|
|
21393
|
-
const
|
|
21465
|
+
const selected = opts.all ? noteList : summaries.slice(0, 1);
|
|
21466
|
+
if (!opts.all && noteList.length > 1) {
|
|
21467
|
+
const detail = summaries.length > 1 ? `${summaries.length} summary notes` : `${noteList.length} notes (1 summary)`;
|
|
21468
|
+
console.error(
|
|
21469
|
+
chalk11.yellow(
|
|
21470
|
+
`Note: this recording has ${detail}; showing the first. Use --all to print them all, or --json for the raw payload.`
|
|
21471
|
+
)
|
|
21472
|
+
);
|
|
21473
|
+
}
|
|
21474
|
+
const sections = [];
|
|
21475
|
+
for (const [i, note] of selected.entries()) {
|
|
21476
|
+
const content = await noteContent(note);
|
|
21477
|
+
const type = typeof note.data_type === "string" ? note.data_type : "unknown";
|
|
21478
|
+
const body = content || `(this note has no content yet \u2014 nothing was returned for "${type}")`;
|
|
21479
|
+
sections.push(
|
|
21480
|
+
opts.all ? `\u2500\u2500\u2500 note ${i + 1}/${selected.length} \xB7 ${type} \u2500\u2500\u2500
|
|
21481
|
+
|
|
21482
|
+
${body}` : body
|
|
21483
|
+
);
|
|
21484
|
+
}
|
|
21485
|
+
const output = sections.join("\n\n");
|
|
21394
21486
|
if (opts.output) {
|
|
21395
|
-
await writeFile5(opts.output,
|
|
21487
|
+
await writeFile5(opts.output, output, "utf-8");
|
|
21396
21488
|
console.log(chalk11.green(`Summary saved to ${opts.output}`));
|
|
21397
21489
|
} else {
|
|
21398
21490
|
console.log(chalk11.bold(`
|
|
21399
|
-
Summary: ${file.name}
|
|
21491
|
+
${opts.all ? "Notes" : "Summary"}: ${file.name}
|
|
21400
21492
|
`));
|
|
21401
|
-
console.log(
|
|
21493
|
+
console.log(output);
|
|
21402
21494
|
console.log();
|
|
21403
21495
|
}
|
|
21404
21496
|
} catch (err) {
|
|
@@ -21426,25 +21518,19 @@ import chalk12 from "chalk";
|
|
|
21426
21518
|
import ora9 from "ora";
|
|
21427
21519
|
var MAX_PAGES = 5;
|
|
21428
21520
|
var PAGE_SIZE = 100;
|
|
21429
|
-
function parseDate(s) {
|
|
21430
|
-
if (!s) return null;
|
|
21431
|
-
const d = new Date(s);
|
|
21432
|
-
return Number.isNaN(d.getTime()) ? null : d.getTime();
|
|
21433
|
-
}
|
|
21434
21521
|
var searchCommand = new Command11("search").description("Search recordings by name keyword (client-side, scans up to 500 most recent recordings)").argument("<keyword>", "Case-insensitive substring to match against recording names").option("--from <date>", "Start date inclusive, YYYY-MM-DD").option("--to <date>", "End date inclusive, YYYY-MM-DD").option("--max <n>", "Maximum matches to display", "50").action(async (keyword, opts) => {
|
|
21435
21522
|
const max = parseInt(opts.max);
|
|
21436
21523
|
if (isNaN(max) || max < 1 || max > 500) {
|
|
21437
21524
|
printError("INVALID_ARGS", "--max must be a number between 1 and 500");
|
|
21438
21525
|
await telemetryExit(ExitCode.ERROR);
|
|
21439
21526
|
}
|
|
21440
|
-
const from =
|
|
21441
|
-
const
|
|
21442
|
-
const to = toRaw !== null ? toRaw + 24 * 60 * 60 * 1e3 - 1 : null;
|
|
21527
|
+
const from = localDayStart(opts.from);
|
|
21528
|
+
const to = localDayEnd(opts.to);
|
|
21443
21529
|
if (opts.from && from === null) {
|
|
21444
21530
|
printError("INVALID_ARGS", `Invalid --from date: ${opts.from}`);
|
|
21445
21531
|
await telemetryExit(ExitCode.ERROR);
|
|
21446
21532
|
}
|
|
21447
|
-
if (opts.to &&
|
|
21533
|
+
if (opts.to && to === null) {
|
|
21448
21534
|
printError("INVALID_ARGS", `Invalid --to date: ${opts.to}`);
|
|
21449
21535
|
await telemetryExit(ExitCode.ERROR);
|
|
21450
21536
|
}
|
|
@@ -21462,7 +21548,7 @@ var searchCommand = new Command11("search").description("Search recordings by na
|
|
|
21462
21548
|
for (const file of result.data) {
|
|
21463
21549
|
if (!(file.name ?? "").toLowerCase().includes(q)) continue;
|
|
21464
21550
|
if (from !== null || to !== null) {
|
|
21465
|
-
const created =
|
|
21551
|
+
const created = parseApiTimestamp(file.created_at);
|
|
21466
21552
|
if (created === null) continue;
|
|
21467
21553
|
if (from !== null && created < from) continue;
|
|
21468
21554
|
if (to !== null && created > to) continue;
|
|
@@ -21537,8 +21623,8 @@ var recentCommand = new Command12("recent").description("List recordings from th
|
|
|
21537
21623
|
let allOlder = true;
|
|
21538
21624
|
let hasValidTimestamps = false;
|
|
21539
21625
|
for (const file of result.data) {
|
|
21540
|
-
const created =
|
|
21541
|
-
if (
|
|
21626
|
+
const created = parseApiTimestamp(file.created_at);
|
|
21627
|
+
if (created === null) continue;
|
|
21542
21628
|
hasValidTimestamps = true;
|
|
21543
21629
|
if (created >= from) {
|
|
21544
21630
|
matches.push(file);
|
|
@@ -21591,8 +21677,8 @@ var todayCommand = new Command12("today").description("List recordings created t
|
|
|
21591
21677
|
const result = await client2.listFiles(1, 50);
|
|
21592
21678
|
spinner.stop();
|
|
21593
21679
|
const matches = result.data.filter((f2) => {
|
|
21594
|
-
const t =
|
|
21595
|
-
return
|
|
21680
|
+
const t = parseApiTimestamp(f2.created_at);
|
|
21681
|
+
return t !== null && t >= startMs;
|
|
21596
21682
|
});
|
|
21597
21683
|
if (matches.length === 0) {
|
|
21598
21684
|
console.log(chalk13.yellow("No recordings created today."));
|
|
@@ -21716,7 +21802,7 @@ async function runWizard() {
|
|
|
21716
21802
|
try {
|
|
21717
21803
|
await initTelemetry({
|
|
21718
21804
|
surface: "cli",
|
|
21719
|
-
appVersion: "0.3.
|
|
21805
|
+
appVersion: "0.3.9"
|
|
21720
21806
|
});
|
|
21721
21807
|
} catch {
|
|
21722
21808
|
}
|
|
@@ -21725,7 +21811,7 @@ async function notifyUpdate() {
|
|
|
21725
21811
|
if (sub === "version" || sub === "update") return;
|
|
21726
21812
|
if (process.env.PLAUD_NO_UPDATE_NOTIFIER) return;
|
|
21727
21813
|
if (!process.stderr.isTTY) return;
|
|
21728
|
-
const current = "0.3.
|
|
21814
|
+
const current = "0.3.9";
|
|
21729
21815
|
if (current === "0.0.0") return;
|
|
21730
21816
|
try {
|
|
21731
21817
|
const newer = await checkForUpdate(current);
|