fluncle 0.275.0 → 0.277.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 +572 -337
- package/package.json +1 -1
package/bin/fluncle.mjs
CHANGED
|
@@ -60,6 +60,50 @@ 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 writeFdSync(fd, text) {
|
|
66
|
+
const buf = Buffer.from(text, "utf8");
|
|
67
|
+
let offset = 0;
|
|
68
|
+
while (offset < buf.length) {
|
|
69
|
+
try {
|
|
70
|
+
offset += writeSync(fd, buf, offset);
|
|
71
|
+
} catch (error) {
|
|
72
|
+
const code = error.code;
|
|
73
|
+
if (code === "EAGAIN") {
|
|
74
|
+
if (stopWaitingForReader()) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
Atomics.wait(EAGAIN_WAIT, 0, 0, 1);
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
if (code === "EPIPE") {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
throw error;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function isJsonFailure(value) {
|
|
88
|
+
return typeof value === "object" && value !== null && typeof value.code === "string" && typeof value.message === "string";
|
|
89
|
+
}
|
|
90
|
+
function printJson(value) {
|
|
91
|
+
writeFdSync(1, JSON.stringify(value, null, 2) + `
|
|
92
|
+
`);
|
|
93
|
+
}
|
|
94
|
+
var EAGAIN_WAIT, stopWaitingForReader = () => false, CliError;
|
|
95
|
+
var init_output = __esm(() => {
|
|
96
|
+
EAGAIN_WAIT = new Int32Array(new SharedArrayBuffer(4));
|
|
97
|
+
CliError = class CliError extends Error {
|
|
98
|
+
code;
|
|
99
|
+
constructor(code, message) {
|
|
100
|
+
super(message);
|
|
101
|
+
this.name = "CliError";
|
|
102
|
+
this.code = code;
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
});
|
|
106
|
+
|
|
63
107
|
// ../../node_modules/dotenv/lib/main.js
|
|
64
108
|
var require_main = __commonJS(function(exports, module) {
|
|
65
109
|
var fs = __require("fs");
|
|
@@ -379,6 +423,42 @@ var require_main = __commonJS(function(exports, module) {
|
|
|
379
423
|
module.exports = DotenvModule;
|
|
380
424
|
});
|
|
381
425
|
|
|
426
|
+
// src/deadline.ts
|
|
427
|
+
function fireDeadlineNow2() {
|
|
428
|
+
state2.fire?.();
|
|
429
|
+
}
|
|
430
|
+
function deadlineAt() {
|
|
431
|
+
return state2.at;
|
|
432
|
+
}
|
|
433
|
+
function deadlineSignal() {
|
|
434
|
+
return state2.controller.signal;
|
|
435
|
+
}
|
|
436
|
+
function remainingDeadlineMs2(now = Date.now) {
|
|
437
|
+
return state2.at === null ? null : state2.at - now();
|
|
438
|
+
}
|
|
439
|
+
function assertBeforeDeadline(doing) {
|
|
440
|
+
const remaining = remainingDeadlineMs2();
|
|
441
|
+
if (remaining !== null && remaining <= 0) {
|
|
442
|
+
fireDeadlineNow2();
|
|
443
|
+
throw new CliError("timeout", `the deadline passed while ${doing}`);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
function noteProgress2(note) {
|
|
447
|
+
state2.note = note;
|
|
448
|
+
}
|
|
449
|
+
var state2;
|
|
450
|
+
var init_deadline = __esm(() => {
|
|
451
|
+
init_output();
|
|
452
|
+
state2 = {
|
|
453
|
+
at: null,
|
|
454
|
+
cancel: null,
|
|
455
|
+
controller: new AbortController,
|
|
456
|
+
fire: null,
|
|
457
|
+
fired: false,
|
|
458
|
+
note: null
|
|
459
|
+
};
|
|
460
|
+
});
|
|
461
|
+
|
|
382
462
|
// src/env.ts
|
|
383
463
|
var exports_env = {};
|
|
384
464
|
__export(exports_env, {
|
|
@@ -422,15 +502,22 @@ function resolveTokenRef() {
|
|
|
422
502
|
if (process.env.FLUNCLE_API_TOKEN !== undefined || !ref || false) {
|
|
423
503
|
return;
|
|
424
504
|
}
|
|
505
|
+
assertBeforeDeadline("reading FLUNCLE_API_TOKEN_REF with op");
|
|
506
|
+
const remaining = remainingDeadlineMs2();
|
|
507
|
+
const timeout = remaining === null ? OP_READ_TIMEOUT_MS : Math.max(1, Math.min(OP_READ_TIMEOUT_MS, remaining));
|
|
425
508
|
try {
|
|
426
509
|
const secretRef = ref.startsWith("op://") ? ref : `op://${ref}`;
|
|
427
510
|
process.env.FLUNCLE_API_TOKEN = execFileSync("op", ["read", "--no-newline", secretRef], {
|
|
428
511
|
encoding: "utf8",
|
|
429
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
512
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
513
|
+
timeout
|
|
430
514
|
});
|
|
431
|
-
} catch {
|
|
432
|
-
|
|
515
|
+
} catch (error) {
|
|
516
|
+
assertBeforeDeadline("reading FLUNCLE_API_TOKEN_REF with op");
|
|
517
|
+
const timedOut = error.code === "ETIMEDOUT";
|
|
518
|
+
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
519
|
}
|
|
520
|
+
assertBeforeDeadline("reading FLUNCLE_API_TOKEN_REF with op");
|
|
434
521
|
}
|
|
435
522
|
function loadConfig() {
|
|
436
523
|
const profile = getEnvProfile();
|
|
@@ -451,8 +538,9 @@ function getEnvProfile() {
|
|
|
451
538
|
function isEnvProfile2(value) {
|
|
452
539
|
return envProfiles2.includes(value);
|
|
453
540
|
}
|
|
454
|
-
var import_dotenv2, envProfiles2, defaultEnvProfile = "production", loadedProfile;
|
|
541
|
+
var import_dotenv2, envProfiles2, defaultEnvProfile = "production", OP_READ_TIMEOUT_MS = 20000, loadedProfile;
|
|
455
542
|
var init_env = __esm(() => {
|
|
543
|
+
init_deadline();
|
|
456
544
|
import_dotenv2 = __toESM(require_main(), 1);
|
|
457
545
|
envProfiles2 = ["local", "production"];
|
|
458
546
|
});
|
|
@@ -591,43 +679,6 @@ var init_util = __esm(() => {
|
|
|
591
679
|
TIKTOK_DRAFT_STALE_MS = 24 * 60 * 60 * 1000;
|
|
592
680
|
});
|
|
593
681
|
|
|
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
682
|
// src/version.ts
|
|
632
683
|
function normalizeVersion(version) {
|
|
633
684
|
return version?.trim().replace(/^v/i, "");
|
|
@@ -651,7 +702,7 @@ function parseVersion(version) {
|
|
|
651
702
|
var currentVersion;
|
|
652
703
|
var init_version = __esm(() => {
|
|
653
704
|
init_output();
|
|
654
|
-
currentVersion = "0.
|
|
705
|
+
currentVersion = "0.277.0".trim() ? "0.277.0".trim() : "0.1.0";
|
|
655
706
|
});
|
|
656
707
|
|
|
657
708
|
// src/update-notifier.ts
|
|
@@ -1332,7 +1383,7 @@ var init_Redactable = __esm(() => {
|
|
|
1332
1383
|
});
|
|
1333
1384
|
|
|
1334
1385
|
// ../../node_modules/effect/dist/Formatter.js
|
|
1335
|
-
function
|
|
1386
|
+
function format2(input, options) {
|
|
1336
1387
|
const space = options?.space ?? 0;
|
|
1337
1388
|
const ancestors = new WeakSet;
|
|
1338
1389
|
const gap = !space ? "" : typeof space === "number" ? " ".repeat(space) : space;
|
|
@@ -1461,7 +1512,7 @@ var init_Inspectable = __esm(() => {
|
|
|
1461
1512
|
return this.toJSON();
|
|
1462
1513
|
},
|
|
1463
1514
|
toString() {
|
|
1464
|
-
return
|
|
1515
|
+
return format2(this.toJSON());
|
|
1465
1516
|
}
|
|
1466
1517
|
};
|
|
1467
1518
|
});
|
|
@@ -1560,7 +1611,7 @@ var EffectTypeId = `~effect/Effect`, ExitTypeId = `~effect/Exit`, effectVariance
|
|
|
1560
1611
|
},
|
|
1561
1612
|
...makePrimitiveProto(options),
|
|
1562
1613
|
toString() {
|
|
1563
|
-
return `${options.op}(${
|
|
1614
|
+
return `${options.op}(${format2(this[args])})`;
|
|
1564
1615
|
},
|
|
1565
1616
|
toJSON() {
|
|
1566
1617
|
return {
|
|
@@ -1634,7 +1685,7 @@ var init_core = __esm(() => {
|
|
|
1634
1685
|
};
|
|
1635
1686
|
},
|
|
1636
1687
|
toString() {
|
|
1637
|
-
return
|
|
1688
|
+
return format2(this.toJSON(), {
|
|
1638
1689
|
ignoreToString: true,
|
|
1639
1690
|
space: 2
|
|
1640
1691
|
});
|
|
@@ -1691,7 +1742,7 @@ var init_core = __esm(() => {
|
|
|
1691
1742
|
};
|
|
1692
1743
|
}
|
|
1693
1744
|
toString() {
|
|
1694
|
-
return `Cause(${
|
|
1745
|
+
return `Cause(${format2(this.reasons)})`;
|
|
1695
1746
|
}
|
|
1696
1747
|
[NodeInspectSymbol]() {
|
|
1697
1748
|
return this.toJSON();
|
|
@@ -1737,7 +1788,7 @@ var init_core = __esm(() => {
|
|
|
1737
1788
|
return pipeArguments(this, arguments);
|
|
1738
1789
|
}
|
|
1739
1790
|
toString() {
|
|
1740
|
-
return
|
|
1791
|
+
return format2(this);
|
|
1741
1792
|
}
|
|
1742
1793
|
[NodeInspectSymbol]() {
|
|
1743
1794
|
return this.toString();
|
|
@@ -1750,7 +1801,7 @@ var init_core = __esm(() => {
|
|
|
1750
1801
|
this.error = error;
|
|
1751
1802
|
}
|
|
1752
1803
|
toString() {
|
|
1753
|
-
return `Fail(${
|
|
1804
|
+
return `Fail(${format2(this.error)})`;
|
|
1754
1805
|
}
|
|
1755
1806
|
toJSON() {
|
|
1756
1807
|
return {
|
|
@@ -1771,7 +1822,7 @@ var init_core = __esm(() => {
|
|
|
1771
1822
|
this.defect = defect;
|
|
1772
1823
|
}
|
|
1773
1824
|
toString() {
|
|
1774
|
-
return `Die(${
|
|
1825
|
+
return `Die(${format2(this.defect)})`;
|
|
1775
1826
|
}
|
|
1776
1827
|
toJSON() {
|
|
1777
1828
|
return {
|
|
@@ -1938,7 +1989,7 @@ var init_option = __esm(() => {
|
|
|
1938
1989
|
return combine(hash(this._tag))(hash(this.value));
|
|
1939
1990
|
},
|
|
1940
1991
|
toString() {
|
|
1941
|
-
return `some(${
|
|
1992
|
+
return `some(${format2(this.value)})`;
|
|
1942
1993
|
},
|
|
1943
1994
|
toJSON() {
|
|
1944
1995
|
return {
|
|
@@ -2011,7 +2062,7 @@ var init_result = __esm(() => {
|
|
|
2011
2062
|
return combine(hash(this._tag))(hash(this.success));
|
|
2012
2063
|
},
|
|
2013
2064
|
toString() {
|
|
2014
|
-
return `success(${
|
|
2065
|
+
return `success(${format2(this.success)})`;
|
|
2015
2066
|
},
|
|
2016
2067
|
toJSON() {
|
|
2017
2068
|
return {
|
|
@@ -2031,7 +2082,7 @@ var init_result = __esm(() => {
|
|
|
2031
2082
|
return combine(hash(this._tag))(hash(this.failure));
|
|
2032
2083
|
},
|
|
2033
2084
|
toString() {
|
|
2034
|
-
return `failure(${
|
|
2085
|
+
return `failure(${format2(this.failure)})`;
|
|
2035
2086
|
},
|
|
2036
2087
|
toJSON() {
|
|
2037
2088
|
return {
|
|
@@ -4208,7 +4259,7 @@ var init_Cron = __esm(() => {
|
|
|
4208
4259
|
return toPojo(this);
|
|
4209
4260
|
},
|
|
4210
4261
|
toString() {
|
|
4211
|
-
return `Cron(${
|
|
4262
|
+
return `Cron(${format2(toPojo(this))})`;
|
|
4212
4263
|
},
|
|
4213
4264
|
toJSON() {
|
|
4214
4265
|
const out = toPojo(this);
|
|
@@ -4518,7 +4569,7 @@ var TypeId11 = "~effect/BigDecimal", BigDecimalProto, isBigDecimal = (u) => hasP
|
|
|
4518
4569
|
}
|
|
4519
4570
|
const powerOfTen = comparisonPowersOfTen[absoluteScaleDifference] ??= bigint102 ** BigInt(absoluteScaleDifference);
|
|
4520
4571
|
return scaleDifference > 0 ? compareBigInt(self.value, that.value * powerOfTen) : compareBigInt(self.value * powerOfTen, that.value);
|
|
4521
|
-
}, sign = (n) => n.value === bigint02 ? 0 : n.value < bigint02 ? -1 : 1,
|
|
4572
|
+
}, sign = (n) => n.value === bigint02 ? 0 : n.value < bigint02 ? -1 : 1, format4 = (n) => {
|
|
4522
4573
|
const normalized = normalize(n);
|
|
4523
4574
|
if (Math.abs(normalized.scale) >= 16) {
|
|
4524
4575
|
return toExponential(normalized);
|
|
@@ -4558,7 +4609,7 @@ var init_BigDecimal = __esm(() => {
|
|
|
4558
4609
|
return isBigDecimal(that) && compare(this, that) === 0;
|
|
4559
4610
|
},
|
|
4560
4611
|
toString() {
|
|
4561
|
-
return `BigDecimal(${
|
|
4612
|
+
return `BigDecimal(${format4(this)})`;
|
|
4562
4613
|
},
|
|
4563
4614
|
toJSON() {
|
|
4564
4615
|
return {
|
|
@@ -4791,7 +4842,7 @@ var init_Chunk = __esm(() => {
|
|
|
4791
4842
|
_A: (_) => _
|
|
4792
4843
|
},
|
|
4793
4844
|
toString() {
|
|
4794
|
-
return `Chunk(${
|
|
4845
|
+
return `Chunk(${format2(toReadonlyArray(this))})`;
|
|
4795
4846
|
},
|
|
4796
4847
|
toJSON() {
|
|
4797
4848
|
return {
|
|
@@ -6229,7 +6280,7 @@ var init_SchemaAST = __esm(() => {
|
|
|
6229
6280
|
constructor(literal, annotations, checks, encoding, context) {
|
|
6230
6281
|
super(annotations, checks, encoding, context);
|
|
6231
6282
|
if (typeof literal === "number" && !globalThis.Number.isFinite(literal)) {
|
|
6232
|
-
throw new Error(`A numeric literal must be finite, got ${
|
|
6283
|
+
throw new Error(`A numeric literal must be finite, got ${format2(literal)}`);
|
|
6233
6284
|
}
|
|
6234
6285
|
this.literal = literal;
|
|
6235
6286
|
}
|
|
@@ -7606,7 +7657,7 @@ function isPattern2(regExp, annotations) {
|
|
|
7606
7657
|
const source = regExp.source;
|
|
7607
7658
|
const flags = regExp.flags;
|
|
7608
7659
|
const canExport = /^[dg]*uy?$/.test(flags);
|
|
7609
|
-
const runtimeRegExp = flags === "" ? `new RegExp(${
|
|
7660
|
+
const runtimeRegExp = flags === "" ? `new RegExp(${format2(source)})` : `new RegExp(${format2(source)}, ${format2(flags)})`;
|
|
7610
7661
|
return isPattern(regExp, {
|
|
7611
7662
|
toJsonSchema: () => canExport ? {
|
|
7612
7663
|
pattern: flags.endsWith("y") ? `^(?:${source})` : source
|
|
@@ -7925,7 +7976,7 @@ var init_MutableHashMap = __esm(() => {
|
|
|
7925
7976
|
return this.backing[Symbol.iterator]();
|
|
7926
7977
|
},
|
|
7927
7978
|
toString() {
|
|
7928
|
-
return `MutableHashMap(${
|
|
7979
|
+
return `MutableHashMap(${format2(Array.from(this))})`;
|
|
7929
7980
|
},
|
|
7930
7981
|
toJSON() {
|
|
7931
7982
|
return {
|
|
@@ -8835,7 +8886,7 @@ var init_MutableHashSet = __esm(() => {
|
|
|
8835
8886
|
return Array.from(this.keyMap).map(([_]) => _)[Symbol.iterator]();
|
|
8836
8887
|
},
|
|
8837
8888
|
toString() {
|
|
8838
|
-
return `MutableHashSet(${
|
|
8889
|
+
return `MutableHashSet(${format2(Array.from(this))})`;
|
|
8839
8890
|
},
|
|
8840
8891
|
toJSON() {
|
|
8841
8892
|
return {
|
|
@@ -9162,7 +9213,7 @@ var init_TxChunk = __esm(() => {
|
|
|
9162
9213
|
return this.toJSON();
|
|
9163
9214
|
},
|
|
9164
9215
|
toString() {
|
|
9165
|
-
return `TxChunk(${
|
|
9216
|
+
return `TxChunk(${format2(toJson(this.ref))})`;
|
|
9166
9217
|
},
|
|
9167
9218
|
toJSON() {
|
|
9168
9219
|
return {
|
|
@@ -9208,7 +9259,7 @@ var init_TxHashMap = __esm(() => {
|
|
|
9208
9259
|
return toJson(this);
|
|
9209
9260
|
},
|
|
9210
9261
|
toString() {
|
|
9211
|
-
return `TxHashMap(${
|
|
9262
|
+
return `TxHashMap(${format2(toJson(this.ref))})`;
|
|
9212
9263
|
},
|
|
9213
9264
|
toJSON() {
|
|
9214
9265
|
return {
|
|
@@ -9234,7 +9285,7 @@ var init_TxHashSet = __esm(() => {
|
|
|
9234
9285
|
return toJson(this);
|
|
9235
9286
|
},
|
|
9236
9287
|
toString() {
|
|
9237
|
-
return `TxHashSet(${
|
|
9288
|
+
return `TxHashSet(${format2(toJson(this.ref))})`;
|
|
9238
9289
|
},
|
|
9239
9290
|
toJSON() {
|
|
9240
9291
|
return {
|
|
@@ -9598,7 +9649,7 @@ async function userApiGet(path) {
|
|
|
9598
9649
|
function userHeaders() {
|
|
9599
9650
|
const stored = readUserToken();
|
|
9600
9651
|
if (!stored) {
|
|
9601
|
-
throw new
|
|
9652
|
+
throw new CliError("not_logged_in", "You're not signed in. Run `fluncle login` to link this device to your account.");
|
|
9602
9653
|
}
|
|
9603
9654
|
return {
|
|
9604
9655
|
Authorization: `Bearer ${stored.token}`
|
|
@@ -9672,11 +9723,15 @@ function adminHeaders() {
|
|
|
9672
9723
|
}
|
|
9673
9724
|
async function apiRequest(path, init = {}) {
|
|
9674
9725
|
const url = `${getApiBaseUrl()}${path}`;
|
|
9726
|
+
noteProgress2(`waiting for the Fluncle API: ${init.method ?? "GET"} ${path}`);
|
|
9675
9727
|
return runPromise2(gen2(function* () {
|
|
9676
9728
|
const { response, text } = yield* tryPromise2({
|
|
9677
9729
|
catch: (cause) => new ApiTransportError({ cause }),
|
|
9678
9730
|
try: async (signal) => {
|
|
9679
|
-
const response = await fetch(url, {
|
|
9731
|
+
const response = await fetch(url, {
|
|
9732
|
+
...init,
|
|
9733
|
+
signal: AbortSignal.any([signal, deadlineSignal()])
|
|
9734
|
+
});
|
|
9680
9735
|
return { response, text: await response.text() };
|
|
9681
9736
|
}
|
|
9682
9737
|
});
|
|
@@ -9689,7 +9744,7 @@ async function apiRequest(path, init = {}) {
|
|
|
9689
9744
|
});
|
|
9690
9745
|
}
|
|
9691
9746
|
return data;
|
|
9692
|
-
}).pipe(mapError2((error) => error._tag === "ApiTransportError" ? error.cause : new
|
|
9747
|
+
}).pipe(mapError2((error) => error._tag === "ApiTransportError" ? error.cause : new CliError(error.code, error.message))));
|
|
9693
9748
|
}
|
|
9694
9749
|
function parseJson2(text) {
|
|
9695
9750
|
if (!text) {
|
|
@@ -9703,6 +9758,7 @@ function parseJson2(text) {
|
|
|
9703
9758
|
var ApiTransportError, ApiResponseError;
|
|
9704
9759
|
var init_api = __esm(() => {
|
|
9705
9760
|
init_dist();
|
|
9761
|
+
init_deadline();
|
|
9706
9762
|
init_env();
|
|
9707
9763
|
init_output();
|
|
9708
9764
|
init_user_token();
|
|
@@ -9788,7 +9844,7 @@ async function freshCommand({
|
|
|
9788
9844
|
if (showTracks) {
|
|
9789
9845
|
payload.tracks = response.tracks;
|
|
9790
9846
|
}
|
|
9791
|
-
|
|
9847
|
+
printJson(payload);
|
|
9792
9848
|
return;
|
|
9793
9849
|
}
|
|
9794
9850
|
const blocks = [];
|
|
@@ -9855,7 +9911,7 @@ async function albumsCommand({
|
|
|
9855
9911
|
if (slug) {
|
|
9856
9912
|
const response = await publicApiGet(`/api/v1/albums/${encodeURIComponent(slug)}`);
|
|
9857
9913
|
if (json) {
|
|
9858
|
-
|
|
9914
|
+
printJson(response);
|
|
9859
9915
|
return;
|
|
9860
9916
|
}
|
|
9861
9917
|
const { album } = response;
|
|
@@ -9869,7 +9925,7 @@ async function albumsCommand({
|
|
|
9869
9925
|
}
|
|
9870
9926
|
const response = await publicApiGet(`/api/v1/albums?page=${page}`);
|
|
9871
9927
|
if (json) {
|
|
9872
|
-
|
|
9928
|
+
printJson(response);
|
|
9873
9929
|
return;
|
|
9874
9930
|
}
|
|
9875
9931
|
printEntityIndex(response.albums, response, { plural: "albums", singular: "album" }, "albums");
|
|
@@ -9888,7 +9944,7 @@ async function artistsCommand({
|
|
|
9888
9944
|
if (slug) {
|
|
9889
9945
|
const response = await publicApiGet(`/api/v1/artists/${encodeURIComponent(slug)}`);
|
|
9890
9946
|
if (json) {
|
|
9891
|
-
|
|
9947
|
+
printJson(response);
|
|
9892
9948
|
return;
|
|
9893
9949
|
}
|
|
9894
9950
|
const { artist } = response;
|
|
@@ -9902,7 +9958,7 @@ async function artistsCommand({
|
|
|
9902
9958
|
}
|
|
9903
9959
|
const response = await publicApiGet(`/api/v1/artists?page=${page}`);
|
|
9904
9960
|
if (json) {
|
|
9905
|
-
|
|
9961
|
+
printJson(response);
|
|
9906
9962
|
return;
|
|
9907
9963
|
}
|
|
9908
9964
|
printEntityIndex(response.artists, response, { plural: "artists", singular: "artist" }, "artists");
|
|
@@ -9921,7 +9977,7 @@ async function labelsCommand({
|
|
|
9921
9977
|
if (slug) {
|
|
9922
9978
|
const response = await publicApiGet(`/api/v1/labels/${encodeURIComponent(slug)}`);
|
|
9923
9979
|
if (json) {
|
|
9924
|
-
|
|
9980
|
+
printJson(response);
|
|
9925
9981
|
return;
|
|
9926
9982
|
}
|
|
9927
9983
|
const { label } = response;
|
|
@@ -9938,7 +9994,7 @@ async function labelsCommand({
|
|
|
9938
9994
|
}
|
|
9939
9995
|
const response = await publicApiGet(`/api/v1/labels?page=${page}`);
|
|
9940
9996
|
if (json) {
|
|
9941
|
-
|
|
9997
|
+
printJson(response);
|
|
9942
9998
|
return;
|
|
9943
9999
|
}
|
|
9944
10000
|
printEntityIndex(response.labels, response, { plural: "labels", singular: "label" }, "labels");
|
|
@@ -9978,7 +10034,7 @@ async function searchCommand({
|
|
|
9978
10034
|
}
|
|
9979
10035
|
const response = await publicApiGet(`/api/v1/search/archive?${params.toString()}`);
|
|
9980
10036
|
if (json) {
|
|
9981
|
-
|
|
10037
|
+
printJson(response);
|
|
9982
10038
|
return;
|
|
9983
10039
|
}
|
|
9984
10040
|
const blocks = [];
|
|
@@ -10049,7 +10105,7 @@ async function mixtapeGetCommand(idOrLogId) {
|
|
|
10049
10105
|
const mixtapes = await mixtapeListCommand();
|
|
10050
10106
|
const match = mixtapes.find((mixtape) => mixtape.id === idOrLogId || mixtape.logId === idOrLogId);
|
|
10051
10107
|
if (!match) {
|
|
10052
|
-
throw new
|
|
10108
|
+
throw new CliError("mixtape_not_found", `No mixtape with id or log id ${idOrLogId}`);
|
|
10053
10109
|
}
|
|
10054
10110
|
return match;
|
|
10055
10111
|
}
|
|
@@ -10071,7 +10127,7 @@ async function distributeYoutube(mixtapeId, videoPath, onProgress) {
|
|
|
10071
10127
|
while (videoId === undefined) {
|
|
10072
10128
|
attempts += 1;
|
|
10073
10129
|
if (attempts > MAX_UPLOAD_ATTEMPTS) {
|
|
10074
|
-
throw new
|
|
10130
|
+
throw new CliError("youtube_upload_failed", `YouTube upload did not complete after ${MAX_UPLOAD_ATTEMPTS} attempts`);
|
|
10075
10131
|
}
|
|
10076
10132
|
onProgress?.(offset > 0 ? `Resuming upload at ${formatBytes(offset)} / ${formatBytes(contentLength)}` : `Uploading video → YouTube`);
|
|
10077
10133
|
const result = await putChunk({
|
|
@@ -10130,7 +10186,7 @@ async function putChunk(args) {
|
|
|
10130
10186
|
if (response.status === 200 || response.status === 201) {
|
|
10131
10187
|
const video = await response.json().catch(() => ({}));
|
|
10132
10188
|
if (!video.id) {
|
|
10133
|
-
throw new
|
|
10189
|
+
throw new CliError("youtube_no_video_id", "YouTube returned no video id on upload completion");
|
|
10134
10190
|
}
|
|
10135
10191
|
return { kind: "done", videoId: video.id };
|
|
10136
10192
|
}
|
|
@@ -10144,7 +10200,7 @@ async function putChunk(args) {
|
|
|
10144
10200
|
return { kind: "reinit" };
|
|
10145
10201
|
}
|
|
10146
10202
|
const detail = (await response.text().catch(() => "")).slice(0, 400);
|
|
10147
|
-
throw new
|
|
10203
|
+
throw new CliError("youtube_put_failed", `YouTube upload PUT failed (${response.status} ${response.statusText})${detail ? `: ${detail}` : ""}`);
|
|
10148
10204
|
}
|
|
10149
10205
|
async function queryOffset(sessionUri, accessToken, contentLength) {
|
|
10150
10206
|
const response = await fetch(sessionUri, {
|
|
@@ -10176,7 +10232,7 @@ function fileSize(path) {
|
|
|
10176
10232
|
try {
|
|
10177
10233
|
return statSync(path).size;
|
|
10178
10234
|
} catch {
|
|
10179
|
-
throw new
|
|
10235
|
+
throw new CliError("video_not_found", `Cannot read video file at ${path}`);
|
|
10180
10236
|
}
|
|
10181
10237
|
}
|
|
10182
10238
|
function formatBytes(bytes) {
|
|
@@ -10200,11 +10256,11 @@ async function distributeMixcloud(mixtapeId, audioPath, onProgress, unlisted = f
|
|
|
10200
10256
|
const mixtape = await mixtapeGetCommand(mixtapeId);
|
|
10201
10257
|
const logId = mixtape.logId;
|
|
10202
10258
|
if (!logId) {
|
|
10203
|
-
throw new
|
|
10259
|
+
throw new CliError("mixtape_no_log_id", "The mixtape has no Log ID; mint it before distributing");
|
|
10204
10260
|
}
|
|
10205
10261
|
const audio = Bun.file(audioPath);
|
|
10206
10262
|
if (!await audio.exists()) {
|
|
10207
|
-
throw new
|
|
10263
|
+
throw new CliError("audio_not_found", `Audio master not found: ${audioPath}`);
|
|
10208
10264
|
}
|
|
10209
10265
|
const form = new FormData;
|
|
10210
10266
|
form.append("mp3", audio);
|
|
@@ -10241,7 +10297,7 @@ async function distributeMixcloud(mixtapeId, audioPath, onProgress, unlisted = f
|
|
|
10241
10297
|
}
|
|
10242
10298
|
const result = parseUploadResult(uploadText);
|
|
10243
10299
|
if (!result.success || !result.key) {
|
|
10244
|
-
throw new
|
|
10300
|
+
throw new CliError("mixcloud_upload_rejected", `Mixcloud rejected the upload: ${result.message ?? uploadText.slice(0, 300)}`);
|
|
10245
10301
|
}
|
|
10246
10302
|
const externalId = result.key;
|
|
10247
10303
|
const url = `https://www.mixcloud.com${result.key}`;
|
|
@@ -10279,7 +10335,7 @@ async function fetchMixcloudToken() {
|
|
|
10279
10335
|
const response = await adminApiPost("/api/v1/admin/mixcloud/token");
|
|
10280
10336
|
return response.accessToken;
|
|
10281
10337
|
} catch {
|
|
10282
|
-
throw new
|
|
10338
|
+
throw new CliError("mixcloud_not_connected", "Mixcloud is not connected. Run `fluncle admin auth mixcloud` to authorize it.");
|
|
10283
10339
|
}
|
|
10284
10340
|
}
|
|
10285
10341
|
async function fetchCover(logId) {
|
|
@@ -10309,9 +10365,9 @@ function parseUploadResult(body) {
|
|
|
10309
10365
|
}
|
|
10310
10366
|
function throwMixcloudError(status, body) {
|
|
10311
10367
|
if (body.includes("An invalid access token was provided")) {
|
|
10312
|
-
throw new
|
|
10368
|
+
throw new CliError("mixcloud_invalid_token", "Mixcloud rejected the access token. Re-auth with `fluncle admin auth mixcloud`.");
|
|
10313
10369
|
}
|
|
10314
|
-
throw new
|
|
10370
|
+
throw new CliError("mixcloud_request_failed", `Mixcloud responded ${status}${body ? `: ${body.slice(0, 300)}` : ""}`);
|
|
10315
10371
|
}
|
|
10316
10372
|
var MIXCLOUD_API = "https://api.mixcloud.com", DESCRIPTION_MAX = 1000, PICTURE_MAX_BYTES, COVER_BASE = "https://www.fluncle.com/api/mixtape-cover";
|
|
10317
10373
|
var init_mixtape_mixcloud = __esm(() => {
|
|
@@ -10333,21 +10389,21 @@ async function mixtapeUpdateCommand(id, options) {
|
|
|
10333
10389
|
async function mixtapeDistributeCommand(idOrLogId, options, onProgress = () => {}) {
|
|
10334
10390
|
const mixtape = await mixtapeGetCommand(idOrLogId);
|
|
10335
10391
|
if (!mixtape.id) {
|
|
10336
|
-
throw new
|
|
10392
|
+
throw new CliError("mixtape_not_found", `No mixtape with id or log id ${idOrLogId}`);
|
|
10337
10393
|
}
|
|
10338
10394
|
const both = !options.youtube && !options.mixcloud;
|
|
10339
10395
|
const doYoutube = both || Boolean(options.youtube);
|
|
10340
10396
|
const doMixcloud = both || Boolean(options.mixcloud);
|
|
10341
10397
|
if (doYoutube && !options.video) {
|
|
10342
|
-
throw new
|
|
10398
|
+
throw new CliError("missing_video", "YouTube distribution needs --video <mp4>");
|
|
10343
10399
|
}
|
|
10344
10400
|
if (doMixcloud && !options.audio) {
|
|
10345
|
-
throw new
|
|
10401
|
+
throw new CliError("missing_audio", "Mixcloud distribution needs --audio <file>");
|
|
10346
10402
|
}
|
|
10347
10403
|
const mixtapeId = mixtape.id;
|
|
10348
10404
|
const logId = mixtape.logId;
|
|
10349
10405
|
if (!logId) {
|
|
10350
|
-
throw new
|
|
10406
|
+
throw new CliError("mixtape_not_promoted", `${mixtapeId} has no coordinate yet. Promote its recording first:
|
|
10351
10407
|
` + " fluncle admin recordings promote <recordingId>");
|
|
10352
10408
|
}
|
|
10353
10409
|
if (!mixtape.durationMs) {
|
|
@@ -10366,7 +10422,7 @@ async function mixtapeDistributeCommand(idOrLogId, options, onProgress = () => {
|
|
|
10366
10422
|
const results = [];
|
|
10367
10423
|
if (doYoutube) {
|
|
10368
10424
|
if (!options.video) {
|
|
10369
|
-
throw new
|
|
10425
|
+
throw new CliError("missing_video", "YouTube distribution needs --video <mp4>");
|
|
10370
10426
|
}
|
|
10371
10427
|
onProgress("YouTube: uploading video…");
|
|
10372
10428
|
await Promise.resolve().then(() => init_mixtape_youtube());
|
|
@@ -10376,7 +10432,7 @@ async function mixtapeDistributeCommand(idOrLogId, options, onProgress = () => {
|
|
|
10376
10432
|
}
|
|
10377
10433
|
if (doMixcloud) {
|
|
10378
10434
|
if (!options.audio) {
|
|
10379
|
-
throw new
|
|
10435
|
+
throw new CliError("missing_audio", "Mixcloud distribution needs --audio <file>");
|
|
10380
10436
|
}
|
|
10381
10437
|
onProgress("Mixcloud: uploading audio…");
|
|
10382
10438
|
await Promise.resolve().then(() => init_mixtape_mixcloud());
|
|
@@ -10389,10 +10445,10 @@ async function mixtapeDistributeCommand(idOrLogId, options, onProgress = () => {
|
|
|
10389
10445
|
async function mixtapeResyncCommand(idOrLogId, options, onProgress = () => {}) {
|
|
10390
10446
|
const mixtape = await mixtapeGetCommand(idOrLogId);
|
|
10391
10447
|
if (!mixtape.id) {
|
|
10392
|
-
throw new
|
|
10448
|
+
throw new CliError("mixtape_not_found", `No mixtape with id or log id ${idOrLogId}`);
|
|
10393
10449
|
}
|
|
10394
10450
|
if (!mixtape.logId) {
|
|
10395
|
-
throw new
|
|
10451
|
+
throw new CliError("mixtape_no_log_id", "The mixtape isn't published yet. Distribute it before re-syncing.");
|
|
10396
10452
|
}
|
|
10397
10453
|
const mixtapeId = mixtape.id;
|
|
10398
10454
|
const explicit = Boolean(options.youtube) || Boolean(options.mixcloud);
|
|
@@ -10404,7 +10460,7 @@ async function mixtapeResyncCommand(idOrLogId, options, onProgress = () => {}) {
|
|
|
10404
10460
|
doYoutube = platforms.has("youtube");
|
|
10405
10461
|
doMixcloud = platforms.has("mixcloud");
|
|
10406
10462
|
if (!doYoutube && !doMixcloud) {
|
|
10407
|
-
throw new
|
|
10463
|
+
throw new CliError("mixtape_not_distributed", "The mixtape has no YouTube or Mixcloud link to re-sync.");
|
|
10408
10464
|
}
|
|
10409
10465
|
}
|
|
10410
10466
|
const results = [];
|
|
@@ -10449,7 +10505,7 @@ function buildBody(options) {
|
|
|
10449
10505
|
if (options.durationMs !== undefined) {
|
|
10450
10506
|
const parsed = parseDuration(options.durationMs);
|
|
10451
10507
|
if (parsed === null) {
|
|
10452
|
-
throw new
|
|
10508
|
+
throw new CliError("invalid_duration", "Duration must be mm:ss or h:mm:ss, or a millisecond count");
|
|
10453
10509
|
}
|
|
10454
10510
|
body.durationMs = parsed;
|
|
10455
10511
|
}
|
|
@@ -10478,7 +10534,7 @@ var init_format = __esm(() => {
|
|
|
10478
10534
|
import { createInterface } from "node:readline/promises";
|
|
10479
10535
|
async function promptLine(label, nonInteractiveMessage) {
|
|
10480
10536
|
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
10481
|
-
throw new
|
|
10537
|
+
throw new CliError("not_interactive", nonInteractiveMessage);
|
|
10482
10538
|
}
|
|
10483
10539
|
const rl = createInterface({
|
|
10484
10540
|
input: process.stdin,
|
|
@@ -10494,7 +10550,7 @@ async function selectWithKeyboard(items, options) {
|
|
|
10494
10550
|
const stdin = options.input ?? process.stdin;
|
|
10495
10551
|
const stdout = options.output ?? process.stdout;
|
|
10496
10552
|
if (!stdin.isTTY || !stdout.isTTY) {
|
|
10497
|
-
throw new
|
|
10553
|
+
throw new CliError("not_interactive", options.nonInteractiveMessage);
|
|
10498
10554
|
}
|
|
10499
10555
|
let selectedIndex = 0;
|
|
10500
10556
|
let renderedLines = 0;
|
|
@@ -10581,7 +10637,7 @@ async function openExternal(target) {
|
|
|
10581
10637
|
const command = platformOpenCommand();
|
|
10582
10638
|
if (!command) {
|
|
10583
10639
|
console.log(target);
|
|
10584
|
-
throw new
|
|
10640
|
+
throw new CliError("unsupported_platform", `Automatic opening is only supported on macOS and Linux. Open this manually: ${target}`);
|
|
10585
10641
|
}
|
|
10586
10642
|
const child = Bun.spawn([command, target], {
|
|
10587
10643
|
stderr: "pipe",
|
|
@@ -10590,7 +10646,7 @@ async function openExternal(target) {
|
|
|
10590
10646
|
const exitCode = await child.exited;
|
|
10591
10647
|
if (exitCode !== 0) {
|
|
10592
10648
|
const stderr = await new Response(child.stderr).text();
|
|
10593
|
-
throw new
|
|
10649
|
+
throw new CliError("open_failed", stderr.trim() || `Could not open ${target} with ${command}`);
|
|
10594
10650
|
}
|
|
10595
10651
|
}
|
|
10596
10652
|
function platformOpenCommand() {
|
|
@@ -10665,7 +10721,7 @@ async function openRecentCommand(options) {
|
|
|
10665
10721
|
function spotifyPlaylistUrlToAppUri(playlistUrl) {
|
|
10666
10722
|
const playlistId = playlistUrl.match(/open\.spotify\.com\/playlist\/([^/?#]+)/)?.[1];
|
|
10667
10723
|
if (!playlistId) {
|
|
10668
|
-
throw new
|
|
10724
|
+
throw new CliError("invalid_playlist_url", `Could not parse Spotify playlist URL: ${playlistUrl}`);
|
|
10669
10725
|
}
|
|
10670
10726
|
return `spotify:playlist:${playlistId}`;
|
|
10671
10727
|
}
|
|
@@ -10714,13 +10770,13 @@ var init_random = __esm(() => {
|
|
|
10714
10770
|
async function subscribeCommand(email, json) {
|
|
10715
10771
|
const address = email?.trim() || await promptLine("Email: ", PROMPT_NON_INTERACTIVE_MESSAGE);
|
|
10716
10772
|
if (!address) {
|
|
10717
|
-
throw new
|
|
10773
|
+
throw new CliError("invalid_email", "Enter a valid email address.");
|
|
10718
10774
|
}
|
|
10719
10775
|
await publicApiPost("/api/v1/newsletter", {
|
|
10720
10776
|
email: address
|
|
10721
10777
|
});
|
|
10722
10778
|
if (json) {
|
|
10723
|
-
|
|
10779
|
+
printJson({
|
|
10724
10780
|
ok: true
|
|
10725
10781
|
});
|
|
10726
10782
|
return;
|
|
@@ -10738,11 +10794,11 @@ var init_subscribe = __esm(() => {
|
|
|
10738
10794
|
async function submitCommand(input) {
|
|
10739
10795
|
const query = input?.trim() || await promptLine("Track or Spotify link: ", PROMPT_NON_INTERACTIVE_MESSAGE2);
|
|
10740
10796
|
if (!query) {
|
|
10741
|
-
throw new
|
|
10797
|
+
throw new CliError("missing_query", "Missing search input");
|
|
10742
10798
|
}
|
|
10743
10799
|
const response = await publicApiGet(`/api/v1/search?q=${encodeURIComponent(query)}`);
|
|
10744
10800
|
if (response.results.length === 0) {
|
|
10745
|
-
throw new
|
|
10801
|
+
throw new CliError("no_results", "Nothing came back for that search. Try the artist and the title.");
|
|
10746
10802
|
}
|
|
10747
10803
|
const selected = await selectCandidate(response.results);
|
|
10748
10804
|
if (!selected) {
|
|
@@ -10844,7 +10900,7 @@ async function requestDeviceCode(baseUrl) {
|
|
|
10844
10900
|
return;
|
|
10845
10901
|
});
|
|
10846
10902
|
if (!response.ok || !data?.device_code || !data.user_code) {
|
|
10847
|
-
throw new
|
|
10903
|
+
throw new CliError("device_code_failed", `Couldn't start the login flow (${response.status}). Try again in a moment.`);
|
|
10848
10904
|
}
|
|
10849
10905
|
return data;
|
|
10850
10906
|
}
|
|
@@ -10876,15 +10932,15 @@ async function pollForToken(baseUrl, device) {
|
|
|
10876
10932
|
intervalMs += 5000;
|
|
10877
10933
|
break;
|
|
10878
10934
|
case "access_denied":
|
|
10879
|
-
throw new
|
|
10935
|
+
throw new CliError("access_denied", "Sign-in was denied in the browser. Nothing linked.");
|
|
10880
10936
|
case "expired_token":
|
|
10881
|
-
throw new
|
|
10937
|
+
throw new CliError("expired_token", "The login request timed out. Run `fluncle login` again.");
|
|
10882
10938
|
default:
|
|
10883
|
-
throw new
|
|
10939
|
+
throw new CliError("device_token_failed", pending?.error_description ?? `Login failed (${response.status}).`);
|
|
10884
10940
|
}
|
|
10885
10941
|
await sleep3(intervalMs);
|
|
10886
10942
|
}
|
|
10887
|
-
throw new
|
|
10943
|
+
throw new CliError("expired_token", "The login request timed out. Run `fluncle login` again.");
|
|
10888
10944
|
}
|
|
10889
10945
|
async function fetchSessionUser(baseUrl, token) {
|
|
10890
10946
|
const response = await fetch(`${baseUrl}/api/v1/me`, {
|
|
@@ -11020,7 +11076,7 @@ var init_about = __esm(() => {
|
|
|
11020
11076
|
async function versionCommand(options) {
|
|
11021
11077
|
const result = options.check ? await buildVersionCheck() : buildCurrentVersion();
|
|
11022
11078
|
if (options.json) {
|
|
11023
|
-
|
|
11079
|
+
printJson({
|
|
11024
11080
|
ok: true,
|
|
11025
11081
|
...result
|
|
11026
11082
|
});
|
|
@@ -11086,7 +11142,7 @@ function parseVersion2(version) {
|
|
|
11086
11142
|
var currentVersion2, latestReleaseUrl = "https://api.github.com/repos/mauricekleine/fluncle/releases/latest";
|
|
11087
11143
|
var init_version2 = __esm(() => {
|
|
11088
11144
|
init_output();
|
|
11089
|
-
currentVersion2 = "0.
|
|
11145
|
+
currentVersion2 = "0.277.0".trim() ? "0.277.0".trim() : "0.1.0";
|
|
11090
11146
|
});
|
|
11091
11147
|
|
|
11092
11148
|
// ../../packages/registry/src/index.ts
|
|
@@ -12605,7 +12661,7 @@ var init_src = __esm(() => {
|
|
|
12605
12661
|
],
|
|
12606
12662
|
kind: "cron",
|
|
12607
12663
|
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,
|
|
12664
|
+
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
12665
|
probeConfig: { cadenceMs: 30 * MINUTE_MS, cronName: "fluncle-publish-advance", kind: "cron" },
|
|
12610
12666
|
statusDescription: "advances the publish queue on his own clock",
|
|
12611
12667
|
title: "Publish advance",
|
|
@@ -12712,7 +12768,7 @@ var init_src = __esm(() => {
|
|
|
12712
12768
|
],
|
|
12713
12769
|
kind: "cron",
|
|
12714
12770
|
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
|
|
12771
|
+
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
12772
|
operatorOnly: "Search-engine notification is plumbing, not a listener-facing automation.",
|
|
12717
12773
|
probeConfig: {
|
|
12718
12774
|
cadenceMs: 24 * 60 * MINUTE_MS,
|
|
@@ -12978,7 +13034,7 @@ function checkBundleCompleteness(files) {
|
|
|
12978
13034
|
function validateBundleCompleteness(files, onProgress, options) {
|
|
12979
13035
|
const completeness = checkBundleCompleteness(files);
|
|
12980
13036
|
if (completeness.uploadingFootage && completeness.missingContract.length > 0 && !options.allowPartial) {
|
|
12981
|
-
throw new
|
|
13037
|
+
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
13038
|
}
|
|
12983
13039
|
if (completeness.uploadingFootage) {
|
|
12984
13040
|
if (completeness.missingContract.length > 0) {
|
|
@@ -12999,7 +13055,7 @@ async function trackVideoCommand(idOrLogId, files, onProgress, options = {}) {
|
|
|
12999
13055
|
path: files[spec.option]
|
|
13000
13056
|
})).filter((spec) => Boolean(spec.path));
|
|
13001
13057
|
if (present.length === 0) {
|
|
13002
|
-
throw new
|
|
13058
|
+
throw new CliError("nothing_to_upload", "No bundle files resolved to upload (pass --dir <bundle> or explicit file flags).");
|
|
13003
13059
|
}
|
|
13004
13060
|
const platesOnly = isPlatesOnlyUpload(files);
|
|
13005
13061
|
const presign = await adminApiPost(`/api/v1/admin/tracks/${encodeURIComponent(idOrLogId)}/video/uploads`, { fields: present.map((spec) => spec.field) });
|
|
@@ -13009,7 +13065,7 @@ async function trackVideoCommand(idOrLogId, files, onProgress, options = {}) {
|
|
|
13009
13065
|
for (const spec of present) {
|
|
13010
13066
|
const upload = byField.get(spec.field);
|
|
13011
13067
|
if (!upload) {
|
|
13012
|
-
throw new
|
|
13068
|
+
throw new CliError("presign_missing", `Worker did not sign an upload for ${spec.field}`);
|
|
13013
13069
|
}
|
|
13014
13070
|
onProgress?.(`Uploading ${spec.field} → ${upload.key}`);
|
|
13015
13071
|
const file = Bun.file(spec.path);
|
|
@@ -13021,7 +13077,7 @@ async function trackVideoCommand(idOrLogId, files, onProgress, options = {}) {
|
|
|
13021
13077
|
});
|
|
13022
13078
|
if (!response.ok) {
|
|
13023
13079
|
const detail = (await response.text().catch(() => "")).slice(0, 300);
|
|
13024
|
-
throw new
|
|
13080
|
+
throw new CliError("r2_put_failed", `R2 rejected ${spec.field} with ${response.status} ${response.statusText}${detail ? `: ${detail}` : ""}`);
|
|
13025
13081
|
}
|
|
13026
13082
|
urls[spec.field] = `${FOUND_BASE}/${upload.key}`;
|
|
13027
13083
|
}
|
|
@@ -26162,6 +26218,10 @@ var init_admin_tracks = __esm(() => {
|
|
|
26162
26218
|
scope: TrackWorkScopeSchema.default("all")
|
|
26163
26219
|
})).output(object({
|
|
26164
26220
|
capabilities: TrackWorkCapabilitiesSchema.optional(),
|
|
26221
|
+
catalogueCapture: object({
|
|
26222
|
+
closedReason: _enum(["paused", "bytes_spent", "tracks_spent"]),
|
|
26223
|
+
open: literal(false)
|
|
26224
|
+
}).optional(),
|
|
26165
26225
|
debtPending: boolean3().optional(),
|
|
26166
26226
|
ok: literal(true),
|
|
26167
26227
|
oldestQueuedCaptureOver24h: boolean3().optional(),
|
|
@@ -28970,7 +29030,7 @@ async function resolveMixtapeId(idOrLogId) {
|
|
|
28970
29030
|
const response = await adminApiGet("/api/v1/admin/mixtapes");
|
|
28971
29031
|
const match = response.mixtapes.find((mixtape) => mixtape.id === idOrLogId || mixtape.logId === idOrLogId);
|
|
28972
29032
|
if (!match?.id) {
|
|
28973
|
-
throw new
|
|
29033
|
+
throw new CliError("mixtape_not_found", `No mixtape with id or Log ID ${idOrLogId}`);
|
|
28974
29034
|
}
|
|
28975
29035
|
return match.id;
|
|
28976
29036
|
}
|
|
@@ -29085,7 +29145,7 @@ function renditionFfmpegArgs(inputPath, outputPath) {
|
|
|
29085
29145
|
}
|
|
29086
29146
|
async function uploadRenditionMultipart(masterPath, presignPath, onProgress = () => {}) {
|
|
29087
29147
|
if (!existsSync(masterPath)) {
|
|
29088
|
-
throw new
|
|
29148
|
+
throw new CliError("file_not_found", `Set-video master not found: ${masterPath}`);
|
|
29089
29149
|
}
|
|
29090
29150
|
await assertFfmpeg();
|
|
29091
29151
|
const renditionPath = join4(tmpdir(), `fluncle-set-${randomUUID()}.mp4`);
|
|
@@ -29104,7 +29164,7 @@ async function uploadRenditionMultipart(masterPath, presignPath, onProgress = ()
|
|
|
29104
29164
|
for (const part of plan.parts) {
|
|
29105
29165
|
const url = urlByPart.get(part.partNumber);
|
|
29106
29166
|
if (!url) {
|
|
29107
|
-
throw new
|
|
29167
|
+
throw new CliError("presign_missing", `Worker did not sign part ${part.partNumber} of ${plan.partCount}`);
|
|
29108
29168
|
}
|
|
29109
29169
|
onProgress(`Set video: part ${part.partNumber}/${plan.partCount}`);
|
|
29110
29170
|
const etag = await putPart(url, renditionPath, part, onProgress);
|
|
@@ -29126,11 +29186,11 @@ async function putPart(url, path, part, onProgress = () => {}) {
|
|
|
29126
29186
|
try {
|
|
29127
29187
|
return await putPartOnce(url, body, part);
|
|
29128
29188
|
} catch (error) {
|
|
29129
|
-
if (error instanceof
|
|
29189
|
+
if (error instanceof CliError || deadlineSignal().aborted) {
|
|
29130
29190
|
throw error;
|
|
29131
29191
|
}
|
|
29132
29192
|
if (attempt >= MAX_PART_ATTEMPTS) {
|
|
29133
|
-
throw new
|
|
29193
|
+
throw new CliError("r2_part_failed", `Part ${part.partNumber} failed after ${MAX_PART_ATTEMPTS} attempts: ${error instanceof Error ? error.message : String(error)}`);
|
|
29134
29194
|
}
|
|
29135
29195
|
const backoffMs = 500 * 2 ** (attempt - 1);
|
|
29136
29196
|
onProgress(`Set video: part ${part.partNumber} dropped, retry ${attempt}/${MAX_PART_ATTEMPTS - 1} in ${backoffMs}ms…`);
|
|
@@ -29139,17 +29199,17 @@ async function putPart(url, path, part, onProgress = () => {}) {
|
|
|
29139
29199
|
}
|
|
29140
29200
|
}
|
|
29141
29201
|
async function putPartOnce(url, body, part) {
|
|
29142
|
-
const response = await fetch(url, { body, method: "PUT" });
|
|
29202
|
+
const response = await fetch(url, { body, method: "PUT", signal: deadlineSignal() });
|
|
29143
29203
|
if (!response.ok) {
|
|
29144
29204
|
const detail = (await response.text().catch(() => "")).slice(0, 300);
|
|
29145
29205
|
if (response.status < 500) {
|
|
29146
|
-
throw new
|
|
29206
|
+
throw new CliError("r2_part_failed", `R2 rejected part ${part.partNumber} (${response.status} ${response.statusText})${detail ? `: ${detail}` : ""}`);
|
|
29147
29207
|
}
|
|
29148
29208
|
throw new Error(`R2 ${response.status} ${response.statusText} on part ${part.partNumber}${detail ? `: ${detail}` : ""}`);
|
|
29149
29209
|
}
|
|
29150
29210
|
const etag = response.headers.get("etag");
|
|
29151
29211
|
if (!etag) {
|
|
29152
|
-
throw new
|
|
29212
|
+
throw new CliError("r2_no_etag", `R2 returned no ETag for part ${part.partNumber}`);
|
|
29153
29213
|
}
|
|
29154
29214
|
return etag;
|
|
29155
29215
|
}
|
|
@@ -29157,15 +29217,16 @@ async function completeUpload(url, parts) {
|
|
|
29157
29217
|
const response = await fetch(url, {
|
|
29158
29218
|
body: buildCompleteXml(parts),
|
|
29159
29219
|
headers: { "content-type": "application/xml" },
|
|
29160
|
-
method: "POST"
|
|
29220
|
+
method: "POST",
|
|
29221
|
+
signal: deadlineSignal()
|
|
29161
29222
|
});
|
|
29162
29223
|
const text = await response.text().catch(() => "");
|
|
29163
29224
|
if (!response.ok || text.includes("<Error>")) {
|
|
29164
|
-
throw new
|
|
29225
|
+
throw new CliError("r2_complete_failed", `R2 CompleteMultipartUpload failed (${response.status} ${response.statusText})${text ? `: ${text.slice(0, 300)}` : ""}`);
|
|
29165
29226
|
}
|
|
29166
29227
|
}
|
|
29167
29228
|
async function abortUpload(url) {
|
|
29168
|
-
await fetch(url, { method: "DELETE" });
|
|
29229
|
+
await fetch(url, { method: "DELETE", signal: AbortSignal.timeout(UPLOAD_ABORT_TIMEOUT_MS) });
|
|
29169
29230
|
}
|
|
29170
29231
|
async function assertFfmpeg() {
|
|
29171
29232
|
try {
|
|
@@ -29175,7 +29236,7 @@ async function assertFfmpeg() {
|
|
|
29175
29236
|
throw new Error("ffmpeg -version exited non-zero");
|
|
29176
29237
|
}
|
|
29177
29238
|
} catch {
|
|
29178
|
-
throw new
|
|
29239
|
+
throw new CliError("ffmpeg_missing", "--set-video needs ffmpeg to derive the 1080p rendition. Install it (brew install ffmpeg).");
|
|
29179
29240
|
}
|
|
29180
29241
|
}
|
|
29181
29242
|
async function deriveRendition(inputPath, outputPath) {
|
|
@@ -29186,13 +29247,14 @@ async function deriveRendition(inputPath, outputPath) {
|
|
|
29186
29247
|
await proc.exited;
|
|
29187
29248
|
if (proc.exitCode !== 0) {
|
|
29188
29249
|
const detail = (await new Response(proc.stderr).text().catch(() => "")).slice(-400);
|
|
29189
|
-
throw new
|
|
29250
|
+
throw new CliError("ffmpeg_failed", `ffmpeg failed to derive the set-video rendition${detail ? `: ${detail}` : ""}`);
|
|
29190
29251
|
}
|
|
29191
29252
|
}
|
|
29192
|
-
var FOUND_BASE2 = "https://found.fluncle.com", SET_VIDEO_RENDITION, MAX_PART_ATTEMPTS = 5;
|
|
29253
|
+
var FOUND_BASE2 = "https://found.fluncle.com", SET_VIDEO_RENDITION, MAX_PART_ATTEMPTS = 5, UPLOAD_ABORT_TIMEOUT_MS = 5000;
|
|
29193
29254
|
var init_mixtape_set_video = __esm(() => {
|
|
29194
29255
|
init_multipart();
|
|
29195
29256
|
init_api();
|
|
29257
|
+
init_deadline();
|
|
29196
29258
|
init_output();
|
|
29197
29259
|
SET_VIDEO_RENDITION = {
|
|
29198
29260
|
audioBitrate: "192k",
|
|
@@ -29289,12 +29351,12 @@ async function clipDripPauseCommand(paused) {
|
|
|
29289
29351
|
}
|
|
29290
29352
|
async function resolveClipSource(clip) {
|
|
29291
29353
|
if (!clip.recordingId) {
|
|
29292
|
-
throw new
|
|
29354
|
+
throw new CliError("clip_unlinked", `Clip ${clip.id} is linked to no recording`);
|
|
29293
29355
|
}
|
|
29294
29356
|
await Promise.resolve().then(() => init_recordings());
|
|
29295
29357
|
const recording = await recordingGet(clip.recordingId);
|
|
29296
29358
|
if (!recording.r2Key) {
|
|
29297
|
-
throw new
|
|
29359
|
+
throw new CliError("recording_not_staged", `Recording ${clip.recordingId} has no staged set video`);
|
|
29298
29360
|
}
|
|
29299
29361
|
return {
|
|
29300
29362
|
setUrl: r2PublicUrl(FOUND_BASE3, recording.r2Key)
|
|
@@ -29304,7 +29366,7 @@ async function clipCutCommand(clipId, onProgress = () => {}) {
|
|
|
29304
29366
|
const clips = await clipsListCommand();
|
|
29305
29367
|
const clip = clips.find((candidate) => candidate.id === clipId);
|
|
29306
29368
|
if (!clip) {
|
|
29307
|
-
throw new
|
|
29369
|
+
throw new CliError("clip_not_found", `No clip with id ${clipId}`);
|
|
29308
29370
|
}
|
|
29309
29371
|
const source = await resolveClipSource(clip);
|
|
29310
29372
|
await assertFfmpeg2();
|
|
@@ -29320,7 +29382,7 @@ async function clipCutCommand(clipId, onProgress = () => {}) {
|
|
|
29320
29382
|
});
|
|
29321
29383
|
const sizeBytes = statSync3(outputPath).size;
|
|
29322
29384
|
if (sizeBytes > MAX_CLIP_BYTES) {
|
|
29323
|
-
throw new
|
|
29385
|
+
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
29386
|
}
|
|
29325
29387
|
onProgress(`Clip ${clipId}: uploading ${(sizeBytes / 1e6).toFixed(1)} MB…`);
|
|
29326
29388
|
const presign = await adminApiPost(`/api/v1/admin/clips/${encodeURIComponent(clipId)}/cut/presign`, { contentType: "video/mp4" });
|
|
@@ -29345,7 +29407,7 @@ async function putClip(url, contentType, path) {
|
|
|
29345
29407
|
});
|
|
29346
29408
|
if (!response.ok) {
|
|
29347
29409
|
const detail = (await response.text().catch(() => "")).slice(0, 300);
|
|
29348
|
-
throw new
|
|
29410
|
+
throw new CliError("r2_put_failed", `R2 rejected the clip upload (${response.status} ${response.statusText})${detail ? `: ${detail}` : ""}`);
|
|
29349
29411
|
}
|
|
29350
29412
|
}
|
|
29351
29413
|
async function assertFfmpeg2() {
|
|
@@ -29356,12 +29418,12 @@ async function assertFfmpeg2() {
|
|
|
29356
29418
|
throw new Error("ffmpeg -version exited non-zero");
|
|
29357
29419
|
}
|
|
29358
29420
|
} catch {
|
|
29359
|
-
throw new
|
|
29421
|
+
throw new CliError("ffmpeg_missing", "The clip cut needs ffmpeg. Install it on the box (apt-get install -y ffmpeg).");
|
|
29360
29422
|
}
|
|
29361
29423
|
}
|
|
29362
29424
|
async function runClipCut(options) {
|
|
29363
29425
|
if (!options.setUrl) {
|
|
29364
|
-
throw new
|
|
29426
|
+
throw new CliError("missing_set_url", "The clip cut needs the set rendition URL");
|
|
29365
29427
|
}
|
|
29366
29428
|
const proc = Bun.spawn(["ffmpeg", ...clipCutFfmpegArgs(options)], {
|
|
29367
29429
|
stderr: "pipe",
|
|
@@ -29370,7 +29432,7 @@ async function runClipCut(options) {
|
|
|
29370
29432
|
await proc.exited;
|
|
29371
29433
|
if (proc.exitCode !== 0) {
|
|
29372
29434
|
const detail = (await new Response(proc.stderr).text().catch(() => "")).slice(-400);
|
|
29373
|
-
throw new
|
|
29435
|
+
throw new CliError("ffmpeg_failed", `ffmpeg failed to cut the clip${detail ? `: ${detail}` : ""}`);
|
|
29374
29436
|
}
|
|
29375
29437
|
}
|
|
29376
29438
|
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 +29466,7 @@ async function recordingsListCommand(options = {}) {
|
|
|
29404
29466
|
const suffix = query.toString() ? `?${query.toString()}` : "";
|
|
29405
29467
|
const response = await adminApiGet(`/api/v1/admin/recordings${suffix}`);
|
|
29406
29468
|
if (options.json) {
|
|
29407
|
-
|
|
29469
|
+
printJson({ ok: true, recordings: response.recordings });
|
|
29408
29470
|
return;
|
|
29409
29471
|
}
|
|
29410
29472
|
if (response.recordings.length === 0) {
|
|
@@ -29416,11 +29478,11 @@ async function recordingsListCommand(options = {}) {
|
|
|
29416
29478
|
}
|
|
29417
29479
|
async function recordingGetCommand(id, options = {}) {
|
|
29418
29480
|
if (!id) {
|
|
29419
|
-
throw new
|
|
29481
|
+
throw new CliError("missing_id", "Missing recording id for: get");
|
|
29420
29482
|
}
|
|
29421
29483
|
const recording = await recordingGet2(id);
|
|
29422
29484
|
if (options.json) {
|
|
29423
|
-
|
|
29485
|
+
printJson({ ok: true, recording });
|
|
29424
29486
|
return;
|
|
29425
29487
|
}
|
|
29426
29488
|
console.log(formatRecordingSummary(recording));
|
|
@@ -29438,7 +29500,7 @@ async function recordingCreateCommand(options = {}) {
|
|
|
29438
29500
|
});
|
|
29439
29501
|
const recording = created.recording;
|
|
29440
29502
|
if (options.json) {
|
|
29441
|
-
|
|
29503
|
+
printJson({ ok: true, recording });
|
|
29442
29504
|
return;
|
|
29443
29505
|
}
|
|
29444
29506
|
console.log(`Plan ${recording.id} created, handle "${recording.title}"`);
|
|
@@ -29446,13 +29508,13 @@ async function recordingCreateCommand(options = {}) {
|
|
|
29446
29508
|
}
|
|
29447
29509
|
const title = options.title?.trim();
|
|
29448
29510
|
if (!title) {
|
|
29449
|
-
throw new
|
|
29511
|
+
throw new CliError("missing_title", "A recording needs a --title (or --plan for a videoless plan)");
|
|
29450
29512
|
}
|
|
29451
29513
|
if (!options.video) {
|
|
29452
|
-
throw new
|
|
29514
|
+
throw new CliError("missing_video", "A recording needs a --video <file> to stage");
|
|
29453
29515
|
}
|
|
29454
29516
|
if (!existsSync2(options.video)) {
|
|
29455
|
-
throw new
|
|
29517
|
+
throw new CliError("file_not_found", `Set-video master not found: ${options.video}`);
|
|
29456
29518
|
}
|
|
29457
29519
|
const created = await adminApiPost("/api/v1/admin/recordings", {
|
|
29458
29520
|
recordedAt: options.recordedAt,
|
|
@@ -29467,14 +29529,14 @@ async function recordingCreateCommand(options = {}) {
|
|
|
29467
29529
|
log(`Recording ${recording.id} created, staging the set video…`);
|
|
29468
29530
|
const upload = await uploadRenditionMultipart(options.video, `/api/v1/admin/recordings/${encodeURIComponent(recording.id)}/set-video/presign`, log);
|
|
29469
29531
|
if (options.json) {
|
|
29470
|
-
|
|
29532
|
+
printJson({ key: upload.key, ok: true, recording, url: upload.url });
|
|
29471
29533
|
return;
|
|
29472
29534
|
}
|
|
29473
29535
|
console.log(`Recording ${recording.id} staged → ${upload.url}`);
|
|
29474
29536
|
}
|
|
29475
29537
|
async function recordingUpdateCommand(id, options = {}) {
|
|
29476
29538
|
if (!id) {
|
|
29477
|
-
throw new
|
|
29539
|
+
throw new CliError("missing_id", "Missing recording id for: update");
|
|
29478
29540
|
}
|
|
29479
29541
|
const body = {};
|
|
29480
29542
|
if (options.title !== undefined) {
|
|
@@ -29488,66 +29550,66 @@ async function recordingUpdateCommand(id, options = {}) {
|
|
|
29488
29550
|
}
|
|
29489
29551
|
if (options.tracklistFile !== undefined) {
|
|
29490
29552
|
if (!existsSync2(options.tracklistFile)) {
|
|
29491
|
-
throw new
|
|
29553
|
+
throw new CliError("file_not_found", `Tracklist file not found: ${options.tracklistFile}`);
|
|
29492
29554
|
}
|
|
29493
29555
|
try {
|
|
29494
29556
|
body.tracklistJson = JSON.parse(readFileSync2(options.tracklistFile, "utf8"));
|
|
29495
29557
|
} catch {
|
|
29496
|
-
throw new
|
|
29558
|
+
throw new CliError("invalid_tracklist", `Tracklist file is not valid JSON: ${options.tracklistFile}`);
|
|
29497
29559
|
}
|
|
29498
29560
|
}
|
|
29499
29561
|
if (Object.keys(body).length === 0) {
|
|
29500
|
-
throw new
|
|
29562
|
+
throw new CliError("no_fields", "Nothing to update. Pass --title, --recorded-at, --parent-id, or --tracklist-file");
|
|
29501
29563
|
}
|
|
29502
29564
|
const response = await adminApiPatch(`/api/v1/admin/recordings/${encodeURIComponent(id)}`, body);
|
|
29503
29565
|
if (options.json) {
|
|
29504
|
-
|
|
29566
|
+
printJson({ ok: true, recording: response.recording });
|
|
29505
29567
|
return;
|
|
29506
29568
|
}
|
|
29507
29569
|
console.log(`Updated ${formatRecordingSummary(response.recording)}`);
|
|
29508
29570
|
}
|
|
29509
29571
|
async function recordingDeleteCommand(id, options = {}) {
|
|
29510
29572
|
if (!id) {
|
|
29511
|
-
throw new
|
|
29573
|
+
throw new CliError("missing_id", "Missing recording id for: delete");
|
|
29512
29574
|
}
|
|
29513
29575
|
await adminApiDelete(`/api/v1/admin/recordings/${encodeURIComponent(id)}`);
|
|
29514
29576
|
if (options.json) {
|
|
29515
|
-
|
|
29577
|
+
printJson({ ok: true });
|
|
29516
29578
|
return;
|
|
29517
29579
|
}
|
|
29518
29580
|
console.log(`Deleted recording ${id} (and its clips).`);
|
|
29519
29581
|
}
|
|
29520
29582
|
async function recordingPromoteCommand(id, options = {}) {
|
|
29521
29583
|
if (!id) {
|
|
29522
|
-
throw new
|
|
29584
|
+
throw new CliError("missing_id", "Missing recording id for: promote");
|
|
29523
29585
|
}
|
|
29524
29586
|
const response = await adminApiPost(`/api/v1/admin/recordings/${encodeURIComponent(id)}/promote`);
|
|
29525
29587
|
const recording = response.recording;
|
|
29526
29588
|
if (options.json) {
|
|
29527
|
-
|
|
29589
|
+
printJson({ ok: true, recording });
|
|
29528
29590
|
return;
|
|
29529
29591
|
}
|
|
29530
29592
|
console.log(recording.logId ? `Promoted recording ${id} → mixtape fluncle://${recording.logId}` : `Promoted recording ${id}`);
|
|
29531
29593
|
}
|
|
29532
29594
|
async function recordingReplaceCuesCommand(id, options = {}) {
|
|
29533
29595
|
if (!id) {
|
|
29534
|
-
throw new
|
|
29596
|
+
throw new CliError("missing_id", "Missing recording id for: replace-cues");
|
|
29535
29597
|
}
|
|
29536
29598
|
if (!options.cuesFile) {
|
|
29537
|
-
throw new
|
|
29599
|
+
throw new CliError("missing_cues_file", "replace-cues needs a --cues-file <file> (the ordered cue array)");
|
|
29538
29600
|
}
|
|
29539
29601
|
if (!existsSync2(options.cuesFile)) {
|
|
29540
|
-
throw new
|
|
29602
|
+
throw new CliError("file_not_found", `Cues file not found: ${options.cuesFile}`);
|
|
29541
29603
|
}
|
|
29542
29604
|
let cues;
|
|
29543
29605
|
try {
|
|
29544
29606
|
cues = JSON.parse(readFileSync2(options.cuesFile, "utf8"));
|
|
29545
29607
|
} catch {
|
|
29546
|
-
throw new
|
|
29608
|
+
throw new CliError("invalid_cues", `Cues file is not valid JSON: ${options.cuesFile}`);
|
|
29547
29609
|
}
|
|
29548
29610
|
const response = await adminApiPut(`/api/v1/admin/recordings/${encodeURIComponent(id)}/cues`, { cues });
|
|
29549
29611
|
if (options.json) {
|
|
29550
|
-
|
|
29612
|
+
printJson({ ok: true, recording: response.recording });
|
|
29551
29613
|
return;
|
|
29552
29614
|
}
|
|
29553
29615
|
console.log(`Replaced cues for ${formatRecordingSummary(response.recording)}`);
|
|
@@ -29565,7 +29627,7 @@ function buildBody2(options, { requireContent }) {
|
|
|
29565
29627
|
if (options.contentFile !== undefined) {
|
|
29566
29628
|
body.contentJson = readContentFile(options.contentFile);
|
|
29567
29629
|
} else if (requireContent) {
|
|
29568
|
-
throw new
|
|
29630
|
+
throw new CliError("missing_content", "A draft needs the structured content payload via --content-file <edition.json>");
|
|
29569
29631
|
}
|
|
29570
29632
|
if (requireContent && typeof options.promptVersion === "number") {
|
|
29571
29633
|
body.promptVersion = options.promptVersion;
|
|
@@ -29583,13 +29645,13 @@ function buildBody2(options, { requireContent }) {
|
|
|
29583
29645
|
}
|
|
29584
29646
|
function readContentFile(filePath) {
|
|
29585
29647
|
if (!existsSync3(filePath)) {
|
|
29586
|
-
throw new
|
|
29648
|
+
throw new CliError("file_not_found", `Edition payload file not found: ${filePath}`);
|
|
29587
29649
|
}
|
|
29588
29650
|
const text = readFileSync3(filePath, "utf-8");
|
|
29589
29651
|
try {
|
|
29590
29652
|
return JSON.parse(text);
|
|
29591
29653
|
} catch (error) {
|
|
29592
|
-
throw new
|
|
29654
|
+
throw new CliError("invalid_content_json", `Edition payload JSON parse failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
29593
29655
|
}
|
|
29594
29656
|
}
|
|
29595
29657
|
async function newsletterDraftCommand(options) {
|
|
@@ -29626,15 +29688,15 @@ function resolveBody(options) {
|
|
|
29626
29688
|
}
|
|
29627
29689
|
if (options.bodyFile !== undefined) {
|
|
29628
29690
|
if (!existsSync4(options.bodyFile)) {
|
|
29629
|
-
throw new
|
|
29691
|
+
throw new CliError("file_not_found", `Body file not found: ${options.bodyFile}`);
|
|
29630
29692
|
}
|
|
29631
29693
|
return readFileSync4(options.bodyFile, "utf-8");
|
|
29632
29694
|
}
|
|
29633
|
-
throw new
|
|
29695
|
+
throw new CliError("missing_body", "An entry needs a body via --body <text> or --body-file <entry.md>");
|
|
29634
29696
|
}
|
|
29635
29697
|
function requireTitle(options) {
|
|
29636
29698
|
if (options.title === undefined || !options.title.trim()) {
|
|
29637
|
-
throw new
|
|
29699
|
+
throw new CliError("missing_title", "An entry needs a title via --title <text>");
|
|
29638
29700
|
}
|
|
29639
29701
|
return options.title;
|
|
29640
29702
|
}
|
|
@@ -29669,20 +29731,20 @@ async function promptDetailCommand(slug) {
|
|
|
29669
29731
|
const prompts = await promptsListCommand();
|
|
29670
29732
|
const detail = prompts.find((prompt) => prompt.slug === slug);
|
|
29671
29733
|
if (!detail) {
|
|
29672
|
-
throw new
|
|
29734
|
+
throw new CliError("unknown_prompt", `No prompt goes by "${slug}". The registered ones: ${prompts.map((prompt) => prompt.slug).join(", ")}`);
|
|
29673
29735
|
}
|
|
29674
29736
|
return detail;
|
|
29675
29737
|
}
|
|
29676
29738
|
function resolveBody2(options) {
|
|
29677
29739
|
if (options.bodyFile === undefined) {
|
|
29678
|
-
throw new
|
|
29740
|
+
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
29741
|
}
|
|
29680
29742
|
if (!existsSync5(options.bodyFile)) {
|
|
29681
|
-
throw new
|
|
29743
|
+
throw new CliError("file_not_found", `Body file not found: ${options.bodyFile}`);
|
|
29682
29744
|
}
|
|
29683
29745
|
const body = readFileSync5(options.bodyFile, "utf-8");
|
|
29684
29746
|
if (body.trim().length === 0) {
|
|
29685
|
-
throw new
|
|
29747
|
+
throw new CliError("empty_body", "A prompt body cannot be empty. Nothing was appended.");
|
|
29686
29748
|
}
|
|
29687
29749
|
return body;
|
|
29688
29750
|
}
|
|
@@ -29697,7 +29759,7 @@ async function promptRollbackCommand(slug, version) {
|
|
|
29697
29759
|
const target = detail.versions.find((candidate) => candidate.version === version);
|
|
29698
29760
|
if (!target) {
|
|
29699
29761
|
const known = detail.versions.map((candidate) => `v${candidate.version}`).join(", ");
|
|
29700
|
-
throw new
|
|
29762
|
+
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
29763
|
}
|
|
29702
29764
|
return restore(detail, { body: target.body, from: version, note: `rolled back to v${version}` });
|
|
29703
29765
|
}
|
|
@@ -29722,7 +29784,7 @@ function parseAgainst(value) {
|
|
|
29722
29784
|
}
|
|
29723
29785
|
const version = parseVersion3(value);
|
|
29724
29786
|
if (version === undefined) {
|
|
29725
|
-
throw new
|
|
29787
|
+
throw new CliError("invalid_against", `--against takes a version (3, or v3) or the word default. Got "${value}".`);
|
|
29726
29788
|
}
|
|
29727
29789
|
return { kind: "version", version };
|
|
29728
29790
|
}
|
|
@@ -29802,7 +29864,7 @@ function resolveAgainstVersion(detail, version) {
|
|
|
29802
29864
|
const target = detail.versions.find((candidate) => candidate.version === version);
|
|
29803
29865
|
if (!target) {
|
|
29804
29866
|
const known = detail.versions.map((candidate) => `v${candidate.version}`).join(", ");
|
|
29805
|
-
throw new
|
|
29867
|
+
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
29868
|
}
|
|
29807
29869
|
return { body: target.body, label: `v${version}`, version };
|
|
29808
29870
|
}
|
|
@@ -29853,7 +29915,7 @@ import { createInterface as createInterface2 } from "node:readline/promises";
|
|
|
29853
29915
|
async function listSubmissionsCommand(options = {}) {
|
|
29854
29916
|
const response = await adminApiGet("/api/v1/admin/submissions");
|
|
29855
29917
|
if (options.json) {
|
|
29856
|
-
|
|
29918
|
+
printJson({ ok: true, submissions: response.submissions });
|
|
29857
29919
|
return;
|
|
29858
29920
|
}
|
|
29859
29921
|
if (response.submissions.length === 0) {
|
|
@@ -29867,7 +29929,7 @@ async function listSubmissionsCommand(options = {}) {
|
|
|
29867
29929
|
async function reviewSubmissionCommand(submissionId, options = {}) {
|
|
29868
29930
|
const submission = await fetchSubmission(submissionId);
|
|
29869
29931
|
if (options.json) {
|
|
29870
|
-
|
|
29932
|
+
printJson({ ok: true, submission });
|
|
29871
29933
|
return;
|
|
29872
29934
|
}
|
|
29873
29935
|
console.log(formatSubmissionDetail(submission));
|
|
@@ -29875,7 +29937,7 @@ async function reviewSubmissionCommand(submissionId, options = {}) {
|
|
|
29875
29937
|
async function rejectSubmissionCommand(submissionId, options = {}) {
|
|
29876
29938
|
const response = await adminApiPost(`/api/v1/admin/submissions/${encodeURIComponent(submissionId)}/reject`);
|
|
29877
29939
|
if (options.json) {
|
|
29878
|
-
|
|
29940
|
+
printJson({ ok: true, submission: response.submission });
|
|
29879
29941
|
return;
|
|
29880
29942
|
}
|
|
29881
29943
|
console.log(`Rejected ${formatTrackLine(response.submission)}.`);
|
|
@@ -29900,7 +29962,7 @@ async function approveSubmissionCommand(submissionId, options = {}) {
|
|
|
29900
29962
|
});
|
|
29901
29963
|
const response = await adminApiPost(`/api/v1/admin/submissions/${encodeURIComponent(submission.id)}/approve`);
|
|
29902
29964
|
if (options.json) {
|
|
29903
|
-
|
|
29965
|
+
printJson({ ok: true, submission: response.submission });
|
|
29904
29966
|
return;
|
|
29905
29967
|
}
|
|
29906
29968
|
console.log(`Approved ${formatTrackLine(submission)}.`);
|
|
@@ -29911,7 +29973,7 @@ async function triageSubmissionCommand(submissionId, verdict, options = {}) {
|
|
|
29911
29973
|
verdict
|
|
29912
29974
|
});
|
|
29913
29975
|
if (options.json) {
|
|
29914
|
-
|
|
29976
|
+
printJson({ ok: true, submission: response.submission });
|
|
29915
29977
|
return;
|
|
29916
29978
|
}
|
|
29917
29979
|
console.log(`Triaged ${formatTrackLine(response.submission)}: ${response.submission.triageVerdict ?? ""}`);
|
|
@@ -29922,7 +29984,7 @@ async function fetchSubmission(submissionId) {
|
|
|
29922
29984
|
}
|
|
29923
29985
|
async function confirm(label) {
|
|
29924
29986
|
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
29925
|
-
throw new
|
|
29987
|
+
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
29988
|
}
|
|
29927
29989
|
const rl = createInterface2({
|
|
29928
29990
|
input: process.stdin,
|
|
@@ -30508,9 +30570,11 @@ function createEvidenceHttp(overrides = {}) {
|
|
|
30508
30570
|
return {
|
|
30509
30571
|
cacheDir: defaultCacheDir(),
|
|
30510
30572
|
cacheTtlMs: 7 * 24 * 60 * 60 * 1000,
|
|
30573
|
+
deadline: null,
|
|
30511
30574
|
fetch: (url, init) => globalThis.fetch(url, init),
|
|
30512
30575
|
now: () => Date.now(),
|
|
30513
30576
|
policies: SOURCE_POLICIES,
|
|
30577
|
+
progress: noteProgress2,
|
|
30514
30578
|
random: Math.random,
|
|
30515
30579
|
refresh: false,
|
|
30516
30580
|
sleep: (ms) => runPromise2(sleep2(ms)),
|
|
@@ -30584,16 +30648,26 @@ async function readNextSlot(slotFile) {
|
|
|
30584
30648
|
const value = Number(raw);
|
|
30585
30649
|
return Number.isFinite(value) ? value : 0;
|
|
30586
30650
|
}
|
|
30651
|
+
function seconds2(ms) {
|
|
30652
|
+
return Math.ceil(ms / 1000);
|
|
30653
|
+
}
|
|
30587
30654
|
async function reserveSlot(http, source) {
|
|
30588
30655
|
const interval = http.policies[source].intervalMs;
|
|
30589
30656
|
const slotAt = await withSlotLock(http, source, async (slotFile) => {
|
|
30590
30657
|
const now = http.now();
|
|
30591
30658
|
const slot = Math.max(now, await readNextSlot(slotFile));
|
|
30659
|
+
if (http.deadline !== null && slot >= http.deadline) {
|
|
30660
|
+
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);
|
|
30661
|
+
}
|
|
30592
30662
|
await writeFile2(slotFile, String(slot + interval));
|
|
30593
30663
|
return slot;
|
|
30594
30664
|
});
|
|
30665
|
+
if (slotAt instanceof EvidenceFetchError) {
|
|
30666
|
+
throw slotAt;
|
|
30667
|
+
}
|
|
30595
30668
|
const wait = slotAt - http.now();
|
|
30596
30669
|
if (wait > 0) {
|
|
30670
|
+
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
30671
|
await http.sleep(wait);
|
|
30598
30672
|
}
|
|
30599
30673
|
}
|
|
@@ -30634,8 +30708,12 @@ async function fetchEvidenceText(http, source, cacheKey, perform, accept = () =>
|
|
|
30634
30708
|
let attempt = 0;
|
|
30635
30709
|
const request = gen2(function* () {
|
|
30636
30710
|
attempt += 1;
|
|
30637
|
-
yield*
|
|
30711
|
+
yield* tryPromise2({
|
|
30712
|
+
catch: (error) => error instanceof EvidenceFetchError ? error : new EvidencePerformError({ cause: error }),
|
|
30713
|
+
try: () => reserveSlot(http, source)
|
|
30714
|
+
});
|
|
30638
30715
|
http.stats.requests += 1;
|
|
30716
|
+
http.progress(`${source} request ${http.stats.requests} in flight`);
|
|
30639
30717
|
let returned = false;
|
|
30640
30718
|
const response = yield* tryPromise2({
|
|
30641
30719
|
catch: (error) => {
|
|
@@ -30705,7 +30783,7 @@ async function fetchEvidenceJson(http, source, url, headers = {}) {
|
|
|
30705
30783
|
const { cached, text } = await fetchEvidenceText(http, source, `GET ${url}`, async (signal) => {
|
|
30706
30784
|
const response = await http.fetch(url, {
|
|
30707
30785
|
headers: { Accept: "application/json", "User-Agent": EVIDENCE_USER_AGENT, ...headers },
|
|
30708
|
-
signal
|
|
30786
|
+
signal: AbortSignal.any([signal, deadlineSignal()])
|
|
30709
30787
|
});
|
|
30710
30788
|
return { headers: response.headers, status: response.status, text: await response.text() };
|
|
30711
30789
|
}, isJson2);
|
|
@@ -30714,6 +30792,7 @@ async function fetchEvidenceJson(http, source, url, headers = {}) {
|
|
|
30714
30792
|
var SOURCE_POLICIES, EVIDENCE_USER_AGENT = "FluncleLabelTriage/1.0 ( https://www.fluncle.com )", EvidenceFetchError, EvidenceRetryable, EvidencePerformError, LOCK_STALE_MS = 1e4;
|
|
30715
30793
|
var init_evidence_http = __esm(() => {
|
|
30716
30794
|
init_dist();
|
|
30795
|
+
init_deadline();
|
|
30717
30796
|
SOURCE_POLICIES = {
|
|
30718
30797
|
apple: { attempts: 3, intervalMs: 3000, maxBackoffMs: 30000, timeoutMs: 1e4 },
|
|
30719
30798
|
beatport: { attempts: 2, intervalMs: 1000, maxBackoffMs: 30000, timeoutMs: 75000 },
|
|
@@ -31407,7 +31486,7 @@ async function labelEvidenceCommand(input, options) {
|
|
|
31407
31486
|
Promise.resolve().then(() => (init_env(), exports_env)),
|
|
31408
31487
|
Promise.resolve().then(() => (init_admin_labels3(), exports_admin_labels))
|
|
31409
31488
|
]);
|
|
31410
|
-
const http = createEvidenceHttp({ refresh: options.refresh });
|
|
31489
|
+
const http = createEvidenceHttp({ deadline: deadlineAt(), refresh: options.refresh });
|
|
31411
31490
|
const discogsToken = readOptionalEnv("DISCOGS_USER_TOKEN");
|
|
31412
31491
|
if (discogsToken) {
|
|
31413
31492
|
http.policies = { ...http.policies, discogs: { ...http.policies.discogs, intervalMs: 1100 } };
|
|
@@ -31458,6 +31537,7 @@ function labelEvidenceLines(evidence) {
|
|
|
31458
31537
|
}
|
|
31459
31538
|
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
31539
|
var init_admin_label_evidence = __esm(() => {
|
|
31540
|
+
init_deadline();
|
|
31461
31541
|
init_evidence_http();
|
|
31462
31542
|
MBID_PATTERN3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
31463
31543
|
EVIDENCE_SOURCES = ["musicbrainz", "discogs", "beatport", "apple"];
|
|
@@ -31500,7 +31580,7 @@ async function paginateWithKeyboard(options) {
|
|
|
31500
31580
|
const stdin = options.input ?? process.stdin;
|
|
31501
31581
|
const stdout = options.output ?? process.stdout;
|
|
31502
31582
|
if (!stdin.isTTY || !stdout.isTTY) {
|
|
31503
|
-
throw new
|
|
31583
|
+
throw new CliError("not_interactive", options.nonInteractiveMessage);
|
|
31504
31584
|
}
|
|
31505
31585
|
const first = await options.fetchPage(undefined);
|
|
31506
31586
|
if (first.lines.length === 0) {
|
|
@@ -33728,8 +33808,114 @@ var fluncleAsciiLogo = `███████╗██╗ ██╗ ██
|
|
|
33728
33808
|
╚═╝ ╚══════╝ ╚═════╝ ╚═╝ ╚═══╝ ╚═════╝╚══════╝╚══════╝`;
|
|
33729
33809
|
var fluncleTagline = "Drum & bass bangers from another dimension";
|
|
33730
33810
|
|
|
33811
|
+
// src/deadline.ts
|
|
33812
|
+
init_output();
|
|
33813
|
+
var DEFAULT_NON_INTERACTIVE_TIMEOUT_SECONDS = 240;
|
|
33814
|
+
var TIMEOUT_EXIT_CODE = 124;
|
|
33815
|
+
var TIMEOUT_ENV = "FLUNCLE_TIMEOUT";
|
|
33816
|
+
var CLEANUP_GRACE_MS = 1e4;
|
|
33817
|
+
var state = {
|
|
33818
|
+
at: null,
|
|
33819
|
+
cancel: null,
|
|
33820
|
+
controller: new AbortController,
|
|
33821
|
+
fire: null,
|
|
33822
|
+
fired: false,
|
|
33823
|
+
note: null
|
|
33824
|
+
};
|
|
33825
|
+
function parseTimeoutSeconds(value, source) {
|
|
33826
|
+
if (value === undefined || value.trim() === "") {
|
|
33827
|
+
return null;
|
|
33828
|
+
}
|
|
33829
|
+
const trimmed = value.trim();
|
|
33830
|
+
if (["0", "off", "none"].includes(trimmed.toLowerCase())) {
|
|
33831
|
+
return 0;
|
|
33832
|
+
}
|
|
33833
|
+
const seconds = Number(trimmed);
|
|
33834
|
+
if (!Number.isFinite(seconds) || seconds <= 0) {
|
|
33835
|
+
throw new CliError("invalid_timeout", `${source} must be a number of seconds (0 disables the deadline), not "${value}"`);
|
|
33836
|
+
}
|
|
33837
|
+
return seconds;
|
|
33838
|
+
}
|
|
33839
|
+
function resolveTimeoutSeconds(input) {
|
|
33840
|
+
const flag = parseTimeoutSeconds(input.flag, "--timeout");
|
|
33841
|
+
if (flag !== null) {
|
|
33842
|
+
return flag;
|
|
33843
|
+
}
|
|
33844
|
+
const env = parseTimeoutSeconds(input.env, TIMEOUT_ENV);
|
|
33845
|
+
if (env !== null) {
|
|
33846
|
+
return env;
|
|
33847
|
+
}
|
|
33848
|
+
return input.interactive ? 0 : DEFAULT_NON_INTERACTIVE_TIMEOUT_SECONDS;
|
|
33849
|
+
}
|
|
33850
|
+
function timeoutMessage(command, seconds, note) {
|
|
33851
|
+
const waiting = note ? `: ${note}` : "";
|
|
33852
|
+
return `fluncle ${command} stopped after ${seconds} s${waiting}. Set --timeout or ${TIMEOUT_ENV} in seconds (0 disables the deadline).`;
|
|
33853
|
+
}
|
|
33854
|
+
function defaultSchedule(fire, ms) {
|
|
33855
|
+
const timer = setTimeout(fire, ms);
|
|
33856
|
+
timer.unref();
|
|
33857
|
+
return () => clearTimeout(timer);
|
|
33858
|
+
}
|
|
33859
|
+
function armDeadline(seconds, options) {
|
|
33860
|
+
disarmDeadline();
|
|
33861
|
+
if (seconds <= 0) {
|
|
33862
|
+
state.at = null;
|
|
33863
|
+
return;
|
|
33864
|
+
}
|
|
33865
|
+
const now = options.now ?? Date.now;
|
|
33866
|
+
const exit = options.exit ?? ((code) => process.exit(code));
|
|
33867
|
+
const schedule = options.schedule ?? defaultSchedule;
|
|
33868
|
+
const report = options.report ?? ((message) => {
|
|
33869
|
+
if (options.json) {
|
|
33870
|
+
printJson({ code: "timeout", message, ok: false });
|
|
33871
|
+
return;
|
|
33872
|
+
}
|
|
33873
|
+
console.error(message);
|
|
33874
|
+
});
|
|
33875
|
+
state.at = now() + seconds * 1000;
|
|
33876
|
+
state.fire = () => {
|
|
33877
|
+
if (state.fired) {
|
|
33878
|
+
return;
|
|
33879
|
+
}
|
|
33880
|
+
const message = timeoutMessage(options.command, seconds, state.note);
|
|
33881
|
+
state.fired = true;
|
|
33882
|
+
disarmDeadline();
|
|
33883
|
+
report(message);
|
|
33884
|
+
process.exitCode = TIMEOUT_EXIT_CODE;
|
|
33885
|
+
state.controller.abort(new CliError("timeout", message));
|
|
33886
|
+
schedule(() => exit(TIMEOUT_EXIT_CODE), options.graceMs ?? CLEANUP_GRACE_MS);
|
|
33887
|
+
};
|
|
33888
|
+
state.cancel = schedule(state.fire, seconds * 1000);
|
|
33889
|
+
}
|
|
33890
|
+
function disarmDeadline() {
|
|
33891
|
+
state.cancel?.();
|
|
33892
|
+
state.cancel = null;
|
|
33893
|
+
}
|
|
33894
|
+
function fireDeadlineNow() {
|
|
33895
|
+
state.fire?.();
|
|
33896
|
+
}
|
|
33897
|
+
function deadlineFired() {
|
|
33898
|
+
return state.fired;
|
|
33899
|
+
}
|
|
33900
|
+
function remainingDeadlineMs(now = Date.now) {
|
|
33901
|
+
return state.at === null ? null : state.at - now();
|
|
33902
|
+
}
|
|
33903
|
+
function fireIfPastDeadline(waitingOn) {
|
|
33904
|
+
const remaining = remainingDeadlineMs();
|
|
33905
|
+
if (remaining === null || remaining > 0) {
|
|
33906
|
+
return false;
|
|
33907
|
+
}
|
|
33908
|
+
noteProgress(waitingOn);
|
|
33909
|
+
fireDeadlineNow();
|
|
33910
|
+
return true;
|
|
33911
|
+
}
|
|
33912
|
+
function noteProgress(note) {
|
|
33913
|
+
state.note = note;
|
|
33914
|
+
}
|
|
33915
|
+
|
|
33731
33916
|
// src/env.ts
|
|
33732
33917
|
var import_dotenv = __toESM(require_main(), 1);
|
|
33918
|
+
init_deadline();
|
|
33733
33919
|
var envProfiles = ["local", "production"];
|
|
33734
33920
|
function setEnvProfile(profile) {
|
|
33735
33921
|
if (!profile) {
|
|
@@ -33803,24 +33989,45 @@ async function maybePrintLiveCallout(args) {
|
|
|
33803
33989
|
}
|
|
33804
33990
|
|
|
33805
33991
|
// src/output.ts
|
|
33806
|
-
import { writeSync } from "node:fs";
|
|
33807
|
-
|
|
33808
|
-
|
|
33992
|
+
import { writeSync as writeSync2 } from "node:fs";
|
|
33993
|
+
import { format } from "node:util";
|
|
33994
|
+
var EAGAIN_WAIT2 = new Int32Array(new SharedArrayBuffer(4));
|
|
33995
|
+
var stopWaitingForReader2 = () => false;
|
|
33996
|
+
function writeFdSync2(fd, text) {
|
|
33809
33997
|
const buf = Buffer.from(text, "utf8");
|
|
33810
33998
|
let offset = 0;
|
|
33811
33999
|
while (offset < buf.length) {
|
|
33812
34000
|
try {
|
|
33813
|
-
offset +=
|
|
34001
|
+
offset += writeSync2(fd, buf, offset);
|
|
33814
34002
|
} catch (error) {
|
|
33815
|
-
|
|
33816
|
-
|
|
34003
|
+
const code = error.code;
|
|
34004
|
+
if (code === "EAGAIN") {
|
|
34005
|
+
if (stopWaitingForReader2()) {
|
|
34006
|
+
return;
|
|
34007
|
+
}
|
|
34008
|
+
Atomics.wait(EAGAIN_WAIT2, 0, 0, 1);
|
|
33817
34009
|
continue;
|
|
33818
34010
|
}
|
|
34011
|
+
if (code === "EPIPE") {
|
|
34012
|
+
return;
|
|
34013
|
+
}
|
|
33819
34014
|
throw error;
|
|
33820
34015
|
}
|
|
33821
34016
|
}
|
|
33822
34017
|
}
|
|
33823
|
-
|
|
34018
|
+
function routeConsoleThroughBlockingWrites(pastDeadline) {
|
|
34019
|
+
stopWaitingForReader2 = pastDeadline;
|
|
34020
|
+
const toStdout = (...args) => writeFdSync2(1, `${format(...args)}
|
|
34021
|
+
`);
|
|
34022
|
+
const toStderr = (...args) => writeFdSync2(2, `${format(...args)}
|
|
34023
|
+
`);
|
|
34024
|
+
console.debug = toStdout;
|
|
34025
|
+
console.error = toStderr;
|
|
34026
|
+
console.info = toStdout;
|
|
34027
|
+
console.log = toStdout;
|
|
34028
|
+
console.warn = toStderr;
|
|
34029
|
+
}
|
|
34030
|
+
class CliError2 extends Error {
|
|
33824
34031
|
code;
|
|
33825
34032
|
constructor(code, message) {
|
|
33826
34033
|
super(message);
|
|
@@ -33828,12 +34035,12 @@ class CliError extends Error {
|
|
|
33828
34035
|
this.code = code;
|
|
33829
34036
|
}
|
|
33830
34037
|
}
|
|
33831
|
-
function
|
|
33832
|
-
|
|
34038
|
+
function printJson2(value) {
|
|
34039
|
+
writeFdSync2(1, JSON.stringify(value, null, 2) + `
|
|
33833
34040
|
`);
|
|
33834
34041
|
}
|
|
33835
34042
|
function toJsonFailure(error) {
|
|
33836
|
-
if (error instanceof
|
|
34043
|
+
if (error instanceof CliError2) {
|
|
33837
34044
|
return {
|
|
33838
34045
|
code: error.code,
|
|
33839
34046
|
message: error.message,
|
|
@@ -33915,9 +34122,17 @@ function artistRuleLines(rules) {
|
|
|
33915
34122
|
}
|
|
33916
34123
|
function createProgram() {
|
|
33917
34124
|
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) => {
|
|
34125
|
+
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
34126
|
const options = actionCommand.optsWithGlobals();
|
|
33920
34127
|
setEnvProfile(options.env);
|
|
34128
|
+
armDeadline(resolveTimeoutSeconds({
|
|
34129
|
+
env: process.env[TIMEOUT_ENV],
|
|
34130
|
+
flag: options.timeout,
|
|
34131
|
+
interactive: Boolean(process.stdout.isTTY)
|
|
34132
|
+
}), {
|
|
34133
|
+
command: commandPath(actionCommand),
|
|
34134
|
+
json: process.argv.includes("--json")
|
|
34135
|
+
});
|
|
33921
34136
|
}).addHelpText("before", `
|
|
33922
34137
|
${fluncleAsciiLogo}
|
|
33923
34138
|
`).addHelpText("after", rootHelpSections);
|
|
@@ -33930,6 +34145,7 @@ ${fluncleAsciiLogo}
|
|
|
33930
34145
|
return program;
|
|
33931
34146
|
}
|
|
33932
34147
|
async function main(args = process.argv.slice(2)) {
|
|
34148
|
+
routeConsoleThroughBlockingWrites(() => fireIfPastDeadline("waiting for the stdout reader to take the output"));
|
|
33933
34149
|
const program = createProgram();
|
|
33934
34150
|
if (args.length === 0) {
|
|
33935
34151
|
program.outputHelp();
|
|
@@ -33944,17 +34160,31 @@ async function main(args = process.argv.slice(2)) {
|
|
|
33944
34160
|
if (isHelpDisplayed(error)) {
|
|
33945
34161
|
return;
|
|
33946
34162
|
}
|
|
34163
|
+
if (deadlineFired()) {
|
|
34164
|
+
process.exit(TIMEOUT_EXIT_CODE);
|
|
34165
|
+
}
|
|
33947
34166
|
const normalized = normalizeCommanderError(error);
|
|
33948
34167
|
if (process.argv.includes("--json") || args.includes("--json")) {
|
|
33949
|
-
|
|
34168
|
+
printJson2(toJsonFailure(normalized));
|
|
33950
34169
|
} else {
|
|
33951
34170
|
console.error(formatError(normalized));
|
|
33952
34171
|
}
|
|
33953
34172
|
process.exit(1);
|
|
33954
34173
|
}
|
|
34174
|
+
disarmDeadline();
|
|
34175
|
+
if (deadlineFired()) {
|
|
34176
|
+
process.exit(TIMEOUT_EXIT_CODE);
|
|
34177
|
+
}
|
|
33955
34178
|
await Promise.resolve().then(() => init_update_notifier());
|
|
33956
34179
|
await notifyIfUpdateAvailable(args);
|
|
33957
34180
|
}
|
|
34181
|
+
function commandPath(command) {
|
|
34182
|
+
const names = [];
|
|
34183
|
+
for (let current = command;current?.parent; current = current.parent) {
|
|
34184
|
+
names.unshift(current.name());
|
|
34185
|
+
}
|
|
34186
|
+
return [...names, ...command.args.slice(0, 1)].join(" ");
|
|
34187
|
+
}
|
|
33958
34188
|
function configureCommand(command) {
|
|
33959
34189
|
return command.exitOverride().helpOption("-h, --help", "Display help for command").addHelpCommand(false).configureOutput({
|
|
33960
34190
|
writeErr: () => {}
|
|
@@ -34109,7 +34339,7 @@ JSON field reference:
|
|
|
34109
34339
|
const receipts = await Promise.resolve().then(() => (init_admin_operation_receipts2(), {}));
|
|
34110
34340
|
const result = await getOperationReceiptCommand(operationKey);
|
|
34111
34341
|
if (options.json) {
|
|
34112
|
-
|
|
34342
|
+
printJson2(result);
|
|
34113
34343
|
return;
|
|
34114
34344
|
}
|
|
34115
34345
|
console.log(operationReceiptLines(result.receipt).join(`
|
|
@@ -34123,7 +34353,7 @@ JSON field reference:
|
|
|
34123
34353
|
requestDigest
|
|
34124
34354
|
});
|
|
34125
34355
|
if (options.json) {
|
|
34126
|
-
|
|
34356
|
+
printJson2(result);
|
|
34127
34357
|
return;
|
|
34128
34358
|
}
|
|
34129
34359
|
console.log(operationReceiptLines(result.receipt).join(`
|
|
@@ -34136,7 +34366,7 @@ JSON field reference:
|
|
|
34136
34366
|
staleBefore: parseOperationReceiptFence(options.staleBefore)
|
|
34137
34367
|
});
|
|
34138
34368
|
if (options.json) {
|
|
34139
|
-
|
|
34369
|
+
printJson2(result);
|
|
34140
34370
|
return;
|
|
34141
34371
|
}
|
|
34142
34372
|
const noun = result.repaired === 1 ? "receipt" : "receipts";
|
|
@@ -34150,7 +34380,7 @@ JSON field reference:
|
|
|
34150
34380
|
const projections = await Promise.resolve().then(() => (init_admin_projections2(), {}));
|
|
34151
34381
|
const result = await getProjectionStatusCommand();
|
|
34152
34382
|
if (options.json) {
|
|
34153
|
-
|
|
34383
|
+
printJson2(result);
|
|
34154
34384
|
return;
|
|
34155
34385
|
}
|
|
34156
34386
|
console.log(projectionStatusLines(result.status).join(`
|
|
@@ -34171,7 +34401,7 @@ JSON field reference:
|
|
|
34171
34401
|
wallMs: options.wallMs === undefined ? undefined : parseProjectionWallMs(options.wallMs)
|
|
34172
34402
|
});
|
|
34173
34403
|
if (options.json) {
|
|
34174
|
-
|
|
34404
|
+
printJson2(result);
|
|
34175
34405
|
return;
|
|
34176
34406
|
}
|
|
34177
34407
|
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 +34416,7 @@ JSON field reference:
|
|
|
34186
34416
|
workKind: options.workKind
|
|
34187
34417
|
});
|
|
34188
34418
|
if (options.json) {
|
|
34189
|
-
|
|
34419
|
+
printJson2(result);
|
|
34190
34420
|
return;
|
|
34191
34421
|
}
|
|
34192
34422
|
console.log(dueWorkRekeyLine(result));
|
|
@@ -34198,7 +34428,7 @@ JSON field reference:
|
|
|
34198
34428
|
target: parseProjectionCutover(options.target)
|
|
34199
34429
|
});
|
|
34200
34430
|
if (options.json) {
|
|
34201
|
-
|
|
34431
|
+
printJson2(result);
|
|
34202
34432
|
return;
|
|
34203
34433
|
}
|
|
34204
34434
|
console.log(`${result.target}: cutover ${result.enabled ? "open" : "dark"}.`);
|
|
@@ -34211,7 +34441,7 @@ JSON field reference:
|
|
|
34211
34441
|
const vectors = await Promise.resolve().then(() => (init_admin_vectors2(), {}));
|
|
34212
34442
|
const result = await getVectorServingCommand(parseVectorTarget(targetValue));
|
|
34213
34443
|
if (options.json) {
|
|
34214
|
-
|
|
34444
|
+
printJson2(result);
|
|
34215
34445
|
return;
|
|
34216
34446
|
}
|
|
34217
34447
|
console.log(vectorServingStatusLines(result.status).join(`
|
|
@@ -34224,7 +34454,7 @@ JSON field reference:
|
|
|
34224
34454
|
target: parseVectorTarget(targetValue)
|
|
34225
34455
|
});
|
|
34226
34456
|
if (options.json) {
|
|
34227
|
-
|
|
34457
|
+
printJson2(result);
|
|
34228
34458
|
return;
|
|
34229
34459
|
}
|
|
34230
34460
|
console.log(vectorServingStatusLines(result.status).join(`
|
|
@@ -34241,7 +34471,7 @@ JSON field reference:
|
|
|
34241
34471
|
contracts: parseArtifactContracts(options.contract)
|
|
34242
34472
|
});
|
|
34243
34473
|
if (options.json) {
|
|
34244
|
-
|
|
34474
|
+
printJson2(result);
|
|
34245
34475
|
return;
|
|
34246
34476
|
}
|
|
34247
34477
|
console.log(`${result.consumer.consumerId}: rebuilding at snapshot seq ${result.consumer.snapshotSeq ?? 0}.`);
|
|
@@ -34250,7 +34480,7 @@ JSON field reference:
|
|
|
34250
34480
|
await Promise.resolve().then(() => init_admin_artifacts2());
|
|
34251
34481
|
const result = await getArtifactConsumerCommand(consumerId);
|
|
34252
34482
|
if (options.json) {
|
|
34253
|
-
|
|
34483
|
+
printJson2(result);
|
|
34254
34484
|
return;
|
|
34255
34485
|
}
|
|
34256
34486
|
console.log(`${result.consumer.consumerId}: ${result.consumer.state}, head ${result.consumer.headSeq}, applied ${result.consumer.appliedThroughSeq ?? "none"}.`);
|
|
@@ -34266,7 +34496,7 @@ JSON field reference:
|
|
|
34266
34496
|
streamVersion: parseArtifactInteger(options.streamVersion, "--stream-version")
|
|
34267
34497
|
});
|
|
34268
34498
|
if (options.json) {
|
|
34269
|
-
|
|
34499
|
+
printJson2(result);
|
|
34270
34500
|
return;
|
|
34271
34501
|
}
|
|
34272
34502
|
console.log(`${result.stream}@${result.streamVersion}/${result.formatVersion}: ${result.itemCount} item(s), snapshot seq ${result.snapshotSeq}, page ${result.pageDigest}.`);
|
|
@@ -34286,7 +34516,7 @@ JSON field reference:
|
|
|
34286
34516
|
streamVersion: parseArtifactInteger(options.streamVersion, "--stream-version")
|
|
34287
34517
|
});
|
|
34288
34518
|
if (options.json) {
|
|
34289
|
-
|
|
34519
|
+
printJson2(result);
|
|
34290
34520
|
return;
|
|
34291
34521
|
}
|
|
34292
34522
|
console.log(`${result.checkpoint.stream}: ${result.checkpoint.state}, ${result.checkpoint.sourceItemCount} item(s) checkpointed.`);
|
|
@@ -34295,7 +34525,7 @@ JSON field reference:
|
|
|
34295
34525
|
await Promise.resolve().then(() => init_admin_artifacts2());
|
|
34296
34526
|
const result = await activateArtifactConsumerCommand(consumerId);
|
|
34297
34527
|
if (options.json) {
|
|
34298
|
-
|
|
34528
|
+
printJson2(result);
|
|
34299
34529
|
return;
|
|
34300
34530
|
}
|
|
34301
34531
|
console.log(`${result.consumer.consumerId}: active at seq ${result.consumer.appliedThroughSeq ?? 0}.`);
|
|
@@ -34309,7 +34539,7 @@ JSON field reference:
|
|
|
34309
34539
|
})
|
|
34310
34540
|
});
|
|
34311
34541
|
if (options.json) {
|
|
34312
|
-
|
|
34542
|
+
printJson2(result);
|
|
34313
34543
|
return;
|
|
34314
34544
|
}
|
|
34315
34545
|
console.log(`${result.events.length} event(s), seq ${result.fromSeq} through ${result.throughSeq}, head ${result.headSeq}, batch ${result.batchDigest}.`);
|
|
@@ -34328,7 +34558,7 @@ JSON field reference:
|
|
|
34328
34558
|
})
|
|
34329
34559
|
});
|
|
34330
34560
|
if (options.json) {
|
|
34331
|
-
|
|
34561
|
+
printJson2(result);
|
|
34332
34562
|
return;
|
|
34333
34563
|
}
|
|
34334
34564
|
console.log(`${result.consumer.consumerId}: applied through seq ${result.consumer.appliedThroughSeq ?? 0}.`);
|
|
@@ -34337,7 +34567,7 @@ JSON field reference:
|
|
|
34337
34567
|
await Promise.resolve().then(() => init_admin_artifacts2());
|
|
34338
34568
|
const result = await inactivateArtifactConsumerCommand(consumerId);
|
|
34339
34569
|
if (options.json) {
|
|
34340
|
-
|
|
34570
|
+
printJson2(result);
|
|
34341
34571
|
return;
|
|
34342
34572
|
}
|
|
34343
34573
|
console.log(`${result.consumer.consumerId}: inactive, bootstrap required before reuse.`);
|
|
@@ -34348,7 +34578,7 @@ JSON field reference:
|
|
|
34348
34578
|
maximum: ARTIFACT_COMPACTION_API_MAX_LIMIT
|
|
34349
34579
|
}));
|
|
34350
34580
|
if (options.json) {
|
|
34351
|
-
|
|
34581
|
+
printJson2(result);
|
|
34352
34582
|
return;
|
|
34353
34583
|
}
|
|
34354
34584
|
console.log(result.deletedCount === 0 ? `Compaction: ${result.reason}.` : `Compaction: deleted ${result.deletedCount} event(s), seq ${result.deletedFromSeq ?? 0} through ${result.deletedThroughSeq ?? 0}.`);
|
|
@@ -34402,15 +34632,15 @@ JSON field reference:
|
|
|
34402
34632
|
});
|
|
34403
34633
|
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
34634
|
await Promise.resolve().then(() => init_admin_tracks2());
|
|
34405
|
-
|
|
34635
|
+
printJson2(await prepareTrackCapturesCommand(JSON.parse(readFileSync6(options.file, "utf8"))));
|
|
34406
34636
|
});
|
|
34407
34637
|
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
34638
|
await Promise.resolve().then(() => init_admin_tracks2());
|
|
34409
|
-
|
|
34639
|
+
printJson2(await commitTrackCapturesCommand(JSON.parse(readFileSync6(options.file, "utf8"))));
|
|
34410
34640
|
});
|
|
34411
34641
|
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
34642
|
await Promise.resolve().then(() => init_admin_tracks2());
|
|
34413
|
-
|
|
34643
|
+
printJson2(await updateTrackEmbeddingsCommand(JSON.parse(readFileSync6(options.file, "utf8"))));
|
|
34414
34644
|
});
|
|
34415
34645
|
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
34646
|
await Promise.resolve().then(() => init_admin_tracks2());
|
|
@@ -34546,7 +34776,7 @@ JSON field reference:
|
|
|
34546
34776
|
await Promise.resolve().then(() => init_digests());
|
|
34547
34777
|
const paused = await getFollowDigestStateCommand();
|
|
34548
34778
|
if (options.json) {
|
|
34549
|
-
|
|
34779
|
+
printJson2({ ok: true, paused });
|
|
34550
34780
|
} else {
|
|
34551
34781
|
console.log(paused ? "Follow digests are paused." : "Follow digests are running.");
|
|
34552
34782
|
}
|
|
@@ -34559,7 +34789,7 @@ JSON field reference:
|
|
|
34559
34789
|
await Promise.resolve().then(() => init_digests());
|
|
34560
34790
|
const result = await setFollowDigestStateCommand(paused);
|
|
34561
34791
|
if (options.json) {
|
|
34562
|
-
|
|
34792
|
+
printJson2({ ok: true, paused: result });
|
|
34563
34793
|
} else {
|
|
34564
34794
|
console.log(result ? "Follow digests are paused." : "Follow digests are running.");
|
|
34565
34795
|
}
|
|
@@ -34573,7 +34803,7 @@ JSON field reference:
|
|
|
34573
34803
|
limit: options.limit === undefined ? undefined : Number(options.limit)
|
|
34574
34804
|
});
|
|
34575
34805
|
if (options.json) {
|
|
34576
|
-
|
|
34806
|
+
printJson2(result);
|
|
34577
34807
|
} else if (result.windowClosed && !result.dryRun) {
|
|
34578
34808
|
console.log("Follow digest sends open Friday at 17:00 Amsterdam.");
|
|
34579
34809
|
} else {
|
|
@@ -34845,7 +35075,7 @@ JSON field reference:
|
|
|
34845
35075
|
await Promise.resolve().then(() => init_admin_frontier2());
|
|
34846
35076
|
const summary = await frontierRefreshCommand(options);
|
|
34847
35077
|
if (options.json) {
|
|
34848
|
-
|
|
35078
|
+
printJson2(summary);
|
|
34849
35079
|
return;
|
|
34850
35080
|
}
|
|
34851
35081
|
const counts = `${summary.refreshed} refreshed, ${summary.minted} minted, ${summary.editionOnly} edition-only, ${summary.unchanged} unchanged, ${summary.failed} failed`;
|
|
@@ -34859,7 +35089,7 @@ JSON field reference:
|
|
|
34859
35089
|
await Promise.resolve().then(() => init_admin_frontier2());
|
|
34860
35090
|
const state = await frontierStatusCommand();
|
|
34861
35091
|
if (options.json) {
|
|
34862
|
-
|
|
35092
|
+
printJson2(state);
|
|
34863
35093
|
return;
|
|
34864
35094
|
}
|
|
34865
35095
|
console.log(state.open ? "Frontier minting is OPEN." : "Frontier minting is closed.");
|
|
@@ -34868,7 +35098,7 @@ JSON field reference:
|
|
|
34868
35098
|
await Promise.resolve().then(() => init_admin_frontier2());
|
|
34869
35099
|
const state = await frontierSetMintingCommand(true);
|
|
34870
35100
|
if (options.json) {
|
|
34871
|
-
|
|
35101
|
+
printJson2(state);
|
|
34872
35102
|
return;
|
|
34873
35103
|
}
|
|
34874
35104
|
console.log("Frontier minting is OPEN.");
|
|
@@ -34877,7 +35107,7 @@ JSON field reference:
|
|
|
34877
35107
|
await Promise.resolve().then(() => init_admin_frontier2());
|
|
34878
35108
|
const state = await frontierSetMintingCommand(false);
|
|
34879
35109
|
if (options.json) {
|
|
34880
|
-
|
|
35110
|
+
printJson2(state);
|
|
34881
35111
|
return;
|
|
34882
35112
|
}
|
|
34883
35113
|
console.log("Frontier minting is closed.");
|
|
@@ -34894,7 +35124,7 @@ JSON field reference:
|
|
|
34894
35124
|
await Promise.resolve().then(() => init_admin_catalogue2());
|
|
34895
35125
|
const summary = await catalogueDemandCommand();
|
|
34896
35126
|
if (options.json) {
|
|
34897
|
-
|
|
35127
|
+
printJson2({ ok: true, summary });
|
|
34898
35128
|
return;
|
|
34899
35129
|
}
|
|
34900
35130
|
if (!summary.configured) {
|
|
@@ -34911,7 +35141,7 @@ JSON field reference:
|
|
|
34911
35141
|
await Promise.resolve().then(() => init_admin_catalogue2());
|
|
34912
35142
|
const { cleared } = await clearWrongAudioCommand(trackId);
|
|
34913
35143
|
if (options.json) {
|
|
34914
|
-
|
|
35144
|
+
printJson2({ cleared, ok: true });
|
|
34915
35145
|
return;
|
|
34916
35146
|
}
|
|
34917
35147
|
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 +35150,7 @@ JSON field reference:
|
|
|
34920
35150
|
await Promise.resolve().then(() => init_admin_catalogue2());
|
|
34921
35151
|
const { paidCleared, requeued } = await requeueAnchorCommand(trackIds, options.clearPaid);
|
|
34922
35152
|
if (options.json) {
|
|
34923
|
-
|
|
35153
|
+
printJson2({ ok: true, paidCleared, requeued });
|
|
34924
35154
|
return;
|
|
34925
35155
|
}
|
|
34926
35156
|
console.log(`Re-queued ${requeued} of ${trackIds.length} row(s) \u2014 the next anchor tick picks them up at their real priority.`);
|
|
@@ -34933,7 +35163,7 @@ JSON field reference:
|
|
|
34933
35163
|
await Promise.resolve().then(() => init_admin_catalogue2());
|
|
34934
35164
|
const state = await spotifyConsumerBudgetCommand();
|
|
34935
35165
|
if (options.json || spotifyBudget.opts().json) {
|
|
34936
|
-
|
|
35166
|
+
printJson2({
|
|
34937
35167
|
consumerBudgets: state.consumerBudgets,
|
|
34938
35168
|
ok: true,
|
|
34939
35169
|
spotifyDailyCalls: state.spotifyDailyCalls
|
|
@@ -34957,7 +35187,7 @@ JSON field reference:
|
|
|
34957
35187
|
await Promise.resolve().then(() => init_admin_catalogue2());
|
|
34958
35188
|
await setSpotifyConsumerBudgetCommand(options.consumer, calls);
|
|
34959
35189
|
if (options.json || spotifyBudget.opts().json) {
|
|
34960
|
-
|
|
35190
|
+
printJson2({ calls, consumer: options.consumer, ok: true });
|
|
34961
35191
|
return;
|
|
34962
35192
|
}
|
|
34963
35193
|
console.log(`SPOTIFY BUDGET ${options.consumer} \u2014 ${calls} calls per day`);
|
|
@@ -34966,7 +35196,7 @@ JSON field reference:
|
|
|
34966
35196
|
await Promise.resolve().then(() => init_admin_catalogue2());
|
|
34967
35197
|
const state = await anchorBreakerCommand();
|
|
34968
35198
|
if (options.json) {
|
|
34969
|
-
|
|
35199
|
+
printJson2({ ...state, ok: true });
|
|
34970
35200
|
return;
|
|
34971
35201
|
}
|
|
34972
35202
|
const minutes = Math.ceil(state.cooldownRemainingMs / 60000);
|
|
@@ -34997,7 +35227,7 @@ JSON field reference:
|
|
|
34997
35227
|
since: options.since
|
|
34998
35228
|
});
|
|
34999
35229
|
if (options.json) {
|
|
35000
|
-
|
|
35230
|
+
printJson2({ ok: true, ...result });
|
|
35001
35231
|
return;
|
|
35002
35232
|
}
|
|
35003
35233
|
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 +35236,7 @@ JSON field reference:
|
|
|
35006
35236
|
await Promise.resolve().then(() => init_admin_catalogue2());
|
|
35007
35237
|
const { requeued, skippedVetoed } = await requeueUnmatchedCommand();
|
|
35008
35238
|
if (options.json) {
|
|
35009
|
-
|
|
35239
|
+
printJson2({ ok: true, requeued, skippedVetoed });
|
|
35010
35240
|
return;
|
|
35011
35241
|
}
|
|
35012
35242
|
console.log(`Re-queued ${requeued} unmatched capture(s) for the upgraded search ladder; ${skippedVetoed} stay terminal under the duration vetoes.`);
|
|
@@ -35015,7 +35245,7 @@ JSON field reference:
|
|
|
35015
35245
|
await Promise.resolve().then(() => init_admin_catalogue2());
|
|
35016
35246
|
const { flagged } = await flagWrongAudioCommand(trackId);
|
|
35017
35247
|
if (options.json) {
|
|
35018
|
-
|
|
35248
|
+
printJson2({ flagged, ok: true });
|
|
35019
35249
|
return;
|
|
35020
35250
|
}
|
|
35021
35251
|
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 +35254,7 @@ JSON field reference:
|
|
|
35024
35254
|
await Promise.resolve().then(() => init_admin_catalogue2());
|
|
35025
35255
|
const { forced } = await forceCaptureCommand(trackId);
|
|
35026
35256
|
if (options.json) {
|
|
35027
|
-
|
|
35257
|
+
printJson2({ forced, ok: true });
|
|
35028
35258
|
return;
|
|
35029
35259
|
}
|
|
35030
35260
|
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 +35264,7 @@ JSON field reference:
|
|
|
35034
35264
|
if (options.queue) {
|
|
35035
35265
|
const { tracks } = await listUnverifiedCapturesCommand(options.limit ? { limit: options.limit } : {});
|
|
35036
35266
|
if (options.json) {
|
|
35037
|
-
|
|
35267
|
+
printJson2({ ok: true, tracks });
|
|
35038
35268
|
return;
|
|
35039
35269
|
}
|
|
35040
35270
|
if (tracks.length === 0) {
|
|
@@ -35055,7 +35285,7 @@ JSON field reference:
|
|
|
35055
35285
|
}
|
|
35056
35286
|
const { action } = await verifyCaptureCommand(trackId, verdict);
|
|
35057
35287
|
if (options.json) {
|
|
35058
|
-
|
|
35288
|
+
printJson2({ action, ok: true });
|
|
35059
35289
|
return;
|
|
35060
35290
|
}
|
|
35061
35291
|
console.log(`Recorded. ${trackId} \u2192 ${action}.`);
|
|
@@ -35064,7 +35294,7 @@ JSON field reference:
|
|
|
35064
35294
|
await Promise.resolve().then(() => init_admin_catalogue2());
|
|
35065
35295
|
const { logId } = await certifyTrackCommand(trackId, options.note);
|
|
35066
35296
|
if (options.json) {
|
|
35067
|
-
|
|
35297
|
+
printJson2({ logId, ok: true });
|
|
35068
35298
|
return;
|
|
35069
35299
|
}
|
|
35070
35300
|
console.log(`Logged ${trackId} \u2014 ${logId}. Enrichment is running; finish it in the admin.`);
|
|
@@ -35073,7 +35303,7 @@ JSON field reference:
|
|
|
35073
35303
|
await Promise.resolve().then(() => init_admin_catalogue2());
|
|
35074
35304
|
const { changed } = await setTrackDismissedCommand(trackId, true);
|
|
35075
35305
|
if (options.json) {
|
|
35076
|
-
|
|
35306
|
+
printJson2({ changed, ok: true });
|
|
35077
35307
|
return;
|
|
35078
35308
|
}
|
|
35079
35309
|
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 +35312,7 @@ JSON field reference:
|
|
|
35082
35312
|
await Promise.resolve().then(() => init_admin_catalogue2());
|
|
35083
35313
|
const { changed } = await setTrackDismissedCommand(trackId, false);
|
|
35084
35314
|
if (options.json) {
|
|
35085
|
-
|
|
35315
|
+
printJson2({ changed, ok: true });
|
|
35086
35316
|
return;
|
|
35087
35317
|
}
|
|
35088
35318
|
console.log(changed ? `Restored ${trackId}. It re-enters the ranking on the next sweep.` : `${trackId} was not dismissed \u2014 nothing to restore.`);
|
|
@@ -35095,7 +35325,7 @@ JSON field reference:
|
|
|
35095
35325
|
}
|
|
35096
35326
|
const body = JSON.parse(readFileSync6(options.phaseFile, "utf8"));
|
|
35097
35327
|
const result = await crawlCataloguePhaseCommand(body);
|
|
35098
|
-
|
|
35328
|
+
printJson2(result);
|
|
35099
35329
|
return;
|
|
35100
35330
|
}
|
|
35101
35331
|
await runCrawlCatalogue(options, crawlCatalogueCommand);
|
|
@@ -35103,7 +35333,7 @@ JSON field reference:
|
|
|
35103
35333
|
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
35334
|
await Promise.resolve().then(() => init_admin_catalogue2());
|
|
35105
35335
|
const body = JSON.parse(readFileSync6(options.file, "utf8"));
|
|
35106
|
-
|
|
35336
|
+
printJson2(await commitCrawlNodesCommand(body));
|
|
35107
35337
|
});
|
|
35108
35338
|
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
35339
|
await Promise.resolve().then(() => init_admin_catalogue2());
|
|
@@ -35117,7 +35347,7 @@ JSON field reference:
|
|
|
35117
35347
|
await Promise.resolve().then(() => init_admin_reach2());
|
|
35118
35348
|
const { collected, failed, inserted, skipped } = await reachCollectCommand();
|
|
35119
35349
|
if (options.json) {
|
|
35120
|
-
|
|
35350
|
+
printJson2({ collected, failed, inserted, ok: true, skipped });
|
|
35121
35351
|
return;
|
|
35122
35352
|
}
|
|
35123
35353
|
const landed = collected.map((entry) => `${entry.platform} (${entry.metrics.join(", ")})`).join("; ");
|
|
@@ -35219,7 +35449,7 @@ JSON field reference:
|
|
|
35219
35449
|
await Promise.resolve().then(() => init_admin_artists2());
|
|
35220
35450
|
const rule = await addArtistRuleCommand(artistRuleInput(artistMbid, options.verdict, options.name));
|
|
35221
35451
|
if (options.json) {
|
|
35222
|
-
|
|
35452
|
+
printJson2({ ok: true, rule });
|
|
35223
35453
|
return;
|
|
35224
35454
|
}
|
|
35225
35455
|
console.log(artistRuleWriteLine(`Rule set for ${rule.resolvedName ?? rule.artistName}: ${rule.verdict.toUpperCase()}`, rule.verdict === "unlisted" ? UNLISTED_RULE_BOUNDARY : ARTIST_RULE_BOUNDARY));
|
|
@@ -35228,7 +35458,7 @@ JSON field reference:
|
|
|
35228
35458
|
await Promise.resolve().then(() => init_admin_artists2());
|
|
35229
35459
|
const rules = await listArtistRulesCommand();
|
|
35230
35460
|
if (options.json) {
|
|
35231
|
-
|
|
35461
|
+
printJson2({ ok: true, rules });
|
|
35232
35462
|
return;
|
|
35233
35463
|
}
|
|
35234
35464
|
console.log(artistRuleLines(rules).join(`
|
|
@@ -35238,7 +35468,7 @@ JSON field reference:
|
|
|
35238
35468
|
await Promise.resolve().then(() => init_admin_artists2());
|
|
35239
35469
|
const result = await removeArtistRuleCommand(id);
|
|
35240
35470
|
if (options.json) {
|
|
35241
|
-
|
|
35471
|
+
printJson2(result);
|
|
35242
35472
|
return;
|
|
35243
35473
|
}
|
|
35244
35474
|
console.log(artistRuleWriteLine(`Rule removed: ${id}`));
|
|
@@ -35274,7 +35504,7 @@ JSON field reference:
|
|
|
35274
35504
|
}
|
|
35275
35505
|
const result = options.replace ? await replaceLabelArtistRulesCommand(slug, parseLabelArtistRulesJson(readFileSync6(options.rulesFile ?? "", "utf8"))) : await listLabelArtistRulesCommand(slug);
|
|
35276
35506
|
if (options.json) {
|
|
35277
|
-
|
|
35507
|
+
printJson2({ ok: true, rules: result.rules });
|
|
35278
35508
|
return;
|
|
35279
35509
|
}
|
|
35280
35510
|
if (options.replace) {
|
|
@@ -35296,7 +35526,7 @@ JSON field reference:
|
|
|
35296
35526
|
await Promise.resolve().then(() => init_admin_labels2());
|
|
35297
35527
|
const label = await updateLabelCommand(slug, seedState, options.rewalk);
|
|
35298
35528
|
if (options.json) {
|
|
35299
|
-
|
|
35529
|
+
printJson2({ label, ok: true });
|
|
35300
35530
|
return;
|
|
35301
35531
|
}
|
|
35302
35532
|
for (const line of labelUpdateLines(label, options)) {
|
|
@@ -35333,7 +35563,7 @@ JSON field reference:
|
|
|
35333
35563
|
process.exitCode = 1;
|
|
35334
35564
|
}
|
|
35335
35565
|
if (options.json) {
|
|
35336
|
-
|
|
35566
|
+
printJson2(evidence);
|
|
35337
35567
|
return;
|
|
35338
35568
|
}
|
|
35339
35569
|
console.log(labelEvidenceLines(evidence).join(`
|
|
@@ -35362,7 +35592,7 @@ JSON field reference:
|
|
|
35362
35592
|
await Promise.resolve().then(() => init_admin_labels2());
|
|
35363
35593
|
const { label, outcome, takenOver } = await mintLabelCommand(mbid, seedState, takeOver);
|
|
35364
35594
|
if (options.json) {
|
|
35365
|
-
|
|
35595
|
+
printJson2({ label, ok: true, outcome, ...takenOver ? { takenOver } : {} });
|
|
35366
35596
|
return;
|
|
35367
35597
|
}
|
|
35368
35598
|
console.log(labelMintLine(label, outcome, mbid, takenOver));
|
|
@@ -35371,7 +35601,7 @@ JSON field reference:
|
|
|
35371
35601
|
await Promise.resolve().then(() => init_admin_labels2());
|
|
35372
35602
|
const result = await mergeLabelCommand(losingSlug, canonicalSlug);
|
|
35373
35603
|
if (options.json) {
|
|
35374
|
-
|
|
35604
|
+
printJson2({ ok: true, result });
|
|
35375
35605
|
return;
|
|
35376
35606
|
}
|
|
35377
35607
|
const {
|
|
@@ -35426,7 +35656,7 @@ async function runTrackPreviewArchive(idOrLogId, options, previewArchiveUploadCo
|
|
|
35426
35656
|
source: options.source
|
|
35427
35657
|
});
|
|
35428
35658
|
if (options.json) {
|
|
35429
|
-
|
|
35659
|
+
printJson2(result);
|
|
35430
35660
|
return;
|
|
35431
35661
|
}
|
|
35432
35662
|
console.log(`Archived preview for ${result.logId}`);
|
|
@@ -35457,7 +35687,7 @@ async function runTrackObserve(idOrLogId, options, trackObserveCommand) {
|
|
|
35457
35687
|
voiceId: options.voiceId
|
|
35458
35688
|
});
|
|
35459
35689
|
if (options.json) {
|
|
35460
|
-
|
|
35690
|
+
printJson2(result);
|
|
35461
35691
|
return;
|
|
35462
35692
|
}
|
|
35463
35693
|
console.log(`Recorded observation for ${result.logId}`);
|
|
@@ -35474,7 +35704,7 @@ async function runTrackContext(idOrLogId, options, trackContextCommand) {
|
|
|
35474
35704
|
refresh: options.refresh
|
|
35475
35705
|
});
|
|
35476
35706
|
if (options.json) {
|
|
35477
|
-
|
|
35707
|
+
printJson2(result);
|
|
35478
35708
|
return;
|
|
35479
35709
|
}
|
|
35480
35710
|
if (result.skipped) {
|
|
@@ -35509,7 +35739,7 @@ async function runTrackNote(idOrLogId, options, trackNoteCommand) {
|
|
|
35509
35739
|
promptVersion: parsePromptVersion(options.promptVersion)
|
|
35510
35740
|
});
|
|
35511
35741
|
if (options.json) {
|
|
35512
|
-
|
|
35742
|
+
printJson2(result);
|
|
35513
35743
|
return;
|
|
35514
35744
|
}
|
|
35515
35745
|
if (result.skipped) {
|
|
@@ -35540,7 +35770,7 @@ async function runEntityDescribe(kind, slug, options, describeCommand) {
|
|
|
35540
35770
|
promptVersion: parsePromptVersion(options.promptVersion)
|
|
35541
35771
|
});
|
|
35542
35772
|
if (options.json) {
|
|
35543
|
-
|
|
35773
|
+
printJson2(result);
|
|
35544
35774
|
return;
|
|
35545
35775
|
}
|
|
35546
35776
|
if (result.skipped) {
|
|
@@ -35565,7 +35795,7 @@ async function runEntityBioQueue(kind, options, queueCommand) {
|
|
|
35565
35795
|
const limit = options.limit ? Number.parseInt(options.limit, 10) : 50;
|
|
35566
35796
|
const items = await queueCommand(Number.isFinite(limit) ? limit : 50);
|
|
35567
35797
|
if (options.json) {
|
|
35568
|
-
|
|
35798
|
+
printJson2(items);
|
|
35569
35799
|
return;
|
|
35570
35800
|
}
|
|
35571
35801
|
if (items.length === 0) {
|
|
@@ -35581,7 +35811,7 @@ async function runEntityBioQueue(kind, options, queueCommand) {
|
|
|
35581
35811
|
async function runEntityBioDraft(kind, slug, options, draftCommand) {
|
|
35582
35812
|
const draft = await draftCommand(slug);
|
|
35583
35813
|
if (options.json) {
|
|
35584
|
-
|
|
35814
|
+
printJson2(draft);
|
|
35585
35815
|
return;
|
|
35586
35816
|
}
|
|
35587
35817
|
if (!draft.found) {
|
|
@@ -35597,7 +35827,7 @@ async function runTrackSimilar(idOrLogId, options, trackSimilarCommand) {
|
|
|
35597
35827
|
const limit = options.limit ? Number.parseInt(options.limit, 10) : undefined;
|
|
35598
35828
|
const result = await trackSimilarCommand(idOrLogId, limit !== undefined && Number.isFinite(limit) ? limit : undefined);
|
|
35599
35829
|
if (options.json) {
|
|
35600
|
-
|
|
35830
|
+
printJson2(result);
|
|
35601
35831
|
return;
|
|
35602
35832
|
}
|
|
35603
35833
|
if (result.findings.length === 0) {
|
|
@@ -35612,7 +35842,7 @@ async function runTrackSimilar(idOrLogId, options, trackSimilarCommand) {
|
|
|
35612
35842
|
}
|
|
35613
35843
|
}
|
|
35614
35844
|
function printSweepJson(payload, failedCount) {
|
|
35615
|
-
|
|
35845
|
+
printJson2({ ...payload, failedCount, ok: failedCount === 0 });
|
|
35616
35846
|
if (failedCount > 0) {
|
|
35617
35847
|
process.exitCode = 1;
|
|
35618
35848
|
}
|
|
@@ -35627,7 +35857,7 @@ async function runMigratePreviewArchive(options, migratePreviewArchiveCommand) {
|
|
|
35627
35857
|
if (mode === "verify") {
|
|
35628
35858
|
const result = await migratePreviewArchiveCommand({ dryRun: true, limit, mode });
|
|
35629
35859
|
if (options.json) {
|
|
35630
|
-
|
|
35860
|
+
printJson2({ mode, ok: true, remaining: result.remaining, sampleKeys: result.sampleKeys });
|
|
35631
35861
|
return;
|
|
35632
35862
|
}
|
|
35633
35863
|
console.log(`${result.remaining} object(s) remain under the public analysis/previews/ prefix.`);
|
|
@@ -35780,7 +36010,7 @@ async function runCrawlCatalogue(options, crawlCatalogueCommand) {
|
|
|
35780
36010
|
const maxHop = Number.parseInt(options.maxHop ?? "2", 10);
|
|
35781
36011
|
const result = await crawlCatalogueCommand(limit, Number.isInteger(maxHop) && maxHop >= 0 ? maxHop : 2, options.dryRun);
|
|
35782
36012
|
if (options.json) {
|
|
35783
|
-
|
|
36013
|
+
printJson2(result);
|
|
35784
36014
|
} else if (result.dryRun) {
|
|
35785
36015
|
console.log(`Dry run: would seed ${result.seeded} enabled label(s); ${result.frontierPending} node(s) pending. Nothing written.`);
|
|
35786
36016
|
} else {
|
|
@@ -35803,7 +36033,7 @@ async function runCrawlCatalogue(options, crawlCatalogueCommand) {
|
|
|
35803
36033
|
async function runCrawlStatus(options, crawlStatusCommand) {
|
|
35804
36034
|
const result = await crawlStatusCommand();
|
|
35805
36035
|
if (options.json) {
|
|
35806
|
-
|
|
36036
|
+
printJson2(result);
|
|
35807
36037
|
return;
|
|
35808
36038
|
}
|
|
35809
36039
|
const { frontier, frontierByKind } = result;
|
|
@@ -35845,7 +36075,7 @@ async function runBackfillDiscogs(options, backfillDiscogsCommand) {
|
|
|
35845
36075
|
cursor = result.nextCursor;
|
|
35846
36076
|
}
|
|
35847
36077
|
if (options.json) {
|
|
35848
|
-
|
|
36078
|
+
printJson2({
|
|
35849
36079
|
dryRun,
|
|
35850
36080
|
ok: true,
|
|
35851
36081
|
rateLimited: throttled,
|
|
@@ -36332,7 +36562,7 @@ async function runBackfillCoverMasters(options, backfillCoverMastersCommand) {
|
|
|
36332
36562
|
cursor = result.nextCursor;
|
|
36333
36563
|
}
|
|
36334
36564
|
if (options.json) {
|
|
36335
|
-
|
|
36565
|
+
printJson2({
|
|
36336
36566
|
dryRun,
|
|
36337
36567
|
failed,
|
|
36338
36568
|
failedCount: failed.length,
|
|
@@ -36395,7 +36625,7 @@ async function runBackfillLabelLineage(options, backfillLabelLineageCommand) {
|
|
|
36395
36625
|
cursor = result.nextCursor;
|
|
36396
36626
|
}
|
|
36397
36627
|
if (options.json) {
|
|
36398
|
-
|
|
36628
|
+
printJson2({
|
|
36399
36629
|
dryRun,
|
|
36400
36630
|
failed,
|
|
36401
36631
|
failedCount: failed.length,
|
|
@@ -36512,7 +36742,7 @@ async function runBackfillRecordingMbids(options, backfillRecordingMbidsCommand)
|
|
|
36512
36742
|
cursor = result.nextCursor;
|
|
36513
36743
|
}
|
|
36514
36744
|
if (options.json) {
|
|
36515
|
-
|
|
36745
|
+
printJson2({
|
|
36516
36746
|
dryRun,
|
|
36517
36747
|
failed,
|
|
36518
36748
|
failedCount: failed.length,
|
|
@@ -36575,7 +36805,7 @@ async function runBackfillArtistEdges(options, backfillArtistEdgesCommand) {
|
|
|
36575
36805
|
cursor = result.nextCursor;
|
|
36576
36806
|
}
|
|
36577
36807
|
if (options.json) {
|
|
36578
|
-
|
|
36808
|
+
printJson2({
|
|
36579
36809
|
dryRun,
|
|
36580
36810
|
edgesWritten,
|
|
36581
36811
|
fullyMatched,
|
|
@@ -36629,7 +36859,7 @@ async function runBackfillArtistCredits(options, backfillArtistCreditsCommand) {
|
|
|
36629
36859
|
cursor = result.nextCursor;
|
|
36630
36860
|
}
|
|
36631
36861
|
if (options.json) {
|
|
36632
|
-
|
|
36862
|
+
printJson2({
|
|
36633
36863
|
adoptedArtists,
|
|
36634
36864
|
dryRun,
|
|
36635
36865
|
edgesWritten,
|
|
@@ -36649,7 +36879,7 @@ async function runArtistResolveQueue(options, listArtistsCommand) {
|
|
|
36649
36879
|
const limit = parseListLimit(options.limit);
|
|
36650
36880
|
const result = await listArtistsCommand(limit);
|
|
36651
36881
|
if (options.json) {
|
|
36652
|
-
|
|
36882
|
+
printJson2({ artists: result.artists, ok: true });
|
|
36653
36883
|
return;
|
|
36654
36884
|
}
|
|
36655
36885
|
if (result.artists.length === 0) {
|
|
@@ -36668,7 +36898,7 @@ async function runArtistResolve(artistId, options, resolveArtistCommand) {
|
|
|
36668
36898
|
}
|
|
36669
36899
|
const result = await resolveArtistCommand(artistId);
|
|
36670
36900
|
if (options.json) {
|
|
36671
|
-
|
|
36901
|
+
printJson2(result);
|
|
36672
36902
|
return;
|
|
36673
36903
|
}
|
|
36674
36904
|
if (result.rateLimited) {
|
|
@@ -36732,7 +36962,7 @@ async function runTrackVideo(idOrLogId, options, trackVideoCommand) {
|
|
|
36732
36962
|
allowPartial: options.allowPartial
|
|
36733
36963
|
});
|
|
36734
36964
|
if (options.json) {
|
|
36735
|
-
|
|
36965
|
+
printJson2(result);
|
|
36736
36966
|
return;
|
|
36737
36967
|
}
|
|
36738
36968
|
console.log(`Linked video to ${result.logId}`);
|
|
@@ -36747,7 +36977,7 @@ async function runTrackDraft(idOrLogId, options, trackDraftCommand) {
|
|
|
36747
36977
|
const platform = options.platform ?? "tiktok";
|
|
36748
36978
|
const result = await trackDraftCommand(idOrLogId, platform);
|
|
36749
36979
|
if (options.json) {
|
|
36750
|
-
|
|
36980
|
+
printJson2(result);
|
|
36751
36981
|
return;
|
|
36752
36982
|
}
|
|
36753
36983
|
console.log(`Pushed ${platform} draft for ${result.trackId} (post ${result.externalId})`);
|
|
@@ -36759,7 +36989,7 @@ async function runTrackSocial(idOrLogId, options, trackSocialShowCommand, trackS
|
|
|
36759
36989
|
if (!options.status) {
|
|
36760
36990
|
const result = await trackSocialShowCommand(idOrLogId);
|
|
36761
36991
|
if (options.json) {
|
|
36762
|
-
|
|
36992
|
+
printJson2(result);
|
|
36763
36993
|
return;
|
|
36764
36994
|
}
|
|
36765
36995
|
if (result.posts.length === 0) {
|
|
@@ -36784,7 +37014,7 @@ async function runTrackSocial(idOrLogId, options, trackSocialShowCommand, trackS
|
|
|
36784
37014
|
url: options.url
|
|
36785
37015
|
});
|
|
36786
37016
|
if (options.json) {
|
|
36787
|
-
|
|
37017
|
+
printJson2(result);
|
|
36788
37018
|
return;
|
|
36789
37019
|
}
|
|
36790
37020
|
console.log(`${platform} \u2192 ${options.status} for ${result.trackId}`);
|
|
@@ -36796,7 +37026,7 @@ async function runTrackSocialCapture(options, trackSocialCaptureCommand) {
|
|
|
36796
37026
|
}
|
|
36797
37027
|
const result = await trackSocialCaptureCommand(limit);
|
|
36798
37028
|
if (options.json) {
|
|
36799
|
-
|
|
37029
|
+
printJson2(result);
|
|
36800
37030
|
return;
|
|
36801
37031
|
}
|
|
36802
37032
|
if (result.captured.length === 0) {
|
|
@@ -36814,7 +37044,7 @@ async function runTrackGet(idOrLogId, options, trackGetCommand) {
|
|
|
36814
37044
|
}
|
|
36815
37045
|
const result = await trackGetCommand(idOrLogId);
|
|
36816
37046
|
if (options.json) {
|
|
36817
|
-
|
|
37047
|
+
printJson2(result);
|
|
36818
37048
|
return;
|
|
36819
37049
|
}
|
|
36820
37050
|
if ("mixtape" in result) {
|
|
@@ -36840,7 +37070,7 @@ async function runMixableOrder(logIds, options, mixableOrderCommand) {
|
|
|
36840
37070
|
}
|
|
36841
37071
|
const result = await mixableOrderCommand(logIds, options.seed);
|
|
36842
37072
|
if (options.json) {
|
|
36843
|
-
|
|
37073
|
+
printJson2(result);
|
|
36844
37074
|
return;
|
|
36845
37075
|
}
|
|
36846
37076
|
console.log(`Proposed mix \u2014 a smooth chain (${result.algorithm}), not an energy-shaped set. Copy into Rekordbox as advisory.
|
|
@@ -36858,7 +37088,7 @@ async function runTrackGetAdmin(idOrLogId, options, trackGetAdminCommand) {
|
|
|
36858
37088
|
}
|
|
36859
37089
|
const result = await trackGetAdminCommand(idOrLogId);
|
|
36860
37090
|
if (options.json) {
|
|
36861
|
-
|
|
37091
|
+
printJson2(result);
|
|
36862
37092
|
return;
|
|
36863
37093
|
}
|
|
36864
37094
|
const t = result.track;
|
|
@@ -36927,7 +37157,7 @@ async function runTrackUpdate(trackId, options, trackUpdateCommand) {
|
|
|
36927
37157
|
videoUrl: options.videoUrl
|
|
36928
37158
|
});
|
|
36929
37159
|
if (options.json) {
|
|
36930
|
-
|
|
37160
|
+
printJson2(result);
|
|
36931
37161
|
return;
|
|
36932
37162
|
}
|
|
36933
37163
|
console.log(`Updated ${result.trackId}: ${result.fields.join(", ")}`);
|
|
@@ -36938,7 +37168,7 @@ async function runTrackRequeueVideo(idOrLogId, options, trackRequeueVideoCommand
|
|
|
36938
37168
|
}
|
|
36939
37169
|
const result = await trackRequeueVideoCommand(idOrLogId);
|
|
36940
37170
|
if (options.json) {
|
|
36941
|
-
|
|
37171
|
+
printJson2(result);
|
|
36942
37172
|
return;
|
|
36943
37173
|
}
|
|
36944
37174
|
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 +37192,7 @@ async function runTrackPinSource(idOrLogId, options, commands) {
|
|
|
36962
37192
|
allowDurationMismatch: options.allowDurationMismatch
|
|
36963
37193
|
});
|
|
36964
37194
|
if (options.json) {
|
|
36965
|
-
|
|
37195
|
+
printJson2(result);
|
|
36966
37196
|
return;
|
|
36967
37197
|
}
|
|
36968
37198
|
const who = result.logId ?? result.trackId;
|
|
@@ -36975,7 +37205,7 @@ async function runTrackPurgeVideo(idOrLogId, options, trackPurgeVideoCommand) {
|
|
|
36975
37205
|
}
|
|
36976
37206
|
const result = await trackPurgeVideoCommand(idOrLogId);
|
|
36977
37207
|
if (options.json) {
|
|
36978
|
-
|
|
37208
|
+
printJson2(result);
|
|
36979
37209
|
return;
|
|
36980
37210
|
}
|
|
36981
37211
|
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 +37216,7 @@ async function runMixtapeUpdate(id, options, mixtapeUpdateCommand) {
|
|
|
36986
37216
|
}
|
|
36987
37217
|
const result = await mixtapeUpdateCommand(id, options);
|
|
36988
37218
|
if (options.json) {
|
|
36989
|
-
|
|
37219
|
+
printJson2(result);
|
|
36990
37220
|
return;
|
|
36991
37221
|
}
|
|
36992
37222
|
console.log(`Saved ${result.mixtape.id}.`);
|
|
@@ -36998,7 +37228,7 @@ async function runMixtapeDistribute(idOrLogId, options, mixtapeDistributeCommand
|
|
|
36998
37228
|
const onProgress = options.json ? () => {} : (message) => console.log(message);
|
|
36999
37229
|
const result = await mixtapeDistributeCommand(idOrLogId, options, onProgress);
|
|
37000
37230
|
if (options.json) {
|
|
37001
|
-
|
|
37231
|
+
printJson2(result);
|
|
37002
37232
|
return;
|
|
37003
37233
|
}
|
|
37004
37234
|
const links = result.results.map((r) => ` ${r.platform}: ${r.url}`).join(`
|
|
@@ -37012,7 +37242,7 @@ async function runMixtapePublishYoutube(idOrLogId, options, publishYoutubeComman
|
|
|
37012
37242
|
}
|
|
37013
37243
|
const result = await publishYoutubeCommand(idOrLogId);
|
|
37014
37244
|
if (options.json) {
|
|
37015
|
-
|
|
37245
|
+
printJson2(result);
|
|
37016
37246
|
return;
|
|
37017
37247
|
}
|
|
37018
37248
|
console.log(`YouTube video is now public: ${result.url}`);
|
|
@@ -37024,7 +37254,7 @@ async function runMixtapeResync(idOrLogId, options, mixtapeResyncCommand) {
|
|
|
37024
37254
|
const onProgress = options.json ? () => {} : (message) => console.log(message);
|
|
37025
37255
|
const result = await mixtapeResyncCommand(idOrLogId, options, onProgress);
|
|
37026
37256
|
if (options.json) {
|
|
37027
|
-
|
|
37257
|
+
printJson2(result);
|
|
37028
37258
|
return;
|
|
37029
37259
|
}
|
|
37030
37260
|
const links = result.results.map((r) => ` ${r.platform}: ${r.url}`).join(`
|
|
@@ -37035,7 +37265,7 @@ ${links}`);
|
|
|
37035
37265
|
async function runMixtapeList(options, mixtapeListCommand) {
|
|
37036
37266
|
const mixtapes = await mixtapeListCommand();
|
|
37037
37267
|
if (options.json) {
|
|
37038
|
-
|
|
37268
|
+
printJson2({ mixtapes, ok: true });
|
|
37039
37269
|
return;
|
|
37040
37270
|
}
|
|
37041
37271
|
if (mixtapes.length === 0) {
|
|
@@ -37055,7 +37285,7 @@ async function runClipsList(options, clipsListCommand, clipPostsListCommand) {
|
|
|
37055
37285
|
]);
|
|
37056
37286
|
const dripByClip = new Map(posts.map((post) => [post.clipId, post]));
|
|
37057
37287
|
if (options.json) {
|
|
37058
|
-
|
|
37288
|
+
printJson2({
|
|
37059
37289
|
clips: clips.map((clip) => ({ ...clip, drip: dripByClip.get(clip.id) })),
|
|
37060
37290
|
ok: true
|
|
37061
37291
|
});
|
|
@@ -37079,7 +37309,7 @@ async function runClipsCut(clipId, options, clipCutCommand) {
|
|
|
37079
37309
|
const onProgress = options.json ? () => {} : (message) => console.log(message);
|
|
37080
37310
|
const result = await clipCutCommand(clipId, onProgress);
|
|
37081
37311
|
if (options.json) {
|
|
37082
|
-
|
|
37312
|
+
printJson2({ ok: true, ...result });
|
|
37083
37313
|
return;
|
|
37084
37314
|
}
|
|
37085
37315
|
console.log(`Cut ${result.clipId} \u2192 ${result.url} (${(result.sizeBytes / 1e6).toFixed(1)} MB).`);
|
|
@@ -37090,7 +37320,7 @@ async function runClipsSchedule(clipId, options, clipScheduleCommand) {
|
|
|
37090
37320
|
}
|
|
37091
37321
|
const post = await clipScheduleCommand(clipId, options.at);
|
|
37092
37322
|
if (options.json) {
|
|
37093
|
-
|
|
37323
|
+
printJson2({ ok: true, post });
|
|
37094
37324
|
return;
|
|
37095
37325
|
}
|
|
37096
37326
|
console.log(`Scheduled ${post.clipId} for ${post.scheduledFor}.`);
|
|
@@ -37098,7 +37328,7 @@ async function runClipsSchedule(clipId, options, clipScheduleCommand) {
|
|
|
37098
37328
|
async function runClipsDripPause(paused, options, clipDripPauseCommand) {
|
|
37099
37329
|
const result = await clipDripPauseCommand(paused);
|
|
37100
37330
|
if (options.json) {
|
|
37101
|
-
|
|
37331
|
+
printJson2({ ok: true, paused: result });
|
|
37102
37332
|
return;
|
|
37103
37333
|
}
|
|
37104
37334
|
console.log(result ? "The drip-feed is paused." : "The drip-feed is running.");
|
|
@@ -37106,7 +37336,7 @@ async function runClipsDripPause(paused, options, clipDripPauseCommand) {
|
|
|
37106
37336
|
async function runPublishAdvance(options, publishAdvanceCommand) {
|
|
37107
37337
|
const result = await publishAdvanceCommand();
|
|
37108
37338
|
if (options.json) {
|
|
37109
|
-
|
|
37339
|
+
printJson2(result);
|
|
37110
37340
|
return;
|
|
37111
37341
|
}
|
|
37112
37342
|
if (result.paused) {
|
|
@@ -37130,7 +37360,7 @@ async function runPublishAdvance(options, publishAdvanceCommand) {
|
|
|
37130
37360
|
}
|
|
37131
37361
|
function printAnchorApifyBudget(state, options) {
|
|
37132
37362
|
if (options.json) {
|
|
37133
|
-
|
|
37363
|
+
printJson2({ ...state, ok: true });
|
|
37134
37364
|
return;
|
|
37135
37365
|
}
|
|
37136
37366
|
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 +37381,7 @@ function printCaptureBudget(state) {
|
|
|
37151
37381
|
async function runCaptureBudget(options, captureBudgetCommand) {
|
|
37152
37382
|
const state = await captureBudgetCommand();
|
|
37153
37383
|
if (options.json) {
|
|
37154
|
-
|
|
37384
|
+
printJson2(state);
|
|
37155
37385
|
return;
|
|
37156
37386
|
}
|
|
37157
37387
|
printCaptureBudget(state);
|
|
@@ -37159,7 +37389,7 @@ async function runCaptureBudget(options, captureBudgetCommand) {
|
|
|
37159
37389
|
async function runSetCaptureBudget(input, options, setCaptureBudgetCommand) {
|
|
37160
37390
|
const state = await setCaptureBudgetCommand(input);
|
|
37161
37391
|
if (options.json) {
|
|
37162
|
-
|
|
37392
|
+
printJson2(state);
|
|
37163
37393
|
return;
|
|
37164
37394
|
}
|
|
37165
37395
|
printCaptureBudget(state);
|
|
@@ -37194,7 +37424,7 @@ async function runSetCaptureCaps(options, setCaptureBudgetCommand) {
|
|
|
37194
37424
|
async function runPublishAdvancePause(paused, options, publishAdvancePauseCommand) {
|
|
37195
37425
|
const result = await publishAdvancePauseCommand(paused);
|
|
37196
37426
|
if (options.json) {
|
|
37197
|
-
|
|
37427
|
+
printJson2({ ok: true, paused: result });
|
|
37198
37428
|
return;
|
|
37199
37429
|
}
|
|
37200
37430
|
console.log(result ? "The publish auto-advance is paused." : "The publish auto-advance is running.");
|
|
@@ -37205,7 +37435,7 @@ async function runMixtapeGet(idOrLogId, options, mixtapeGetCommand) {
|
|
|
37205
37435
|
}
|
|
37206
37436
|
const mixtape = await mixtapeGetCommand(idOrLogId);
|
|
37207
37437
|
if (options.json) {
|
|
37208
|
-
|
|
37438
|
+
printJson2(mixtape);
|
|
37209
37439
|
return;
|
|
37210
37440
|
}
|
|
37211
37441
|
const coordinate = mixtape.logId ?? "unminted";
|
|
@@ -37236,7 +37466,7 @@ function formatCue(ms) {
|
|
|
37236
37466
|
async function runNewsletterDraft(options, newsletterDraftCommand) {
|
|
37237
37467
|
const result = await newsletterDraftCommand(options);
|
|
37238
37468
|
if (options.json) {
|
|
37239
|
-
|
|
37469
|
+
printJson2(result);
|
|
37240
37470
|
return;
|
|
37241
37471
|
}
|
|
37242
37472
|
console.log(`Drafted edition ${result.edition.id}. It stays a draft until the operator sends it.`);
|
|
@@ -37247,7 +37477,7 @@ async function runNewsletterUpdate(id, options, newsletterUpdateCommand) {
|
|
|
37247
37477
|
}
|
|
37248
37478
|
const result = await newsletterUpdateCommand(id, options);
|
|
37249
37479
|
if (options.json) {
|
|
37250
|
-
|
|
37480
|
+
printJson2(result);
|
|
37251
37481
|
return;
|
|
37252
37482
|
}
|
|
37253
37483
|
console.log(`Saved draft ${result.edition.id}.`);
|
|
@@ -37258,7 +37488,7 @@ async function runNewsletterSend(id, options, newsletterSendCommand) {
|
|
|
37258
37488
|
}
|
|
37259
37489
|
const result = await newsletterSendCommand(id);
|
|
37260
37490
|
if (options.json) {
|
|
37261
|
-
|
|
37491
|
+
printJson2(result);
|
|
37262
37492
|
return;
|
|
37263
37493
|
}
|
|
37264
37494
|
const number = result.edition.number;
|
|
@@ -37273,7 +37503,7 @@ async function runNewsletterDelete(id, options, newsletterDeleteCommand) {
|
|
|
37273
37503
|
}
|
|
37274
37504
|
const result = await newsletterDeleteCommand(id);
|
|
37275
37505
|
if (options.json) {
|
|
37276
|
-
|
|
37506
|
+
printJson2({ ...result, ok: true });
|
|
37277
37507
|
return;
|
|
37278
37508
|
}
|
|
37279
37509
|
console.log(`Deleted edition ${result.id}. The send window reopens to cover its finds.`);
|
|
@@ -37281,7 +37511,7 @@ async function runNewsletterDelete(id, options, newsletterDeleteCommand) {
|
|
|
37281
37511
|
async function runNewsletterList(options, newsletterListCommand) {
|
|
37282
37512
|
const editions = await newsletterListCommand();
|
|
37283
37513
|
if (options.json) {
|
|
37284
|
-
|
|
37514
|
+
printJson2({ editions, ok: true });
|
|
37285
37515
|
return;
|
|
37286
37516
|
}
|
|
37287
37517
|
if (editions.length === 0) {
|
|
@@ -37298,7 +37528,7 @@ async function runLogbookGaps(options, logbookGapsCommand) {
|
|
|
37298
37528
|
const limit = options.limit === undefined ? undefined : Number.parseInt(options.limit, 10);
|
|
37299
37529
|
const { gaps, spent } = await logbookGapsCommand(limit !== undefined && Number.isFinite(limit) ? limit : undefined);
|
|
37300
37530
|
if (options.json) {
|
|
37301
|
-
|
|
37531
|
+
printJson2({ gaps, ok: true, spent });
|
|
37302
37532
|
return;
|
|
37303
37533
|
}
|
|
37304
37534
|
if (gaps.length === 0) {
|
|
@@ -37320,7 +37550,7 @@ async function runLogbookWrite(sector, options, writeCommand) {
|
|
|
37320
37550
|
title: options.title
|
|
37321
37551
|
});
|
|
37322
37552
|
if (options.json) {
|
|
37323
|
-
|
|
37553
|
+
printJson2(result);
|
|
37324
37554
|
return;
|
|
37325
37555
|
}
|
|
37326
37556
|
const skipped = "skipped" in result && result.skipped;
|
|
@@ -37335,7 +37565,7 @@ function requirePromptSlug(slug) {
|
|
|
37335
37565
|
async function runPromptsList(options, promptsListCommand) {
|
|
37336
37566
|
const prompts = await promptsListCommand();
|
|
37337
37567
|
if (options.json) {
|
|
37338
|
-
|
|
37568
|
+
printJson2({ ok: true, prompts });
|
|
37339
37569
|
return;
|
|
37340
37570
|
}
|
|
37341
37571
|
await Promise.resolve().then(() => init_admin_prompts2());
|
|
@@ -37346,7 +37576,7 @@ async function runPromptsList(options, promptsListCommand) {
|
|
|
37346
37576
|
async function runPromptGet(slug, options, promptGetCommand) {
|
|
37347
37577
|
const resolved = await promptGetCommand(requirePromptSlug(slug));
|
|
37348
37578
|
if (options.json) {
|
|
37349
|
-
|
|
37579
|
+
printJson2(resolved);
|
|
37350
37580
|
return;
|
|
37351
37581
|
}
|
|
37352
37582
|
const live = resolved.source === "override" ? `v${resolved.version}, an operator edit` : "the repo's baked default (v0)";
|
|
@@ -37357,7 +37587,7 @@ async function runPromptGet(slug, options, promptGetCommand) {
|
|
|
37357
37587
|
async function runPromptHistory(slug, options, promptDetailCommand) {
|
|
37358
37588
|
const detail = await promptDetailCommand(requirePromptSlug(slug));
|
|
37359
37589
|
if (options.json) {
|
|
37360
|
-
|
|
37590
|
+
printJson2({
|
|
37361
37591
|
activeVersion: detail.activeVersion,
|
|
37362
37592
|
ok: true,
|
|
37363
37593
|
slug: detail.slug,
|
|
@@ -37379,7 +37609,7 @@ async function runPromptDiff(slug, options, commands) {
|
|
|
37379
37609
|
const against = commands.parseAgainst(options.against);
|
|
37380
37610
|
const result = await commands.promptDiffCommand(requirePromptSlug(slug), against);
|
|
37381
37611
|
if (options.json) {
|
|
37382
|
-
|
|
37612
|
+
printJson2({ ok: true, ...result });
|
|
37383
37613
|
return;
|
|
37384
37614
|
}
|
|
37385
37615
|
const live = result.live.source === "override" ? `v${result.live.version}` : "the repo's baked default";
|
|
@@ -37400,7 +37630,7 @@ async function runPromptUpdate(slug, options, promptUpdateCommand) {
|
|
|
37400
37630
|
note: options.note
|
|
37401
37631
|
});
|
|
37402
37632
|
if (options.json) {
|
|
37403
|
-
|
|
37633
|
+
printJson2({ ok: true, ...result });
|
|
37404
37634
|
return;
|
|
37405
37635
|
}
|
|
37406
37636
|
console.log(`${result.slug}: v${result.version} is live. Nothing to deploy.`);
|
|
@@ -37416,7 +37646,7 @@ async function runPromptRollback(slug, version, options, commands) {
|
|
|
37416
37646
|
}
|
|
37417
37647
|
const result = await commands.promptRollbackCommand(promptSlug, parsed);
|
|
37418
37648
|
if (options.json) {
|
|
37419
|
-
|
|
37649
|
+
printJson2({ ok: true, ...result });
|
|
37420
37650
|
return;
|
|
37421
37651
|
}
|
|
37422
37652
|
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 +37654,7 @@ async function runPromptRollback(slug, version, options, commands) {
|
|
|
37424
37654
|
async function runPromptReset(slug, options, promptResetCommand) {
|
|
37425
37655
|
const result = await promptResetCommand(requirePromptSlug(slug));
|
|
37426
37656
|
if (options.json) {
|
|
37427
|
-
|
|
37657
|
+
printJson2({ ok: true, ...result });
|
|
37428
37658
|
return;
|
|
37429
37659
|
}
|
|
37430
37660
|
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 +37669,7 @@ async function runAdd(spotifyUrl, options, addCommand) {
|
|
|
37439
37669
|
note: options.note
|
|
37440
37670
|
});
|
|
37441
37671
|
if (options.json) {
|
|
37442
|
-
|
|
37672
|
+
printJson2({
|
|
37443
37673
|
ok: true,
|
|
37444
37674
|
...result
|
|
37445
37675
|
});
|
|
@@ -37467,7 +37697,7 @@ async function runRecent(options, recentCommand) {
|
|
|
37467
37697
|
const limit = parseListLimit(options.limit);
|
|
37468
37698
|
const tracks = await recentCommand(limit);
|
|
37469
37699
|
if (options.json) {
|
|
37470
|
-
|
|
37700
|
+
printJson2({
|
|
37471
37701
|
ok: true,
|
|
37472
37702
|
tracks
|
|
37473
37703
|
});
|
|
@@ -37485,7 +37715,7 @@ async function runGalaxies(slug, options, commands) {
|
|
|
37485
37715
|
if (slug) {
|
|
37486
37716
|
const { findings, galaxy } = await commands.galaxyGetCommand(slug);
|
|
37487
37717
|
if (options.json) {
|
|
37488
|
-
|
|
37718
|
+
printJson2({ findings, galaxy, ok: true });
|
|
37489
37719
|
return;
|
|
37490
37720
|
}
|
|
37491
37721
|
console.log(`${galaxy.name} (${galaxy.slug})`);
|
|
@@ -37498,7 +37728,7 @@ async function runGalaxies(slug, options, commands) {
|
|
|
37498
37728
|
}
|
|
37499
37729
|
const galaxies = await commands.galaxiesListCommand();
|
|
37500
37730
|
if (options.json) {
|
|
37501
|
-
|
|
37731
|
+
printJson2({ galaxies, ok: true });
|
|
37502
37732
|
return;
|
|
37503
37733
|
}
|
|
37504
37734
|
if (galaxies.length === 0) {
|
|
@@ -37515,7 +37745,7 @@ async function runArtistsRank(options, rankArtistsCommand) {
|
|
|
37515
37745
|
limit: options.limit
|
|
37516
37746
|
});
|
|
37517
37747
|
if (options.json) {
|
|
37518
|
-
|
|
37748
|
+
printJson2({ ok: true, summary });
|
|
37519
37749
|
return;
|
|
37520
37750
|
}
|
|
37521
37751
|
const removed = summary.centroidsRemoved > 0 ? ` Purged ${summary.centroidsRemoved} orphan(s).` : "";
|
|
@@ -37527,7 +37757,7 @@ async function runCatalogueRank(options, catalogueRankCommand) {
|
|
|
37527
37757
|
limit: options.limit
|
|
37528
37758
|
});
|
|
37529
37759
|
if (options.json) {
|
|
37530
|
-
|
|
37760
|
+
printJson2({ ok: true, summary, telescope });
|
|
37531
37761
|
return;
|
|
37532
37762
|
}
|
|
37533
37763
|
const quarantine = summary.quarantined > 0 ? ` Quarantined ${summary.quarantined} as wrong audio.` : "";
|
|
@@ -37548,7 +37778,7 @@ async function runCatalogueList(options, catalogueListCommand) {
|
|
|
37548
37778
|
limit: options.limit
|
|
37549
37779
|
});
|
|
37550
37780
|
if (options.json) {
|
|
37551
|
-
|
|
37781
|
+
printJson2({ ok: true, summary, tracks });
|
|
37552
37782
|
return;
|
|
37553
37783
|
}
|
|
37554
37784
|
if (tracks.length === 0) {
|
|
@@ -37584,7 +37814,7 @@ async function runCatalogueList(options, catalogueListCommand) {
|
|
|
37584
37814
|
async function runNoteHeld(options, noteHeldCommand) {
|
|
37585
37815
|
const { gate, rejections } = await noteHeldCommand({ settled: options.settled === true });
|
|
37586
37816
|
if (options.json) {
|
|
37587
|
-
|
|
37817
|
+
printJson2({ gate, ok: true, rejections });
|
|
37588
37818
|
return;
|
|
37589
37819
|
}
|
|
37590
37820
|
if (rejections.length === 0) {
|
|
@@ -37614,7 +37844,7 @@ async function runNoteGate(options, noteGateCommand) {
|
|
|
37614
37844
|
...minPhraseWords === undefined ? {} : { minPhraseWords }
|
|
37615
37845
|
});
|
|
37616
37846
|
if (options.json) {
|
|
37617
|
-
|
|
37847
|
+
printJson2({ gate, ok: true });
|
|
37618
37848
|
return;
|
|
37619
37849
|
}
|
|
37620
37850
|
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 +37852,7 @@ async function runNoteGate(options, noteGateCommand) {
|
|
|
37622
37852
|
async function runObservationHeld(options, observationHeldCommand) {
|
|
37623
37853
|
const { gate, rejections } = await observationHeldCommand({ settled: options.settled === true });
|
|
37624
37854
|
if (options.json) {
|
|
37625
|
-
|
|
37855
|
+
printJson2({ gate, ok: true, rejections });
|
|
37626
37856
|
return;
|
|
37627
37857
|
}
|
|
37628
37858
|
if (rejections.length === 0) {
|
|
@@ -37652,7 +37882,7 @@ async function runObservationGate(options, observationGateCommand) {
|
|
|
37652
37882
|
...minPhraseWords === undefined ? {} : { minPhraseWords }
|
|
37653
37883
|
});
|
|
37654
37884
|
if (options.json) {
|
|
37655
|
-
|
|
37885
|
+
printJson2({ gate, ok: true });
|
|
37656
37886
|
return;
|
|
37657
37887
|
}
|
|
37658
37888
|
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 +37890,7 @@ async function runObservationGate(options, observationGateCommand) {
|
|
|
37660
37890
|
async function runGalaxyMapRead(options, galaxyMapReadCommand) {
|
|
37661
37891
|
const galaxies = await galaxyMapReadCommand();
|
|
37662
37892
|
if (options.json) {
|
|
37663
|
-
|
|
37893
|
+
printJson2({ galaxies, ok: true });
|
|
37664
37894
|
return;
|
|
37665
37895
|
}
|
|
37666
37896
|
if (galaxies.length === 0) {
|
|
@@ -37676,7 +37906,7 @@ async function runGalaxyMapRead(options, galaxyMapReadCommand) {
|
|
|
37676
37906
|
async function runGalaxyEmbeddings(options, galaxyEmbeddingsCommand) {
|
|
37677
37907
|
const result = await galaxyEmbeddingsCommand({ cursor: options.cursor, limit: options.limit });
|
|
37678
37908
|
if (options.json) {
|
|
37679
|
-
|
|
37909
|
+
printJson2(result);
|
|
37680
37910
|
return;
|
|
37681
37911
|
}
|
|
37682
37912
|
console.log(`${result.embeddings.length} embedding(s)${result.nextCursor ? ` \xB7 nextCursor: ${result.nextCursor}` : " \xB7 end of corpus"}`);
|
|
@@ -37689,7 +37919,7 @@ async function runGalaxyMapWrite(options, galaxyMapWriteCommand) {
|
|
|
37689
37919
|
}
|
|
37690
37920
|
const galaxies = await galaxyMapWriteCommand(clusters);
|
|
37691
37921
|
if (options.json) {
|
|
37692
|
-
|
|
37922
|
+
printJson2({ galaxies, ok: true });
|
|
37693
37923
|
return;
|
|
37694
37924
|
}
|
|
37695
37925
|
console.log(`Wrote ${clusters.length} cluster(s); the map now holds ${galaxies.length} galaxy(ies).`);
|
|
@@ -37697,7 +37927,7 @@ async function runGalaxyMapWrite(options, galaxyMapWriteCommand) {
|
|
|
37697
37927
|
async function runMixtapes(options, mixtapesCommand) {
|
|
37698
37928
|
const mixtapes = await mixtapesCommand();
|
|
37699
37929
|
if (options.json) {
|
|
37700
|
-
|
|
37930
|
+
printJson2({ mixtapes, ok: true });
|
|
37701
37931
|
return;
|
|
37702
37932
|
}
|
|
37703
37933
|
if (mixtapes.length === 0) {
|
|
@@ -37832,7 +38062,7 @@ async function runAdminTracksList(options, listCommand) {
|
|
|
37832
38062
|
const hasKey = resolveHasKey(options);
|
|
37833
38063
|
const tracks = await listCommand({ hasKey, limit, order });
|
|
37834
38064
|
if (options.json) {
|
|
37835
|
-
|
|
38065
|
+
printJson2({ ok: true, tracks });
|
|
37836
38066
|
return;
|
|
37837
38067
|
}
|
|
37838
38068
|
if (tracks.length === 0) {
|
|
@@ -37850,7 +38080,7 @@ async function runAdminTracksList(options, listCommand) {
|
|
|
37850
38080
|
async function runAdminAttention(options, attentionQueueCommand) {
|
|
37851
38081
|
const queue = await attentionQueueCommand();
|
|
37852
38082
|
if (options.json) {
|
|
37853
|
-
|
|
38083
|
+
printJson2({ attention: queue, ok: true });
|
|
37854
38084
|
return;
|
|
37855
38085
|
}
|
|
37856
38086
|
await Promise.resolve().then(() => init_admin_attention());
|
|
@@ -37881,7 +38111,7 @@ async function runAdminTelemetry(options, telemetryCommand) {
|
|
|
37881
38111
|
until
|
|
37882
38112
|
});
|
|
37883
38113
|
if (options.json) {
|
|
37884
|
-
|
|
38114
|
+
printJson2({ ok: true, ...page });
|
|
37885
38115
|
return;
|
|
37886
38116
|
}
|
|
37887
38117
|
await Promise.resolve().then(() => init_admin_telemetry());
|
|
@@ -37894,7 +38124,7 @@ async function runAdminQueue(options, queueCommand) {
|
|
|
37894
38124
|
hasObservation: options.hasObservation ? true : undefined
|
|
37895
38125
|
});
|
|
37896
38126
|
if (options.json) {
|
|
37897
|
-
|
|
38127
|
+
printJson2({
|
|
37898
38128
|
ok: true,
|
|
37899
38129
|
tracks
|
|
37900
38130
|
});
|
|
@@ -37919,7 +38149,7 @@ async function runQueueView({
|
|
|
37919
38149
|
const limit = parseListLimit(options.limit);
|
|
37920
38150
|
const tracks = await fetch2(limit);
|
|
37921
38151
|
if (options.json) {
|
|
37922
|
-
|
|
38152
|
+
printJson2({
|
|
37923
38153
|
ok: true,
|
|
37924
38154
|
tracks
|
|
37925
38155
|
});
|
|
@@ -38007,7 +38237,7 @@ async function runAdminTrackWork(options, trackWorkCommand) {
|
|
|
38007
38237
|
scope
|
|
38008
38238
|
});
|
|
38009
38239
|
if (options.json) {
|
|
38010
|
-
|
|
38240
|
+
printJson2({ debtPending, ok: true, queued, tracks });
|
|
38011
38241
|
return;
|
|
38012
38242
|
}
|
|
38013
38243
|
if (debtPending === true) {
|
|
@@ -38091,7 +38321,7 @@ async function runAdminVehicles(options, vehiclesCommand) {
|
|
|
38091
38321
|
const limit = parseListLimit(options.limit);
|
|
38092
38322
|
const vehicles = await vehiclesCommand(limit);
|
|
38093
38323
|
if (options.json) {
|
|
38094
|
-
|
|
38324
|
+
printJson2({
|
|
38095
38325
|
ok: true,
|
|
38096
38326
|
vehicles
|
|
38097
38327
|
});
|
|
@@ -38137,7 +38367,7 @@ async function runOpen(target, extra, options, openCommands) {
|
|
|
38137
38367
|
async function runRandom(options, randomCommand) {
|
|
38138
38368
|
const track = await randomCommand();
|
|
38139
38369
|
if (options.json) {
|
|
38140
|
-
|
|
38370
|
+
printJson2({
|
|
38141
38371
|
ok: true,
|
|
38142
38372
|
track
|
|
38143
38373
|
});
|
|
@@ -38157,7 +38387,7 @@ async function runRandom(options, randomCommand) {
|
|
|
38157
38387
|
async function runStatus(options, statusCommand) {
|
|
38158
38388
|
const snapshot = await statusCommand();
|
|
38159
38389
|
if (options.json) {
|
|
38160
|
-
|
|
38390
|
+
printJson2({
|
|
38161
38391
|
ok: true,
|
|
38162
38392
|
...snapshot
|
|
38163
38393
|
});
|
|
@@ -38170,7 +38400,7 @@ async function runStatus(options, statusCommand) {
|
|
|
38170
38400
|
async function runMe(options, meCommand) {
|
|
38171
38401
|
const me = await meCommand();
|
|
38172
38402
|
if (options.json) {
|
|
38173
|
-
|
|
38403
|
+
printJson2({ ok: true, ...me });
|
|
38174
38404
|
return;
|
|
38175
38405
|
}
|
|
38176
38406
|
console.log(me.name);
|
|
@@ -38291,6 +38521,10 @@ function topLevelCommand(args) {
|
|
|
38291
38521
|
if (arg.startsWith("--env=")) {
|
|
38292
38522
|
continue;
|
|
38293
38523
|
}
|
|
38524
|
+
if (stringOptions.has(arg)) {
|
|
38525
|
+
index += 1;
|
|
38526
|
+
continue;
|
|
38527
|
+
}
|
|
38294
38528
|
if (!arg.startsWith("-")) {
|
|
38295
38529
|
return arg;
|
|
38296
38530
|
}
|
|
@@ -38311,6 +38545,7 @@ function normalizeCommanderError(error) {
|
|
|
38311
38545
|
return new Error(message);
|
|
38312
38546
|
}
|
|
38313
38547
|
var stringOptions = new Set([
|
|
38548
|
+
"--timeout",
|
|
38314
38549
|
"--isrc-refresh-limit",
|
|
38315
38550
|
"--action",
|
|
38316
38551
|
"--against",
|