fluncle 0.166.0 → 0.168.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 +124 -7
- 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.168.0".trim() ? "0.168.0".trim() : "0.1.0";
|
|
565
565
|
});
|
|
566
566
|
|
|
567
567
|
// src/update-notifier.ts
|
|
@@ -2229,7 +2229,7 @@ function parseVersion2(version) {
|
|
|
2229
2229
|
var currentVersion2, latestReleaseUrl = "https://api.github.com/repos/mauricekleine/fluncle/releases/latest";
|
|
2230
2230
|
var init_version2 = __esm(() => {
|
|
2231
2231
|
init_output();
|
|
2232
|
-
currentVersion2 = "0.
|
|
2232
|
+
currentVersion2 = "0.168.0".trim() ? "0.168.0".trim() : "0.1.0";
|
|
2233
2233
|
});
|
|
2234
2234
|
|
|
2235
2235
|
// ../../packages/registry/src/index.ts
|
|
@@ -2708,6 +2708,29 @@ var init_src = __esm(() => {
|
|
|
2708
2708
|
url: `${SITE}/feed.json`,
|
|
2709
2709
|
weights: { web: "secondary" }
|
|
2710
2710
|
},
|
|
2711
|
+
{
|
|
2712
|
+
apiFormat: "application/rss+xml",
|
|
2713
|
+
exposedContent: [
|
|
2714
|
+
"the newest drum & bass releases over a 30-day window, as RSS (release-dated, not found-dated)"
|
|
2715
|
+
],
|
|
2716
|
+
kind: "feed",
|
|
2717
|
+
name: "feed.fresh.rss",
|
|
2718
|
+
probeConfig: { cadenceMs: PROBE_CADENCE_MS, kind: "http", timeoutMs: PROBE_TIMEOUT_MS },
|
|
2719
|
+
route: "/fresh.xml",
|
|
2720
|
+
url: `${SITE}/fresh.xml`,
|
|
2721
|
+
weights: { web: "secondary" }
|
|
2722
|
+
},
|
|
2723
|
+
{
|
|
2724
|
+
apiFormat: "application/feed+json",
|
|
2725
|
+
exposedContent: [
|
|
2726
|
+
"the newest drum & bass releases over a 30-day window, as a JSON Feed (release-dated)"
|
|
2727
|
+
],
|
|
2728
|
+
kind: "feed",
|
|
2729
|
+
name: "feed.fresh.json",
|
|
2730
|
+
route: "/fresh.json",
|
|
2731
|
+
url: `${SITE}/fresh.json`,
|
|
2732
|
+
weights: { web: "secondary" }
|
|
2733
|
+
},
|
|
2711
2734
|
{
|
|
2712
2735
|
apiFormat: "application/rss+xml",
|
|
2713
2736
|
exposedContent: ["the mixtapes as a podcast feed (episode audio on found.fluncle.com)"],
|
|
@@ -2833,7 +2856,7 @@ var init_src = __esm(() => {
|
|
|
2833
2856
|
apiFormat: "application/json",
|
|
2834
2857
|
discoveryUrl: `${SITE}/.well-known/mcp/server-card.json`,
|
|
2835
2858
|
exposedContent: [
|
|
2836
|
-
"the archive as MCP tools (Streamable HTTP, no auth): list_tracks, get_track, get_random_track, get_status, search_tracks, submit_track, subscribe_newsletter",
|
|
2859
|
+
"the archive as MCP tools (Streamable HTTP, no auth): list_tracks, list_fresh, get_track, get_random_track, get_status, search_tracks, submit_track, subscribe_newsletter",
|
|
2837
2860
|
"the archive as MCP resources: each finding/mixtape at fluncle://finding/<logId> or fluncle://mixtape/<logId> (its public record)",
|
|
2838
2861
|
"Fluncle-voiced MCP prompts: recommend_finding, walk_recent_night, decode_coordinate"
|
|
2839
2862
|
],
|
|
@@ -2860,8 +2883,8 @@ var init_src = __esm(() => {
|
|
|
2860
2883
|
{
|
|
2861
2884
|
command: "ssh rave.fluncle.com",
|
|
2862
2885
|
exposedContent: [
|
|
2863
|
-
"the rave terminal TUI: Latest bangers, Artist archive, Sonic galaxies, Mixtape archive, Random banger, Submit, Subscribe, Install CLI, System status, About",
|
|
2864
|
-
"deep-register one-shots: `ssh rave.fluncle.com latest|random`"
|
|
2886
|
+
"the rave terminal TUI: Latest bangers, Fresh releases, Artist archive, Sonic galaxies, Mixtape archive, Random banger, Submit, Subscribe, Install CLI, System status, About",
|
|
2887
|
+
"deep-register one-shots: `ssh rave.fluncle.com latest|fresh|random`"
|
|
2865
2888
|
],
|
|
2866
2889
|
kind: "ssh",
|
|
2867
2890
|
name: "ssh.rave",
|
|
@@ -2877,6 +2900,13 @@ var init_src = __esm(() => {
|
|
|
2877
2900
|
name: "cli.recent",
|
|
2878
2901
|
weights: { cli: "primary", web: "tertiary" }
|
|
2879
2902
|
},
|
|
2903
|
+
{
|
|
2904
|
+
command: "fluncle fresh",
|
|
2905
|
+
exposedContent: ["the newest drum & bass releases, newest out first"],
|
|
2906
|
+
kind: "cli",
|
|
2907
|
+
name: "cli.fresh",
|
|
2908
|
+
weights: { cli: "secondary", web: "tertiary" }
|
|
2909
|
+
},
|
|
2880
2910
|
{
|
|
2881
2911
|
command: "fluncle mixtapes",
|
|
2882
2912
|
exposedContent: ["Fluncle's checkpoint sets"],
|
|
@@ -3089,6 +3119,19 @@ var init_src = __esm(() => {
|
|
|
3089
3119
|
title: "Recording MBIDs",
|
|
3090
3120
|
weights: { status: "hidden" }
|
|
3091
3121
|
},
|
|
3122
|
+
{
|
|
3123
|
+
command: "fluncle admin backfills label-lineage",
|
|
3124
|
+
exposedContent: [
|
|
3125
|
+
"resolve each label's founding date + place + parent imprint from MusicBrainz → the labels row"
|
|
3126
|
+
],
|
|
3127
|
+
kind: "cron",
|
|
3128
|
+
name: "cron.label-lineage",
|
|
3129
|
+
operatorNotes: "every 60m, run by a rave-02 HOST systemd timer (docs/agents/hermes/label-lineage-timer/). The label entity's LINEAGE half (RFC label-lineage-remixer, U1): gives each label its founding facts + its place in the imprint hierarchy from MusicBrainz — `life-span.begin` → `founding_date`, `area.name` → `founded_location`, and the `backward` `label ownership` / `imprint` label-rels → `parent_label_id` (matched to an EXISTING label by MBID; NEVER minted — an unmatched parent is only counted). A dedicated sweep, not a rider on the label-image sweep, because that one is terminal per label and a logo-resolved label would never get its lineage: this carries its OWN `lineage_state` machine so it reaches every label once. METADATA ONLY — it certifies nothing, mints nothing, publishes nothing (agent tier, the `backfill_label_images` precedent). Worker-paced (the box holds no MusicBrainz budget): one bounded batch per tick, 1 req/s, circuit-broken on a throttle, reusing the shared MB client + exact-fold identity search. The `labels` row carries the durable reliability state (lineage_state/lineage_attempted_at/lineage_failures), so a resolved/none label is terminal. Emitted as the `/label/<slug>` Organization's `foundingDate` / `location` / `parentOrganization` / `subOrganization`. Zero LLM tokens. Source: docs/agents/hermes/scripts/label-lineage-sweep.*. See docs/label-entity.md.",
|
|
3130
|
+
probeConfig: { cadenceMs: 60 * MINUTE_MS, cronName: "fluncle-label-lineage", kind: "cron" },
|
|
3131
|
+
statusDescription: "resolves each label's founding and imprint",
|
|
3132
|
+
title: "Label lineage",
|
|
3133
|
+
weights: { status: "hidden" }
|
|
3134
|
+
},
|
|
3092
3135
|
{
|
|
3093
3136
|
command: "fluncle admin backfills cover-masters",
|
|
3094
3137
|
exposedContent: [
|
|
@@ -3625,7 +3668,8 @@ async function trackVideoCommand(idOrLogId, files, onProgress, options = {}) {
|
|
|
3625
3668
|
...squared ? { squared: true } : {},
|
|
3626
3669
|
...manifest.vehicle ? { videoVehicle: manifest.vehicle } : {},
|
|
3627
3670
|
...manifest.grain ? { videoGrain: manifest.grain } : {},
|
|
3628
|
-
...manifest.register ? { videoRegister: manifest.register } : {}
|
|
3671
|
+
...manifest.register ? { videoRegister: manifest.register } : {},
|
|
3672
|
+
...manifest.palette ? { videoPalette: manifest.palette } : {}
|
|
3629
3673
|
});
|
|
3630
3674
|
return { logId: finalize.logId, ok: true, trackId: finalize.trackId, urls };
|
|
3631
3675
|
}
|
|
@@ -3634,7 +3678,7 @@ async function readManifestFields(renderPath) {
|
|
|
3634
3678
|
try {
|
|
3635
3679
|
const manifest = await Bun.file(renderPath).json();
|
|
3636
3680
|
const parsed = {};
|
|
3637
|
-
for (const key of ["vehicle", "grain", "model", "reasoning", "register"]) {
|
|
3681
|
+
for (const key of ["vehicle", "grain", "model", "reasoning", "register", "palette"]) {
|
|
3638
3682
|
const value = manifest[key];
|
|
3639
3683
|
if (typeof value === "string" && value.trim()) {
|
|
3640
3684
|
parsed[key] = value.trim().slice(0, 120);
|
|
@@ -4146,6 +4190,7 @@ async function vehiclesCommand(limit) {
|
|
|
4146
4190
|
artists: track.artists,
|
|
4147
4191
|
grain: track.videoGrain,
|
|
4148
4192
|
logId: track.logId,
|
|
4193
|
+
palette: track.videoPalette,
|
|
4149
4194
|
register: track.videoRegister,
|
|
4150
4195
|
title: track.title,
|
|
4151
4196
|
vehicle: track.videoVehicle
|
|
@@ -6218,6 +6263,7 @@ __export(exports_admin_labels, {
|
|
|
6218
6263
|
labelsBioQueueCommand: () => labelsBioQueueCommand,
|
|
6219
6264
|
draftLabelBioCommand: () => draftLabelBioCommand,
|
|
6220
6265
|
describeLabelCommand: () => describeLabelCommand,
|
|
6266
|
+
backfillLabelLineageCommand: () => backfillLabelLineageCommand,
|
|
6221
6267
|
backfillLabelImagesCommand: () => backfillLabelImagesCommand
|
|
6222
6268
|
});
|
|
6223
6269
|
async function describeLabelCommand(slug, options) {
|
|
@@ -6237,6 +6283,13 @@ async function backfillLabelImagesCommand(limit, dryRun, cursor) {
|
|
|
6237
6283
|
}
|
|
6238
6284
|
return adminApiPost(`/api/admin/backfill/label-images?${params.toString()}`);
|
|
6239
6285
|
}
|
|
6286
|
+
async function backfillLabelLineageCommand(limit, dryRun, cursor) {
|
|
6287
|
+
const params = new URLSearchParams({ dryRun: String(dryRun), limit: String(limit) });
|
|
6288
|
+
if (cursor) {
|
|
6289
|
+
params.set("cursor", cursor);
|
|
6290
|
+
}
|
|
6291
|
+
return adminApiPost(`/api/admin/backfill/label-lineage?${params.toString()}`);
|
|
6292
|
+
}
|
|
6240
6293
|
var init_admin_labels = __esm(() => {
|
|
6241
6294
|
init_api();
|
|
6242
6295
|
init_admin_artists2();
|
|
@@ -9478,6 +9531,10 @@ function addAdminCommands(program2) {
|
|
|
9478
9531
|
const { backfillLabelImagesCommand: backfillLabelImagesCommand2 } = await Promise.resolve().then(() => (init_admin_labels(), exports_admin_labels));
|
|
9479
9532
|
await runBackfillLabelImages(options, backfillLabelImagesCommand2);
|
|
9480
9533
|
});
|
|
9534
|
+
backfill.command("label-lineage").description("Resolve label lineage (founding date, place, parent imprint) from MusicBrainz").option("--dry-run", "Report the eligible worklist without any vendor call or write", false).option("--limit <limit>", "Max labels to process", "50").option("--json", "Print JSON", false).action(async (options) => {
|
|
9535
|
+
const { backfillLabelLineageCommand: backfillLabelLineageCommand2 } = await Promise.resolve().then(() => (init_admin_labels(), exports_admin_labels));
|
|
9536
|
+
await runBackfillLabelLineage(options, backfillLabelLineageCommand2);
|
|
9537
|
+
});
|
|
9481
9538
|
backfill.command("recording-mbids").description("Fill MusicBrainz recording MBIDs (crawler PK strip + ISRC resolve) over tracks").option("--dry-run", "Report the eligible worklist without any vendor call or write", false).option("--limit <limit>", "Max ISRC lookups to process", "50").option("--json", "Print JSON", false).action(async (options) => {
|
|
9482
9539
|
const { backfillRecordingMbidsCommand: backfillRecordingMbidsCommand2 } = await Promise.resolve().then(() => (init_admin_tracks(), exports_admin_tracks));
|
|
9483
9540
|
await runBackfillRecordingMbids(options, backfillRecordingMbidsCommand2);
|
|
@@ -10276,6 +10333,66 @@ async function runBackfillCoverMasters(options, backfillCoverMastersCommand2) {
|
|
|
10276
10333
|
process.exitCode = 1;
|
|
10277
10334
|
}
|
|
10278
10335
|
}
|
|
10336
|
+
async function runBackfillLabelLineage(options, backfillLabelLineageCommand2) {
|
|
10337
|
+
const limit = parseListLimit(options.limit);
|
|
10338
|
+
const resolved = [];
|
|
10339
|
+
const none = [];
|
|
10340
|
+
const failed = [];
|
|
10341
|
+
let cursor;
|
|
10342
|
+
let dryRun = options.dryRun;
|
|
10343
|
+
let throttled = false;
|
|
10344
|
+
let unmatchedParents = 0;
|
|
10345
|
+
while (resolved.length + none.length + failed.length < limit) {
|
|
10346
|
+
const remaining = limit - (resolved.length + none.length + failed.length);
|
|
10347
|
+
const result = await backfillLabelLineageCommand2(remaining, options.dryRun, cursor);
|
|
10348
|
+
dryRun = result.dryRun;
|
|
10349
|
+
resolved.push(...result.resolved);
|
|
10350
|
+
none.push(...result.none);
|
|
10351
|
+
failed.push(...result.failed);
|
|
10352
|
+
unmatchedParents += result.unmatchedParents;
|
|
10353
|
+
if (!options.json) {
|
|
10354
|
+
const verb2 = result.dryRun ? "would walk" : "walked";
|
|
10355
|
+
console.log(` \u2026${verb2} ${result.resolvedCount}; ${result.noneCount} with no MusicBrainz identity; ${result.failedCount} failed; ${result.unmatchedParents} unmatched parent(s)`);
|
|
10356
|
+
}
|
|
10357
|
+
if (result.rateLimited) {
|
|
10358
|
+
throttled = true;
|
|
10359
|
+
break;
|
|
10360
|
+
}
|
|
10361
|
+
if (result.nextCursor === null) {
|
|
10362
|
+
break;
|
|
10363
|
+
}
|
|
10364
|
+
cursor = result.nextCursor;
|
|
10365
|
+
}
|
|
10366
|
+
if (options.json) {
|
|
10367
|
+
printJson({
|
|
10368
|
+
dryRun,
|
|
10369
|
+
failed,
|
|
10370
|
+
failedCount: failed.length,
|
|
10371
|
+
none,
|
|
10372
|
+
noneCount: none.length,
|
|
10373
|
+
ok: true,
|
|
10374
|
+
rateLimited: throttled,
|
|
10375
|
+
resolved,
|
|
10376
|
+
resolvedCount: resolved.length,
|
|
10377
|
+
unmatchedParents
|
|
10378
|
+
});
|
|
10379
|
+
if (failed.length > 0) {
|
|
10380
|
+
process.exitCode = 1;
|
|
10381
|
+
}
|
|
10382
|
+
return;
|
|
10383
|
+
}
|
|
10384
|
+
const verb = dryRun ? "Would walk" : "Walked";
|
|
10385
|
+
console.log(`${verb} ${resolved.length} label lineage(s); ${none.length} with no MusicBrainz identity; ${failed.length} failed; ${unmatchedParents} unmatched parent(s).`);
|
|
10386
|
+
for (const slug of resolved) {
|
|
10387
|
+
console.log(` ${slug}`);
|
|
10388
|
+
}
|
|
10389
|
+
for (const item of failed) {
|
|
10390
|
+
console.log(` ${item.slug}: ${item.error}`);
|
|
10391
|
+
}
|
|
10392
|
+
if (failed.length > 0) {
|
|
10393
|
+
process.exitCode = 1;
|
|
10394
|
+
}
|
|
10395
|
+
}
|
|
10279
10396
|
async function runBackfillLabelImages(options, backfillLabelImagesCommand2) {
|
|
10280
10397
|
const limit = parseListLimit(options.limit);
|
|
10281
10398
|
const resolved = [];
|
package/package.json
CHANGED