fluncle 0.143.0 → 0.145.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 +76 -3
- package/package.json +1 -1
package/bin/fluncle.mjs
CHANGED
|
@@ -561,7 +561,7 @@ function parseVersion(version) {
|
|
|
561
561
|
var currentVersion;
|
|
562
562
|
var init_version = __esm(() => {
|
|
563
563
|
init_output();
|
|
564
|
-
currentVersion = "0.
|
|
564
|
+
currentVersion = "0.145.0".trim() ? "0.145.0".trim() : "0.1.0";
|
|
565
565
|
});
|
|
566
566
|
|
|
567
567
|
// src/update-notifier.ts
|
|
@@ -2189,7 +2189,7 @@ function parseVersion2(version) {
|
|
|
2189
2189
|
var currentVersion2, latestReleaseUrl = "https://api.github.com/repos/mauricekleine/fluncle/releases/latest";
|
|
2190
2190
|
var init_version2 = __esm(() => {
|
|
2191
2191
|
init_output();
|
|
2192
|
-
currentVersion2 = "0.
|
|
2192
|
+
currentVersion2 = "0.145.0".trim() ? "0.145.0".trim() : "0.1.0";
|
|
2193
2193
|
});
|
|
2194
2194
|
|
|
2195
2195
|
// ../../packages/registry/src/index.ts
|
|
@@ -2783,7 +2783,7 @@ var init_src = __esm(() => {
|
|
|
2783
2783
|
{
|
|
2784
2784
|
command: "ssh rave.fluncle.com",
|
|
2785
2785
|
exposedContent: [
|
|
2786
|
-
"the rave terminal TUI: Latest bangers, Mixtape archive, Submit, Subscribe, Install CLI, About",
|
|
2786
|
+
"the rave terminal TUI: Latest bangers, Artist archive, Sonic galaxies, Mixtape archive, Random banger, Submit, Subscribe, Install CLI, System status, About",
|
|
2787
2787
|
"deep-register one-shots: `ssh rave.fluncle.com latest|random`"
|
|
2788
2788
|
],
|
|
2789
2789
|
kind: "ssh",
|
|
@@ -2980,6 +2980,17 @@ var init_src = __esm(() => {
|
|
|
2980
2980
|
probeConfig: { cadenceMs: 5 * MINUTE_MS, cronName: "fluncle-capture", kind: "cron" },
|
|
2981
2981
|
weights: { status: "hidden" }
|
|
2982
2982
|
},
|
|
2983
|
+
{
|
|
2984
|
+
command: "fluncle admin catalogue verify --queue",
|
|
2985
|
+
exposedContent: [
|
|
2986
|
+
"fingerprint-check each captured song against its official preview → the wrong-audio verdict"
|
|
2987
|
+
],
|
|
2988
|
+
kind: "cron",
|
|
2989
|
+
name: "cron.verify-captures",
|
|
2990
|
+
operatorNotes: "every 30m, run by a rave-02 HOST systemd timer (docs/agents/hermes/verify-captures-timer/). The HISTORIC half of the capture verification gate (docs/the-ear.md § Wrong audio): the capture sweep verifies every NEW download at ingest, and this sweep walks every capture that landed before the gate existed and gives each the same Chromaprint check against the track's ISRC-resolved official preview. The box only MEASURES (fpcalc + the sliding-window match) and reports a plain verdict; the Worker ROUTES it — match/no-preview stamp `capture_verification`, a CATALOGUE mismatch quarantines for re-capture, a FINDING mismatch only raises the `capture-suspect` /admin attention item (a machine never rewinds a public finding; the operator rules with flag_wrong_audio). Resumable by construction (a stamped row leaves the worklist); degrades honestly without fpcalc (pre-rebake: `fpcalc_missing`, nothing stamped). Zero LLM tokens. Source: docs/agents/hermes/scripts/verify-captures.* + fingerprint-match.ts. See docs/the-ear.md.",
|
|
2991
|
+
probeConfig: { cadenceMs: 30 * MINUTE_MS, cronName: "fluncle-verify-captures", kind: "cron" },
|
|
2992
|
+
weights: { status: "hidden" }
|
|
2993
|
+
},
|
|
2983
2994
|
{
|
|
2984
2995
|
command: "fluncle admin tracks context --queue",
|
|
2985
2996
|
exposedContent: [
|
|
@@ -3572,6 +3583,7 @@ var init_admin_attention = __esm(() => {
|
|
|
3572
3583
|
SOURCE_LABELS = {
|
|
3573
3584
|
"artist-review": "artist links",
|
|
3574
3585
|
"attach-cues": "cues",
|
|
3586
|
+
"capture-suspect": "capture check",
|
|
3575
3587
|
distribute: "distribute",
|
|
3576
3588
|
"drip-empty": "clip drip",
|
|
3577
3589
|
"label-review": "label",
|
|
@@ -5715,7 +5727,10 @@ var init_admin_notes = __esm(() => {
|
|
|
5715
5727
|
// src/commands/admin-catalogue.ts
|
|
5716
5728
|
var exports_admin_catalogue = {};
|
|
5717
5729
|
__export(exports_admin_catalogue, {
|
|
5730
|
+
verifyCaptureCommand: () => verifyCaptureCommand,
|
|
5718
5731
|
setTrackDismissedCommand: () => setTrackDismissedCommand,
|
|
5732
|
+
listUnverifiedCapturesCommand: () => listUnverifiedCapturesCommand,
|
|
5733
|
+
flagWrongAudioCommand: () => flagWrongAudioCommand,
|
|
5719
5734
|
crawlStatusCommand: () => crawlStatusCommand,
|
|
5720
5735
|
crawlCatalogueCommand: () => crawlCatalogueCommand,
|
|
5721
5736
|
clearWrongAudioCommand: () => clearWrongAudioCommand,
|
|
@@ -5741,6 +5756,11 @@ async function clearWrongAudioCommand(trackId) {
|
|
|
5741
5756
|
trackId
|
|
5742
5757
|
});
|
|
5743
5758
|
}
|
|
5759
|
+
async function flagWrongAudioCommand(trackId) {
|
|
5760
|
+
return adminApiPost("/api/admin/catalogue/wrong-audio/flag", {
|
|
5761
|
+
trackId
|
|
5762
|
+
});
|
|
5763
|
+
}
|
|
5744
5764
|
async function certifyTrackCommand(trackId, note) {
|
|
5745
5765
|
return adminApiPost("/api/admin/catalogue/certify", {
|
|
5746
5766
|
...note ? { note } : {},
|
|
@@ -5753,6 +5773,19 @@ async function setTrackDismissedCommand(trackId, dismissed) {
|
|
|
5753
5773
|
trackId
|
|
5754
5774
|
});
|
|
5755
5775
|
}
|
|
5776
|
+
async function listUnverifiedCapturesCommand(options) {
|
|
5777
|
+
const params = new URLSearchParams;
|
|
5778
|
+
if (options.limit) {
|
|
5779
|
+
params.set("limit", options.limit);
|
|
5780
|
+
}
|
|
5781
|
+
return adminApiGet(`/api/admin/catalogue/captures/unverified?${params.toString()}`);
|
|
5782
|
+
}
|
|
5783
|
+
async function verifyCaptureCommand(trackId, verdict) {
|
|
5784
|
+
return adminApiPost("/api/admin/catalogue/captures/verify", {
|
|
5785
|
+
trackId,
|
|
5786
|
+
verdict
|
|
5787
|
+
});
|
|
5788
|
+
}
|
|
5756
5789
|
async function crawlCatalogueCommand(limit, maxHop, dryRun) {
|
|
5757
5790
|
const params = new URLSearchParams({ limit: String(limit), maxHop: String(maxHop) });
|
|
5758
5791
|
if (dryRun) {
|
|
@@ -8828,6 +8861,46 @@ function addAdminCommands(program2) {
|
|
|
8828
8861
|
}
|
|
8829
8862
|
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.`);
|
|
8830
8863
|
});
|
|
8864
|
+
catalogue.command("flag-wrong-audio").description("Flag a finding's captured audio as the wrong recording (operator)").argument("<trackId>", "The finding's track id whose capture is wrong").option("--json", "Print JSON", false).action(async (trackId, options) => {
|
|
8865
|
+
const { flagWrongAudioCommand: flagWrongAudioCommand2 } = await Promise.resolve().then(() => (init_admin_catalogue(), exports_admin_catalogue));
|
|
8866
|
+
const { flagged } = await flagWrongAudioCommand2(trackId);
|
|
8867
|
+
if (options.json) {
|
|
8868
|
+
printJson({ flagged, ok: true });
|
|
8869
|
+
return;
|
|
8870
|
+
}
|
|
8871
|
+
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.`);
|
|
8872
|
+
});
|
|
8873
|
+
catalogue.command("verify").description("Capture verification: the unverified worklist (--queue), or record one verdict").argument("[trackId]", "The track whose capture verdict to record (omit with --queue)").option("--queue", "List captured rows not yet verified against their preview", false).option("--verdict <verdict>", "The fingerprint verdict: match | mismatch | no-preview").option("--limit <limit>", "Worklist rows (default 50, max 200)").option("--json", "Print JSON", false).action(async (trackId, options) => {
|
|
8874
|
+
const { listUnverifiedCapturesCommand: listUnverifiedCapturesCommand2, verifyCaptureCommand: verifyCaptureCommand2 } = await Promise.resolve().then(() => (init_admin_catalogue(), exports_admin_catalogue));
|
|
8875
|
+
if (options.queue) {
|
|
8876
|
+
const { tracks } = await listUnverifiedCapturesCommand2(options.limit ? { limit: options.limit } : {});
|
|
8877
|
+
if (options.json) {
|
|
8878
|
+
printJson({ ok: true, tracks });
|
|
8879
|
+
return;
|
|
8880
|
+
}
|
|
8881
|
+
if (tracks.length === 0) {
|
|
8882
|
+
console.log("Every capture is verified. Nothing to check.");
|
|
8883
|
+
return;
|
|
8884
|
+
}
|
|
8885
|
+
for (const track of tracks) {
|
|
8886
|
+
console.log(`${track.logId ?? `${track.trackId} \xB7 catalogue`} \u2014 ${track.artists.join(", ")} \u2014 ${track.title}`);
|
|
8887
|
+
}
|
|
8888
|
+
return;
|
|
8889
|
+
}
|
|
8890
|
+
if (!trackId) {
|
|
8891
|
+
throw new Error("Pass a trackId with --verdict, or --queue for the worklist.");
|
|
8892
|
+
}
|
|
8893
|
+
const verdict = options.verdict;
|
|
8894
|
+
if (verdict !== "match" && verdict !== "mismatch" && verdict !== "no-preview") {
|
|
8895
|
+
throw new Error("--verdict must be match, mismatch, or no-preview.");
|
|
8896
|
+
}
|
|
8897
|
+
const { action } = await verifyCaptureCommand2(trackId, verdict);
|
|
8898
|
+
if (options.json) {
|
|
8899
|
+
printJson({ action, ok: true });
|
|
8900
|
+
return;
|
|
8901
|
+
}
|
|
8902
|
+
console.log(`Recorded. ${trackId} \u2192 ${action}.`);
|
|
8903
|
+
});
|
|
8831
8904
|
catalogue.command("certify").description("Certify an existing catalogue track in place \u2014 mint its finding (operator)").argument("<trackId>", "The catalogue track id to log").option("--note <note>", "An optional editorial note to mint onto the finding").option("--json", "Print JSON", false).action(async (trackId, options) => {
|
|
8832
8905
|
const { certifyTrackCommand: certifyTrackCommand2 } = await Promise.resolve().then(() => (init_admin_catalogue(), exports_admin_catalogue));
|
|
8833
8906
|
const { logId } = await certifyTrackCommand2(trackId, options.note);
|
package/package.json
CHANGED