fluncle 0.52.0 → 0.53.0
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/bin/fluncle.mjs +128 -5
- package/package.json +1 -1
package/bin/fluncle.mjs
CHANGED
|
@@ -423,7 +423,7 @@ function parseVersion(version) {
|
|
|
423
423
|
var currentVersion;
|
|
424
424
|
var init_version = __esm(() => {
|
|
425
425
|
init_output();
|
|
426
|
-
currentVersion = "0.
|
|
426
|
+
currentVersion = "0.53.0".trim() ? "0.53.0".trim() : "0.1.0";
|
|
427
427
|
});
|
|
428
428
|
|
|
429
429
|
// src/update-notifier.ts
|
|
@@ -1912,7 +1912,7 @@ function parseVersion2(version) {
|
|
|
1912
1912
|
var currentVersion2, latestReleaseUrl = "https://api.github.com/repos/mauricekleine/fluncle/releases/latest";
|
|
1913
1913
|
var init_version2 = __esm(() => {
|
|
1914
1914
|
init_output();
|
|
1915
|
-
currentVersion2 = "0.
|
|
1915
|
+
currentVersion2 = "0.53.0".trim() ? "0.53.0".trim() : "0.1.0";
|
|
1916
1916
|
});
|
|
1917
1917
|
|
|
1918
1918
|
// src/commands/track.ts
|
|
@@ -2540,6 +2540,62 @@ var init_mixtape_youtube2 = __esm(() => {
|
|
|
2540
2540
|
init_output();
|
|
2541
2541
|
});
|
|
2542
2542
|
|
|
2543
|
+
// src/commands/newsletter.ts
|
|
2544
|
+
var exports_newsletter = {};
|
|
2545
|
+
__export(exports_newsletter, {
|
|
2546
|
+
newsletterUpdateCommand: () => newsletterUpdateCommand,
|
|
2547
|
+
newsletterSendCommand: () => newsletterSendCommand,
|
|
2548
|
+
newsletterListCommand: () => newsletterListCommand,
|
|
2549
|
+
newsletterDraftCommand: () => newsletterDraftCommand
|
|
2550
|
+
});
|
|
2551
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
|
|
2552
|
+
function buildBody2(options, { requireContent }) {
|
|
2553
|
+
const body = {};
|
|
2554
|
+
if (options.contentFile !== undefined) {
|
|
2555
|
+
body.contentJson = readContentFile(options.contentFile);
|
|
2556
|
+
} else if (requireContent) {
|
|
2557
|
+
throw new CliError2("missing_content", "A draft needs the structured content payload via --content-file <edition.json>");
|
|
2558
|
+
}
|
|
2559
|
+
if (options.subject !== undefined) {
|
|
2560
|
+
body.subject = options.subject;
|
|
2561
|
+
}
|
|
2562
|
+
if (options.windowSince !== undefined) {
|
|
2563
|
+
body.windowSince = options.windowSince;
|
|
2564
|
+
}
|
|
2565
|
+
if (options.windowUntil !== undefined) {
|
|
2566
|
+
body.windowUntil = options.windowUntil;
|
|
2567
|
+
}
|
|
2568
|
+
return body;
|
|
2569
|
+
}
|
|
2570
|
+
function readContentFile(filePath) {
|
|
2571
|
+
if (!existsSync2(filePath)) {
|
|
2572
|
+
throw new CliError2("file_not_found", `Content file not found: ${filePath}`);
|
|
2573
|
+
}
|
|
2574
|
+
const text = readFileSync2(filePath, "utf-8");
|
|
2575
|
+
try {
|
|
2576
|
+
return JSON.parse(text);
|
|
2577
|
+
} catch (error) {
|
|
2578
|
+
throw new CliError2("invalid_content_json", `Content JSON parse failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
2579
|
+
}
|
|
2580
|
+
}
|
|
2581
|
+
async function newsletterDraftCommand(options) {
|
|
2582
|
+
return adminApiPost("/api/admin/newsletter/editions", buildBody2(options, { requireContent: true }));
|
|
2583
|
+
}
|
|
2584
|
+
async function newsletterUpdateCommand(id, options) {
|
|
2585
|
+
return adminApiPatch(`/api/admin/newsletter/editions/${encodeURIComponent(id)}`, buildBody2(options, { requireContent: false }));
|
|
2586
|
+
}
|
|
2587
|
+
async function newsletterSendCommand(id) {
|
|
2588
|
+
return adminApiPost(`/api/admin/newsletter/editions/${encodeURIComponent(id)}/send`);
|
|
2589
|
+
}
|
|
2590
|
+
async function newsletterListCommand() {
|
|
2591
|
+
const response = await adminApiGet("/api/admin/newsletter/editions");
|
|
2592
|
+
return response.editions;
|
|
2593
|
+
}
|
|
2594
|
+
var init_newsletter = __esm(() => {
|
|
2595
|
+
init_api();
|
|
2596
|
+
init_output();
|
|
2597
|
+
});
|
|
2598
|
+
|
|
2543
2599
|
// src/commands/add.ts
|
|
2544
2600
|
async function addCommand2(spotifyUrl, options) {
|
|
2545
2601
|
const result = await adminApiPost("/api/admin/tracks", {
|
|
@@ -3149,7 +3205,7 @@ var COORD_FALLBACK2 = "—";
|
|
|
3149
3205
|
var init_format2 = () => {};
|
|
3150
3206
|
|
|
3151
3207
|
// src/cli.ts
|
|
3152
|
-
import { existsSync as
|
|
3208
|
+
import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
|
|
3153
3209
|
import path2 from "path";
|
|
3154
3210
|
|
|
3155
3211
|
// ../../node_modules/commander/lib/error.js
|
|
@@ -5476,6 +5532,26 @@ function addAdminCommands(program2) {
|
|
|
5476
5532
|
const { publishYoutubeCommand: publishYoutubeCommand3 } = await Promise.resolve().then(() => (init_mixtape_youtube2(), exports_mixtape_youtube2));
|
|
5477
5533
|
await runMixtapePublishYoutube(idOrLogId, options, publishYoutubeCommand3);
|
|
5478
5534
|
});
|
|
5535
|
+
const adminNewsletter = configureCommand(admin.command("newsletter").description("Newsletter edition commands"));
|
|
5536
|
+
adminNewsletter.action(() => {
|
|
5537
|
+
adminNewsletter.outputHelp();
|
|
5538
|
+
});
|
|
5539
|
+
adminNewsletter.command("draft").description("Persist a newsletter edition draft (the agent authors it, you send it)").option("--content-file <file>", "Structured edition content payload (JSON)").option("--subject <text>", "Email subject line").option("--window-since <date>", "Discovery-window start (ISO)").option("--window-until <date>", "Discovery-window end (ISO)").option("--json", "Print JSON", false).allowExcessArguments().action(async (options) => {
|
|
5540
|
+
const { newsletterDraftCommand: newsletterDraftCommand2 } = await Promise.resolve().then(() => (init_newsletter(), exports_newsletter));
|
|
5541
|
+
await runNewsletterDraft(options, newsletterDraftCommand2);
|
|
5542
|
+
});
|
|
5543
|
+
adminNewsletter.command("update").description("Update a draft edition's payload, subject, or window").argument("[id]").option("--content-file <file>", "Structured edition content payload (JSON)").option("--subject <text>", "Email subject line").option("--window-since <date>", "Discovery-window start (ISO)").option("--window-until <date>", "Discovery-window end (ISO)").option("--json", "Print JSON", false).allowExcessArguments().action(async (id, options) => {
|
|
5544
|
+
const { newsletterUpdateCommand: newsletterUpdateCommand2 } = await Promise.resolve().then(() => (init_newsletter(), exports_newsletter));
|
|
5545
|
+
await runNewsletterUpdate(id, options, newsletterUpdateCommand2);
|
|
5546
|
+
});
|
|
5547
|
+
adminNewsletter.command("send").description("Send an edition \u2014 OPERATOR only (Resend broadcast + mint the number)").argument("[id]").option("--json", "Print JSON", false).allowExcessArguments().action(async (id, options) => {
|
|
5548
|
+
const { newsletterSendCommand: newsletterSendCommand2 } = await Promise.resolve().then(() => (init_newsletter(), exports_newsletter));
|
|
5549
|
+
await runNewsletterSend(id, options, newsletterSendCommand2);
|
|
5550
|
+
});
|
|
5551
|
+
adminNewsletter.command("list").description("List every edition including drafts (the cron's miss-recovery read)").option("--json", "Print JSON", false).allowExcessArguments().action(async (options) => {
|
|
5552
|
+
const { newsletterListCommand: newsletterListCommand2 } = await Promise.resolve().then(() => (init_newsletter(), exports_newsletter));
|
|
5553
|
+
await runNewsletterList(options, newsletterListCommand2);
|
|
5554
|
+
});
|
|
5479
5555
|
const submissions = configureCommand(admin.command("submissions").description("Review listener submissions"));
|
|
5480
5556
|
submissions.option("--json", "Print JSON", false).action(async (options) => {
|
|
5481
5557
|
const { listSubmissionsCommand: listSubmissionsCommand2 } = await Promise.resolve().then(() => (init_submissions(), exports_submissions));
|
|
@@ -5555,7 +5631,7 @@ async function runTrackPreviewArchive(idOrLogId, options, previewArchiveUploadCo
|
|
|
5555
5631
|
console.log(` mime: ${result.mime}`);
|
|
5556
5632
|
}
|
|
5557
5633
|
async function runTrackObserve(idOrLogId, options, trackObserveCommand2) {
|
|
5558
|
-
const script = options.scriptFile ?
|
|
5634
|
+
const script = options.scriptFile ? readFileSync3(options.scriptFile, "utf8") : options.script;
|
|
5559
5635
|
if (!idOrLogId || !script || !script.trim()) {
|
|
5560
5636
|
throw new Error("Usage: fluncle admin tracks observe <track_id|log_id> (--script <text> | --script-file <file>) [--voice-id <id>] [--model <model>] [--duration-ms <ms>] [--context-note <text>] [--json]");
|
|
5561
5637
|
}
|
|
@@ -5717,7 +5793,7 @@ async function runTrackVideo(idOrLogId, options, trackVideoCommand2) {
|
|
|
5717
5793
|
return;
|
|
5718
5794
|
}
|
|
5719
5795
|
const candidate = path2.join(dir, name);
|
|
5720
|
-
return
|
|
5796
|
+
return existsSync3(candidate) ? candidate : undefined;
|
|
5721
5797
|
};
|
|
5722
5798
|
const resolveFile = (explicit, name) => {
|
|
5723
5799
|
if (explicit) {
|
|
@@ -5983,6 +6059,53 @@ function formatCue(ms) {
|
|
|
5983
6059
|
}
|
|
5984
6060
|
return `${minutes}:${seconds.toString().padStart(2, "0")}`;
|
|
5985
6061
|
}
|
|
6062
|
+
async function runNewsletterDraft(options, newsletterDraftCommand2) {
|
|
6063
|
+
const result = await newsletterDraftCommand2(options);
|
|
6064
|
+
if (options.json) {
|
|
6065
|
+
printJson(result);
|
|
6066
|
+
return;
|
|
6067
|
+
}
|
|
6068
|
+
console.log(`Drafted edition ${result.edition.id}. It stays a draft until the operator sends it.`);
|
|
6069
|
+
}
|
|
6070
|
+
async function runNewsletterUpdate(id, options, newsletterUpdateCommand2) {
|
|
6071
|
+
if (!id) {
|
|
6072
|
+
throw new Error("Missing edition id. Usage: fluncle admin newsletter update <id>");
|
|
6073
|
+
}
|
|
6074
|
+
const result = await newsletterUpdateCommand2(id, options);
|
|
6075
|
+
if (options.json) {
|
|
6076
|
+
printJson(result);
|
|
6077
|
+
return;
|
|
6078
|
+
}
|
|
6079
|
+
console.log(`Saved draft ${result.edition.id}.`);
|
|
6080
|
+
}
|
|
6081
|
+
async function runNewsletterSend(id, options, newsletterSendCommand2) {
|
|
6082
|
+
if (!id) {
|
|
6083
|
+
throw new Error("Missing edition id. Usage: fluncle admin newsletter send <id>");
|
|
6084
|
+
}
|
|
6085
|
+
const result = await newsletterSendCommand2(id);
|
|
6086
|
+
if (options.json) {
|
|
6087
|
+
printJson(result);
|
|
6088
|
+
return;
|
|
6089
|
+
}
|
|
6090
|
+
const number = result.edition.number;
|
|
6091
|
+
console.log(number === undefined ? `Sent edition ${result.edition.id}.` : `Sent edition #${number} \u2014 it's out to the list and in the archive.`);
|
|
6092
|
+
}
|
|
6093
|
+
async function runNewsletterList(options, newsletterListCommand2) {
|
|
6094
|
+
const editions = await newsletterListCommand2();
|
|
6095
|
+
if (options.json) {
|
|
6096
|
+
printJson({ editions, ok: true });
|
|
6097
|
+
return;
|
|
6098
|
+
}
|
|
6099
|
+
if (editions.length === 0) {
|
|
6100
|
+
console.log("No editions yet.");
|
|
6101
|
+
return;
|
|
6102
|
+
}
|
|
6103
|
+
for (const edition of editions) {
|
|
6104
|
+
const label = edition.number === undefined ? "draft" : `#${edition.number}`;
|
|
6105
|
+
const subject = edition.subject ?? "(no subject)";
|
|
6106
|
+
console.log(`${label} ${edition.status} ${edition.id} ${subject}`);
|
|
6107
|
+
}
|
|
6108
|
+
}
|
|
5986
6109
|
async function runAdd(spotifyUrl, options, addCommand3) {
|
|
5987
6110
|
if (!spotifyUrl) {
|
|
5988
6111
|
throw new Error("Missing Spotify track URL");
|
package/package.json
CHANGED