fluncle 0.275.0 → 0.276.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 +502 -314
- package/package.json +1 -1
package/bin/fluncle.mjs
CHANGED
|
@@ -60,6 +60,43 @@ var __esm = (fn, res, err) => () => {
|
|
|
60
60
|
};
|
|
61
61
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
62
62
|
|
|
63
|
+
// src/output.ts
|
|
64
|
+
import { writeSync } from "node:fs";
|
|
65
|
+
function writeStdoutSync(text) {
|
|
66
|
+
const buf = Buffer.from(text, "utf8");
|
|
67
|
+
let offset = 0;
|
|
68
|
+
while (offset < buf.length) {
|
|
69
|
+
try {
|
|
70
|
+
offset += writeSync(1, buf, offset);
|
|
71
|
+
} catch (error) {
|
|
72
|
+
if (error.code === "EAGAIN") {
|
|
73
|
+
Atomics.wait(EAGAIN_WAIT, 0, 0, 1);
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
throw error;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
function isJsonFailure(value) {
|
|
81
|
+
return typeof value === "object" && value !== null && typeof value.code === "string" && typeof value.message === "string";
|
|
82
|
+
}
|
|
83
|
+
function printJson(value) {
|
|
84
|
+
writeStdoutSync(JSON.stringify(value, null, 2) + `
|
|
85
|
+
`);
|
|
86
|
+
}
|
|
87
|
+
var EAGAIN_WAIT, CliError;
|
|
88
|
+
var init_output = __esm(() => {
|
|
89
|
+
EAGAIN_WAIT = new Int32Array(new SharedArrayBuffer(4));
|
|
90
|
+
CliError = class CliError extends Error {
|
|
91
|
+
code;
|
|
92
|
+
constructor(code, message) {
|
|
93
|
+
super(message);
|
|
94
|
+
this.name = "CliError";
|
|
95
|
+
this.code = code;
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
});
|
|
99
|
+
|
|
63
100
|
// ../../node_modules/dotenv/lib/main.js
|
|
64
101
|
var require_main = __commonJS(function(exports, module) {
|
|
65
102
|
var fs = __require("fs");
|
|
@@ -379,6 +416,42 @@ var require_main = __commonJS(function(exports, module) {
|
|
|
379
416
|
module.exports = DotenvModule;
|
|
380
417
|
});
|
|
381
418
|
|
|
419
|
+
// src/deadline.ts
|
|
420
|
+
function fireDeadlineNow() {
|
|
421
|
+
state2.fire?.();
|
|
422
|
+
}
|
|
423
|
+
function deadlineAt() {
|
|
424
|
+
return state2.at;
|
|
425
|
+
}
|
|
426
|
+
function deadlineSignal() {
|
|
427
|
+
return state2.controller.signal;
|
|
428
|
+
}
|
|
429
|
+
function remainingDeadlineMs(now = Date.now) {
|
|
430
|
+
return state2.at === null ? null : state2.at - now();
|
|
431
|
+
}
|
|
432
|
+
function assertBeforeDeadline(doing) {
|
|
433
|
+
const remaining = remainingDeadlineMs();
|
|
434
|
+
if (remaining !== null && remaining <= 0) {
|
|
435
|
+
fireDeadlineNow();
|
|
436
|
+
throw new CliError("timeout", `the deadline passed while ${doing}`);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
function noteProgress(note) {
|
|
440
|
+
state2.note = note;
|
|
441
|
+
}
|
|
442
|
+
var state2;
|
|
443
|
+
var init_deadline = __esm(() => {
|
|
444
|
+
init_output();
|
|
445
|
+
state2 = {
|
|
446
|
+
at: null,
|
|
447
|
+
cancel: null,
|
|
448
|
+
controller: new AbortController,
|
|
449
|
+
fire: null,
|
|
450
|
+
fired: false,
|
|
451
|
+
note: null
|
|
452
|
+
};
|
|
453
|
+
});
|
|
454
|
+
|
|
382
455
|
// src/env.ts
|
|
383
456
|
var exports_env = {};
|
|
384
457
|
__export(exports_env, {
|
|
@@ -422,15 +495,22 @@ function resolveTokenRef() {
|
|
|
422
495
|
if (process.env.FLUNCLE_API_TOKEN !== undefined || !ref || false) {
|
|
423
496
|
return;
|
|
424
497
|
}
|
|
498
|
+
assertBeforeDeadline("reading FLUNCLE_API_TOKEN_REF with op");
|
|
499
|
+
const remaining = remainingDeadlineMs();
|
|
500
|
+
const timeout = remaining === null ? OP_READ_TIMEOUT_MS : Math.max(1, Math.min(OP_READ_TIMEOUT_MS, remaining));
|
|
425
501
|
try {
|
|
426
502
|
const secretRef = ref.startsWith("op://") ? ref : `op://${ref}`;
|
|
427
503
|
process.env.FLUNCLE_API_TOKEN = execFileSync("op", ["read", "--no-newline", secretRef], {
|
|
428
504
|
encoding: "utf8",
|
|
429
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
505
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
506
|
+
timeout
|
|
430
507
|
});
|
|
431
|
-
} catch {
|
|
432
|
-
|
|
508
|
+
} catch (error) {
|
|
509
|
+
assertBeforeDeadline("reading FLUNCLE_API_TOKEN_REF with op");
|
|
510
|
+
const timedOut = error.code === "ETIMEDOUT";
|
|
511
|
+
throw new Error(timedOut ? `op did not return FLUNCLE_API_TOKEN_REF (${ref}) within ${Math.ceil(timeout / 1000)} s; unlock 1Password or set FLUNCLE_API_TOKEN.` : `Could not read FLUNCLE_API_TOKEN_REF (${ref}) with op.`);
|
|
433
512
|
}
|
|
513
|
+
assertBeforeDeadline("reading FLUNCLE_API_TOKEN_REF with op");
|
|
434
514
|
}
|
|
435
515
|
function loadConfig() {
|
|
436
516
|
const profile = getEnvProfile();
|
|
@@ -451,8 +531,9 @@ function getEnvProfile() {
|
|
|
451
531
|
function isEnvProfile2(value) {
|
|
452
532
|
return envProfiles2.includes(value);
|
|
453
533
|
}
|
|
454
|
-
var import_dotenv2, envProfiles2, defaultEnvProfile = "production", loadedProfile;
|
|
534
|
+
var import_dotenv2, envProfiles2, defaultEnvProfile = "production", OP_READ_TIMEOUT_MS = 20000, loadedProfile;
|
|
455
535
|
var init_env = __esm(() => {
|
|
536
|
+
init_deadline();
|
|
456
537
|
import_dotenv2 = __toESM(require_main(), 1);
|
|
457
538
|
envProfiles2 = ["local", "production"];
|
|
458
539
|
});
|
|
@@ -591,43 +672,6 @@ var init_util = __esm(() => {
|
|
|
591
672
|
TIKTOK_DRAFT_STALE_MS = 24 * 60 * 60 * 1000;
|
|
592
673
|
});
|
|
593
674
|
|
|
594
|
-
// src/output.ts
|
|
595
|
-
import { writeSync as writeSync2 } from "node:fs";
|
|
596
|
-
function writeStdoutSync2(text) {
|
|
597
|
-
const buf = Buffer.from(text, "utf8");
|
|
598
|
-
let offset = 0;
|
|
599
|
-
while (offset < buf.length) {
|
|
600
|
-
try {
|
|
601
|
-
offset += writeSync2(1, buf, offset);
|
|
602
|
-
} catch (error) {
|
|
603
|
-
if (error.code === "EAGAIN") {
|
|
604
|
-
Atomics.wait(EAGAIN_WAIT2, 0, 0, 1);
|
|
605
|
-
continue;
|
|
606
|
-
}
|
|
607
|
-
throw error;
|
|
608
|
-
}
|
|
609
|
-
}
|
|
610
|
-
}
|
|
611
|
-
function isJsonFailure(value) {
|
|
612
|
-
return typeof value === "object" && value !== null && typeof value.code === "string" && typeof value.message === "string";
|
|
613
|
-
}
|
|
614
|
-
function printJson2(value) {
|
|
615
|
-
writeStdoutSync2(JSON.stringify(value, null, 2) + `
|
|
616
|
-
`);
|
|
617
|
-
}
|
|
618
|
-
var EAGAIN_WAIT2, CliError2;
|
|
619
|
-
var init_output = __esm(() => {
|
|
620
|
-
EAGAIN_WAIT2 = new Int32Array(new SharedArrayBuffer(4));
|
|
621
|
-
CliError2 = class CliError2 extends Error {
|
|
622
|
-
code;
|
|
623
|
-
constructor(code, message) {
|
|
624
|
-
super(message);
|
|
625
|
-
this.name = "CliError";
|
|
626
|
-
this.code = code;
|
|
627
|
-
}
|
|
628
|
-
};
|
|
629
|
-
});
|
|
630
|
-
|
|
631
675
|
// src/version.ts
|
|
632
676
|
function normalizeVersion(version) {
|
|
633
677
|
return version?.trim().replace(/^v/i, "");
|
|
@@ -651,7 +695,7 @@ function parseVersion(version) {
|
|
|
651
695
|
var currentVersion;
|
|
652
696
|
var init_version = __esm(() => {
|
|
653
697
|
init_output();
|
|
654
|
-
currentVersion = "0.
|
|
698
|
+
currentVersion = "0.276.0".trim() ? "0.276.0".trim() : "0.1.0";
|
|
655
699
|
});
|
|
656
700
|
|
|
657
701
|
// src/update-notifier.ts
|
|
@@ -9598,7 +9642,7 @@ async function userApiGet(path) {
|
|
|
9598
9642
|
function userHeaders() {
|
|
9599
9643
|
const stored = readUserToken();
|
|
9600
9644
|
if (!stored) {
|
|
9601
|
-
throw new
|
|
9645
|
+
throw new CliError("not_logged_in", "You're not signed in. Run `fluncle login` to link this device to your account.");
|
|
9602
9646
|
}
|
|
9603
9647
|
return {
|
|
9604
9648
|
Authorization: `Bearer ${stored.token}`
|
|
@@ -9672,11 +9716,15 @@ function adminHeaders() {
|
|
|
9672
9716
|
}
|
|
9673
9717
|
async function apiRequest(path, init = {}) {
|
|
9674
9718
|
const url = `${getApiBaseUrl()}${path}`;
|
|
9719
|
+
noteProgress(`waiting for the Fluncle API: ${init.method ?? "GET"} ${path}`);
|
|
9675
9720
|
return runPromise2(gen2(function* () {
|
|
9676
9721
|
const { response, text } = yield* tryPromise2({
|
|
9677
9722
|
catch: (cause) => new ApiTransportError({ cause }),
|
|
9678
9723
|
try: async (signal) => {
|
|
9679
|
-
const response = await fetch(url, {
|
|
9724
|
+
const response = await fetch(url, {
|
|
9725
|
+
...init,
|
|
9726
|
+
signal: AbortSignal.any([signal, deadlineSignal()])
|
|
9727
|
+
});
|
|
9680
9728
|
return { response, text: await response.text() };
|
|
9681
9729
|
}
|
|
9682
9730
|
});
|
|
@@ -9689,7 +9737,7 @@ async function apiRequest(path, init = {}) {
|
|
|
9689
9737
|
});
|
|
9690
9738
|
}
|
|
9691
9739
|
return data;
|
|
9692
|
-
}).pipe(mapError2((error) => error._tag === "ApiTransportError" ? error.cause : new
|
|
9740
|
+
}).pipe(mapError2((error) => error._tag === "ApiTransportError" ? error.cause : new CliError(error.code, error.message))));
|
|
9693
9741
|
}
|
|
9694
9742
|
function parseJson2(text) {
|
|
9695
9743
|
if (!text) {
|
|
@@ -9703,6 +9751,7 @@ function parseJson2(text) {
|
|
|
9703
9751
|
var ApiTransportError, ApiResponseError;
|
|
9704
9752
|
var init_api = __esm(() => {
|
|
9705
9753
|
init_dist();
|
|
9754
|
+
init_deadline();
|
|
9706
9755
|
init_env();
|
|
9707
9756
|
init_output();
|
|
9708
9757
|
init_user_token();
|
|
@@ -9788,7 +9837,7 @@ async function freshCommand({
|
|
|
9788
9837
|
if (showTracks) {
|
|
9789
9838
|
payload.tracks = response.tracks;
|
|
9790
9839
|
}
|
|
9791
|
-
|
|
9840
|
+
printJson(payload);
|
|
9792
9841
|
return;
|
|
9793
9842
|
}
|
|
9794
9843
|
const blocks = [];
|
|
@@ -9855,7 +9904,7 @@ async function albumsCommand({
|
|
|
9855
9904
|
if (slug) {
|
|
9856
9905
|
const response = await publicApiGet(`/api/v1/albums/${encodeURIComponent(slug)}`);
|
|
9857
9906
|
if (json) {
|
|
9858
|
-
|
|
9907
|
+
printJson(response);
|
|
9859
9908
|
return;
|
|
9860
9909
|
}
|
|
9861
9910
|
const { album } = response;
|
|
@@ -9869,7 +9918,7 @@ async function albumsCommand({
|
|
|
9869
9918
|
}
|
|
9870
9919
|
const response = await publicApiGet(`/api/v1/albums?page=${page}`);
|
|
9871
9920
|
if (json) {
|
|
9872
|
-
|
|
9921
|
+
printJson(response);
|
|
9873
9922
|
return;
|
|
9874
9923
|
}
|
|
9875
9924
|
printEntityIndex(response.albums, response, { plural: "albums", singular: "album" }, "albums");
|
|
@@ -9888,7 +9937,7 @@ async function artistsCommand({
|
|
|
9888
9937
|
if (slug) {
|
|
9889
9938
|
const response = await publicApiGet(`/api/v1/artists/${encodeURIComponent(slug)}`);
|
|
9890
9939
|
if (json) {
|
|
9891
|
-
|
|
9940
|
+
printJson(response);
|
|
9892
9941
|
return;
|
|
9893
9942
|
}
|
|
9894
9943
|
const { artist } = response;
|
|
@@ -9902,7 +9951,7 @@ async function artistsCommand({
|
|
|
9902
9951
|
}
|
|
9903
9952
|
const response = await publicApiGet(`/api/v1/artists?page=${page}`);
|
|
9904
9953
|
if (json) {
|
|
9905
|
-
|
|
9954
|
+
printJson(response);
|
|
9906
9955
|
return;
|
|
9907
9956
|
}
|
|
9908
9957
|
printEntityIndex(response.artists, response, { plural: "artists", singular: "artist" }, "artists");
|
|
@@ -9921,7 +9970,7 @@ async function labelsCommand({
|
|
|
9921
9970
|
if (slug) {
|
|
9922
9971
|
const response = await publicApiGet(`/api/v1/labels/${encodeURIComponent(slug)}`);
|
|
9923
9972
|
if (json) {
|
|
9924
|
-
|
|
9973
|
+
printJson(response);
|
|
9925
9974
|
return;
|
|
9926
9975
|
}
|
|
9927
9976
|
const { label } = response;
|
|
@@ -9938,7 +9987,7 @@ async function labelsCommand({
|
|
|
9938
9987
|
}
|
|
9939
9988
|
const response = await publicApiGet(`/api/v1/labels?page=${page}`);
|
|
9940
9989
|
if (json) {
|
|
9941
|
-
|
|
9990
|
+
printJson(response);
|
|
9942
9991
|
return;
|
|
9943
9992
|
}
|
|
9944
9993
|
printEntityIndex(response.labels, response, { plural: "labels", singular: "label" }, "labels");
|
|
@@ -9978,7 +10027,7 @@ async function searchCommand({
|
|
|
9978
10027
|
}
|
|
9979
10028
|
const response = await publicApiGet(`/api/v1/search/archive?${params.toString()}`);
|
|
9980
10029
|
if (json) {
|
|
9981
|
-
|
|
10030
|
+
printJson(response);
|
|
9982
10031
|
return;
|
|
9983
10032
|
}
|
|
9984
10033
|
const blocks = [];
|
|
@@ -10049,7 +10098,7 @@ async function mixtapeGetCommand(idOrLogId) {
|
|
|
10049
10098
|
const mixtapes = await mixtapeListCommand();
|
|
10050
10099
|
const match = mixtapes.find((mixtape) => mixtape.id === idOrLogId || mixtape.logId === idOrLogId);
|
|
10051
10100
|
if (!match) {
|
|
10052
|
-
throw new
|
|
10101
|
+
throw new CliError("mixtape_not_found", `No mixtape with id or log id ${idOrLogId}`);
|
|
10053
10102
|
}
|
|
10054
10103
|
return match;
|
|
10055
10104
|
}
|
|
@@ -10071,7 +10120,7 @@ async function distributeYoutube(mixtapeId, videoPath, onProgress) {
|
|
|
10071
10120
|
while (videoId === undefined) {
|
|
10072
10121
|
attempts += 1;
|
|
10073
10122
|
if (attempts > MAX_UPLOAD_ATTEMPTS) {
|
|
10074
|
-
throw new
|
|
10123
|
+
throw new CliError("youtube_upload_failed", `YouTube upload did not complete after ${MAX_UPLOAD_ATTEMPTS} attempts`);
|
|
10075
10124
|
}
|
|
10076
10125
|
onProgress?.(offset > 0 ? `Resuming upload at ${formatBytes(offset)} / ${formatBytes(contentLength)}` : `Uploading video → YouTube`);
|
|
10077
10126
|
const result = await putChunk({
|
|
@@ -10130,7 +10179,7 @@ async function putChunk(args) {
|
|
|
10130
10179
|
if (response.status === 200 || response.status === 201) {
|
|
10131
10180
|
const video = await response.json().catch(() => ({}));
|
|
10132
10181
|
if (!video.id) {
|
|
10133
|
-
throw new
|
|
10182
|
+
throw new CliError("youtube_no_video_id", "YouTube returned no video id on upload completion");
|
|
10134
10183
|
}
|
|
10135
10184
|
return { kind: "done", videoId: video.id };
|
|
10136
10185
|
}
|
|
@@ -10144,7 +10193,7 @@ async function putChunk(args) {
|
|
|
10144
10193
|
return { kind: "reinit" };
|
|
10145
10194
|
}
|
|
10146
10195
|
const detail = (await response.text().catch(() => "")).slice(0, 400);
|
|
10147
|
-
throw new
|
|
10196
|
+
throw new CliError("youtube_put_failed", `YouTube upload PUT failed (${response.status} ${response.statusText})${detail ? `: ${detail}` : ""}`);
|
|
10148
10197
|
}
|
|
10149
10198
|
async function queryOffset(sessionUri, accessToken, contentLength) {
|
|
10150
10199
|
const response = await fetch(sessionUri, {
|
|
@@ -10176,7 +10225,7 @@ function fileSize(path) {
|
|
|
10176
10225
|
try {
|
|
10177
10226
|
return statSync(path).size;
|
|
10178
10227
|
} catch {
|
|
10179
|
-
throw new
|
|
10228
|
+
throw new CliError("video_not_found", `Cannot read video file at ${path}`);
|
|
10180
10229
|
}
|
|
10181
10230
|
}
|
|
10182
10231
|
function formatBytes(bytes) {
|
|
@@ -10200,11 +10249,11 @@ async function distributeMixcloud(mixtapeId, audioPath, onProgress, unlisted = f
|
|
|
10200
10249
|
const mixtape = await mixtapeGetCommand(mixtapeId);
|
|
10201
10250
|
const logId = mixtape.logId;
|
|
10202
10251
|
if (!logId) {
|
|
10203
|
-
throw new
|
|
10252
|
+
throw new CliError("mixtape_no_log_id", "The mixtape has no Log ID; mint it before distributing");
|
|
10204
10253
|
}
|
|
10205
10254
|
const audio = Bun.file(audioPath);
|
|
10206
10255
|
if (!await audio.exists()) {
|
|
10207
|
-
throw new
|
|
10256
|
+
throw new CliError("audio_not_found", `Audio master not found: ${audioPath}`);
|
|
10208
10257
|
}
|
|
10209
10258
|
const form = new FormData;
|
|
10210
10259
|
form.append("mp3", audio);
|
|
@@ -10241,7 +10290,7 @@ async function distributeMixcloud(mixtapeId, audioPath, onProgress, unlisted = f
|
|
|
10241
10290
|
}
|
|
10242
10291
|
const result = parseUploadResult(uploadText);
|
|
10243
10292
|
if (!result.success || !result.key) {
|
|
10244
|
-
throw new
|
|
10293
|
+
throw new CliError("mixcloud_upload_rejected", `Mixcloud rejected the upload: ${result.message ?? uploadText.slice(0, 300)}`);
|
|
10245
10294
|
}
|
|
10246
10295
|
const externalId = result.key;
|
|
10247
10296
|
const url = `https://www.mixcloud.com${result.key}`;
|
|
@@ -10279,7 +10328,7 @@ async function fetchMixcloudToken() {
|
|
|
10279
10328
|
const response = await adminApiPost("/api/v1/admin/mixcloud/token");
|
|
10280
10329
|
return response.accessToken;
|
|
10281
10330
|
} catch {
|
|
10282
|
-
throw new
|
|
10331
|
+
throw new CliError("mixcloud_not_connected", "Mixcloud is not connected. Run `fluncle admin auth mixcloud` to authorize it.");
|
|
10283
10332
|
}
|
|
10284
10333
|
}
|
|
10285
10334
|
async function fetchCover(logId) {
|
|
@@ -10309,9 +10358,9 @@ function parseUploadResult(body) {
|
|
|
10309
10358
|
}
|
|
10310
10359
|
function throwMixcloudError(status, body) {
|
|
10311
10360
|
if (body.includes("An invalid access token was provided")) {
|
|
10312
|
-
throw new
|
|
10361
|
+
throw new CliError("mixcloud_invalid_token", "Mixcloud rejected the access token. Re-auth with `fluncle admin auth mixcloud`.");
|
|
10313
10362
|
}
|
|
10314
|
-
throw new
|
|
10363
|
+
throw new CliError("mixcloud_request_failed", `Mixcloud responded ${status}${body ? `: ${body.slice(0, 300)}` : ""}`);
|
|
10315
10364
|
}
|
|
10316
10365
|
var MIXCLOUD_API = "https://api.mixcloud.com", DESCRIPTION_MAX = 1000, PICTURE_MAX_BYTES, COVER_BASE = "https://www.fluncle.com/api/mixtape-cover";
|
|
10317
10366
|
var init_mixtape_mixcloud = __esm(() => {
|
|
@@ -10333,21 +10382,21 @@ async function mixtapeUpdateCommand(id, options) {
|
|
|
10333
10382
|
async function mixtapeDistributeCommand(idOrLogId, options, onProgress = () => {}) {
|
|
10334
10383
|
const mixtape = await mixtapeGetCommand(idOrLogId);
|
|
10335
10384
|
if (!mixtape.id) {
|
|
10336
|
-
throw new
|
|
10385
|
+
throw new CliError("mixtape_not_found", `No mixtape with id or log id ${idOrLogId}`);
|
|
10337
10386
|
}
|
|
10338
10387
|
const both = !options.youtube && !options.mixcloud;
|
|
10339
10388
|
const doYoutube = both || Boolean(options.youtube);
|
|
10340
10389
|
const doMixcloud = both || Boolean(options.mixcloud);
|
|
10341
10390
|
if (doYoutube && !options.video) {
|
|
10342
|
-
throw new
|
|
10391
|
+
throw new CliError("missing_video", "YouTube distribution needs --video <mp4>");
|
|
10343
10392
|
}
|
|
10344
10393
|
if (doMixcloud && !options.audio) {
|
|
10345
|
-
throw new
|
|
10394
|
+
throw new CliError("missing_audio", "Mixcloud distribution needs --audio <file>");
|
|
10346
10395
|
}
|
|
10347
10396
|
const mixtapeId = mixtape.id;
|
|
10348
10397
|
const logId = mixtape.logId;
|
|
10349
10398
|
if (!logId) {
|
|
10350
|
-
throw new
|
|
10399
|
+
throw new CliError("mixtape_not_promoted", `${mixtapeId} has no coordinate yet. Promote its recording first:
|
|
10351
10400
|
` + " fluncle admin recordings promote <recordingId>");
|
|
10352
10401
|
}
|
|
10353
10402
|
if (!mixtape.durationMs) {
|
|
@@ -10366,7 +10415,7 @@ async function mixtapeDistributeCommand(idOrLogId, options, onProgress = () => {
|
|
|
10366
10415
|
const results = [];
|
|
10367
10416
|
if (doYoutube) {
|
|
10368
10417
|
if (!options.video) {
|
|
10369
|
-
throw new
|
|
10418
|
+
throw new CliError("missing_video", "YouTube distribution needs --video <mp4>");
|
|
10370
10419
|
}
|
|
10371
10420
|
onProgress("YouTube: uploading video…");
|
|
10372
10421
|
await Promise.resolve().then(() => init_mixtape_youtube());
|
|
@@ -10376,7 +10425,7 @@ async function mixtapeDistributeCommand(idOrLogId, options, onProgress = () => {
|
|
|
10376
10425
|
}
|
|
10377
10426
|
if (doMixcloud) {
|
|
10378
10427
|
if (!options.audio) {
|
|
10379
|
-
throw new
|
|
10428
|
+
throw new CliError("missing_audio", "Mixcloud distribution needs --audio <file>");
|
|
10380
10429
|
}
|
|
10381
10430
|
onProgress("Mixcloud: uploading audio…");
|
|
10382
10431
|
await Promise.resolve().then(() => init_mixtape_mixcloud());
|
|
@@ -10389,10 +10438,10 @@ async function mixtapeDistributeCommand(idOrLogId, options, onProgress = () => {
|
|
|
10389
10438
|
async function mixtapeResyncCommand(idOrLogId, options, onProgress = () => {}) {
|
|
10390
10439
|
const mixtape = await mixtapeGetCommand(idOrLogId);
|
|
10391
10440
|
if (!mixtape.id) {
|
|
10392
|
-
throw new
|
|
10441
|
+
throw new CliError("mixtape_not_found", `No mixtape with id or log id ${idOrLogId}`);
|
|
10393
10442
|
}
|
|
10394
10443
|
if (!mixtape.logId) {
|
|
10395
|
-
throw new
|
|
10444
|
+
throw new CliError("mixtape_no_log_id", "The mixtape isn't published yet. Distribute it before re-syncing.");
|
|
10396
10445
|
}
|
|
10397
10446
|
const mixtapeId = mixtape.id;
|
|
10398
10447
|
const explicit = Boolean(options.youtube) || Boolean(options.mixcloud);
|
|
@@ -10404,7 +10453,7 @@ async function mixtapeResyncCommand(idOrLogId, options, onProgress = () => {}) {
|
|
|
10404
10453
|
doYoutube = platforms.has("youtube");
|
|
10405
10454
|
doMixcloud = platforms.has("mixcloud");
|
|
10406
10455
|
if (!doYoutube && !doMixcloud) {
|
|
10407
|
-
throw new
|
|
10456
|
+
throw new CliError("mixtape_not_distributed", "The mixtape has no YouTube or Mixcloud link to re-sync.");
|
|
10408
10457
|
}
|
|
10409
10458
|
}
|
|
10410
10459
|
const results = [];
|
|
@@ -10449,7 +10498,7 @@ function buildBody(options) {
|
|
|
10449
10498
|
if (options.durationMs !== undefined) {
|
|
10450
10499
|
const parsed = parseDuration(options.durationMs);
|
|
10451
10500
|
if (parsed === null) {
|
|
10452
|
-
throw new
|
|
10501
|
+
throw new CliError("invalid_duration", "Duration must be mm:ss or h:mm:ss, or a millisecond count");
|
|
10453
10502
|
}
|
|
10454
10503
|
body.durationMs = parsed;
|
|
10455
10504
|
}
|
|
@@ -10478,7 +10527,7 @@ var init_format = __esm(() => {
|
|
|
10478
10527
|
import { createInterface } from "node:readline/promises";
|
|
10479
10528
|
async function promptLine(label, nonInteractiveMessage) {
|
|
10480
10529
|
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
10481
|
-
throw new
|
|
10530
|
+
throw new CliError("not_interactive", nonInteractiveMessage);
|
|
10482
10531
|
}
|
|
10483
10532
|
const rl = createInterface({
|
|
10484
10533
|
input: process.stdin,
|
|
@@ -10494,7 +10543,7 @@ async function selectWithKeyboard(items, options) {
|
|
|
10494
10543
|
const stdin = options.input ?? process.stdin;
|
|
10495
10544
|
const stdout = options.output ?? process.stdout;
|
|
10496
10545
|
if (!stdin.isTTY || !stdout.isTTY) {
|
|
10497
|
-
throw new
|
|
10546
|
+
throw new CliError("not_interactive", options.nonInteractiveMessage);
|
|
10498
10547
|
}
|
|
10499
10548
|
let selectedIndex = 0;
|
|
10500
10549
|
let renderedLines = 0;
|
|
@@ -10581,7 +10630,7 @@ async function openExternal(target) {
|
|
|
10581
10630
|
const command = platformOpenCommand();
|
|
10582
10631
|
if (!command) {
|
|
10583
10632
|
console.log(target);
|
|
10584
|
-
throw new
|
|
10633
|
+
throw new CliError("unsupported_platform", `Automatic opening is only supported on macOS and Linux. Open this manually: ${target}`);
|
|
10585
10634
|
}
|
|
10586
10635
|
const child = Bun.spawn([command, target], {
|
|
10587
10636
|
stderr: "pipe",
|
|
@@ -10590,7 +10639,7 @@ async function openExternal(target) {
|
|
|
10590
10639
|
const exitCode = await child.exited;
|
|
10591
10640
|
if (exitCode !== 0) {
|
|
10592
10641
|
const stderr = await new Response(child.stderr).text();
|
|
10593
|
-
throw new
|
|
10642
|
+
throw new CliError("open_failed", stderr.trim() || `Could not open ${target} with ${command}`);
|
|
10594
10643
|
}
|
|
10595
10644
|
}
|
|
10596
10645
|
function platformOpenCommand() {
|
|
@@ -10665,7 +10714,7 @@ async function openRecentCommand(options) {
|
|
|
10665
10714
|
function spotifyPlaylistUrlToAppUri(playlistUrl) {
|
|
10666
10715
|
const playlistId = playlistUrl.match(/open\.spotify\.com\/playlist\/([^/?#]+)/)?.[1];
|
|
10667
10716
|
if (!playlistId) {
|
|
10668
|
-
throw new
|
|
10717
|
+
throw new CliError("invalid_playlist_url", `Could not parse Spotify playlist URL: ${playlistUrl}`);
|
|
10669
10718
|
}
|
|
10670
10719
|
return `spotify:playlist:${playlistId}`;
|
|
10671
10720
|
}
|
|
@@ -10714,13 +10763,13 @@ var init_random = __esm(() => {
|
|
|
10714
10763
|
async function subscribeCommand(email, json) {
|
|
10715
10764
|
const address = email?.trim() || await promptLine("Email: ", PROMPT_NON_INTERACTIVE_MESSAGE);
|
|
10716
10765
|
if (!address) {
|
|
10717
|
-
throw new
|
|
10766
|
+
throw new CliError("invalid_email", "Enter a valid email address.");
|
|
10718
10767
|
}
|
|
10719
10768
|
await publicApiPost("/api/v1/newsletter", {
|
|
10720
10769
|
email: address
|
|
10721
10770
|
});
|
|
10722
10771
|
if (json) {
|
|
10723
|
-
|
|
10772
|
+
printJson({
|
|
10724
10773
|
ok: true
|
|
10725
10774
|
});
|
|
10726
10775
|
return;
|
|
@@ -10738,11 +10787,11 @@ var init_subscribe = __esm(() => {
|
|
|
10738
10787
|
async function submitCommand(input) {
|
|
10739
10788
|
const query = input?.trim() || await promptLine("Track or Spotify link: ", PROMPT_NON_INTERACTIVE_MESSAGE2);
|
|
10740
10789
|
if (!query) {
|
|
10741
|
-
throw new
|
|
10790
|
+
throw new CliError("missing_query", "Missing search input");
|
|
10742
10791
|
}
|
|
10743
10792
|
const response = await publicApiGet(`/api/v1/search?q=${encodeURIComponent(query)}`);
|
|
10744
10793
|
if (response.results.length === 0) {
|
|
10745
|
-
throw new
|
|
10794
|
+
throw new CliError("no_results", "Nothing came back for that search. Try the artist and the title.");
|
|
10746
10795
|
}
|
|
10747
10796
|
const selected = await selectCandidate(response.results);
|
|
10748
10797
|
if (!selected) {
|
|
@@ -10844,7 +10893,7 @@ async function requestDeviceCode(baseUrl) {
|
|
|
10844
10893
|
return;
|
|
10845
10894
|
});
|
|
10846
10895
|
if (!response.ok || !data?.device_code || !data.user_code) {
|
|
10847
|
-
throw new
|
|
10896
|
+
throw new CliError("device_code_failed", `Couldn't start the login flow (${response.status}). Try again in a moment.`);
|
|
10848
10897
|
}
|
|
10849
10898
|
return data;
|
|
10850
10899
|
}
|
|
@@ -10876,15 +10925,15 @@ async function pollForToken(baseUrl, device) {
|
|
|
10876
10925
|
intervalMs += 5000;
|
|
10877
10926
|
break;
|
|
10878
10927
|
case "access_denied":
|
|
10879
|
-
throw new
|
|
10928
|
+
throw new CliError("access_denied", "Sign-in was denied in the browser. Nothing linked.");
|
|
10880
10929
|
case "expired_token":
|
|
10881
|
-
throw new
|
|
10930
|
+
throw new CliError("expired_token", "The login request timed out. Run `fluncle login` again.");
|
|
10882
10931
|
default:
|
|
10883
|
-
throw new
|
|
10932
|
+
throw new CliError("device_token_failed", pending?.error_description ?? `Login failed (${response.status}).`);
|
|
10884
10933
|
}
|
|
10885
10934
|
await sleep3(intervalMs);
|
|
10886
10935
|
}
|
|
10887
|
-
throw new
|
|
10936
|
+
throw new CliError("expired_token", "The login request timed out. Run `fluncle login` again.");
|
|
10888
10937
|
}
|
|
10889
10938
|
async function fetchSessionUser(baseUrl, token) {
|
|
10890
10939
|
const response = await fetch(`${baseUrl}/api/v1/me`, {
|
|
@@ -11020,7 +11069,7 @@ var init_about = __esm(() => {
|
|
|
11020
11069
|
async function versionCommand(options) {
|
|
11021
11070
|
const result = options.check ? await buildVersionCheck() : buildCurrentVersion();
|
|
11022
11071
|
if (options.json) {
|
|
11023
|
-
|
|
11072
|
+
printJson({
|
|
11024
11073
|
ok: true,
|
|
11025
11074
|
...result
|
|
11026
11075
|
});
|
|
@@ -11086,7 +11135,7 @@ function parseVersion2(version) {
|
|
|
11086
11135
|
var currentVersion2, latestReleaseUrl = "https://api.github.com/repos/mauricekleine/fluncle/releases/latest";
|
|
11087
11136
|
var init_version2 = __esm(() => {
|
|
11088
11137
|
init_output();
|
|
11089
|
-
currentVersion2 = "0.
|
|
11138
|
+
currentVersion2 = "0.276.0".trim() ? "0.276.0".trim() : "0.1.0";
|
|
11090
11139
|
});
|
|
11091
11140
|
|
|
11092
11141
|
// ../../packages/registry/src/index.ts
|
|
@@ -12605,7 +12654,7 @@ var init_src = __esm(() => {
|
|
|
12605
12654
|
],
|
|
12606
12655
|
kind: "cron",
|
|
12607
12656
|
name: "cron.publish-advance",
|
|
12608
|
-
operatorNotes: "every 30m. Pure HTTP trigger, zero LLM tokens. The last autonomy gap: render finishes → this pushes, with no operator beat between. Admin tier (needs the Worker's Postiz key, which the box never sees — the box only triggers; the `drip_clips` / `capture_post_urls` precedent). SHIPS DARK: the Worker's kill switch is DEFAULT-DENY (only an explicit `false` in the `publish_advance_paused` setting runs it), so the timer ticks and posts nothing until `fluncle admin publish resume`. The Worker reads the switch FIRST, then advances at most ONE ready finding — both masters finalized,
|
|
12657
|
+
operatorNotes: "every 30m. Pure HTTP trigger, zero LLM tokens. The last autonomy gap: render finishes → this pushes, with no operator beat between. Admin tier (needs the Worker's Postiz key, which the box never sees — the box only triggers; the `drip_clips` / `capture_post_urls` precedent). SHIPS DARK: the Worker's kill switch is DEFAULT-DENY (only an explicit `false` in the `publish_advance_paused` setting runs it), so the timer ticks and posts nothing until `fluncle admin publish resume`. The Worker reads the switch FIRST, then advances at most ONE ready finding — both masters finalized, settled six hours, the whole bundle served on R2, the (track, platform) row CLAIMED atomically before any Postiz call, a rolling-24h cap of 4 pushes. A failed push is left `failed` for the operator and never auto-retried. Source: docs/agents/hermes/scripts/publish-advance-sweep.sh. Probed on /status as cron.publish-advance.",
|
|
12609
12658
|
probeConfig: { cadenceMs: 30 * MINUTE_MS, cronName: "fluncle-publish-advance", kind: "cron" },
|
|
12610
12659
|
statusDescription: "advances the publish queue on his own clock",
|
|
12611
12660
|
title: "Publish advance",
|
|
@@ -12712,7 +12761,7 @@ var init_src = __esm(() => {
|
|
|
12712
12761
|
],
|
|
12713
12762
|
kind: "cron",
|
|
12714
12763
|
name: "cron.indexnow",
|
|
12715
|
-
operatorNotes: "06:00 Europe/Amsterdam, after nightly hub reconciliation, with a 07:15 retry. Calls the agent-tier submit_indexnow walk, claim, and ack phases in bounded admitted windows. The box posts paced batches of 1,000, up to
|
|
12764
|
+
operatorNotes: "06:00 Europe/Amsterdam, after nightly hub reconciliation, with a 07:15 retry. Calls the agent-tier submit_indexnow walk, claim, and ack phases in bounded admitted windows. The box posts paced batches of 1,000, up to 2,000 URLs per daily run, with Yandex fallback on 429 and bounded Retry-After backoff. A complete walk within 12 hours skips the retry walk. HTTP 200/202 allow matching-version stamps; unaccepted versions stay due, partial rate limits remain resumable, and zero-acceptance rate limits or other rejections fail the run summary. Source: docs/agents/hermes/scripts/indexnow.* and docs/agents/hermes/indexnow-timer/.",
|
|
12716
12765
|
operatorOnly: "Search-engine notification is plumbing, not a listener-facing automation.",
|
|
12717
12766
|
probeConfig: {
|
|
12718
12767
|
cadenceMs: 24 * 60 * MINUTE_MS,
|
|
@@ -12978,7 +13027,7 @@ function checkBundleCompleteness(files) {
|
|
|
12978
13027
|
function validateBundleCompleteness(files, onProgress, options) {
|
|
12979
13028
|
const completeness = checkBundleCompleteness(files);
|
|
12980
13029
|
if (completeness.uploadingFootage && completeness.missingContract.length > 0 && !options.allowPartial) {
|
|
12981
|
-
throw new
|
|
13030
|
+
throw new CliError("bundle_incomplete", `Refusing to upload a PARTIAL bundle: footage is being uploaded but the re-render contract is missing ${completeness.missingContract.join(", ")}. ` + `A footage-only upload leaves composition.tsx/props.json/render.json stale on R2 and desyncs the render.json from the DB ledger. ` + `Ship the complete bundle (re-run \`ship\` and upload with --dir), or pass --allow-partial for a deliberate partial refresh (e.g. poster-only).`);
|
|
12982
13031
|
}
|
|
12983
13032
|
if (completeness.uploadingFootage) {
|
|
12984
13033
|
if (completeness.missingContract.length > 0) {
|
|
@@ -12999,7 +13048,7 @@ async function trackVideoCommand(idOrLogId, files, onProgress, options = {}) {
|
|
|
12999
13048
|
path: files[spec.option]
|
|
13000
13049
|
})).filter((spec) => Boolean(spec.path));
|
|
13001
13050
|
if (present.length === 0) {
|
|
13002
|
-
throw new
|
|
13051
|
+
throw new CliError("nothing_to_upload", "No bundle files resolved to upload (pass --dir <bundle> or explicit file flags).");
|
|
13003
13052
|
}
|
|
13004
13053
|
const platesOnly = isPlatesOnlyUpload(files);
|
|
13005
13054
|
const presign = await adminApiPost(`/api/v1/admin/tracks/${encodeURIComponent(idOrLogId)}/video/uploads`, { fields: present.map((spec) => spec.field) });
|
|
@@ -13009,7 +13058,7 @@ async function trackVideoCommand(idOrLogId, files, onProgress, options = {}) {
|
|
|
13009
13058
|
for (const spec of present) {
|
|
13010
13059
|
const upload = byField.get(spec.field);
|
|
13011
13060
|
if (!upload) {
|
|
13012
|
-
throw new
|
|
13061
|
+
throw new CliError("presign_missing", `Worker did not sign an upload for ${spec.field}`);
|
|
13013
13062
|
}
|
|
13014
13063
|
onProgress?.(`Uploading ${spec.field} → ${upload.key}`);
|
|
13015
13064
|
const file = Bun.file(spec.path);
|
|
@@ -13021,7 +13070,7 @@ async function trackVideoCommand(idOrLogId, files, onProgress, options = {}) {
|
|
|
13021
13070
|
});
|
|
13022
13071
|
if (!response.ok) {
|
|
13023
13072
|
const detail = (await response.text().catch(() => "")).slice(0, 300);
|
|
13024
|
-
throw new
|
|
13073
|
+
throw new CliError("r2_put_failed", `R2 rejected ${spec.field} with ${response.status} ${response.statusText}${detail ? `: ${detail}` : ""}`);
|
|
13025
13074
|
}
|
|
13026
13075
|
urls[spec.field] = `${FOUND_BASE}/${upload.key}`;
|
|
13027
13076
|
}
|
|
@@ -26162,6 +26211,10 @@ var init_admin_tracks = __esm(() => {
|
|
|
26162
26211
|
scope: TrackWorkScopeSchema.default("all")
|
|
26163
26212
|
})).output(object({
|
|
26164
26213
|
capabilities: TrackWorkCapabilitiesSchema.optional(),
|
|
26214
|
+
catalogueCapture: object({
|
|
26215
|
+
closedReason: _enum(["paused", "bytes_spent", "tracks_spent"]),
|
|
26216
|
+
open: literal(false)
|
|
26217
|
+
}).optional(),
|
|
26165
26218
|
debtPending: boolean3().optional(),
|
|
26166
26219
|
ok: literal(true),
|
|
26167
26220
|
oldestQueuedCaptureOver24h: boolean3().optional(),
|
|
@@ -28970,7 +29023,7 @@ async function resolveMixtapeId(idOrLogId) {
|
|
|
28970
29023
|
const response = await adminApiGet("/api/v1/admin/mixtapes");
|
|
28971
29024
|
const match = response.mixtapes.find((mixtape) => mixtape.id === idOrLogId || mixtape.logId === idOrLogId);
|
|
28972
29025
|
if (!match?.id) {
|
|
28973
|
-
throw new
|
|
29026
|
+
throw new CliError("mixtape_not_found", `No mixtape with id or Log ID ${idOrLogId}`);
|
|
28974
29027
|
}
|
|
28975
29028
|
return match.id;
|
|
28976
29029
|
}
|
|
@@ -29085,7 +29138,7 @@ function renditionFfmpegArgs(inputPath, outputPath) {
|
|
|
29085
29138
|
}
|
|
29086
29139
|
async function uploadRenditionMultipart(masterPath, presignPath, onProgress = () => {}) {
|
|
29087
29140
|
if (!existsSync(masterPath)) {
|
|
29088
|
-
throw new
|
|
29141
|
+
throw new CliError("file_not_found", `Set-video master not found: ${masterPath}`);
|
|
29089
29142
|
}
|
|
29090
29143
|
await assertFfmpeg();
|
|
29091
29144
|
const renditionPath = join4(tmpdir(), `fluncle-set-${randomUUID()}.mp4`);
|
|
@@ -29104,7 +29157,7 @@ async function uploadRenditionMultipart(masterPath, presignPath, onProgress = ()
|
|
|
29104
29157
|
for (const part of plan.parts) {
|
|
29105
29158
|
const url = urlByPart.get(part.partNumber);
|
|
29106
29159
|
if (!url) {
|
|
29107
|
-
throw new
|
|
29160
|
+
throw new CliError("presign_missing", `Worker did not sign part ${part.partNumber} of ${plan.partCount}`);
|
|
29108
29161
|
}
|
|
29109
29162
|
onProgress(`Set video: part ${part.partNumber}/${plan.partCount}`);
|
|
29110
29163
|
const etag = await putPart(url, renditionPath, part, onProgress);
|
|
@@ -29126,11 +29179,11 @@ async function putPart(url, path, part, onProgress = () => {}) {
|
|
|
29126
29179
|
try {
|
|
29127
29180
|
return await putPartOnce(url, body, part);
|
|
29128
29181
|
} catch (error) {
|
|
29129
|
-
if (error instanceof
|
|
29182
|
+
if (error instanceof CliError || deadlineSignal().aborted) {
|
|
29130
29183
|
throw error;
|
|
29131
29184
|
}
|
|
29132
29185
|
if (attempt >= MAX_PART_ATTEMPTS) {
|
|
29133
|
-
throw new
|
|
29186
|
+
throw new CliError("r2_part_failed", `Part ${part.partNumber} failed after ${MAX_PART_ATTEMPTS} attempts: ${error instanceof Error ? error.message : String(error)}`);
|
|
29134
29187
|
}
|
|
29135
29188
|
const backoffMs = 500 * 2 ** (attempt - 1);
|
|
29136
29189
|
onProgress(`Set video: part ${part.partNumber} dropped, retry ${attempt}/${MAX_PART_ATTEMPTS - 1} in ${backoffMs}ms…`);
|
|
@@ -29139,17 +29192,17 @@ async function putPart(url, path, part, onProgress = () => {}) {
|
|
|
29139
29192
|
}
|
|
29140
29193
|
}
|
|
29141
29194
|
async function putPartOnce(url, body, part) {
|
|
29142
|
-
const response = await fetch(url, { body, method: "PUT" });
|
|
29195
|
+
const response = await fetch(url, { body, method: "PUT", signal: deadlineSignal() });
|
|
29143
29196
|
if (!response.ok) {
|
|
29144
29197
|
const detail = (await response.text().catch(() => "")).slice(0, 300);
|
|
29145
29198
|
if (response.status < 500) {
|
|
29146
|
-
throw new
|
|
29199
|
+
throw new CliError("r2_part_failed", `R2 rejected part ${part.partNumber} (${response.status} ${response.statusText})${detail ? `: ${detail}` : ""}`);
|
|
29147
29200
|
}
|
|
29148
29201
|
throw new Error(`R2 ${response.status} ${response.statusText} on part ${part.partNumber}${detail ? `: ${detail}` : ""}`);
|
|
29149
29202
|
}
|
|
29150
29203
|
const etag = response.headers.get("etag");
|
|
29151
29204
|
if (!etag) {
|
|
29152
|
-
throw new
|
|
29205
|
+
throw new CliError("r2_no_etag", `R2 returned no ETag for part ${part.partNumber}`);
|
|
29153
29206
|
}
|
|
29154
29207
|
return etag;
|
|
29155
29208
|
}
|
|
@@ -29157,15 +29210,16 @@ async function completeUpload(url, parts) {
|
|
|
29157
29210
|
const response = await fetch(url, {
|
|
29158
29211
|
body: buildCompleteXml(parts),
|
|
29159
29212
|
headers: { "content-type": "application/xml" },
|
|
29160
|
-
method: "POST"
|
|
29213
|
+
method: "POST",
|
|
29214
|
+
signal: deadlineSignal()
|
|
29161
29215
|
});
|
|
29162
29216
|
const text = await response.text().catch(() => "");
|
|
29163
29217
|
if (!response.ok || text.includes("<Error>")) {
|
|
29164
|
-
throw new
|
|
29218
|
+
throw new CliError("r2_complete_failed", `R2 CompleteMultipartUpload failed (${response.status} ${response.statusText})${text ? `: ${text.slice(0, 300)}` : ""}`);
|
|
29165
29219
|
}
|
|
29166
29220
|
}
|
|
29167
29221
|
async function abortUpload(url) {
|
|
29168
|
-
await fetch(url, { method: "DELETE" });
|
|
29222
|
+
await fetch(url, { method: "DELETE", signal: AbortSignal.timeout(UPLOAD_ABORT_TIMEOUT_MS) });
|
|
29169
29223
|
}
|
|
29170
29224
|
async function assertFfmpeg() {
|
|
29171
29225
|
try {
|
|
@@ -29175,7 +29229,7 @@ async function assertFfmpeg() {
|
|
|
29175
29229
|
throw new Error("ffmpeg -version exited non-zero");
|
|
29176
29230
|
}
|
|
29177
29231
|
} catch {
|
|
29178
|
-
throw new
|
|
29232
|
+
throw new CliError("ffmpeg_missing", "--set-video needs ffmpeg to derive the 1080p rendition. Install it (brew install ffmpeg).");
|
|
29179
29233
|
}
|
|
29180
29234
|
}
|
|
29181
29235
|
async function deriveRendition(inputPath, outputPath) {
|
|
@@ -29186,13 +29240,14 @@ async function deriveRendition(inputPath, outputPath) {
|
|
|
29186
29240
|
await proc.exited;
|
|
29187
29241
|
if (proc.exitCode !== 0) {
|
|
29188
29242
|
const detail = (await new Response(proc.stderr).text().catch(() => "")).slice(-400);
|
|
29189
|
-
throw new
|
|
29243
|
+
throw new CliError("ffmpeg_failed", `ffmpeg failed to derive the set-video rendition${detail ? `: ${detail}` : ""}`);
|
|
29190
29244
|
}
|
|
29191
29245
|
}
|
|
29192
|
-
var FOUND_BASE2 = "https://found.fluncle.com", SET_VIDEO_RENDITION, MAX_PART_ATTEMPTS = 5;
|
|
29246
|
+
var FOUND_BASE2 = "https://found.fluncle.com", SET_VIDEO_RENDITION, MAX_PART_ATTEMPTS = 5, UPLOAD_ABORT_TIMEOUT_MS = 5000;
|
|
29193
29247
|
var init_mixtape_set_video = __esm(() => {
|
|
29194
29248
|
init_multipart();
|
|
29195
29249
|
init_api();
|
|
29250
|
+
init_deadline();
|
|
29196
29251
|
init_output();
|
|
29197
29252
|
SET_VIDEO_RENDITION = {
|
|
29198
29253
|
audioBitrate: "192k",
|
|
@@ -29289,12 +29344,12 @@ async function clipDripPauseCommand(paused) {
|
|
|
29289
29344
|
}
|
|
29290
29345
|
async function resolveClipSource(clip) {
|
|
29291
29346
|
if (!clip.recordingId) {
|
|
29292
|
-
throw new
|
|
29347
|
+
throw new CliError("clip_unlinked", `Clip ${clip.id} is linked to no recording`);
|
|
29293
29348
|
}
|
|
29294
29349
|
await Promise.resolve().then(() => init_recordings());
|
|
29295
29350
|
const recording = await recordingGet(clip.recordingId);
|
|
29296
29351
|
if (!recording.r2Key) {
|
|
29297
|
-
throw new
|
|
29352
|
+
throw new CliError("recording_not_staged", `Recording ${clip.recordingId} has no staged set video`);
|
|
29298
29353
|
}
|
|
29299
29354
|
return {
|
|
29300
29355
|
setUrl: r2PublicUrl(FOUND_BASE3, recording.r2Key)
|
|
@@ -29304,7 +29359,7 @@ async function clipCutCommand(clipId, onProgress = () => {}) {
|
|
|
29304
29359
|
const clips = await clipsListCommand();
|
|
29305
29360
|
const clip = clips.find((candidate) => candidate.id === clipId);
|
|
29306
29361
|
if (!clip) {
|
|
29307
|
-
throw new
|
|
29362
|
+
throw new CliError("clip_not_found", `No clip with id ${clipId}`);
|
|
29308
29363
|
}
|
|
29309
29364
|
const source = await resolveClipSource(clip);
|
|
29310
29365
|
await assertFfmpeg2();
|
|
@@ -29320,7 +29375,7 @@ async function clipCutCommand(clipId, onProgress = () => {}) {
|
|
|
29320
29375
|
});
|
|
29321
29376
|
const sizeBytes = statSync3(outputPath).size;
|
|
29322
29377
|
if (sizeBytes > MAX_CLIP_BYTES) {
|
|
29323
|
-
throw new
|
|
29378
|
+
throw new CliError("clip_too_large", `The cut is ${(sizeBytes / 1e6).toFixed(1)} MB (> 100 MB Cloudflare MT ceiling). Shorten the window or lower the bitrate cap`);
|
|
29324
29379
|
}
|
|
29325
29380
|
onProgress(`Clip ${clipId}: uploading ${(sizeBytes / 1e6).toFixed(1)} MB…`);
|
|
29326
29381
|
const presign = await adminApiPost(`/api/v1/admin/clips/${encodeURIComponent(clipId)}/cut/presign`, { contentType: "video/mp4" });
|
|
@@ -29345,7 +29400,7 @@ async function putClip(url, contentType, path) {
|
|
|
29345
29400
|
});
|
|
29346
29401
|
if (!response.ok) {
|
|
29347
29402
|
const detail = (await response.text().catch(() => "")).slice(0, 300);
|
|
29348
|
-
throw new
|
|
29403
|
+
throw new CliError("r2_put_failed", `R2 rejected the clip upload (${response.status} ${response.statusText})${detail ? `: ${detail}` : ""}`);
|
|
29349
29404
|
}
|
|
29350
29405
|
}
|
|
29351
29406
|
async function assertFfmpeg2() {
|
|
@@ -29356,12 +29411,12 @@ async function assertFfmpeg2() {
|
|
|
29356
29411
|
throw new Error("ffmpeg -version exited non-zero");
|
|
29357
29412
|
}
|
|
29358
29413
|
} catch {
|
|
29359
|
-
throw new
|
|
29414
|
+
throw new CliError("ffmpeg_missing", "The clip cut needs ffmpeg. Install it on the box (apt-get install -y ffmpeg).");
|
|
29360
29415
|
}
|
|
29361
29416
|
}
|
|
29362
29417
|
async function runClipCut(options) {
|
|
29363
29418
|
if (!options.setUrl) {
|
|
29364
|
-
throw new
|
|
29419
|
+
throw new CliError("missing_set_url", "The clip cut needs the set rendition URL");
|
|
29365
29420
|
}
|
|
29366
29421
|
const proc = Bun.spawn(["ffmpeg", ...clipCutFfmpegArgs(options)], {
|
|
29367
29422
|
stderr: "pipe",
|
|
@@ -29370,7 +29425,7 @@ async function runClipCut(options) {
|
|
|
29370
29425
|
await proc.exited;
|
|
29371
29426
|
if (proc.exitCode !== 0) {
|
|
29372
29427
|
const detail = (await new Response(proc.stderr).text().catch(() => "")).slice(-400);
|
|
29373
|
-
throw new
|
|
29428
|
+
throw new CliError("ffmpeg_failed", `ffmpeg failed to cut the clip${detail ? `: ${detail}` : ""}`);
|
|
29374
29429
|
}
|
|
29375
29430
|
}
|
|
29376
29431
|
var FOUND_BASE3 = "https://found.fluncle.com", CLIP_WIDTH = 1080, CLIP_HEIGHT = 1920, CLIP_CRF = 21, CLIP_MAXRATE = "10M", CLIP_BUFSIZE = "20M", CLIP_AUDIO_BITRATE = "192k", MAX_CLIP_BYTES;
|
|
@@ -29404,7 +29459,7 @@ async function recordingsListCommand(options = {}) {
|
|
|
29404
29459
|
const suffix = query.toString() ? `?${query.toString()}` : "";
|
|
29405
29460
|
const response = await adminApiGet(`/api/v1/admin/recordings${suffix}`);
|
|
29406
29461
|
if (options.json) {
|
|
29407
|
-
|
|
29462
|
+
printJson({ ok: true, recordings: response.recordings });
|
|
29408
29463
|
return;
|
|
29409
29464
|
}
|
|
29410
29465
|
if (response.recordings.length === 0) {
|
|
@@ -29416,11 +29471,11 @@ async function recordingsListCommand(options = {}) {
|
|
|
29416
29471
|
}
|
|
29417
29472
|
async function recordingGetCommand(id, options = {}) {
|
|
29418
29473
|
if (!id) {
|
|
29419
|
-
throw new
|
|
29474
|
+
throw new CliError("missing_id", "Missing recording id for: get");
|
|
29420
29475
|
}
|
|
29421
29476
|
const recording = await recordingGet2(id);
|
|
29422
29477
|
if (options.json) {
|
|
29423
|
-
|
|
29478
|
+
printJson({ ok: true, recording });
|
|
29424
29479
|
return;
|
|
29425
29480
|
}
|
|
29426
29481
|
console.log(formatRecordingSummary(recording));
|
|
@@ -29438,7 +29493,7 @@ async function recordingCreateCommand(options = {}) {
|
|
|
29438
29493
|
});
|
|
29439
29494
|
const recording = created.recording;
|
|
29440
29495
|
if (options.json) {
|
|
29441
|
-
|
|
29496
|
+
printJson({ ok: true, recording });
|
|
29442
29497
|
return;
|
|
29443
29498
|
}
|
|
29444
29499
|
console.log(`Plan ${recording.id} created, handle "${recording.title}"`);
|
|
@@ -29446,13 +29501,13 @@ async function recordingCreateCommand(options = {}) {
|
|
|
29446
29501
|
}
|
|
29447
29502
|
const title = options.title?.trim();
|
|
29448
29503
|
if (!title) {
|
|
29449
|
-
throw new
|
|
29504
|
+
throw new CliError("missing_title", "A recording needs a --title (or --plan for a videoless plan)");
|
|
29450
29505
|
}
|
|
29451
29506
|
if (!options.video) {
|
|
29452
|
-
throw new
|
|
29507
|
+
throw new CliError("missing_video", "A recording needs a --video <file> to stage");
|
|
29453
29508
|
}
|
|
29454
29509
|
if (!existsSync2(options.video)) {
|
|
29455
|
-
throw new
|
|
29510
|
+
throw new CliError("file_not_found", `Set-video master not found: ${options.video}`);
|
|
29456
29511
|
}
|
|
29457
29512
|
const created = await adminApiPost("/api/v1/admin/recordings", {
|
|
29458
29513
|
recordedAt: options.recordedAt,
|
|
@@ -29467,14 +29522,14 @@ async function recordingCreateCommand(options = {}) {
|
|
|
29467
29522
|
log(`Recording ${recording.id} created, staging the set video…`);
|
|
29468
29523
|
const upload = await uploadRenditionMultipart(options.video, `/api/v1/admin/recordings/${encodeURIComponent(recording.id)}/set-video/presign`, log);
|
|
29469
29524
|
if (options.json) {
|
|
29470
|
-
|
|
29525
|
+
printJson({ key: upload.key, ok: true, recording, url: upload.url });
|
|
29471
29526
|
return;
|
|
29472
29527
|
}
|
|
29473
29528
|
console.log(`Recording ${recording.id} staged → ${upload.url}`);
|
|
29474
29529
|
}
|
|
29475
29530
|
async function recordingUpdateCommand(id, options = {}) {
|
|
29476
29531
|
if (!id) {
|
|
29477
|
-
throw new
|
|
29532
|
+
throw new CliError("missing_id", "Missing recording id for: update");
|
|
29478
29533
|
}
|
|
29479
29534
|
const body = {};
|
|
29480
29535
|
if (options.title !== undefined) {
|
|
@@ -29488,66 +29543,66 @@ async function recordingUpdateCommand(id, options = {}) {
|
|
|
29488
29543
|
}
|
|
29489
29544
|
if (options.tracklistFile !== undefined) {
|
|
29490
29545
|
if (!existsSync2(options.tracklistFile)) {
|
|
29491
|
-
throw new
|
|
29546
|
+
throw new CliError("file_not_found", `Tracklist file not found: ${options.tracklistFile}`);
|
|
29492
29547
|
}
|
|
29493
29548
|
try {
|
|
29494
29549
|
body.tracklistJson = JSON.parse(readFileSync2(options.tracklistFile, "utf8"));
|
|
29495
29550
|
} catch {
|
|
29496
|
-
throw new
|
|
29551
|
+
throw new CliError("invalid_tracklist", `Tracklist file is not valid JSON: ${options.tracklistFile}`);
|
|
29497
29552
|
}
|
|
29498
29553
|
}
|
|
29499
29554
|
if (Object.keys(body).length === 0) {
|
|
29500
|
-
throw new
|
|
29555
|
+
throw new CliError("no_fields", "Nothing to update. Pass --title, --recorded-at, --parent-id, or --tracklist-file");
|
|
29501
29556
|
}
|
|
29502
29557
|
const response = await adminApiPatch(`/api/v1/admin/recordings/${encodeURIComponent(id)}`, body);
|
|
29503
29558
|
if (options.json) {
|
|
29504
|
-
|
|
29559
|
+
printJson({ ok: true, recording: response.recording });
|
|
29505
29560
|
return;
|
|
29506
29561
|
}
|
|
29507
29562
|
console.log(`Updated ${formatRecordingSummary(response.recording)}`);
|
|
29508
29563
|
}
|
|
29509
29564
|
async function recordingDeleteCommand(id, options = {}) {
|
|
29510
29565
|
if (!id) {
|
|
29511
|
-
throw new
|
|
29566
|
+
throw new CliError("missing_id", "Missing recording id for: delete");
|
|
29512
29567
|
}
|
|
29513
29568
|
await adminApiDelete(`/api/v1/admin/recordings/${encodeURIComponent(id)}`);
|
|
29514
29569
|
if (options.json) {
|
|
29515
|
-
|
|
29570
|
+
printJson({ ok: true });
|
|
29516
29571
|
return;
|
|
29517
29572
|
}
|
|
29518
29573
|
console.log(`Deleted recording ${id} (and its clips).`);
|
|
29519
29574
|
}
|
|
29520
29575
|
async function recordingPromoteCommand(id, options = {}) {
|
|
29521
29576
|
if (!id) {
|
|
29522
|
-
throw new
|
|
29577
|
+
throw new CliError("missing_id", "Missing recording id for: promote");
|
|
29523
29578
|
}
|
|
29524
29579
|
const response = await adminApiPost(`/api/v1/admin/recordings/${encodeURIComponent(id)}/promote`);
|
|
29525
29580
|
const recording = response.recording;
|
|
29526
29581
|
if (options.json) {
|
|
29527
|
-
|
|
29582
|
+
printJson({ ok: true, recording });
|
|
29528
29583
|
return;
|
|
29529
29584
|
}
|
|
29530
29585
|
console.log(recording.logId ? `Promoted recording ${id} → mixtape fluncle://${recording.logId}` : `Promoted recording ${id}`);
|
|
29531
29586
|
}
|
|
29532
29587
|
async function recordingReplaceCuesCommand(id, options = {}) {
|
|
29533
29588
|
if (!id) {
|
|
29534
|
-
throw new
|
|
29589
|
+
throw new CliError("missing_id", "Missing recording id for: replace-cues");
|
|
29535
29590
|
}
|
|
29536
29591
|
if (!options.cuesFile) {
|
|
29537
|
-
throw new
|
|
29592
|
+
throw new CliError("missing_cues_file", "replace-cues needs a --cues-file <file> (the ordered cue array)");
|
|
29538
29593
|
}
|
|
29539
29594
|
if (!existsSync2(options.cuesFile)) {
|
|
29540
|
-
throw new
|
|
29595
|
+
throw new CliError("file_not_found", `Cues file not found: ${options.cuesFile}`);
|
|
29541
29596
|
}
|
|
29542
29597
|
let cues;
|
|
29543
29598
|
try {
|
|
29544
29599
|
cues = JSON.parse(readFileSync2(options.cuesFile, "utf8"));
|
|
29545
29600
|
} catch {
|
|
29546
|
-
throw new
|
|
29601
|
+
throw new CliError("invalid_cues", `Cues file is not valid JSON: ${options.cuesFile}`);
|
|
29547
29602
|
}
|
|
29548
29603
|
const response = await adminApiPut(`/api/v1/admin/recordings/${encodeURIComponent(id)}/cues`, { cues });
|
|
29549
29604
|
if (options.json) {
|
|
29550
|
-
|
|
29605
|
+
printJson({ ok: true, recording: response.recording });
|
|
29551
29606
|
return;
|
|
29552
29607
|
}
|
|
29553
29608
|
console.log(`Replaced cues for ${formatRecordingSummary(response.recording)}`);
|
|
@@ -29565,7 +29620,7 @@ function buildBody2(options, { requireContent }) {
|
|
|
29565
29620
|
if (options.contentFile !== undefined) {
|
|
29566
29621
|
body.contentJson = readContentFile(options.contentFile);
|
|
29567
29622
|
} else if (requireContent) {
|
|
29568
|
-
throw new
|
|
29623
|
+
throw new CliError("missing_content", "A draft needs the structured content payload via --content-file <edition.json>");
|
|
29569
29624
|
}
|
|
29570
29625
|
if (requireContent && typeof options.promptVersion === "number") {
|
|
29571
29626
|
body.promptVersion = options.promptVersion;
|
|
@@ -29583,13 +29638,13 @@ function buildBody2(options, { requireContent }) {
|
|
|
29583
29638
|
}
|
|
29584
29639
|
function readContentFile(filePath) {
|
|
29585
29640
|
if (!existsSync3(filePath)) {
|
|
29586
|
-
throw new
|
|
29641
|
+
throw new CliError("file_not_found", `Edition payload file not found: ${filePath}`);
|
|
29587
29642
|
}
|
|
29588
29643
|
const text = readFileSync3(filePath, "utf-8");
|
|
29589
29644
|
try {
|
|
29590
29645
|
return JSON.parse(text);
|
|
29591
29646
|
} catch (error) {
|
|
29592
|
-
throw new
|
|
29647
|
+
throw new CliError("invalid_content_json", `Edition payload JSON parse failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
29593
29648
|
}
|
|
29594
29649
|
}
|
|
29595
29650
|
async function newsletterDraftCommand(options) {
|
|
@@ -29626,15 +29681,15 @@ function resolveBody(options) {
|
|
|
29626
29681
|
}
|
|
29627
29682
|
if (options.bodyFile !== undefined) {
|
|
29628
29683
|
if (!existsSync4(options.bodyFile)) {
|
|
29629
|
-
throw new
|
|
29684
|
+
throw new CliError("file_not_found", `Body file not found: ${options.bodyFile}`);
|
|
29630
29685
|
}
|
|
29631
29686
|
return readFileSync4(options.bodyFile, "utf-8");
|
|
29632
29687
|
}
|
|
29633
|
-
throw new
|
|
29688
|
+
throw new CliError("missing_body", "An entry needs a body via --body <text> or --body-file <entry.md>");
|
|
29634
29689
|
}
|
|
29635
29690
|
function requireTitle(options) {
|
|
29636
29691
|
if (options.title === undefined || !options.title.trim()) {
|
|
29637
|
-
throw new
|
|
29692
|
+
throw new CliError("missing_title", "An entry needs a title via --title <text>");
|
|
29638
29693
|
}
|
|
29639
29694
|
return options.title;
|
|
29640
29695
|
}
|
|
@@ -29669,20 +29724,20 @@ async function promptDetailCommand(slug) {
|
|
|
29669
29724
|
const prompts = await promptsListCommand();
|
|
29670
29725
|
const detail = prompts.find((prompt) => prompt.slug === slug);
|
|
29671
29726
|
if (!detail) {
|
|
29672
|
-
throw new
|
|
29727
|
+
throw new CliError("unknown_prompt", `No prompt goes by "${slug}". The registered ones: ${prompts.map((prompt) => prompt.slug).join(", ")}`);
|
|
29673
29728
|
}
|
|
29674
29729
|
return detail;
|
|
29675
29730
|
}
|
|
29676
29731
|
function resolveBody2(options) {
|
|
29677
29732
|
if (options.bodyFile === undefined) {
|
|
29678
|
-
throw new
|
|
29733
|
+
throw new CliError("missing_body", "An edit needs a body via --body-file <prompt.txt>. Start from `fluncle admin prompts get <slug> --json | jq -r .body`.");
|
|
29679
29734
|
}
|
|
29680
29735
|
if (!existsSync5(options.bodyFile)) {
|
|
29681
|
-
throw new
|
|
29736
|
+
throw new CliError("file_not_found", `Body file not found: ${options.bodyFile}`);
|
|
29682
29737
|
}
|
|
29683
29738
|
const body = readFileSync5(options.bodyFile, "utf-8");
|
|
29684
29739
|
if (body.trim().length === 0) {
|
|
29685
|
-
throw new
|
|
29740
|
+
throw new CliError("empty_body", "A prompt body cannot be empty. Nothing was appended.");
|
|
29686
29741
|
}
|
|
29687
29742
|
return body;
|
|
29688
29743
|
}
|
|
@@ -29697,7 +29752,7 @@ async function promptRollbackCommand(slug, version) {
|
|
|
29697
29752
|
const target = detail.versions.find((candidate) => candidate.version === version);
|
|
29698
29753
|
if (!target) {
|
|
29699
29754
|
const known = detail.versions.map((candidate) => `v${candidate.version}`).join(", ");
|
|
29700
|
-
throw new
|
|
29755
|
+
throw new CliError("unknown_version", known.length > 0 ? `${slug} has no v${version}. On file: ${known}. For the repo's baked default, run \`fluncle admin prompts reset ${slug}\`.` : `${slug} has no history yet: the repo's baked default is what runs. There is nothing to roll back to.`);
|
|
29701
29756
|
}
|
|
29702
29757
|
return restore(detail, { body: target.body, from: version, note: `rolled back to v${version}` });
|
|
29703
29758
|
}
|
|
@@ -29722,7 +29777,7 @@ function parseAgainst(value) {
|
|
|
29722
29777
|
}
|
|
29723
29778
|
const version = parseVersion3(value);
|
|
29724
29779
|
if (version === undefined) {
|
|
29725
|
-
throw new
|
|
29780
|
+
throw new CliError("invalid_against", `--against takes a version (3, or v3) or the word default. Got "${value}".`);
|
|
29726
29781
|
}
|
|
29727
29782
|
return { kind: "version", version };
|
|
29728
29783
|
}
|
|
@@ -29802,7 +29857,7 @@ function resolveAgainstVersion(detail, version) {
|
|
|
29802
29857
|
const target = detail.versions.find((candidate) => candidate.version === version);
|
|
29803
29858
|
if (!target) {
|
|
29804
29859
|
const known = detail.versions.map((candidate) => `v${candidate.version}`).join(", ");
|
|
29805
|
-
throw new
|
|
29860
|
+
throw new CliError("unknown_version", known.length > 0 ? `${detail.slug} has no v${version}. On file: ${known}.` : `${detail.slug} has no history yet. Diff against the repo's default instead: drop --against.`);
|
|
29806
29861
|
}
|
|
29807
29862
|
return { body: target.body, label: `v${version}`, version };
|
|
29808
29863
|
}
|
|
@@ -29853,7 +29908,7 @@ import { createInterface as createInterface2 } from "node:readline/promises";
|
|
|
29853
29908
|
async function listSubmissionsCommand(options = {}) {
|
|
29854
29909
|
const response = await adminApiGet("/api/v1/admin/submissions");
|
|
29855
29910
|
if (options.json) {
|
|
29856
|
-
|
|
29911
|
+
printJson({ ok: true, submissions: response.submissions });
|
|
29857
29912
|
return;
|
|
29858
29913
|
}
|
|
29859
29914
|
if (response.submissions.length === 0) {
|
|
@@ -29867,7 +29922,7 @@ async function listSubmissionsCommand(options = {}) {
|
|
|
29867
29922
|
async function reviewSubmissionCommand(submissionId, options = {}) {
|
|
29868
29923
|
const submission = await fetchSubmission(submissionId);
|
|
29869
29924
|
if (options.json) {
|
|
29870
|
-
|
|
29925
|
+
printJson({ ok: true, submission });
|
|
29871
29926
|
return;
|
|
29872
29927
|
}
|
|
29873
29928
|
console.log(formatSubmissionDetail(submission));
|
|
@@ -29875,7 +29930,7 @@ async function reviewSubmissionCommand(submissionId, options = {}) {
|
|
|
29875
29930
|
async function rejectSubmissionCommand(submissionId, options = {}) {
|
|
29876
29931
|
const response = await adminApiPost(`/api/v1/admin/submissions/${encodeURIComponent(submissionId)}/reject`);
|
|
29877
29932
|
if (options.json) {
|
|
29878
|
-
|
|
29933
|
+
printJson({ ok: true, submission: response.submission });
|
|
29879
29934
|
return;
|
|
29880
29935
|
}
|
|
29881
29936
|
console.log(`Rejected ${formatTrackLine(response.submission)}.`);
|
|
@@ -29900,7 +29955,7 @@ async function approveSubmissionCommand(submissionId, options = {}) {
|
|
|
29900
29955
|
});
|
|
29901
29956
|
const response = await adminApiPost(`/api/v1/admin/submissions/${encodeURIComponent(submission.id)}/approve`);
|
|
29902
29957
|
if (options.json) {
|
|
29903
|
-
|
|
29958
|
+
printJson({ ok: true, submission: response.submission });
|
|
29904
29959
|
return;
|
|
29905
29960
|
}
|
|
29906
29961
|
console.log(`Approved ${formatTrackLine(submission)}.`);
|
|
@@ -29911,7 +29966,7 @@ async function triageSubmissionCommand(submissionId, verdict, options = {}) {
|
|
|
29911
29966
|
verdict
|
|
29912
29967
|
});
|
|
29913
29968
|
if (options.json) {
|
|
29914
|
-
|
|
29969
|
+
printJson({ ok: true, submission: response.submission });
|
|
29915
29970
|
return;
|
|
29916
29971
|
}
|
|
29917
29972
|
console.log(`Triaged ${formatTrackLine(response.submission)}: ${response.submission.triageVerdict ?? ""}`);
|
|
@@ -29922,7 +29977,7 @@ async function fetchSubmission(submissionId) {
|
|
|
29922
29977
|
}
|
|
29923
29978
|
async function confirm(label) {
|
|
29924
29979
|
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
29925
|
-
throw new
|
|
29980
|
+
throw new CliError("not_interactive", "Approving publishes a submission and needs a yes. Run this in a terminal, or pass --json to approve without the prompt.");
|
|
29926
29981
|
}
|
|
29927
29982
|
const rl = createInterface2({
|
|
29928
29983
|
input: process.stdin,
|
|
@@ -30508,9 +30563,11 @@ function createEvidenceHttp(overrides = {}) {
|
|
|
30508
30563
|
return {
|
|
30509
30564
|
cacheDir: defaultCacheDir(),
|
|
30510
30565
|
cacheTtlMs: 7 * 24 * 60 * 60 * 1000,
|
|
30566
|
+
deadline: null,
|
|
30511
30567
|
fetch: (url, init) => globalThis.fetch(url, init),
|
|
30512
30568
|
now: () => Date.now(),
|
|
30513
30569
|
policies: SOURCE_POLICIES,
|
|
30570
|
+
progress: noteProgress,
|
|
30514
30571
|
random: Math.random,
|
|
30515
30572
|
refresh: false,
|
|
30516
30573
|
sleep: (ms) => runPromise2(sleep2(ms)),
|
|
@@ -30584,16 +30641,26 @@ async function readNextSlot(slotFile) {
|
|
|
30584
30641
|
const value = Number(raw);
|
|
30585
30642
|
return Number.isFinite(value) ? value : 0;
|
|
30586
30643
|
}
|
|
30644
|
+
function seconds2(ms) {
|
|
30645
|
+
return Math.ceil(ms / 1000);
|
|
30646
|
+
}
|
|
30587
30647
|
async function reserveSlot(http, source) {
|
|
30588
30648
|
const interval = http.policies[source].intervalMs;
|
|
30589
30649
|
const slotAt = await withSlotLock(http, source, async (slotFile) => {
|
|
30590
30650
|
const now = http.now();
|
|
30591
30651
|
const slot = Math.max(now, await readNextSlot(slotFile));
|
|
30652
|
+
if (http.deadline !== null && slot >= http.deadline) {
|
|
30653
|
+
return new EvidenceFetchError("timeout", `${source} queue is ${seconds2(slot - now)} s long, past the deadline ${seconds2(http.deadline - now)} s away; fetched responses are cached, so a later run resumes`, 0);
|
|
30654
|
+
}
|
|
30592
30655
|
await writeFile2(slotFile, String(slot + interval));
|
|
30593
30656
|
return slot;
|
|
30594
30657
|
});
|
|
30658
|
+
if (slotAt instanceof EvidenceFetchError) {
|
|
30659
|
+
throw slotAt;
|
|
30660
|
+
}
|
|
30595
30661
|
const wait = slotAt - http.now();
|
|
30596
30662
|
if (wait > 0) {
|
|
30663
|
+
http.progress(`waiting ${seconds2(wait)} s for a ${source} slot behind other callers on this machine (${http.stats.requests} requests sent so far; fetched responses are cached, so a later run resumes)`);
|
|
30597
30664
|
await http.sleep(wait);
|
|
30598
30665
|
}
|
|
30599
30666
|
}
|
|
@@ -30634,8 +30701,12 @@ async function fetchEvidenceText(http, source, cacheKey, perform, accept = () =>
|
|
|
30634
30701
|
let attempt = 0;
|
|
30635
30702
|
const request = gen2(function* () {
|
|
30636
30703
|
attempt += 1;
|
|
30637
|
-
yield*
|
|
30704
|
+
yield* tryPromise2({
|
|
30705
|
+
catch: (error) => error instanceof EvidenceFetchError ? error : new EvidencePerformError({ cause: error }),
|
|
30706
|
+
try: () => reserveSlot(http, source)
|
|
30707
|
+
});
|
|
30638
30708
|
http.stats.requests += 1;
|
|
30709
|
+
http.progress(`${source} request ${http.stats.requests} in flight`);
|
|
30639
30710
|
let returned = false;
|
|
30640
30711
|
const response = yield* tryPromise2({
|
|
30641
30712
|
catch: (error) => {
|
|
@@ -30705,7 +30776,7 @@ async function fetchEvidenceJson(http, source, url, headers = {}) {
|
|
|
30705
30776
|
const { cached, text } = await fetchEvidenceText(http, source, `GET ${url}`, async (signal) => {
|
|
30706
30777
|
const response = await http.fetch(url, {
|
|
30707
30778
|
headers: { Accept: "application/json", "User-Agent": EVIDENCE_USER_AGENT, ...headers },
|
|
30708
|
-
signal
|
|
30779
|
+
signal: AbortSignal.any([signal, deadlineSignal()])
|
|
30709
30780
|
});
|
|
30710
30781
|
return { headers: response.headers, status: response.status, text: await response.text() };
|
|
30711
30782
|
}, isJson2);
|
|
@@ -30714,6 +30785,7 @@ async function fetchEvidenceJson(http, source, url, headers = {}) {
|
|
|
30714
30785
|
var SOURCE_POLICIES, EVIDENCE_USER_AGENT = "FluncleLabelTriage/1.0 ( https://www.fluncle.com )", EvidenceFetchError, EvidenceRetryable, EvidencePerformError, LOCK_STALE_MS = 1e4;
|
|
30715
30786
|
var init_evidence_http = __esm(() => {
|
|
30716
30787
|
init_dist();
|
|
30788
|
+
init_deadline();
|
|
30717
30789
|
SOURCE_POLICIES = {
|
|
30718
30790
|
apple: { attempts: 3, intervalMs: 3000, maxBackoffMs: 30000, timeoutMs: 1e4 },
|
|
30719
30791
|
beatport: { attempts: 2, intervalMs: 1000, maxBackoffMs: 30000, timeoutMs: 75000 },
|
|
@@ -31407,7 +31479,7 @@ async function labelEvidenceCommand(input, options) {
|
|
|
31407
31479
|
Promise.resolve().then(() => (init_env(), exports_env)),
|
|
31408
31480
|
Promise.resolve().then(() => (init_admin_labels3(), exports_admin_labels))
|
|
31409
31481
|
]);
|
|
31410
|
-
const http = createEvidenceHttp({ refresh: options.refresh });
|
|
31482
|
+
const http = createEvidenceHttp({ deadline: deadlineAt(), refresh: options.refresh });
|
|
31411
31483
|
const discogsToken = readOptionalEnv("DISCOGS_USER_TOKEN");
|
|
31412
31484
|
if (discogsToken) {
|
|
31413
31485
|
http.policies = { ...http.policies, discogs: { ...http.policies.discogs, intervalMs: 1100 } };
|
|
@@ -31458,6 +31530,7 @@ function labelEvidenceLines(evidence) {
|
|
|
31458
31530
|
}
|
|
31459
31531
|
var MBID_PATTERN3, MB_ROOT = "https://musicbrainz.org/ws/2", DISCOGS_ROOT = "https://api.discogs.com", FIRECRAWL_SCRAPE_URL = "https://api.firecrawl.dev/v2/scrape", VARIOUS_ARTISTS_MBID = "89ad4ac3-39f7-470e-963a-56509c546377", RELEASE_SAMPLE = 12, FIRST_CREDIT_ARTISTS = 25, APPLE_LOOKUPS = 5, DISCOGS_RELEASE_SAMPLE = 8, DISCOGS_STYLE_TARGET = 10, DISCOGS_RELEASE_READS = 8, PROFILE_CHARS = 800, EVIDENCE_SOURCES, MAX_CENSUS_PAGES = 5;
|
|
31460
31532
|
var init_admin_label_evidence = __esm(() => {
|
|
31533
|
+
init_deadline();
|
|
31461
31534
|
init_evidence_http();
|
|
31462
31535
|
MBID_PATTERN3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
31463
31536
|
EVIDENCE_SOURCES = ["musicbrainz", "discogs", "beatport", "apple"];
|
|
@@ -31500,7 +31573,7 @@ async function paginateWithKeyboard(options) {
|
|
|
31500
31573
|
const stdin = options.input ?? process.stdin;
|
|
31501
31574
|
const stdout = options.output ?? process.stdout;
|
|
31502
31575
|
if (!stdin.isTTY || !stdout.isTTY) {
|
|
31503
|
-
throw new
|
|
31576
|
+
throw new CliError("not_interactive", options.nonInteractiveMessage);
|
|
31504
31577
|
}
|
|
31505
31578
|
const first = await options.fetchPage(undefined);
|
|
31506
31579
|
if (first.lines.length === 0) {
|
|
@@ -33728,8 +33801,96 @@ var fluncleAsciiLogo = `███████╗██╗ ██╗ ██
|
|
|
33728
33801
|
╚═╝ ╚══════╝ ╚═════╝ ╚═╝ ╚═══╝ ╚═════╝╚══════╝╚══════╝`;
|
|
33729
33802
|
var fluncleTagline = "Drum & bass bangers from another dimension";
|
|
33730
33803
|
|
|
33804
|
+
// src/deadline.ts
|
|
33805
|
+
init_output();
|
|
33806
|
+
var DEFAULT_NON_INTERACTIVE_TIMEOUT_SECONDS = 240;
|
|
33807
|
+
var TIMEOUT_EXIT_CODE = 124;
|
|
33808
|
+
var TIMEOUT_ENV = "FLUNCLE_TIMEOUT";
|
|
33809
|
+
var CLEANUP_GRACE_MS = 1e4;
|
|
33810
|
+
var state = {
|
|
33811
|
+
at: null,
|
|
33812
|
+
cancel: null,
|
|
33813
|
+
controller: new AbortController,
|
|
33814
|
+
fire: null,
|
|
33815
|
+
fired: false,
|
|
33816
|
+
note: null
|
|
33817
|
+
};
|
|
33818
|
+
function parseTimeoutSeconds(value, source) {
|
|
33819
|
+
if (value === undefined || value.trim() === "") {
|
|
33820
|
+
return null;
|
|
33821
|
+
}
|
|
33822
|
+
const trimmed = value.trim();
|
|
33823
|
+
if (["0", "off", "none"].includes(trimmed.toLowerCase())) {
|
|
33824
|
+
return 0;
|
|
33825
|
+
}
|
|
33826
|
+
const seconds = Number(trimmed);
|
|
33827
|
+
if (!Number.isFinite(seconds) || seconds <= 0) {
|
|
33828
|
+
throw new CliError("invalid_timeout", `${source} must be a number of seconds (0 disables the deadline), not "${value}"`);
|
|
33829
|
+
}
|
|
33830
|
+
return seconds;
|
|
33831
|
+
}
|
|
33832
|
+
function resolveTimeoutSeconds(input) {
|
|
33833
|
+
const flag = parseTimeoutSeconds(input.flag, "--timeout");
|
|
33834
|
+
if (flag !== null) {
|
|
33835
|
+
return flag;
|
|
33836
|
+
}
|
|
33837
|
+
const env = parseTimeoutSeconds(input.env, TIMEOUT_ENV);
|
|
33838
|
+
if (env !== null) {
|
|
33839
|
+
return env;
|
|
33840
|
+
}
|
|
33841
|
+
return input.interactive ? 0 : DEFAULT_NON_INTERACTIVE_TIMEOUT_SECONDS;
|
|
33842
|
+
}
|
|
33843
|
+
function timeoutMessage(command, seconds, note) {
|
|
33844
|
+
const waiting = note ? `: ${note}` : "";
|
|
33845
|
+
return `fluncle ${command} stopped after ${seconds} s${waiting}. Set --timeout or ${TIMEOUT_ENV} in seconds (0 disables the deadline).`;
|
|
33846
|
+
}
|
|
33847
|
+
function defaultSchedule(fire, ms) {
|
|
33848
|
+
const timer = setTimeout(fire, ms);
|
|
33849
|
+
timer.unref();
|
|
33850
|
+
return () => clearTimeout(timer);
|
|
33851
|
+
}
|
|
33852
|
+
function armDeadline(seconds, options) {
|
|
33853
|
+
disarmDeadline();
|
|
33854
|
+
if (seconds <= 0) {
|
|
33855
|
+
state.at = null;
|
|
33856
|
+
return;
|
|
33857
|
+
}
|
|
33858
|
+
const now = options.now ?? Date.now;
|
|
33859
|
+
const exit = options.exit ?? ((code) => process.exit(code));
|
|
33860
|
+
const schedule = options.schedule ?? defaultSchedule;
|
|
33861
|
+
const report = options.report ?? ((message) => {
|
|
33862
|
+
if (options.json) {
|
|
33863
|
+
printJson({ code: "timeout", message, ok: false });
|
|
33864
|
+
return;
|
|
33865
|
+
}
|
|
33866
|
+
console.error(message);
|
|
33867
|
+
});
|
|
33868
|
+
state.at = now() + seconds * 1000;
|
|
33869
|
+
state.fire = () => {
|
|
33870
|
+
if (state.fired) {
|
|
33871
|
+
return;
|
|
33872
|
+
}
|
|
33873
|
+
const message = timeoutMessage(options.command, seconds, state.note);
|
|
33874
|
+
state.fired = true;
|
|
33875
|
+
disarmDeadline();
|
|
33876
|
+
report(message);
|
|
33877
|
+
process.exitCode = TIMEOUT_EXIT_CODE;
|
|
33878
|
+
state.controller.abort(new CliError("timeout", message));
|
|
33879
|
+
schedule(() => exit(TIMEOUT_EXIT_CODE), options.graceMs ?? CLEANUP_GRACE_MS);
|
|
33880
|
+
};
|
|
33881
|
+
state.cancel = schedule(state.fire, seconds * 1000);
|
|
33882
|
+
}
|
|
33883
|
+
function disarmDeadline() {
|
|
33884
|
+
state.cancel?.();
|
|
33885
|
+
state.cancel = null;
|
|
33886
|
+
}
|
|
33887
|
+
function deadlineFired() {
|
|
33888
|
+
return state.fired;
|
|
33889
|
+
}
|
|
33890
|
+
|
|
33731
33891
|
// src/env.ts
|
|
33732
33892
|
var import_dotenv = __toESM(require_main(), 1);
|
|
33893
|
+
init_deadline();
|
|
33733
33894
|
var envProfiles = ["local", "production"];
|
|
33734
33895
|
function setEnvProfile(profile) {
|
|
33735
33896
|
if (!profile) {
|
|
@@ -33803,24 +33964,24 @@ async function maybePrintLiveCallout(args) {
|
|
|
33803
33964
|
}
|
|
33804
33965
|
|
|
33805
33966
|
// src/output.ts
|
|
33806
|
-
import { writeSync } from "node:fs";
|
|
33807
|
-
var
|
|
33808
|
-
function
|
|
33967
|
+
import { writeSync as writeSync2 } from "node:fs";
|
|
33968
|
+
var EAGAIN_WAIT2 = new Int32Array(new SharedArrayBuffer(4));
|
|
33969
|
+
function writeStdoutSync2(text) {
|
|
33809
33970
|
const buf = Buffer.from(text, "utf8");
|
|
33810
33971
|
let offset = 0;
|
|
33811
33972
|
while (offset < buf.length) {
|
|
33812
33973
|
try {
|
|
33813
|
-
offset +=
|
|
33974
|
+
offset += writeSync2(1, buf, offset);
|
|
33814
33975
|
} catch (error) {
|
|
33815
33976
|
if (error.code === "EAGAIN") {
|
|
33816
|
-
Atomics.wait(
|
|
33977
|
+
Atomics.wait(EAGAIN_WAIT2, 0, 0, 1);
|
|
33817
33978
|
continue;
|
|
33818
33979
|
}
|
|
33819
33980
|
throw error;
|
|
33820
33981
|
}
|
|
33821
33982
|
}
|
|
33822
33983
|
}
|
|
33823
|
-
class
|
|
33984
|
+
class CliError2 extends Error {
|
|
33824
33985
|
code;
|
|
33825
33986
|
constructor(code, message) {
|
|
33826
33987
|
super(message);
|
|
@@ -33828,12 +33989,12 @@ class CliError extends Error {
|
|
|
33828
33989
|
this.code = code;
|
|
33829
33990
|
}
|
|
33830
33991
|
}
|
|
33831
|
-
function
|
|
33832
|
-
|
|
33992
|
+
function printJson2(value) {
|
|
33993
|
+
writeStdoutSync2(JSON.stringify(value, null, 2) + `
|
|
33833
33994
|
`);
|
|
33834
33995
|
}
|
|
33835
33996
|
function toJsonFailure(error) {
|
|
33836
|
-
if (error instanceof
|
|
33997
|
+
if (error instanceof CliError2) {
|
|
33837
33998
|
return {
|
|
33838
33999
|
code: error.code,
|
|
33839
34000
|
message: error.message,
|
|
@@ -33915,9 +34076,17 @@ function artistRuleLines(rules) {
|
|
|
33915
34076
|
}
|
|
33916
34077
|
function createProgram() {
|
|
33917
34078
|
const program = configureCommand(new Command);
|
|
33918
|
-
program.name("fluncle").description(fluncleTagline).option("--env <local|production>", "Config profile to load (default: production)").showSuggestionAfterError(false).addHelpCommand("help [command]", "Display help for command").hook("preAction", (_thisCommand, actionCommand) => {
|
|
34079
|
+
program.name("fluncle").description(fluncleTagline).option("--env <local|production>", "Config profile to load (default: production)").option("--timeout <seconds>", `Stop the command after this many seconds with exit code 124 (0 disables; default 240 when stdout is not a terminal, or ${TIMEOUT_ENV})`).showSuggestionAfterError(false).addHelpCommand("help [command]", "Display help for command").hook("preAction", (_thisCommand, actionCommand) => {
|
|
33919
34080
|
const options = actionCommand.optsWithGlobals();
|
|
33920
34081
|
setEnvProfile(options.env);
|
|
34082
|
+
armDeadline(resolveTimeoutSeconds({
|
|
34083
|
+
env: process.env[TIMEOUT_ENV],
|
|
34084
|
+
flag: options.timeout,
|
|
34085
|
+
interactive: Boolean(process.stdout.isTTY)
|
|
34086
|
+
}), {
|
|
34087
|
+
command: commandPath(actionCommand),
|
|
34088
|
+
json: process.argv.includes("--json")
|
|
34089
|
+
});
|
|
33921
34090
|
}).addHelpText("before", `
|
|
33922
34091
|
${fluncleAsciiLogo}
|
|
33923
34092
|
`).addHelpText("after", rootHelpSections);
|
|
@@ -33944,17 +34113,31 @@ async function main(args = process.argv.slice(2)) {
|
|
|
33944
34113
|
if (isHelpDisplayed(error)) {
|
|
33945
34114
|
return;
|
|
33946
34115
|
}
|
|
34116
|
+
if (deadlineFired()) {
|
|
34117
|
+
process.exit(TIMEOUT_EXIT_CODE);
|
|
34118
|
+
}
|
|
33947
34119
|
const normalized = normalizeCommanderError(error);
|
|
33948
34120
|
if (process.argv.includes("--json") || args.includes("--json")) {
|
|
33949
|
-
|
|
34121
|
+
printJson2(toJsonFailure(normalized));
|
|
33950
34122
|
} else {
|
|
33951
34123
|
console.error(formatError(normalized));
|
|
33952
34124
|
}
|
|
33953
34125
|
process.exit(1);
|
|
33954
34126
|
}
|
|
34127
|
+
disarmDeadline();
|
|
34128
|
+
if (deadlineFired()) {
|
|
34129
|
+
process.exit(TIMEOUT_EXIT_CODE);
|
|
34130
|
+
}
|
|
33955
34131
|
await Promise.resolve().then(() => init_update_notifier());
|
|
33956
34132
|
await notifyIfUpdateAvailable(args);
|
|
33957
34133
|
}
|
|
34134
|
+
function commandPath(command) {
|
|
34135
|
+
const names = [];
|
|
34136
|
+
for (let current = command;current?.parent; current = current.parent) {
|
|
34137
|
+
names.unshift(current.name());
|
|
34138
|
+
}
|
|
34139
|
+
return [...names, ...command.args.slice(0, 1)].join(" ");
|
|
34140
|
+
}
|
|
33958
34141
|
function configureCommand(command) {
|
|
33959
34142
|
return command.exitOverride().helpOption("-h, --help", "Display help for command").addHelpCommand(false).configureOutput({
|
|
33960
34143
|
writeErr: () => {}
|
|
@@ -34109,7 +34292,7 @@ JSON field reference:
|
|
|
34109
34292
|
const receipts = await Promise.resolve().then(() => (init_admin_operation_receipts2(), {}));
|
|
34110
34293
|
const result = await getOperationReceiptCommand(operationKey);
|
|
34111
34294
|
if (options.json) {
|
|
34112
|
-
|
|
34295
|
+
printJson2(result);
|
|
34113
34296
|
return;
|
|
34114
34297
|
}
|
|
34115
34298
|
console.log(operationReceiptLines(result.receipt).join(`
|
|
@@ -34123,7 +34306,7 @@ JSON field reference:
|
|
|
34123
34306
|
requestDigest
|
|
34124
34307
|
});
|
|
34125
34308
|
if (options.json) {
|
|
34126
|
-
|
|
34309
|
+
printJson2(result);
|
|
34127
34310
|
return;
|
|
34128
34311
|
}
|
|
34129
34312
|
console.log(operationReceiptLines(result.receipt).join(`
|
|
@@ -34136,7 +34319,7 @@ JSON field reference:
|
|
|
34136
34319
|
staleBefore: parseOperationReceiptFence(options.staleBefore)
|
|
34137
34320
|
});
|
|
34138
34321
|
if (options.json) {
|
|
34139
|
-
|
|
34322
|
+
printJson2(result);
|
|
34140
34323
|
return;
|
|
34141
34324
|
}
|
|
34142
34325
|
const noun = result.repaired === 1 ? "receipt" : "receipts";
|
|
@@ -34150,7 +34333,7 @@ JSON field reference:
|
|
|
34150
34333
|
const projections = await Promise.resolve().then(() => (init_admin_projections2(), {}));
|
|
34151
34334
|
const result = await getProjectionStatusCommand();
|
|
34152
34335
|
if (options.json) {
|
|
34153
|
-
|
|
34336
|
+
printJson2(result);
|
|
34154
34337
|
return;
|
|
34155
34338
|
}
|
|
34156
34339
|
console.log(projectionStatusLines(result.status).join(`
|
|
@@ -34171,7 +34354,7 @@ JSON field reference:
|
|
|
34171
34354
|
wallMs: options.wallMs === undefined ? undefined : parseProjectionWallMs(options.wallMs)
|
|
34172
34355
|
});
|
|
34173
34356
|
if (options.json) {
|
|
34174
|
-
|
|
34357
|
+
printJson2(result);
|
|
34175
34358
|
return;
|
|
34176
34359
|
}
|
|
34177
34360
|
console.log(`${result.target} ${result.action}: steps ${result.steps}, processed ${result.processed}, scheduled ${result.scheduled}, ${result.complete ? "complete" : result.wallStopped ? "wall budget spent, more work remains" : "more work remains"}.`);
|
|
@@ -34186,7 +34369,7 @@ JSON field reference:
|
|
|
34186
34369
|
workKind: options.workKind
|
|
34187
34370
|
});
|
|
34188
34371
|
if (options.json) {
|
|
34189
|
-
|
|
34372
|
+
printJson2(result);
|
|
34190
34373
|
return;
|
|
34191
34374
|
}
|
|
34192
34375
|
console.log(dueWorkRekeyLine(result));
|
|
@@ -34198,7 +34381,7 @@ JSON field reference:
|
|
|
34198
34381
|
target: parseProjectionCutover(options.target)
|
|
34199
34382
|
});
|
|
34200
34383
|
if (options.json) {
|
|
34201
|
-
|
|
34384
|
+
printJson2(result);
|
|
34202
34385
|
return;
|
|
34203
34386
|
}
|
|
34204
34387
|
console.log(`${result.target}: cutover ${result.enabled ? "open" : "dark"}.`);
|
|
@@ -34211,7 +34394,7 @@ JSON field reference:
|
|
|
34211
34394
|
const vectors = await Promise.resolve().then(() => (init_admin_vectors2(), {}));
|
|
34212
34395
|
const result = await getVectorServingCommand(parseVectorTarget(targetValue));
|
|
34213
34396
|
if (options.json) {
|
|
34214
|
-
|
|
34397
|
+
printJson2(result);
|
|
34215
34398
|
return;
|
|
34216
34399
|
}
|
|
34217
34400
|
console.log(vectorServingStatusLines(result.status).join(`
|
|
@@ -34224,7 +34407,7 @@ JSON field reference:
|
|
|
34224
34407
|
target: parseVectorTarget(targetValue)
|
|
34225
34408
|
});
|
|
34226
34409
|
if (options.json) {
|
|
34227
|
-
|
|
34410
|
+
printJson2(result);
|
|
34228
34411
|
return;
|
|
34229
34412
|
}
|
|
34230
34413
|
console.log(vectorServingStatusLines(result.status).join(`
|
|
@@ -34241,7 +34424,7 @@ JSON field reference:
|
|
|
34241
34424
|
contracts: parseArtifactContracts(options.contract)
|
|
34242
34425
|
});
|
|
34243
34426
|
if (options.json) {
|
|
34244
|
-
|
|
34427
|
+
printJson2(result);
|
|
34245
34428
|
return;
|
|
34246
34429
|
}
|
|
34247
34430
|
console.log(`${result.consumer.consumerId}: rebuilding at snapshot seq ${result.consumer.snapshotSeq ?? 0}.`);
|
|
@@ -34250,7 +34433,7 @@ JSON field reference:
|
|
|
34250
34433
|
await Promise.resolve().then(() => init_admin_artifacts2());
|
|
34251
34434
|
const result = await getArtifactConsumerCommand(consumerId);
|
|
34252
34435
|
if (options.json) {
|
|
34253
|
-
|
|
34436
|
+
printJson2(result);
|
|
34254
34437
|
return;
|
|
34255
34438
|
}
|
|
34256
34439
|
console.log(`${result.consumer.consumerId}: ${result.consumer.state}, head ${result.consumer.headSeq}, applied ${result.consumer.appliedThroughSeq ?? "none"}.`);
|
|
@@ -34266,7 +34449,7 @@ JSON field reference:
|
|
|
34266
34449
|
streamVersion: parseArtifactInteger(options.streamVersion, "--stream-version")
|
|
34267
34450
|
});
|
|
34268
34451
|
if (options.json) {
|
|
34269
|
-
|
|
34452
|
+
printJson2(result);
|
|
34270
34453
|
return;
|
|
34271
34454
|
}
|
|
34272
34455
|
console.log(`${result.stream}@${result.streamVersion}/${result.formatVersion}: ${result.itemCount} item(s), snapshot seq ${result.snapshotSeq}, page ${result.pageDigest}.`);
|
|
@@ -34286,7 +34469,7 @@ JSON field reference:
|
|
|
34286
34469
|
streamVersion: parseArtifactInteger(options.streamVersion, "--stream-version")
|
|
34287
34470
|
});
|
|
34288
34471
|
if (options.json) {
|
|
34289
|
-
|
|
34472
|
+
printJson2(result);
|
|
34290
34473
|
return;
|
|
34291
34474
|
}
|
|
34292
34475
|
console.log(`${result.checkpoint.stream}: ${result.checkpoint.state}, ${result.checkpoint.sourceItemCount} item(s) checkpointed.`);
|
|
@@ -34295,7 +34478,7 @@ JSON field reference:
|
|
|
34295
34478
|
await Promise.resolve().then(() => init_admin_artifacts2());
|
|
34296
34479
|
const result = await activateArtifactConsumerCommand(consumerId);
|
|
34297
34480
|
if (options.json) {
|
|
34298
|
-
|
|
34481
|
+
printJson2(result);
|
|
34299
34482
|
return;
|
|
34300
34483
|
}
|
|
34301
34484
|
console.log(`${result.consumer.consumerId}: active at seq ${result.consumer.appliedThroughSeq ?? 0}.`);
|
|
@@ -34309,7 +34492,7 @@ JSON field reference:
|
|
|
34309
34492
|
})
|
|
34310
34493
|
});
|
|
34311
34494
|
if (options.json) {
|
|
34312
|
-
|
|
34495
|
+
printJson2(result);
|
|
34313
34496
|
return;
|
|
34314
34497
|
}
|
|
34315
34498
|
console.log(`${result.events.length} event(s), seq ${result.fromSeq} through ${result.throughSeq}, head ${result.headSeq}, batch ${result.batchDigest}.`);
|
|
@@ -34328,7 +34511,7 @@ JSON field reference:
|
|
|
34328
34511
|
})
|
|
34329
34512
|
});
|
|
34330
34513
|
if (options.json) {
|
|
34331
|
-
|
|
34514
|
+
printJson2(result);
|
|
34332
34515
|
return;
|
|
34333
34516
|
}
|
|
34334
34517
|
console.log(`${result.consumer.consumerId}: applied through seq ${result.consumer.appliedThroughSeq ?? 0}.`);
|
|
@@ -34337,7 +34520,7 @@ JSON field reference:
|
|
|
34337
34520
|
await Promise.resolve().then(() => init_admin_artifacts2());
|
|
34338
34521
|
const result = await inactivateArtifactConsumerCommand(consumerId);
|
|
34339
34522
|
if (options.json) {
|
|
34340
|
-
|
|
34523
|
+
printJson2(result);
|
|
34341
34524
|
return;
|
|
34342
34525
|
}
|
|
34343
34526
|
console.log(`${result.consumer.consumerId}: inactive, bootstrap required before reuse.`);
|
|
@@ -34348,7 +34531,7 @@ JSON field reference:
|
|
|
34348
34531
|
maximum: ARTIFACT_COMPACTION_API_MAX_LIMIT
|
|
34349
34532
|
}));
|
|
34350
34533
|
if (options.json) {
|
|
34351
|
-
|
|
34534
|
+
printJson2(result);
|
|
34352
34535
|
return;
|
|
34353
34536
|
}
|
|
34354
34537
|
console.log(result.deletedCount === 0 ? `Compaction: ${result.reason}.` : `Compaction: deleted ${result.deletedCount} event(s), seq ${result.deletedFromSeq ?? 0} through ${result.deletedThroughSeq ?? 0}.`);
|
|
@@ -34402,15 +34585,15 @@ JSON field reference:
|
|
|
34402
34585
|
});
|
|
34403
34586
|
adminTracks.command("prepare-captures").description("Freeze a batch of capture snapshots in one admitted phase").requiredOption("--file <path>", "JSON file holding the batch body ({ items: [...] })").option("--json", "Print JSON", false).action(async (options) => {
|
|
34404
34587
|
await Promise.resolve().then(() => init_admin_tracks2());
|
|
34405
|
-
|
|
34588
|
+
printJson2(await prepareTrackCapturesCommand(JSON.parse(readFileSync6(options.file, "utf8"))));
|
|
34406
34589
|
});
|
|
34407
34590
|
adminTracks.command("commit-captures").description("Commit a batch of prepared capture results in one admitted phase").requiredOption("--file <path>", "JSON file holding the batch body ({ items: [...] })").option("--json", "Print JSON", false).action(async (options) => {
|
|
34408
34591
|
await Promise.resolve().then(() => init_admin_tracks2());
|
|
34409
|
-
|
|
34592
|
+
printJson2(await commitTrackCapturesCommand(JSON.parse(readFileSync6(options.file, "utf8"))));
|
|
34410
34593
|
});
|
|
34411
34594
|
adminTracks.command("update-embeddings").description("Write a batch of audio embeddings in one admitted phase").requiredOption("--file <path>", "JSON file holding the batch body ({ items: [...] })").option("--json", "Print JSON", false).action(async (options) => {
|
|
34412
34595
|
await Promise.resolve().then(() => init_admin_tracks2());
|
|
34413
|
-
|
|
34596
|
+
printJson2(await updateTrackEmbeddingsCommand(JSON.parse(readFileSync6(options.file, "utf8"))));
|
|
34414
34597
|
});
|
|
34415
34598
|
adminTracks.command("requeue-analysis").description("Re-queue findings whose BPM/key are preview-grade (dry-run; --apply to flip)").option("--apply", "Actually flip statuses (default is a dry-run preview)", false).option("--limit <limit>", "Cap the archive walk (default: the whole archive)").option("--json", "Print JSON", false).action(async (options) => {
|
|
34416
34599
|
await Promise.resolve().then(() => init_admin_tracks2());
|
|
@@ -34546,7 +34729,7 @@ JSON field reference:
|
|
|
34546
34729
|
await Promise.resolve().then(() => init_digests());
|
|
34547
34730
|
const paused = await getFollowDigestStateCommand();
|
|
34548
34731
|
if (options.json) {
|
|
34549
|
-
|
|
34732
|
+
printJson2({ ok: true, paused });
|
|
34550
34733
|
} else {
|
|
34551
34734
|
console.log(paused ? "Follow digests are paused." : "Follow digests are running.");
|
|
34552
34735
|
}
|
|
@@ -34559,7 +34742,7 @@ JSON field reference:
|
|
|
34559
34742
|
await Promise.resolve().then(() => init_digests());
|
|
34560
34743
|
const result = await setFollowDigestStateCommand(paused);
|
|
34561
34744
|
if (options.json) {
|
|
34562
|
-
|
|
34745
|
+
printJson2({ ok: true, paused: result });
|
|
34563
34746
|
} else {
|
|
34564
34747
|
console.log(result ? "Follow digests are paused." : "Follow digests are running.");
|
|
34565
34748
|
}
|
|
@@ -34573,7 +34756,7 @@ JSON field reference:
|
|
|
34573
34756
|
limit: options.limit === undefined ? undefined : Number(options.limit)
|
|
34574
34757
|
});
|
|
34575
34758
|
if (options.json) {
|
|
34576
|
-
|
|
34759
|
+
printJson2(result);
|
|
34577
34760
|
} else if (result.windowClosed && !result.dryRun) {
|
|
34578
34761
|
console.log("Follow digest sends open Friday at 17:00 Amsterdam.");
|
|
34579
34762
|
} else {
|
|
@@ -34845,7 +35028,7 @@ JSON field reference:
|
|
|
34845
35028
|
await Promise.resolve().then(() => init_admin_frontier2());
|
|
34846
35029
|
const summary = await frontierRefreshCommand(options);
|
|
34847
35030
|
if (options.json) {
|
|
34848
|
-
|
|
35031
|
+
printJson2(summary);
|
|
34849
35032
|
return;
|
|
34850
35033
|
}
|
|
34851
35034
|
const counts = `${summary.refreshed} refreshed, ${summary.minted} minted, ${summary.editionOnly} edition-only, ${summary.unchanged} unchanged, ${summary.failed} failed`;
|
|
@@ -34859,7 +35042,7 @@ JSON field reference:
|
|
|
34859
35042
|
await Promise.resolve().then(() => init_admin_frontier2());
|
|
34860
35043
|
const state = await frontierStatusCommand();
|
|
34861
35044
|
if (options.json) {
|
|
34862
|
-
|
|
35045
|
+
printJson2(state);
|
|
34863
35046
|
return;
|
|
34864
35047
|
}
|
|
34865
35048
|
console.log(state.open ? "Frontier minting is OPEN." : "Frontier minting is closed.");
|
|
@@ -34868,7 +35051,7 @@ JSON field reference:
|
|
|
34868
35051
|
await Promise.resolve().then(() => init_admin_frontier2());
|
|
34869
35052
|
const state = await frontierSetMintingCommand(true);
|
|
34870
35053
|
if (options.json) {
|
|
34871
|
-
|
|
35054
|
+
printJson2(state);
|
|
34872
35055
|
return;
|
|
34873
35056
|
}
|
|
34874
35057
|
console.log("Frontier minting is OPEN.");
|
|
@@ -34877,7 +35060,7 @@ JSON field reference:
|
|
|
34877
35060
|
await Promise.resolve().then(() => init_admin_frontier2());
|
|
34878
35061
|
const state = await frontierSetMintingCommand(false);
|
|
34879
35062
|
if (options.json) {
|
|
34880
|
-
|
|
35063
|
+
printJson2(state);
|
|
34881
35064
|
return;
|
|
34882
35065
|
}
|
|
34883
35066
|
console.log("Frontier minting is closed.");
|
|
@@ -34894,7 +35077,7 @@ JSON field reference:
|
|
|
34894
35077
|
await Promise.resolve().then(() => init_admin_catalogue2());
|
|
34895
35078
|
const summary = await catalogueDemandCommand();
|
|
34896
35079
|
if (options.json) {
|
|
34897
|
-
|
|
35080
|
+
printJson2({ ok: true, summary });
|
|
34898
35081
|
return;
|
|
34899
35082
|
}
|
|
34900
35083
|
if (!summary.configured) {
|
|
@@ -34911,7 +35094,7 @@ JSON field reference:
|
|
|
34911
35094
|
await Promise.resolve().then(() => init_admin_catalogue2());
|
|
34912
35095
|
const { cleared } = await clearWrongAudioCommand(trackId);
|
|
34913
35096
|
if (options.json) {
|
|
34914
|
-
|
|
35097
|
+
printJson2({ cleared, ok: true });
|
|
34915
35098
|
return;
|
|
34916
35099
|
}
|
|
34917
35100
|
console.log(cleared ? `Kept ${trackId}. Its audio re-embeds and rejoins the ranking on the next sweep.` : `${trackId} was not quarantined \u2014 nothing to clear.`);
|
|
@@ -34920,7 +35103,7 @@ JSON field reference:
|
|
|
34920
35103
|
await Promise.resolve().then(() => init_admin_catalogue2());
|
|
34921
35104
|
const { paidCleared, requeued } = await requeueAnchorCommand(trackIds, options.clearPaid);
|
|
34922
35105
|
if (options.json) {
|
|
34923
|
-
|
|
35106
|
+
printJson2({ ok: true, paidCleared, requeued });
|
|
34924
35107
|
return;
|
|
34925
35108
|
}
|
|
34926
35109
|
console.log(`Re-queued ${requeued} of ${trackIds.length} row(s) \u2014 the next anchor tick picks them up at their real priority.`);
|
|
@@ -34933,7 +35116,7 @@ JSON field reference:
|
|
|
34933
35116
|
await Promise.resolve().then(() => init_admin_catalogue2());
|
|
34934
35117
|
const state = await spotifyConsumerBudgetCommand();
|
|
34935
35118
|
if (options.json || spotifyBudget.opts().json) {
|
|
34936
|
-
|
|
35119
|
+
printJson2({
|
|
34937
35120
|
consumerBudgets: state.consumerBudgets,
|
|
34938
35121
|
ok: true,
|
|
34939
35122
|
spotifyDailyCalls: state.spotifyDailyCalls
|
|
@@ -34957,7 +35140,7 @@ JSON field reference:
|
|
|
34957
35140
|
await Promise.resolve().then(() => init_admin_catalogue2());
|
|
34958
35141
|
await setSpotifyConsumerBudgetCommand(options.consumer, calls);
|
|
34959
35142
|
if (options.json || spotifyBudget.opts().json) {
|
|
34960
|
-
|
|
35143
|
+
printJson2({ calls, consumer: options.consumer, ok: true });
|
|
34961
35144
|
return;
|
|
34962
35145
|
}
|
|
34963
35146
|
console.log(`SPOTIFY BUDGET ${options.consumer} \u2014 ${calls} calls per day`);
|
|
@@ -34966,7 +35149,7 @@ JSON field reference:
|
|
|
34966
35149
|
await Promise.resolve().then(() => init_admin_catalogue2());
|
|
34967
35150
|
const state = await anchorBreakerCommand();
|
|
34968
35151
|
if (options.json) {
|
|
34969
|
-
|
|
35152
|
+
printJson2({ ...state, ok: true });
|
|
34970
35153
|
return;
|
|
34971
35154
|
}
|
|
34972
35155
|
const minutes = Math.ceil(state.cooldownRemainingMs / 60000);
|
|
@@ -34997,7 +35180,7 @@ JSON field reference:
|
|
|
34997
35180
|
since: options.since
|
|
34998
35181
|
});
|
|
34999
35182
|
if (options.json) {
|
|
35000
|
-
|
|
35183
|
+
printJson2({ ok: true, ...result });
|
|
35001
35184
|
return;
|
|
35002
35185
|
}
|
|
35003
35186
|
console.log(result.dryRun ? `DRY RUN \u2014 ${result.matched} row(s) stamped Deezer-empty since ${options.since}. Re-run with --apply to clear them.` : `Cleared ${result.requeued} of ${result.matched} row(s) \u2014 the next isrc-recovery tick asks them again.`);
|
|
@@ -35006,7 +35189,7 @@ JSON field reference:
|
|
|
35006
35189
|
await Promise.resolve().then(() => init_admin_catalogue2());
|
|
35007
35190
|
const { requeued, skippedVetoed } = await requeueUnmatchedCommand();
|
|
35008
35191
|
if (options.json) {
|
|
35009
|
-
|
|
35192
|
+
printJson2({ ok: true, requeued, skippedVetoed });
|
|
35010
35193
|
return;
|
|
35011
35194
|
}
|
|
35012
35195
|
console.log(`Re-queued ${requeued} unmatched capture(s) for the upgraded search ladder; ${skippedVetoed} stay terminal under the duration vetoes.`);
|
|
@@ -35015,7 +35198,7 @@ JSON field reference:
|
|
|
35015
35198
|
await Promise.resolve().then(() => init_admin_catalogue2());
|
|
35016
35199
|
const { flagged } = await flagWrongAudioCommand(trackId);
|
|
35017
35200
|
if (options.json) {
|
|
35018
|
-
|
|
35201
|
+
printJson2({ flagged, ok: true });
|
|
35019
35202
|
return;
|
|
35020
35203
|
}
|
|
35021
35204
|
console.log(flagged ? `Flagged ${trackId}. Its vector is out of the ranking and a fresh capture is queued (the bad bytes are hash-rejected).` : `${trackId} is not a captured finding \u2014 nothing to flag.`);
|
|
@@ -35024,7 +35207,7 @@ JSON field reference:
|
|
|
35024
35207
|
await Promise.resolve().then(() => init_admin_catalogue2());
|
|
35025
35208
|
const { forced } = await forceCaptureCommand(trackId);
|
|
35026
35209
|
if (options.json) {
|
|
35027
|
-
|
|
35210
|
+
printJson2({ forced, ok: true });
|
|
35028
35211
|
return;
|
|
35029
35212
|
}
|
|
35030
35213
|
console.log(forced ? `Forced ${trackId}. The duplicate veto is lifted; it re-ranks onto the capture ladder and the next open-budget tick buys it.` : `${trackId} was not vetoed as a duplicate \u2014 nothing to force.`);
|
|
@@ -35034,7 +35217,7 @@ JSON field reference:
|
|
|
35034
35217
|
if (options.queue) {
|
|
35035
35218
|
const { tracks } = await listUnverifiedCapturesCommand(options.limit ? { limit: options.limit } : {});
|
|
35036
35219
|
if (options.json) {
|
|
35037
|
-
|
|
35220
|
+
printJson2({ ok: true, tracks });
|
|
35038
35221
|
return;
|
|
35039
35222
|
}
|
|
35040
35223
|
if (tracks.length === 0) {
|
|
@@ -35055,7 +35238,7 @@ JSON field reference:
|
|
|
35055
35238
|
}
|
|
35056
35239
|
const { action } = await verifyCaptureCommand(trackId, verdict);
|
|
35057
35240
|
if (options.json) {
|
|
35058
|
-
|
|
35241
|
+
printJson2({ action, ok: true });
|
|
35059
35242
|
return;
|
|
35060
35243
|
}
|
|
35061
35244
|
console.log(`Recorded. ${trackId} \u2192 ${action}.`);
|
|
@@ -35064,7 +35247,7 @@ JSON field reference:
|
|
|
35064
35247
|
await Promise.resolve().then(() => init_admin_catalogue2());
|
|
35065
35248
|
const { logId } = await certifyTrackCommand(trackId, options.note);
|
|
35066
35249
|
if (options.json) {
|
|
35067
|
-
|
|
35250
|
+
printJson2({ logId, ok: true });
|
|
35068
35251
|
return;
|
|
35069
35252
|
}
|
|
35070
35253
|
console.log(`Logged ${trackId} \u2014 ${logId}. Enrichment is running; finish it in the admin.`);
|
|
@@ -35073,7 +35256,7 @@ JSON field reference:
|
|
|
35073
35256
|
await Promise.resolve().then(() => init_admin_catalogue2());
|
|
35074
35257
|
const { changed } = await setTrackDismissedCommand(trackId, true);
|
|
35075
35258
|
if (options.json) {
|
|
35076
|
-
|
|
35259
|
+
printJson2({ changed, ok: true });
|
|
35077
35260
|
return;
|
|
35078
35261
|
}
|
|
35079
35262
|
console.log(changed ? `Dismissed ${trackId}. It leaves the ranking and the capture ladder; restore it any time.` : `${trackId} was not a live catalogue row \u2014 nothing dismissed.`);
|
|
@@ -35082,7 +35265,7 @@ JSON field reference:
|
|
|
35082
35265
|
await Promise.resolve().then(() => init_admin_catalogue2());
|
|
35083
35266
|
const { changed } = await setTrackDismissedCommand(trackId, false);
|
|
35084
35267
|
if (options.json) {
|
|
35085
|
-
|
|
35268
|
+
printJson2({ changed, ok: true });
|
|
35086
35269
|
return;
|
|
35087
35270
|
}
|
|
35088
35271
|
console.log(changed ? `Restored ${trackId}. It re-enters the ranking on the next sweep.` : `${trackId} was not dismissed \u2014 nothing to restore.`);
|
|
@@ -35095,7 +35278,7 @@ JSON field reference:
|
|
|
35095
35278
|
}
|
|
35096
35279
|
const body = JSON.parse(readFileSync6(options.phaseFile, "utf8"));
|
|
35097
35280
|
const result = await crawlCataloguePhaseCommand(body);
|
|
35098
|
-
|
|
35281
|
+
printJson2(result);
|
|
35099
35282
|
return;
|
|
35100
35283
|
}
|
|
35101
35284
|
await runCrawlCatalogue(options, crawlCatalogueCommand);
|
|
@@ -35103,7 +35286,7 @@ JSON field reference:
|
|
|
35103
35286
|
catalogue.command("commit-nodes").description("Commit one claim's fetched crawl nodes in a single admitted phase").requiredOption("--file <path>", "JSON file holding the batch body ({ items: [...] })").option("--json", "Print JSON", false).action(async (options) => {
|
|
35104
35287
|
await Promise.resolve().then(() => init_admin_catalogue2());
|
|
35105
35288
|
const body = JSON.parse(readFileSync6(options.file, "utf8"));
|
|
35106
|
-
|
|
35289
|
+
printJson2(await commitCrawlNodesCommand(body));
|
|
35107
35290
|
});
|
|
35108
35291
|
catalogue.command("status").description("The crawl frontier's state, the catalogue's size, and the seed set").option("--json", "Print JSON", false).action(async (options) => {
|
|
35109
35292
|
await Promise.resolve().then(() => init_admin_catalogue2());
|
|
@@ -35117,7 +35300,7 @@ JSON field reference:
|
|
|
35117
35300
|
await Promise.resolve().then(() => init_admin_reach2());
|
|
35118
35301
|
const { collected, failed, inserted, skipped } = await reachCollectCommand();
|
|
35119
35302
|
if (options.json) {
|
|
35120
|
-
|
|
35303
|
+
printJson2({ collected, failed, inserted, ok: true, skipped });
|
|
35121
35304
|
return;
|
|
35122
35305
|
}
|
|
35123
35306
|
const landed = collected.map((entry) => `${entry.platform} (${entry.metrics.join(", ")})`).join("; ");
|
|
@@ -35219,7 +35402,7 @@ JSON field reference:
|
|
|
35219
35402
|
await Promise.resolve().then(() => init_admin_artists2());
|
|
35220
35403
|
const rule = await addArtistRuleCommand(artistRuleInput(artistMbid, options.verdict, options.name));
|
|
35221
35404
|
if (options.json) {
|
|
35222
|
-
|
|
35405
|
+
printJson2({ ok: true, rule });
|
|
35223
35406
|
return;
|
|
35224
35407
|
}
|
|
35225
35408
|
console.log(artistRuleWriteLine(`Rule set for ${rule.resolvedName ?? rule.artistName}: ${rule.verdict.toUpperCase()}`, rule.verdict === "unlisted" ? UNLISTED_RULE_BOUNDARY : ARTIST_RULE_BOUNDARY));
|
|
@@ -35228,7 +35411,7 @@ JSON field reference:
|
|
|
35228
35411
|
await Promise.resolve().then(() => init_admin_artists2());
|
|
35229
35412
|
const rules = await listArtistRulesCommand();
|
|
35230
35413
|
if (options.json) {
|
|
35231
|
-
|
|
35414
|
+
printJson2({ ok: true, rules });
|
|
35232
35415
|
return;
|
|
35233
35416
|
}
|
|
35234
35417
|
console.log(artistRuleLines(rules).join(`
|
|
@@ -35238,7 +35421,7 @@ JSON field reference:
|
|
|
35238
35421
|
await Promise.resolve().then(() => init_admin_artists2());
|
|
35239
35422
|
const result = await removeArtistRuleCommand(id);
|
|
35240
35423
|
if (options.json) {
|
|
35241
|
-
|
|
35424
|
+
printJson2(result);
|
|
35242
35425
|
return;
|
|
35243
35426
|
}
|
|
35244
35427
|
console.log(artistRuleWriteLine(`Rule removed: ${id}`));
|
|
@@ -35274,7 +35457,7 @@ JSON field reference:
|
|
|
35274
35457
|
}
|
|
35275
35458
|
const result = options.replace ? await replaceLabelArtistRulesCommand(slug, parseLabelArtistRulesJson(readFileSync6(options.rulesFile ?? "", "utf8"))) : await listLabelArtistRulesCommand(slug);
|
|
35276
35459
|
if (options.json) {
|
|
35277
|
-
|
|
35460
|
+
printJson2({ ok: true, rules: result.rules });
|
|
35278
35461
|
return;
|
|
35279
35462
|
}
|
|
35280
35463
|
if (options.replace) {
|
|
@@ -35296,7 +35479,7 @@ JSON field reference:
|
|
|
35296
35479
|
await Promise.resolve().then(() => init_admin_labels2());
|
|
35297
35480
|
const label = await updateLabelCommand(slug, seedState, options.rewalk);
|
|
35298
35481
|
if (options.json) {
|
|
35299
|
-
|
|
35482
|
+
printJson2({ label, ok: true });
|
|
35300
35483
|
return;
|
|
35301
35484
|
}
|
|
35302
35485
|
for (const line of labelUpdateLines(label, options)) {
|
|
@@ -35333,7 +35516,7 @@ JSON field reference:
|
|
|
35333
35516
|
process.exitCode = 1;
|
|
35334
35517
|
}
|
|
35335
35518
|
if (options.json) {
|
|
35336
|
-
|
|
35519
|
+
printJson2(evidence);
|
|
35337
35520
|
return;
|
|
35338
35521
|
}
|
|
35339
35522
|
console.log(labelEvidenceLines(evidence).join(`
|
|
@@ -35362,7 +35545,7 @@ JSON field reference:
|
|
|
35362
35545
|
await Promise.resolve().then(() => init_admin_labels2());
|
|
35363
35546
|
const { label, outcome, takenOver } = await mintLabelCommand(mbid, seedState, takeOver);
|
|
35364
35547
|
if (options.json) {
|
|
35365
|
-
|
|
35548
|
+
printJson2({ label, ok: true, outcome, ...takenOver ? { takenOver } : {} });
|
|
35366
35549
|
return;
|
|
35367
35550
|
}
|
|
35368
35551
|
console.log(labelMintLine(label, outcome, mbid, takenOver));
|
|
@@ -35371,7 +35554,7 @@ JSON field reference:
|
|
|
35371
35554
|
await Promise.resolve().then(() => init_admin_labels2());
|
|
35372
35555
|
const result = await mergeLabelCommand(losingSlug, canonicalSlug);
|
|
35373
35556
|
if (options.json) {
|
|
35374
|
-
|
|
35557
|
+
printJson2({ ok: true, result });
|
|
35375
35558
|
return;
|
|
35376
35559
|
}
|
|
35377
35560
|
const {
|
|
@@ -35426,7 +35609,7 @@ async function runTrackPreviewArchive(idOrLogId, options, previewArchiveUploadCo
|
|
|
35426
35609
|
source: options.source
|
|
35427
35610
|
});
|
|
35428
35611
|
if (options.json) {
|
|
35429
|
-
|
|
35612
|
+
printJson2(result);
|
|
35430
35613
|
return;
|
|
35431
35614
|
}
|
|
35432
35615
|
console.log(`Archived preview for ${result.logId}`);
|
|
@@ -35457,7 +35640,7 @@ async function runTrackObserve(idOrLogId, options, trackObserveCommand) {
|
|
|
35457
35640
|
voiceId: options.voiceId
|
|
35458
35641
|
});
|
|
35459
35642
|
if (options.json) {
|
|
35460
|
-
|
|
35643
|
+
printJson2(result);
|
|
35461
35644
|
return;
|
|
35462
35645
|
}
|
|
35463
35646
|
console.log(`Recorded observation for ${result.logId}`);
|
|
@@ -35474,7 +35657,7 @@ async function runTrackContext(idOrLogId, options, trackContextCommand) {
|
|
|
35474
35657
|
refresh: options.refresh
|
|
35475
35658
|
});
|
|
35476
35659
|
if (options.json) {
|
|
35477
|
-
|
|
35660
|
+
printJson2(result);
|
|
35478
35661
|
return;
|
|
35479
35662
|
}
|
|
35480
35663
|
if (result.skipped) {
|
|
@@ -35509,7 +35692,7 @@ async function runTrackNote(idOrLogId, options, trackNoteCommand) {
|
|
|
35509
35692
|
promptVersion: parsePromptVersion(options.promptVersion)
|
|
35510
35693
|
});
|
|
35511
35694
|
if (options.json) {
|
|
35512
|
-
|
|
35695
|
+
printJson2(result);
|
|
35513
35696
|
return;
|
|
35514
35697
|
}
|
|
35515
35698
|
if (result.skipped) {
|
|
@@ -35540,7 +35723,7 @@ async function runEntityDescribe(kind, slug, options, describeCommand) {
|
|
|
35540
35723
|
promptVersion: parsePromptVersion(options.promptVersion)
|
|
35541
35724
|
});
|
|
35542
35725
|
if (options.json) {
|
|
35543
|
-
|
|
35726
|
+
printJson2(result);
|
|
35544
35727
|
return;
|
|
35545
35728
|
}
|
|
35546
35729
|
if (result.skipped) {
|
|
@@ -35565,7 +35748,7 @@ async function runEntityBioQueue(kind, options, queueCommand) {
|
|
|
35565
35748
|
const limit = options.limit ? Number.parseInt(options.limit, 10) : 50;
|
|
35566
35749
|
const items = await queueCommand(Number.isFinite(limit) ? limit : 50);
|
|
35567
35750
|
if (options.json) {
|
|
35568
|
-
|
|
35751
|
+
printJson2(items);
|
|
35569
35752
|
return;
|
|
35570
35753
|
}
|
|
35571
35754
|
if (items.length === 0) {
|
|
@@ -35581,7 +35764,7 @@ async function runEntityBioQueue(kind, options, queueCommand) {
|
|
|
35581
35764
|
async function runEntityBioDraft(kind, slug, options, draftCommand) {
|
|
35582
35765
|
const draft = await draftCommand(slug);
|
|
35583
35766
|
if (options.json) {
|
|
35584
|
-
|
|
35767
|
+
printJson2(draft);
|
|
35585
35768
|
return;
|
|
35586
35769
|
}
|
|
35587
35770
|
if (!draft.found) {
|
|
@@ -35597,7 +35780,7 @@ async function runTrackSimilar(idOrLogId, options, trackSimilarCommand) {
|
|
|
35597
35780
|
const limit = options.limit ? Number.parseInt(options.limit, 10) : undefined;
|
|
35598
35781
|
const result = await trackSimilarCommand(idOrLogId, limit !== undefined && Number.isFinite(limit) ? limit : undefined);
|
|
35599
35782
|
if (options.json) {
|
|
35600
|
-
|
|
35783
|
+
printJson2(result);
|
|
35601
35784
|
return;
|
|
35602
35785
|
}
|
|
35603
35786
|
if (result.findings.length === 0) {
|
|
@@ -35612,7 +35795,7 @@ async function runTrackSimilar(idOrLogId, options, trackSimilarCommand) {
|
|
|
35612
35795
|
}
|
|
35613
35796
|
}
|
|
35614
35797
|
function printSweepJson(payload, failedCount) {
|
|
35615
|
-
|
|
35798
|
+
printJson2({ ...payload, failedCount, ok: failedCount === 0 });
|
|
35616
35799
|
if (failedCount > 0) {
|
|
35617
35800
|
process.exitCode = 1;
|
|
35618
35801
|
}
|
|
@@ -35627,7 +35810,7 @@ async function runMigratePreviewArchive(options, migratePreviewArchiveCommand) {
|
|
|
35627
35810
|
if (mode === "verify") {
|
|
35628
35811
|
const result = await migratePreviewArchiveCommand({ dryRun: true, limit, mode });
|
|
35629
35812
|
if (options.json) {
|
|
35630
|
-
|
|
35813
|
+
printJson2({ mode, ok: true, remaining: result.remaining, sampleKeys: result.sampleKeys });
|
|
35631
35814
|
return;
|
|
35632
35815
|
}
|
|
35633
35816
|
console.log(`${result.remaining} object(s) remain under the public analysis/previews/ prefix.`);
|
|
@@ -35780,7 +35963,7 @@ async function runCrawlCatalogue(options, crawlCatalogueCommand) {
|
|
|
35780
35963
|
const maxHop = Number.parseInt(options.maxHop ?? "2", 10);
|
|
35781
35964
|
const result = await crawlCatalogueCommand(limit, Number.isInteger(maxHop) && maxHop >= 0 ? maxHop : 2, options.dryRun);
|
|
35782
35965
|
if (options.json) {
|
|
35783
|
-
|
|
35966
|
+
printJson2(result);
|
|
35784
35967
|
} else if (result.dryRun) {
|
|
35785
35968
|
console.log(`Dry run: would seed ${result.seeded} enabled label(s); ${result.frontierPending} node(s) pending. Nothing written.`);
|
|
35786
35969
|
} else {
|
|
@@ -35803,7 +35986,7 @@ async function runCrawlCatalogue(options, crawlCatalogueCommand) {
|
|
|
35803
35986
|
async function runCrawlStatus(options, crawlStatusCommand) {
|
|
35804
35987
|
const result = await crawlStatusCommand();
|
|
35805
35988
|
if (options.json) {
|
|
35806
|
-
|
|
35989
|
+
printJson2(result);
|
|
35807
35990
|
return;
|
|
35808
35991
|
}
|
|
35809
35992
|
const { frontier, frontierByKind } = result;
|
|
@@ -35845,7 +36028,7 @@ async function runBackfillDiscogs(options, backfillDiscogsCommand) {
|
|
|
35845
36028
|
cursor = result.nextCursor;
|
|
35846
36029
|
}
|
|
35847
36030
|
if (options.json) {
|
|
35848
|
-
|
|
36031
|
+
printJson2({
|
|
35849
36032
|
dryRun,
|
|
35850
36033
|
ok: true,
|
|
35851
36034
|
rateLimited: throttled,
|
|
@@ -36332,7 +36515,7 @@ async function runBackfillCoverMasters(options, backfillCoverMastersCommand) {
|
|
|
36332
36515
|
cursor = result.nextCursor;
|
|
36333
36516
|
}
|
|
36334
36517
|
if (options.json) {
|
|
36335
|
-
|
|
36518
|
+
printJson2({
|
|
36336
36519
|
dryRun,
|
|
36337
36520
|
failed,
|
|
36338
36521
|
failedCount: failed.length,
|
|
@@ -36395,7 +36578,7 @@ async function runBackfillLabelLineage(options, backfillLabelLineageCommand) {
|
|
|
36395
36578
|
cursor = result.nextCursor;
|
|
36396
36579
|
}
|
|
36397
36580
|
if (options.json) {
|
|
36398
|
-
|
|
36581
|
+
printJson2({
|
|
36399
36582
|
dryRun,
|
|
36400
36583
|
failed,
|
|
36401
36584
|
failedCount: failed.length,
|
|
@@ -36512,7 +36695,7 @@ async function runBackfillRecordingMbids(options, backfillRecordingMbidsCommand)
|
|
|
36512
36695
|
cursor = result.nextCursor;
|
|
36513
36696
|
}
|
|
36514
36697
|
if (options.json) {
|
|
36515
|
-
|
|
36698
|
+
printJson2({
|
|
36516
36699
|
dryRun,
|
|
36517
36700
|
failed,
|
|
36518
36701
|
failedCount: failed.length,
|
|
@@ -36575,7 +36758,7 @@ async function runBackfillArtistEdges(options, backfillArtistEdgesCommand) {
|
|
|
36575
36758
|
cursor = result.nextCursor;
|
|
36576
36759
|
}
|
|
36577
36760
|
if (options.json) {
|
|
36578
|
-
|
|
36761
|
+
printJson2({
|
|
36579
36762
|
dryRun,
|
|
36580
36763
|
edgesWritten,
|
|
36581
36764
|
fullyMatched,
|
|
@@ -36629,7 +36812,7 @@ async function runBackfillArtistCredits(options, backfillArtistCreditsCommand) {
|
|
|
36629
36812
|
cursor = result.nextCursor;
|
|
36630
36813
|
}
|
|
36631
36814
|
if (options.json) {
|
|
36632
|
-
|
|
36815
|
+
printJson2({
|
|
36633
36816
|
adoptedArtists,
|
|
36634
36817
|
dryRun,
|
|
36635
36818
|
edgesWritten,
|
|
@@ -36649,7 +36832,7 @@ async function runArtistResolveQueue(options, listArtistsCommand) {
|
|
|
36649
36832
|
const limit = parseListLimit(options.limit);
|
|
36650
36833
|
const result = await listArtistsCommand(limit);
|
|
36651
36834
|
if (options.json) {
|
|
36652
|
-
|
|
36835
|
+
printJson2({ artists: result.artists, ok: true });
|
|
36653
36836
|
return;
|
|
36654
36837
|
}
|
|
36655
36838
|
if (result.artists.length === 0) {
|
|
@@ -36668,7 +36851,7 @@ async function runArtistResolve(artistId, options, resolveArtistCommand) {
|
|
|
36668
36851
|
}
|
|
36669
36852
|
const result = await resolveArtistCommand(artistId);
|
|
36670
36853
|
if (options.json) {
|
|
36671
|
-
|
|
36854
|
+
printJson2(result);
|
|
36672
36855
|
return;
|
|
36673
36856
|
}
|
|
36674
36857
|
if (result.rateLimited) {
|
|
@@ -36732,7 +36915,7 @@ async function runTrackVideo(idOrLogId, options, trackVideoCommand) {
|
|
|
36732
36915
|
allowPartial: options.allowPartial
|
|
36733
36916
|
});
|
|
36734
36917
|
if (options.json) {
|
|
36735
|
-
|
|
36918
|
+
printJson2(result);
|
|
36736
36919
|
return;
|
|
36737
36920
|
}
|
|
36738
36921
|
console.log(`Linked video to ${result.logId}`);
|
|
@@ -36747,7 +36930,7 @@ async function runTrackDraft(idOrLogId, options, trackDraftCommand) {
|
|
|
36747
36930
|
const platform = options.platform ?? "tiktok";
|
|
36748
36931
|
const result = await trackDraftCommand(idOrLogId, platform);
|
|
36749
36932
|
if (options.json) {
|
|
36750
|
-
|
|
36933
|
+
printJson2(result);
|
|
36751
36934
|
return;
|
|
36752
36935
|
}
|
|
36753
36936
|
console.log(`Pushed ${platform} draft for ${result.trackId} (post ${result.externalId})`);
|
|
@@ -36759,7 +36942,7 @@ async function runTrackSocial(idOrLogId, options, trackSocialShowCommand, trackS
|
|
|
36759
36942
|
if (!options.status) {
|
|
36760
36943
|
const result = await trackSocialShowCommand(idOrLogId);
|
|
36761
36944
|
if (options.json) {
|
|
36762
|
-
|
|
36945
|
+
printJson2(result);
|
|
36763
36946
|
return;
|
|
36764
36947
|
}
|
|
36765
36948
|
if (result.posts.length === 0) {
|
|
@@ -36784,7 +36967,7 @@ async function runTrackSocial(idOrLogId, options, trackSocialShowCommand, trackS
|
|
|
36784
36967
|
url: options.url
|
|
36785
36968
|
});
|
|
36786
36969
|
if (options.json) {
|
|
36787
|
-
|
|
36970
|
+
printJson2(result);
|
|
36788
36971
|
return;
|
|
36789
36972
|
}
|
|
36790
36973
|
console.log(`${platform} \u2192 ${options.status} for ${result.trackId}`);
|
|
@@ -36796,7 +36979,7 @@ async function runTrackSocialCapture(options, trackSocialCaptureCommand) {
|
|
|
36796
36979
|
}
|
|
36797
36980
|
const result = await trackSocialCaptureCommand(limit);
|
|
36798
36981
|
if (options.json) {
|
|
36799
|
-
|
|
36982
|
+
printJson2(result);
|
|
36800
36983
|
return;
|
|
36801
36984
|
}
|
|
36802
36985
|
if (result.captured.length === 0) {
|
|
@@ -36814,7 +36997,7 @@ async function runTrackGet(idOrLogId, options, trackGetCommand) {
|
|
|
36814
36997
|
}
|
|
36815
36998
|
const result = await trackGetCommand(idOrLogId);
|
|
36816
36999
|
if (options.json) {
|
|
36817
|
-
|
|
37000
|
+
printJson2(result);
|
|
36818
37001
|
return;
|
|
36819
37002
|
}
|
|
36820
37003
|
if ("mixtape" in result) {
|
|
@@ -36840,7 +37023,7 @@ async function runMixableOrder(logIds, options, mixableOrderCommand) {
|
|
|
36840
37023
|
}
|
|
36841
37024
|
const result = await mixableOrderCommand(logIds, options.seed);
|
|
36842
37025
|
if (options.json) {
|
|
36843
|
-
|
|
37026
|
+
printJson2(result);
|
|
36844
37027
|
return;
|
|
36845
37028
|
}
|
|
36846
37029
|
console.log(`Proposed mix \u2014 a smooth chain (${result.algorithm}), not an energy-shaped set. Copy into Rekordbox as advisory.
|
|
@@ -36858,7 +37041,7 @@ async function runTrackGetAdmin(idOrLogId, options, trackGetAdminCommand) {
|
|
|
36858
37041
|
}
|
|
36859
37042
|
const result = await trackGetAdminCommand(idOrLogId);
|
|
36860
37043
|
if (options.json) {
|
|
36861
|
-
|
|
37044
|
+
printJson2(result);
|
|
36862
37045
|
return;
|
|
36863
37046
|
}
|
|
36864
37047
|
const t = result.track;
|
|
@@ -36927,7 +37110,7 @@ async function runTrackUpdate(trackId, options, trackUpdateCommand) {
|
|
|
36927
37110
|
videoUrl: options.videoUrl
|
|
36928
37111
|
});
|
|
36929
37112
|
if (options.json) {
|
|
36930
|
-
|
|
37113
|
+
printJson2(result);
|
|
36931
37114
|
return;
|
|
36932
37115
|
}
|
|
36933
37116
|
console.log(`Updated ${result.trackId}: ${result.fields.join(", ")}`);
|
|
@@ -36938,7 +37121,7 @@ async function runTrackRequeueVideo(idOrLogId, options, trackRequeueVideoCommand
|
|
|
36938
37121
|
}
|
|
36939
37122
|
const result = await trackRequeueVideoCommand(idOrLogId);
|
|
36940
37123
|
if (options.json) {
|
|
36941
|
-
|
|
37124
|
+
printJson2(result);
|
|
36942
37125
|
return;
|
|
36943
37126
|
}
|
|
36944
37127
|
console.log(result.alreadyClear ? `${result.logId} already had no video. Nothing to clear.` : `Cleared the video for ${result.logId}. It's back on the render queue (and off radio until re-rendered).`);
|
|
@@ -36962,7 +37145,7 @@ async function runTrackPinSource(idOrLogId, options, commands) {
|
|
|
36962
37145
|
allowDurationMismatch: options.allowDurationMismatch
|
|
36963
37146
|
});
|
|
36964
37147
|
if (options.json) {
|
|
36965
|
-
|
|
37148
|
+
printJson2(result);
|
|
36966
37149
|
return;
|
|
36967
37150
|
}
|
|
36968
37151
|
const who = result.logId ?? result.trackId;
|
|
@@ -36975,7 +37158,7 @@ async function runTrackPurgeVideo(idOrLogId, options, trackPurgeVideoCommand) {
|
|
|
36975
37158
|
}
|
|
36976
37159
|
const result = await trackPurgeVideoCommand(idOrLogId);
|
|
36977
37160
|
if (options.json) {
|
|
36978
|
-
|
|
37161
|
+
printJson2(result);
|
|
36979
37162
|
return;
|
|
36980
37163
|
}
|
|
36981
37164
|
console.log(result.noVideo ? `${result.logId} has no video. Nothing to purge.` : `Purging the stale renditions for ${result.logId} from the edge. The next play picks up the fresh render.`);
|
|
@@ -36986,7 +37169,7 @@ async function runMixtapeUpdate(id, options, mixtapeUpdateCommand) {
|
|
|
36986
37169
|
}
|
|
36987
37170
|
const result = await mixtapeUpdateCommand(id, options);
|
|
36988
37171
|
if (options.json) {
|
|
36989
|
-
|
|
37172
|
+
printJson2(result);
|
|
36990
37173
|
return;
|
|
36991
37174
|
}
|
|
36992
37175
|
console.log(`Saved ${result.mixtape.id}.`);
|
|
@@ -36998,7 +37181,7 @@ async function runMixtapeDistribute(idOrLogId, options, mixtapeDistributeCommand
|
|
|
36998
37181
|
const onProgress = options.json ? () => {} : (message) => console.log(message);
|
|
36999
37182
|
const result = await mixtapeDistributeCommand(idOrLogId, options, onProgress);
|
|
37000
37183
|
if (options.json) {
|
|
37001
|
-
|
|
37184
|
+
printJson2(result);
|
|
37002
37185
|
return;
|
|
37003
37186
|
}
|
|
37004
37187
|
const links = result.results.map((r) => ` ${r.platform}: ${r.url}`).join(`
|
|
@@ -37012,7 +37195,7 @@ async function runMixtapePublishYoutube(idOrLogId, options, publishYoutubeComman
|
|
|
37012
37195
|
}
|
|
37013
37196
|
const result = await publishYoutubeCommand(idOrLogId);
|
|
37014
37197
|
if (options.json) {
|
|
37015
|
-
|
|
37198
|
+
printJson2(result);
|
|
37016
37199
|
return;
|
|
37017
37200
|
}
|
|
37018
37201
|
console.log(`YouTube video is now public: ${result.url}`);
|
|
@@ -37024,7 +37207,7 @@ async function runMixtapeResync(idOrLogId, options, mixtapeResyncCommand) {
|
|
|
37024
37207
|
const onProgress = options.json ? () => {} : (message) => console.log(message);
|
|
37025
37208
|
const result = await mixtapeResyncCommand(idOrLogId, options, onProgress);
|
|
37026
37209
|
if (options.json) {
|
|
37027
|
-
|
|
37210
|
+
printJson2(result);
|
|
37028
37211
|
return;
|
|
37029
37212
|
}
|
|
37030
37213
|
const links = result.results.map((r) => ` ${r.platform}: ${r.url}`).join(`
|
|
@@ -37035,7 +37218,7 @@ ${links}`);
|
|
|
37035
37218
|
async function runMixtapeList(options, mixtapeListCommand) {
|
|
37036
37219
|
const mixtapes = await mixtapeListCommand();
|
|
37037
37220
|
if (options.json) {
|
|
37038
|
-
|
|
37221
|
+
printJson2({ mixtapes, ok: true });
|
|
37039
37222
|
return;
|
|
37040
37223
|
}
|
|
37041
37224
|
if (mixtapes.length === 0) {
|
|
@@ -37055,7 +37238,7 @@ async function runClipsList(options, clipsListCommand, clipPostsListCommand) {
|
|
|
37055
37238
|
]);
|
|
37056
37239
|
const dripByClip = new Map(posts.map((post) => [post.clipId, post]));
|
|
37057
37240
|
if (options.json) {
|
|
37058
|
-
|
|
37241
|
+
printJson2({
|
|
37059
37242
|
clips: clips.map((clip) => ({ ...clip, drip: dripByClip.get(clip.id) })),
|
|
37060
37243
|
ok: true
|
|
37061
37244
|
});
|
|
@@ -37079,7 +37262,7 @@ async function runClipsCut(clipId, options, clipCutCommand) {
|
|
|
37079
37262
|
const onProgress = options.json ? () => {} : (message) => console.log(message);
|
|
37080
37263
|
const result = await clipCutCommand(clipId, onProgress);
|
|
37081
37264
|
if (options.json) {
|
|
37082
|
-
|
|
37265
|
+
printJson2({ ok: true, ...result });
|
|
37083
37266
|
return;
|
|
37084
37267
|
}
|
|
37085
37268
|
console.log(`Cut ${result.clipId} \u2192 ${result.url} (${(result.sizeBytes / 1e6).toFixed(1)} MB).`);
|
|
@@ -37090,7 +37273,7 @@ async function runClipsSchedule(clipId, options, clipScheduleCommand) {
|
|
|
37090
37273
|
}
|
|
37091
37274
|
const post = await clipScheduleCommand(clipId, options.at);
|
|
37092
37275
|
if (options.json) {
|
|
37093
|
-
|
|
37276
|
+
printJson2({ ok: true, post });
|
|
37094
37277
|
return;
|
|
37095
37278
|
}
|
|
37096
37279
|
console.log(`Scheduled ${post.clipId} for ${post.scheduledFor}.`);
|
|
@@ -37098,7 +37281,7 @@ async function runClipsSchedule(clipId, options, clipScheduleCommand) {
|
|
|
37098
37281
|
async function runClipsDripPause(paused, options, clipDripPauseCommand) {
|
|
37099
37282
|
const result = await clipDripPauseCommand(paused);
|
|
37100
37283
|
if (options.json) {
|
|
37101
|
-
|
|
37284
|
+
printJson2({ ok: true, paused: result });
|
|
37102
37285
|
return;
|
|
37103
37286
|
}
|
|
37104
37287
|
console.log(result ? "The drip-feed is paused." : "The drip-feed is running.");
|
|
@@ -37106,7 +37289,7 @@ async function runClipsDripPause(paused, options, clipDripPauseCommand) {
|
|
|
37106
37289
|
async function runPublishAdvance(options, publishAdvanceCommand) {
|
|
37107
37290
|
const result = await publishAdvanceCommand();
|
|
37108
37291
|
if (options.json) {
|
|
37109
|
-
|
|
37292
|
+
printJson2(result);
|
|
37110
37293
|
return;
|
|
37111
37294
|
}
|
|
37112
37295
|
if (result.paused) {
|
|
@@ -37130,7 +37313,7 @@ async function runPublishAdvance(options, publishAdvanceCommand) {
|
|
|
37130
37313
|
}
|
|
37131
37314
|
function printAnchorApifyBudget(state, options) {
|
|
37132
37315
|
if (options.json) {
|
|
37133
|
-
|
|
37316
|
+
printJson2({ ...state, ok: true });
|
|
37134
37317
|
return;
|
|
37135
37318
|
}
|
|
37136
37319
|
console.log(state.spent ? `APIFY ROWS SPENT for ${state.day} \u2014 the paid anchor rung sends nothing more today.` : `APIFY ROWS OPEN for ${state.day} \u2014 the paid anchor rung may still be sent rows.`);
|
|
@@ -37151,7 +37334,7 @@ function printCaptureBudget(state) {
|
|
|
37151
37334
|
async function runCaptureBudget(options, captureBudgetCommand) {
|
|
37152
37335
|
const state = await captureBudgetCommand();
|
|
37153
37336
|
if (options.json) {
|
|
37154
|
-
|
|
37337
|
+
printJson2(state);
|
|
37155
37338
|
return;
|
|
37156
37339
|
}
|
|
37157
37340
|
printCaptureBudget(state);
|
|
@@ -37159,7 +37342,7 @@ async function runCaptureBudget(options, captureBudgetCommand) {
|
|
|
37159
37342
|
async function runSetCaptureBudget(input, options, setCaptureBudgetCommand) {
|
|
37160
37343
|
const state = await setCaptureBudgetCommand(input);
|
|
37161
37344
|
if (options.json) {
|
|
37162
|
-
|
|
37345
|
+
printJson2(state);
|
|
37163
37346
|
return;
|
|
37164
37347
|
}
|
|
37165
37348
|
printCaptureBudget(state);
|
|
@@ -37194,7 +37377,7 @@ async function runSetCaptureCaps(options, setCaptureBudgetCommand) {
|
|
|
37194
37377
|
async function runPublishAdvancePause(paused, options, publishAdvancePauseCommand) {
|
|
37195
37378
|
const result = await publishAdvancePauseCommand(paused);
|
|
37196
37379
|
if (options.json) {
|
|
37197
|
-
|
|
37380
|
+
printJson2({ ok: true, paused: result });
|
|
37198
37381
|
return;
|
|
37199
37382
|
}
|
|
37200
37383
|
console.log(result ? "The publish auto-advance is paused." : "The publish auto-advance is running.");
|
|
@@ -37205,7 +37388,7 @@ async function runMixtapeGet(idOrLogId, options, mixtapeGetCommand) {
|
|
|
37205
37388
|
}
|
|
37206
37389
|
const mixtape = await mixtapeGetCommand(idOrLogId);
|
|
37207
37390
|
if (options.json) {
|
|
37208
|
-
|
|
37391
|
+
printJson2(mixtape);
|
|
37209
37392
|
return;
|
|
37210
37393
|
}
|
|
37211
37394
|
const coordinate = mixtape.logId ?? "unminted";
|
|
@@ -37236,7 +37419,7 @@ function formatCue(ms) {
|
|
|
37236
37419
|
async function runNewsletterDraft(options, newsletterDraftCommand) {
|
|
37237
37420
|
const result = await newsletterDraftCommand(options);
|
|
37238
37421
|
if (options.json) {
|
|
37239
|
-
|
|
37422
|
+
printJson2(result);
|
|
37240
37423
|
return;
|
|
37241
37424
|
}
|
|
37242
37425
|
console.log(`Drafted edition ${result.edition.id}. It stays a draft until the operator sends it.`);
|
|
@@ -37247,7 +37430,7 @@ async function runNewsletterUpdate(id, options, newsletterUpdateCommand) {
|
|
|
37247
37430
|
}
|
|
37248
37431
|
const result = await newsletterUpdateCommand(id, options);
|
|
37249
37432
|
if (options.json) {
|
|
37250
|
-
|
|
37433
|
+
printJson2(result);
|
|
37251
37434
|
return;
|
|
37252
37435
|
}
|
|
37253
37436
|
console.log(`Saved draft ${result.edition.id}.`);
|
|
@@ -37258,7 +37441,7 @@ async function runNewsletterSend(id, options, newsletterSendCommand) {
|
|
|
37258
37441
|
}
|
|
37259
37442
|
const result = await newsletterSendCommand(id);
|
|
37260
37443
|
if (options.json) {
|
|
37261
|
-
|
|
37444
|
+
printJson2(result);
|
|
37262
37445
|
return;
|
|
37263
37446
|
}
|
|
37264
37447
|
const number = result.edition.number;
|
|
@@ -37273,7 +37456,7 @@ async function runNewsletterDelete(id, options, newsletterDeleteCommand) {
|
|
|
37273
37456
|
}
|
|
37274
37457
|
const result = await newsletterDeleteCommand(id);
|
|
37275
37458
|
if (options.json) {
|
|
37276
|
-
|
|
37459
|
+
printJson2({ ...result, ok: true });
|
|
37277
37460
|
return;
|
|
37278
37461
|
}
|
|
37279
37462
|
console.log(`Deleted edition ${result.id}. The send window reopens to cover its finds.`);
|
|
@@ -37281,7 +37464,7 @@ async function runNewsletterDelete(id, options, newsletterDeleteCommand) {
|
|
|
37281
37464
|
async function runNewsletterList(options, newsletterListCommand) {
|
|
37282
37465
|
const editions = await newsletterListCommand();
|
|
37283
37466
|
if (options.json) {
|
|
37284
|
-
|
|
37467
|
+
printJson2({ editions, ok: true });
|
|
37285
37468
|
return;
|
|
37286
37469
|
}
|
|
37287
37470
|
if (editions.length === 0) {
|
|
@@ -37298,7 +37481,7 @@ async function runLogbookGaps(options, logbookGapsCommand) {
|
|
|
37298
37481
|
const limit = options.limit === undefined ? undefined : Number.parseInt(options.limit, 10);
|
|
37299
37482
|
const { gaps, spent } = await logbookGapsCommand(limit !== undefined && Number.isFinite(limit) ? limit : undefined);
|
|
37300
37483
|
if (options.json) {
|
|
37301
|
-
|
|
37484
|
+
printJson2({ gaps, ok: true, spent });
|
|
37302
37485
|
return;
|
|
37303
37486
|
}
|
|
37304
37487
|
if (gaps.length === 0) {
|
|
@@ -37320,7 +37503,7 @@ async function runLogbookWrite(sector, options, writeCommand) {
|
|
|
37320
37503
|
title: options.title
|
|
37321
37504
|
});
|
|
37322
37505
|
if (options.json) {
|
|
37323
|
-
|
|
37506
|
+
printJson2(result);
|
|
37324
37507
|
return;
|
|
37325
37508
|
}
|
|
37326
37509
|
const skipped = "skipped" in result && result.skipped;
|
|
@@ -37335,7 +37518,7 @@ function requirePromptSlug(slug) {
|
|
|
37335
37518
|
async function runPromptsList(options, promptsListCommand) {
|
|
37336
37519
|
const prompts = await promptsListCommand();
|
|
37337
37520
|
if (options.json) {
|
|
37338
|
-
|
|
37521
|
+
printJson2({ ok: true, prompts });
|
|
37339
37522
|
return;
|
|
37340
37523
|
}
|
|
37341
37524
|
await Promise.resolve().then(() => init_admin_prompts2());
|
|
@@ -37346,7 +37529,7 @@ async function runPromptsList(options, promptsListCommand) {
|
|
|
37346
37529
|
async function runPromptGet(slug, options, promptGetCommand) {
|
|
37347
37530
|
const resolved = await promptGetCommand(requirePromptSlug(slug));
|
|
37348
37531
|
if (options.json) {
|
|
37349
|
-
|
|
37532
|
+
printJson2(resolved);
|
|
37350
37533
|
return;
|
|
37351
37534
|
}
|
|
37352
37535
|
const live = resolved.source === "override" ? `v${resolved.version}, an operator edit` : "the repo's baked default (v0)";
|
|
@@ -37357,7 +37540,7 @@ async function runPromptGet(slug, options, promptGetCommand) {
|
|
|
37357
37540
|
async function runPromptHistory(slug, options, promptDetailCommand) {
|
|
37358
37541
|
const detail = await promptDetailCommand(requirePromptSlug(slug));
|
|
37359
37542
|
if (options.json) {
|
|
37360
|
-
|
|
37543
|
+
printJson2({
|
|
37361
37544
|
activeVersion: detail.activeVersion,
|
|
37362
37545
|
ok: true,
|
|
37363
37546
|
slug: detail.slug,
|
|
@@ -37379,7 +37562,7 @@ async function runPromptDiff(slug, options, commands) {
|
|
|
37379
37562
|
const against = commands.parseAgainst(options.against);
|
|
37380
37563
|
const result = await commands.promptDiffCommand(requirePromptSlug(slug), against);
|
|
37381
37564
|
if (options.json) {
|
|
37382
|
-
|
|
37565
|
+
printJson2({ ok: true, ...result });
|
|
37383
37566
|
return;
|
|
37384
37567
|
}
|
|
37385
37568
|
const live = result.live.source === "override" ? `v${result.live.version}` : "the repo's baked default";
|
|
@@ -37400,7 +37583,7 @@ async function runPromptUpdate(slug, options, promptUpdateCommand) {
|
|
|
37400
37583
|
note: options.note
|
|
37401
37584
|
});
|
|
37402
37585
|
if (options.json) {
|
|
37403
|
-
|
|
37586
|
+
printJson2({ ok: true, ...result });
|
|
37404
37587
|
return;
|
|
37405
37588
|
}
|
|
37406
37589
|
console.log(`${result.slug}: v${result.version} is live. Nothing to deploy.`);
|
|
@@ -37416,7 +37599,7 @@ async function runPromptRollback(slug, version, options, commands) {
|
|
|
37416
37599
|
}
|
|
37417
37600
|
const result = await commands.promptRollbackCommand(promptSlug, parsed);
|
|
37418
37601
|
if (options.json) {
|
|
37419
|
-
|
|
37602
|
+
printJson2({ ok: true, ...result });
|
|
37420
37603
|
return;
|
|
37421
37604
|
}
|
|
37422
37605
|
console.log(result.skipped ? `${result.slug}: v${result.from} is already the body running. Nothing appended.` : `${result.slug}: back on v${result.from}'s body, live as v${result.version}.`);
|
|
@@ -37424,7 +37607,7 @@ async function runPromptRollback(slug, version, options, commands) {
|
|
|
37424
37607
|
async function runPromptReset(slug, options, promptResetCommand) {
|
|
37425
37608
|
const result = await promptResetCommand(requirePromptSlug(slug));
|
|
37426
37609
|
if (options.json) {
|
|
37427
|
-
|
|
37610
|
+
printJson2({ ok: true, ...result });
|
|
37428
37611
|
return;
|
|
37429
37612
|
}
|
|
37430
37613
|
console.log(result.skipped ? `${result.slug}: already running the repo's baked default. Nothing appended.` : `${result.slug}: back on the repo's baked default, live as v${result.version}.`);
|
|
@@ -37439,7 +37622,7 @@ async function runAdd(spotifyUrl, options, addCommand) {
|
|
|
37439
37622
|
note: options.note
|
|
37440
37623
|
});
|
|
37441
37624
|
if (options.json) {
|
|
37442
|
-
|
|
37625
|
+
printJson2({
|
|
37443
37626
|
ok: true,
|
|
37444
37627
|
...result
|
|
37445
37628
|
});
|
|
@@ -37467,7 +37650,7 @@ async function runRecent(options, recentCommand) {
|
|
|
37467
37650
|
const limit = parseListLimit(options.limit);
|
|
37468
37651
|
const tracks = await recentCommand(limit);
|
|
37469
37652
|
if (options.json) {
|
|
37470
|
-
|
|
37653
|
+
printJson2({
|
|
37471
37654
|
ok: true,
|
|
37472
37655
|
tracks
|
|
37473
37656
|
});
|
|
@@ -37485,7 +37668,7 @@ async function runGalaxies(slug, options, commands) {
|
|
|
37485
37668
|
if (slug) {
|
|
37486
37669
|
const { findings, galaxy } = await commands.galaxyGetCommand(slug);
|
|
37487
37670
|
if (options.json) {
|
|
37488
|
-
|
|
37671
|
+
printJson2({ findings, galaxy, ok: true });
|
|
37489
37672
|
return;
|
|
37490
37673
|
}
|
|
37491
37674
|
console.log(`${galaxy.name} (${galaxy.slug})`);
|
|
@@ -37498,7 +37681,7 @@ async function runGalaxies(slug, options, commands) {
|
|
|
37498
37681
|
}
|
|
37499
37682
|
const galaxies = await commands.galaxiesListCommand();
|
|
37500
37683
|
if (options.json) {
|
|
37501
|
-
|
|
37684
|
+
printJson2({ galaxies, ok: true });
|
|
37502
37685
|
return;
|
|
37503
37686
|
}
|
|
37504
37687
|
if (galaxies.length === 0) {
|
|
@@ -37515,7 +37698,7 @@ async function runArtistsRank(options, rankArtistsCommand) {
|
|
|
37515
37698
|
limit: options.limit
|
|
37516
37699
|
});
|
|
37517
37700
|
if (options.json) {
|
|
37518
|
-
|
|
37701
|
+
printJson2({ ok: true, summary });
|
|
37519
37702
|
return;
|
|
37520
37703
|
}
|
|
37521
37704
|
const removed = summary.centroidsRemoved > 0 ? ` Purged ${summary.centroidsRemoved} orphan(s).` : "";
|
|
@@ -37527,7 +37710,7 @@ async function runCatalogueRank(options, catalogueRankCommand) {
|
|
|
37527
37710
|
limit: options.limit
|
|
37528
37711
|
});
|
|
37529
37712
|
if (options.json) {
|
|
37530
|
-
|
|
37713
|
+
printJson2({ ok: true, summary, telescope });
|
|
37531
37714
|
return;
|
|
37532
37715
|
}
|
|
37533
37716
|
const quarantine = summary.quarantined > 0 ? ` Quarantined ${summary.quarantined} as wrong audio.` : "";
|
|
@@ -37548,7 +37731,7 @@ async function runCatalogueList(options, catalogueListCommand) {
|
|
|
37548
37731
|
limit: options.limit
|
|
37549
37732
|
});
|
|
37550
37733
|
if (options.json) {
|
|
37551
|
-
|
|
37734
|
+
printJson2({ ok: true, summary, tracks });
|
|
37552
37735
|
return;
|
|
37553
37736
|
}
|
|
37554
37737
|
if (tracks.length === 0) {
|
|
@@ -37584,7 +37767,7 @@ async function runCatalogueList(options, catalogueListCommand) {
|
|
|
37584
37767
|
async function runNoteHeld(options, noteHeldCommand) {
|
|
37585
37768
|
const { gate, rejections } = await noteHeldCommand({ settled: options.settled === true });
|
|
37586
37769
|
if (options.json) {
|
|
37587
|
-
|
|
37770
|
+
printJson2({ gate, ok: true, rejections });
|
|
37588
37771
|
return;
|
|
37589
37772
|
}
|
|
37590
37773
|
if (rejections.length === 0) {
|
|
@@ -37614,7 +37797,7 @@ async function runNoteGate(options, noteGateCommand) {
|
|
|
37614
37797
|
...minPhraseWords === undefined ? {} : { minPhraseWords }
|
|
37615
37798
|
});
|
|
37616
37799
|
if (options.json) {
|
|
37617
|
-
|
|
37800
|
+
printJson2({ gate, ok: true });
|
|
37618
37801
|
return;
|
|
37619
37802
|
}
|
|
37620
37803
|
console.log(`The echo gate: a lift is ${gate.minPhraseWords}+ shared words; an echo is ${Math.round(gate.maxOverlap * 100)}%+ of a neighbour's words.`);
|
|
@@ -37622,7 +37805,7 @@ async function runNoteGate(options, noteGateCommand) {
|
|
|
37622
37805
|
async function runObservationHeld(options, observationHeldCommand) {
|
|
37623
37806
|
const { gate, rejections } = await observationHeldCommand({ settled: options.settled === true });
|
|
37624
37807
|
if (options.json) {
|
|
37625
|
-
|
|
37808
|
+
printJson2({ gate, ok: true, rejections });
|
|
37626
37809
|
return;
|
|
37627
37810
|
}
|
|
37628
37811
|
if (rejections.length === 0) {
|
|
@@ -37652,7 +37835,7 @@ async function runObservationGate(options, observationGateCommand) {
|
|
|
37652
37835
|
...minPhraseWords === undefined ? {} : { minPhraseWords }
|
|
37653
37836
|
});
|
|
37654
37837
|
if (options.json) {
|
|
37655
|
-
|
|
37838
|
+
printJson2({ gate, ok: true });
|
|
37656
37839
|
return;
|
|
37657
37840
|
}
|
|
37658
37841
|
console.log(`The observation echo gate: a lift is ${gate.minPhraseWords}+ shared words; an echo is ${Math.round(gate.maxOverlap * 100)}%+ of a neighbour's words.`);
|
|
@@ -37660,7 +37843,7 @@ async function runObservationGate(options, observationGateCommand) {
|
|
|
37660
37843
|
async function runGalaxyMapRead(options, galaxyMapReadCommand) {
|
|
37661
37844
|
const galaxies = await galaxyMapReadCommand();
|
|
37662
37845
|
if (options.json) {
|
|
37663
|
-
|
|
37846
|
+
printJson2({ galaxies, ok: true });
|
|
37664
37847
|
return;
|
|
37665
37848
|
}
|
|
37666
37849
|
if (galaxies.length === 0) {
|
|
@@ -37676,7 +37859,7 @@ async function runGalaxyMapRead(options, galaxyMapReadCommand) {
|
|
|
37676
37859
|
async function runGalaxyEmbeddings(options, galaxyEmbeddingsCommand) {
|
|
37677
37860
|
const result = await galaxyEmbeddingsCommand({ cursor: options.cursor, limit: options.limit });
|
|
37678
37861
|
if (options.json) {
|
|
37679
|
-
|
|
37862
|
+
printJson2(result);
|
|
37680
37863
|
return;
|
|
37681
37864
|
}
|
|
37682
37865
|
console.log(`${result.embeddings.length} embedding(s)${result.nextCursor ? ` \xB7 nextCursor: ${result.nextCursor}` : " \xB7 end of corpus"}`);
|
|
@@ -37689,7 +37872,7 @@ async function runGalaxyMapWrite(options, galaxyMapWriteCommand) {
|
|
|
37689
37872
|
}
|
|
37690
37873
|
const galaxies = await galaxyMapWriteCommand(clusters);
|
|
37691
37874
|
if (options.json) {
|
|
37692
|
-
|
|
37875
|
+
printJson2({ galaxies, ok: true });
|
|
37693
37876
|
return;
|
|
37694
37877
|
}
|
|
37695
37878
|
console.log(`Wrote ${clusters.length} cluster(s); the map now holds ${galaxies.length} galaxy(ies).`);
|
|
@@ -37697,7 +37880,7 @@ async function runGalaxyMapWrite(options, galaxyMapWriteCommand) {
|
|
|
37697
37880
|
async function runMixtapes(options, mixtapesCommand) {
|
|
37698
37881
|
const mixtapes = await mixtapesCommand();
|
|
37699
37882
|
if (options.json) {
|
|
37700
|
-
|
|
37883
|
+
printJson2({ mixtapes, ok: true });
|
|
37701
37884
|
return;
|
|
37702
37885
|
}
|
|
37703
37886
|
if (mixtapes.length === 0) {
|
|
@@ -37832,7 +38015,7 @@ async function runAdminTracksList(options, listCommand) {
|
|
|
37832
38015
|
const hasKey = resolveHasKey(options);
|
|
37833
38016
|
const tracks = await listCommand({ hasKey, limit, order });
|
|
37834
38017
|
if (options.json) {
|
|
37835
|
-
|
|
38018
|
+
printJson2({ ok: true, tracks });
|
|
37836
38019
|
return;
|
|
37837
38020
|
}
|
|
37838
38021
|
if (tracks.length === 0) {
|
|
@@ -37850,7 +38033,7 @@ async function runAdminTracksList(options, listCommand) {
|
|
|
37850
38033
|
async function runAdminAttention(options, attentionQueueCommand) {
|
|
37851
38034
|
const queue = await attentionQueueCommand();
|
|
37852
38035
|
if (options.json) {
|
|
37853
|
-
|
|
38036
|
+
printJson2({ attention: queue, ok: true });
|
|
37854
38037
|
return;
|
|
37855
38038
|
}
|
|
37856
38039
|
await Promise.resolve().then(() => init_admin_attention());
|
|
@@ -37881,7 +38064,7 @@ async function runAdminTelemetry(options, telemetryCommand) {
|
|
|
37881
38064
|
until
|
|
37882
38065
|
});
|
|
37883
38066
|
if (options.json) {
|
|
37884
|
-
|
|
38067
|
+
printJson2({ ok: true, ...page });
|
|
37885
38068
|
return;
|
|
37886
38069
|
}
|
|
37887
38070
|
await Promise.resolve().then(() => init_admin_telemetry());
|
|
@@ -37894,7 +38077,7 @@ async function runAdminQueue(options, queueCommand) {
|
|
|
37894
38077
|
hasObservation: options.hasObservation ? true : undefined
|
|
37895
38078
|
});
|
|
37896
38079
|
if (options.json) {
|
|
37897
|
-
|
|
38080
|
+
printJson2({
|
|
37898
38081
|
ok: true,
|
|
37899
38082
|
tracks
|
|
37900
38083
|
});
|
|
@@ -37919,7 +38102,7 @@ async function runQueueView({
|
|
|
37919
38102
|
const limit = parseListLimit(options.limit);
|
|
37920
38103
|
const tracks = await fetch2(limit);
|
|
37921
38104
|
if (options.json) {
|
|
37922
|
-
|
|
38105
|
+
printJson2({
|
|
37923
38106
|
ok: true,
|
|
37924
38107
|
tracks
|
|
37925
38108
|
});
|
|
@@ -38007,7 +38190,7 @@ async function runAdminTrackWork(options, trackWorkCommand) {
|
|
|
38007
38190
|
scope
|
|
38008
38191
|
});
|
|
38009
38192
|
if (options.json) {
|
|
38010
|
-
|
|
38193
|
+
printJson2({ debtPending, ok: true, queued, tracks });
|
|
38011
38194
|
return;
|
|
38012
38195
|
}
|
|
38013
38196
|
if (debtPending === true) {
|
|
@@ -38091,7 +38274,7 @@ async function runAdminVehicles(options, vehiclesCommand) {
|
|
|
38091
38274
|
const limit = parseListLimit(options.limit);
|
|
38092
38275
|
const vehicles = await vehiclesCommand(limit);
|
|
38093
38276
|
if (options.json) {
|
|
38094
|
-
|
|
38277
|
+
printJson2({
|
|
38095
38278
|
ok: true,
|
|
38096
38279
|
vehicles
|
|
38097
38280
|
});
|
|
@@ -38137,7 +38320,7 @@ async function runOpen(target, extra, options, openCommands) {
|
|
|
38137
38320
|
async function runRandom(options, randomCommand) {
|
|
38138
38321
|
const track = await randomCommand();
|
|
38139
38322
|
if (options.json) {
|
|
38140
|
-
|
|
38323
|
+
printJson2({
|
|
38141
38324
|
ok: true,
|
|
38142
38325
|
track
|
|
38143
38326
|
});
|
|
@@ -38157,7 +38340,7 @@ async function runRandom(options, randomCommand) {
|
|
|
38157
38340
|
async function runStatus(options, statusCommand) {
|
|
38158
38341
|
const snapshot = await statusCommand();
|
|
38159
38342
|
if (options.json) {
|
|
38160
|
-
|
|
38343
|
+
printJson2({
|
|
38161
38344
|
ok: true,
|
|
38162
38345
|
...snapshot
|
|
38163
38346
|
});
|
|
@@ -38170,7 +38353,7 @@ async function runStatus(options, statusCommand) {
|
|
|
38170
38353
|
async function runMe(options, meCommand) {
|
|
38171
38354
|
const me = await meCommand();
|
|
38172
38355
|
if (options.json) {
|
|
38173
|
-
|
|
38356
|
+
printJson2({ ok: true, ...me });
|
|
38174
38357
|
return;
|
|
38175
38358
|
}
|
|
38176
38359
|
console.log(me.name);
|
|
@@ -38291,6 +38474,10 @@ function topLevelCommand(args) {
|
|
|
38291
38474
|
if (arg.startsWith("--env=")) {
|
|
38292
38475
|
continue;
|
|
38293
38476
|
}
|
|
38477
|
+
if (stringOptions.has(arg)) {
|
|
38478
|
+
index += 1;
|
|
38479
|
+
continue;
|
|
38480
|
+
}
|
|
38294
38481
|
if (!arg.startsWith("-")) {
|
|
38295
38482
|
return arg;
|
|
38296
38483
|
}
|
|
@@ -38311,6 +38498,7 @@ function normalizeCommanderError(error) {
|
|
|
38311
38498
|
return new Error(message);
|
|
38312
38499
|
}
|
|
38313
38500
|
var stringOptions = new Set([
|
|
38501
|
+
"--timeout",
|
|
38314
38502
|
"--isrc-refresh-limit",
|
|
38315
38503
|
"--action",
|
|
38316
38504
|
"--against",
|