fluncle 0.131.0 → 0.133.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 +163 -6
- 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.133.0".trim() ? "0.133.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.133.0".trim() ? "0.133.0".trim() : "0.1.0";
|
|
2193
2193
|
});
|
|
2194
2194
|
|
|
2195
2195
|
// ../../packages/registry/src/index.ts
|
|
@@ -2651,14 +2651,25 @@ var init_src = __esm(() => {
|
|
|
2651
2651
|
},
|
|
2652
2652
|
{
|
|
2653
2653
|
apiFormat: "application/xml",
|
|
2654
|
-
exposedContent: ["the XML sitemap of every public page"],
|
|
2654
|
+
exposedContent: ["the XML sitemap index of every public page"],
|
|
2655
2655
|
kind: "discovery",
|
|
2656
2656
|
name: "discovery.sitemap",
|
|
2657
|
+
operatorNotes: "A sitemap INDEX, not a flat urlset: the URLs live in children at /sitemap/<kind>-<n>.xml (pages/findings/graph/logbook), each auto-paged under Google's 50,000-URL ceiling so a breach cannot happen rather than merely not having happened yet. robots.txt still names this one URL — a crawler discovers the children from here. Splitting by kind is also the diagnostic: Search Console reports coverage PER sitemap.",
|
|
2657
2658
|
probeConfig: { cadenceMs: PROBE_CADENCE_MS, kind: "http", timeoutMs: PROBE_TIMEOUT_MS },
|
|
2658
2659
|
route: "/sitemap.xml",
|
|
2659
2660
|
url: `${SITE}/sitemap.xml`,
|
|
2660
2661
|
weights: { web: "secondary" }
|
|
2661
2662
|
},
|
|
2663
|
+
{
|
|
2664
|
+
apiFormat: "application/xml",
|
|
2665
|
+
exposedContent: ["one child sitemap: the pages / findings / graph / logbook URLs, auto-paged"],
|
|
2666
|
+
kind: "discovery",
|
|
2667
|
+
name: "discovery.sitemap-shard",
|
|
2668
|
+
probeConfig: { cadenceMs: PROBE_CADENCE_MS, kind: "http", timeoutMs: PROBE_TIMEOUT_MS },
|
|
2669
|
+
route: "/sitemap/$shard",
|
|
2670
|
+
url: `${SITE}/sitemap/pages-1.xml`,
|
|
2671
|
+
weights: {}
|
|
2672
|
+
},
|
|
2662
2673
|
{
|
|
2663
2674
|
apiFormat: "text/plain",
|
|
2664
2675
|
exposedContent: [
|
|
@@ -2836,6 +2847,15 @@ var init_src = __esm(() => {
|
|
|
2836
2847
|
name: "cli.tracks-get",
|
|
2837
2848
|
weights: { cli: "tertiary" }
|
|
2838
2849
|
},
|
|
2850
|
+
{
|
|
2851
|
+
command: "fluncle tracks similar",
|
|
2852
|
+
exposedContent: [
|
|
2853
|
+
"the findings that sound nearest to one (the sonic neighbourhood, off the MuQ audio embedding), each with its note"
|
|
2854
|
+
],
|
|
2855
|
+
kind: "cli",
|
|
2856
|
+
name: "cli.tracks-similar",
|
|
2857
|
+
weights: { cli: "tertiary" }
|
|
2858
|
+
},
|
|
2839
2859
|
{
|
|
2840
2860
|
command: "fluncle about",
|
|
2841
2861
|
exposedContent: ["Fluncle, and where to find him"],
|
|
@@ -3221,6 +3241,7 @@ __export(exports_track, {
|
|
|
3221
3241
|
trackSocialUpdateCommand: () => trackSocialUpdateCommand,
|
|
3222
3242
|
trackSocialShowCommand: () => trackSocialShowCommand,
|
|
3223
3243
|
trackSocialCaptureCommand: () => trackSocialCaptureCommand,
|
|
3244
|
+
trackSimilarCommand: () => trackSimilarCommand,
|
|
3224
3245
|
trackRequeueVideoCommand: () => trackRequeueVideoCommand,
|
|
3225
3246
|
trackPurgeVideoCommand: () => trackPurgeVideoCommand,
|
|
3226
3247
|
trackObserveCommand: () => trackObserveCommand,
|
|
@@ -3235,6 +3256,10 @@ __export(exports_track, {
|
|
|
3235
3256
|
async function trackGetCommand(idOrLogId) {
|
|
3236
3257
|
return publicApiGet(`/api/tracks/${encodeURIComponent(idOrLogId)}`);
|
|
3237
3258
|
}
|
|
3259
|
+
async function trackSimilarCommand(idOrLogId, limit) {
|
|
3260
|
+
const query = limit === undefined ? "" : `?limit=${encodeURIComponent(String(limit))}`;
|
|
3261
|
+
return publicApiGet(`/api/tracks/${encodeURIComponent(idOrLogId)}/similar${query}`);
|
|
3262
|
+
}
|
|
3238
3263
|
async function trackGetAdminCommand(idOrLogId) {
|
|
3239
3264
|
return adminApiGet(`/api/admin/tracks/${encodeURIComponent(idOrLogId)}`);
|
|
3240
3265
|
}
|
|
@@ -3438,6 +3463,9 @@ async function trackContextCommand(idOrLogId, options = {}) {
|
|
|
3438
3463
|
}
|
|
3439
3464
|
async function trackNoteCommand(idOrLogId, options) {
|
|
3440
3465
|
const body = { note: options.note };
|
|
3466
|
+
if (options.dryRun) {
|
|
3467
|
+
body.dryRun = true;
|
|
3468
|
+
}
|
|
3441
3469
|
return adminApiPost(`/api/admin/tracks/${encodeURIComponent(idOrLogId)}/note`, body);
|
|
3442
3470
|
}
|
|
3443
3471
|
var DEFAULT_VIDEO_MODEL = "anthropic/claude-opus-4-8", DEFAULT_VIDEO_REASONING = "high", FOUND_BASE = "https://found.fluncle.com", VIDEO_FIELDS, RERENDER_CONTRACT_FIELDS, RERENDER_ADVISORY_FIELDS, FOOTAGE_FIELDS, PLATE_FIELDS, NON_FILE_OPTIONS;
|
|
@@ -4200,6 +4228,22 @@ var init_publish = __esm(() => {
|
|
|
4200
4228
|
init_api();
|
|
4201
4229
|
});
|
|
4202
4230
|
|
|
4231
|
+
// src/commands/capture.ts
|
|
4232
|
+
var exports_capture = {};
|
|
4233
|
+
__export(exports_capture, {
|
|
4234
|
+
setCaptureBudgetCommand: () => setCaptureBudgetCommand,
|
|
4235
|
+
captureBudgetCommand: () => captureBudgetCommand
|
|
4236
|
+
});
|
|
4237
|
+
async function captureBudgetCommand() {
|
|
4238
|
+
return adminApiGet("/api/admin/catalogue/capture-budget");
|
|
4239
|
+
}
|
|
4240
|
+
async function setCaptureBudgetCommand(input) {
|
|
4241
|
+
return adminApiPut("/api/admin/catalogue/capture-budget", input);
|
|
4242
|
+
}
|
|
4243
|
+
var init_capture = __esm(() => {
|
|
4244
|
+
init_api();
|
|
4245
|
+
});
|
|
4246
|
+
|
|
4203
4247
|
// ../../packages/contracts/src/util/multipart.ts
|
|
4204
4248
|
function planMultipart(contentLength, partSize = DEFAULT_PART_SIZE) {
|
|
4205
4249
|
if (!Number.isInteger(contentLength) || contentLength <= 0) {
|
|
@@ -8019,6 +8063,10 @@ function addTrackCommands(program2) {
|
|
|
8019
8063
|
const { trackGetCommand: trackGetCommand2 } = await Promise.resolve().then(() => (init_track(), exports_track));
|
|
8020
8064
|
await runTrackGet(idOrLogId, options, trackGetCommand2);
|
|
8021
8065
|
});
|
|
8066
|
+
tracks.command("similar").description("The findings that sound nearest to one (the sonic neighbourhood)").argument("[idOrLogId]").option("--limit <limit>", "Number of neighbours to show", "6").option("--json", "Print JSON", false).allowExcessArguments().action(async (idOrLogId, options) => {
|
|
8067
|
+
const { trackSimilarCommand: trackSimilarCommand2 } = await Promise.resolve().then(() => (init_track(), exports_track));
|
|
8068
|
+
await runTrackSimilar(idOrLogId, options, trackSimilarCommand2);
|
|
8069
|
+
});
|
|
8022
8070
|
}
|
|
8023
8071
|
function addAdminCommands(program2) {
|
|
8024
8072
|
const admin = configureCommand(program2.command("admin", { hidden: true }).description("Operator commands"));
|
|
@@ -8147,7 +8195,7 @@ function addAdminCommands(program2) {
|
|
|
8147
8195
|
const { trackContextCommand: trackContextCommand2 } = await Promise.resolve().then(() => (init_track(), exports_track));
|
|
8148
8196
|
await runTrackContext(idOrLogId, options, trackContextCommand2);
|
|
8149
8197
|
});
|
|
8150
|
-
adminTrack.command("note").description("Author the editorial note for a finding (fills an empty note only)").argument("[idOrLogId]").option("--queue", "Show the note worklist (context'd findings with no note yet), oldest first", false).option("--limit <limit>", "Number of findings to show with --queue", "10").option("--script <text>", "The voice-gated editorial note").option("--script-file <file>", "Read the editorial note from a file").option("--json", "Print JSON", false).allowExcessArguments().action(async (idOrLogId, options) => {
|
|
8198
|
+
adminTrack.command("note").description("Author the editorial note for a finding (fills an empty note only)").argument("[idOrLogId]").option("--queue", "Show the note worklist (context'd findings with no note yet), oldest first", false).option("--limit <limit>", "Number of findings to show with --queue", "10").option("--script <text>", "The voice-gated editorial note").option("--script-file <file>", "Read the editorial note from a file").option("--dry-run", "Run the voice + echo gates and report the verdict without storing anything", false).option("--json", "Print JSON", false).allowExcessArguments().action(async (idOrLogId, options) => {
|
|
8151
8199
|
if (options.queue) {
|
|
8152
8200
|
const { noteQueueCommand: noteQueueCommand2 } = await Promise.resolve().then(() => (init_admin_tracks(), exports_admin_tracks));
|
|
8153
8201
|
await runAdminNoteQueue(options, noteQueueCommand2);
|
|
@@ -8200,6 +8248,26 @@ function addAdminCommands(program2) {
|
|
|
8200
8248
|
const { publishAdvancePauseCommand: publishAdvancePauseCommand2 } = await Promise.resolve().then(() => (init_publish(), exports_publish));
|
|
8201
8249
|
await runPublishAdvancePause(false, options, publishAdvancePauseCommand2);
|
|
8202
8250
|
});
|
|
8251
|
+
const adminCapture = configureCommand(admin.command("capture").description("The metered audio-capture budget and its kill switch"));
|
|
8252
|
+
adminCapture.action(() => {
|
|
8253
|
+
adminCapture.outputHelp();
|
|
8254
|
+
});
|
|
8255
|
+
adminCapture.command("budget").description("What catalogue capture spent in the last 24h, and how much budget is left").option("--json", "Print JSON", false).allowExcessArguments().action(async (options) => {
|
|
8256
|
+
const { captureBudgetCommand: captureBudgetCommand2 } = await Promise.resolve().then(() => (init_capture(), exports_capture));
|
|
8257
|
+
await runCaptureBudget(options, captureBudgetCommand2);
|
|
8258
|
+
});
|
|
8259
|
+
adminCapture.command("pause").description("Stop all catalogue audio capture \u2014 the kill switch (operator)").option("--json", "Print JSON", false).allowExcessArguments().action(async (options) => {
|
|
8260
|
+
const { setCaptureBudgetCommand: setCaptureBudgetCommand2 } = await Promise.resolve().then(() => (init_capture(), exports_capture));
|
|
8261
|
+
await runSetCaptureBudget({ paused: true }, options, setCaptureBudgetCommand2);
|
|
8262
|
+
});
|
|
8263
|
+
adminCapture.command("resume").description("Let catalogue audio capture spend again, up to its budget (operator)").option("--json", "Print JSON", false).allowExcessArguments().action(async (options) => {
|
|
8264
|
+
const { setCaptureBudgetCommand: setCaptureBudgetCommand2 } = await Promise.resolve().then(() => (init_capture(), exports_capture));
|
|
8265
|
+
await runSetCaptureBudget({ paused: false }, options, setCaptureBudgetCommand2);
|
|
8266
|
+
});
|
|
8267
|
+
adminCapture.command("set").description("Set the rolling-24h capture caps (operator)").option("--tracks <n>", "Max catalogue downloads per rolling 24h").option("--gb <n>", "Max GB downloaded per rolling 24h").option("--json", "Print JSON", false).allowExcessArguments().action(async (options) => {
|
|
8268
|
+
const { setCaptureBudgetCommand: setCaptureBudgetCommand2 } = await Promise.resolve().then(() => (init_capture(), exports_capture));
|
|
8269
|
+
await runSetCaptureCaps(options, setCaptureBudgetCommand2);
|
|
8270
|
+
});
|
|
8203
8271
|
const adminClips = configureCommand(admin.command("clips").description("Mixtape clip (Fluncle Studio) commands"));
|
|
8204
8272
|
adminClips.action(() => {
|
|
8205
8273
|
adminClips.outputHelp();
|
|
@@ -8509,9 +8577,12 @@ async function runTrackContext(idOrLogId, options, trackContextCommand2) {
|
|
|
8509
8577
|
async function runTrackNote(idOrLogId, options, trackNoteCommand2) {
|
|
8510
8578
|
const note = options.scriptFile ? readFileSync6(options.scriptFile, "utf8") : options.script;
|
|
8511
8579
|
if (!idOrLogId || !note || !note.trim()) {
|
|
8512
|
-
throw new Error("Usage: fluncle admin tracks note <track_id|log_id> (--script <text> | --script-file <file>) [--json]");
|
|
8580
|
+
throw new Error("Usage: fluncle admin tracks note <track_id|log_id> (--script <text> | --script-file <file>) [--dry-run] [--json]");
|
|
8513
8581
|
}
|
|
8514
|
-
const result = await trackNoteCommand2(idOrLogId, {
|
|
8582
|
+
const result = await trackNoteCommand2(idOrLogId, {
|
|
8583
|
+
dryRun: options.dryRun,
|
|
8584
|
+
note: note.trim()
|
|
8585
|
+
});
|
|
8515
8586
|
if (options.json) {
|
|
8516
8587
|
printJson(result);
|
|
8517
8588
|
return;
|
|
@@ -8520,9 +8591,39 @@ async function runTrackNote(idOrLogId, options, trackNoteCommand2) {
|
|
|
8520
8591
|
console.log(`A note is already on file for ${result.logId}. The operator's note stands.`);
|
|
8521
8592
|
return;
|
|
8522
8593
|
}
|
|
8594
|
+
if (result.dryRun) {
|
|
8595
|
+
console.log(`Both gates passed for ${result.logId}. Nothing was stored (dry run).`);
|
|
8596
|
+
console.log(` ${result.note}`);
|
|
8597
|
+
if (result.echo?.logId) {
|
|
8598
|
+
const reading = result.echo.phrase ? `lifts "${result.echo.phrase}" from ${result.echo.logId}` : `${Math.round(result.echo.overlap * 100)}% word overlap with ${result.echo.logId}`;
|
|
8599
|
+
console.log(` echo: ${reading}`);
|
|
8600
|
+
}
|
|
8601
|
+
return;
|
|
8602
|
+
}
|
|
8523
8603
|
console.log(`Authored the note for ${result.logId}:`);
|
|
8524
8604
|
console.log(` ${result.note}`);
|
|
8525
8605
|
}
|
|
8606
|
+
async function runTrackSimilar(idOrLogId, options, trackSimilarCommand2) {
|
|
8607
|
+
if (!idOrLogId) {
|
|
8608
|
+
throw new Error("Missing id. Usage: fluncle tracks similar <track_id|log_id> [--limit <n>] [--json]");
|
|
8609
|
+
}
|
|
8610
|
+
const limit = options.limit ? Number.parseInt(options.limit, 10) : undefined;
|
|
8611
|
+
const result = await trackSimilarCommand2(idOrLogId, limit !== undefined && Number.isFinite(limit) ? limit : undefined);
|
|
8612
|
+
if (options.json) {
|
|
8613
|
+
printJson(result);
|
|
8614
|
+
return;
|
|
8615
|
+
}
|
|
8616
|
+
if (result.findings.length === 0) {
|
|
8617
|
+
console.log("Nothing sounds near this one yet. It may still be waiting on its embedding.");
|
|
8618
|
+
return;
|
|
8619
|
+
}
|
|
8620
|
+
for (const finding of result.findings) {
|
|
8621
|
+
console.log(`${finding.logId ?? "\u2014"} ${finding.artists.join(", ")} \u2014 ${finding.title}`);
|
|
8622
|
+
if (finding.note) {
|
|
8623
|
+
console.log(` ${finding.note}`);
|
|
8624
|
+
}
|
|
8625
|
+
}
|
|
8626
|
+
}
|
|
8526
8627
|
function printSweepJson(payload, failedCount) {
|
|
8527
8628
|
printJson({ ...payload, failedCount, ok: failedCount === 0 });
|
|
8528
8629
|
if (failedCount > 0) {
|
|
@@ -9319,6 +9420,60 @@ async function runPublishAdvance(options, publishAdvanceCommand2) {
|
|
|
9319
9420
|
console.log(`Failed ${failure.platform} for ${failure.trackId} \u2014 left for the operator.`);
|
|
9320
9421
|
}
|
|
9321
9422
|
}
|
|
9423
|
+
var GB = 1073741824;
|
|
9424
|
+
function formatGb(bytes) {
|
|
9425
|
+
return `${(bytes / GB).toFixed(2)} GB`;
|
|
9426
|
+
}
|
|
9427
|
+
function printCaptureBudget(state) {
|
|
9428
|
+
const reason = state.closedReason === "paused" ? "paused \u2014 you stopped it" : state.closedReason === "tracks_spent" ? "the daily track cap is spent" : state.closedReason === "bytes_spent" ? "the daily GB cap is spent" : "";
|
|
9429
|
+
console.log(state.open ? "Catalogue capture is RUNNING \u2014 it may buy audio, up to the budget below." : `Catalogue capture is STOPPED (${reason}). Findings still capture as normal.`);
|
|
9430
|
+
console.log(` Last ${state.windowHours}h: ${state.spend.tracks} ${state.spend.tracks === 1 ? "track" : "tracks"} \xB7 ${formatGb(state.spend.bytes)}`);
|
|
9431
|
+
console.log(` Budget: ${state.budget.dailyTracks} tracks \xB7 ${formatGb(state.budget.dailyBytes)} per ${state.windowHours}h`);
|
|
9432
|
+
console.log(` Left: ${state.remainingTracks} ${state.remainingTracks === 1 ? "track" : "tracks"} \xB7 ${formatGb(state.remainingBytes)}`);
|
|
9433
|
+
}
|
|
9434
|
+
async function runCaptureBudget(options, captureBudgetCommand2) {
|
|
9435
|
+
const state = await captureBudgetCommand2();
|
|
9436
|
+
if (options.json) {
|
|
9437
|
+
printJson(state);
|
|
9438
|
+
return;
|
|
9439
|
+
}
|
|
9440
|
+
printCaptureBudget(state);
|
|
9441
|
+
}
|
|
9442
|
+
async function runSetCaptureBudget(input, options, setCaptureBudgetCommand2) {
|
|
9443
|
+
const state = await setCaptureBudgetCommand2(input);
|
|
9444
|
+
if (options.json) {
|
|
9445
|
+
printJson(state);
|
|
9446
|
+
return;
|
|
9447
|
+
}
|
|
9448
|
+
printCaptureBudget(state);
|
|
9449
|
+
}
|
|
9450
|
+
async function runSetCaptureCaps(options, setCaptureBudgetCommand2) {
|
|
9451
|
+
const input = {};
|
|
9452
|
+
if (options.tracks !== undefined) {
|
|
9453
|
+
const tracks = Number(options.tracks);
|
|
9454
|
+
if (!Number.isInteger(tracks) || tracks < 0) {
|
|
9455
|
+
console.error("--tracks must be a whole number of tracks (0 or more).");
|
|
9456
|
+
process.exitCode = 1;
|
|
9457
|
+
return;
|
|
9458
|
+
}
|
|
9459
|
+
input.dailyTracks = tracks;
|
|
9460
|
+
}
|
|
9461
|
+
if (options.gb !== undefined) {
|
|
9462
|
+
const gb = Number(options.gb);
|
|
9463
|
+
if (!Number.isFinite(gb) || gb < 0) {
|
|
9464
|
+
console.error("--gb must be a number of gigabytes (0 or more).");
|
|
9465
|
+
process.exitCode = 1;
|
|
9466
|
+
return;
|
|
9467
|
+
}
|
|
9468
|
+
input.dailyBytes = Math.round(gb * GB);
|
|
9469
|
+
}
|
|
9470
|
+
if (input.dailyTracks === undefined && input.dailyBytes === undefined) {
|
|
9471
|
+
console.error("Nothing to set \u2014 pass --tracks and/or --gb.");
|
|
9472
|
+
process.exitCode = 1;
|
|
9473
|
+
return;
|
|
9474
|
+
}
|
|
9475
|
+
await runSetCaptureBudget(input, options, setCaptureBudgetCommand2);
|
|
9476
|
+
}
|
|
9322
9477
|
async function runPublishAdvancePause(paused, options, publishAdvancePauseCommand2) {
|
|
9323
9478
|
const result = await publishAdvancePauseCommand2(paused);
|
|
9324
9479
|
if (options.json) {
|
|
@@ -10189,6 +10344,7 @@ var stringOptions = new Set([
|
|
|
10189
10344
|
"--footage-social",
|
|
10190
10345
|
"--from",
|
|
10191
10346
|
"--galaxy-id",
|
|
10347
|
+
"--gb",
|
|
10192
10348
|
"--has-key",
|
|
10193
10349
|
"--intent",
|
|
10194
10350
|
"--key",
|
|
@@ -10227,6 +10383,7 @@ var stringOptions = new Set([
|
|
|
10227
10383
|
"--title",
|
|
10228
10384
|
"--token",
|
|
10229
10385
|
"--tracklist-file",
|
|
10386
|
+
"--tracks",
|
|
10230
10387
|
"--url",
|
|
10231
10388
|
"--verdict",
|
|
10232
10389
|
"--verdict-file",
|
package/package.json
CHANGED