fluncle 0.132.0 → 0.134.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.
Files changed (2) hide show
  1. package/bin/fluncle.mjs +116 -8
  2. 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.132.0".trim() ? "0.132.0".trim() : "0.1.0";
564
+ currentVersion = "0.134.0".trim() ? "0.134.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.132.0".trim() ? "0.132.0".trim() : "0.1.0";
2192
+ currentVersion2 = "0.134.0".trim() ? "0.134.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: [
@@ -3732,8 +3743,11 @@ async function trackWorkCommand(options) {
3732
3743
  limit: String(Math.min(Math.max(1, options.limit), 200)),
3733
3744
  scope: options.scope
3734
3745
  });
3746
+ if (options.count) {
3747
+ params.set("count", "true");
3748
+ }
3735
3749
  const response = await adminApiGet(`/api/admin/tracks/work?${params.toString()}`);
3736
- return response.tracks ?? [];
3750
+ return { queued: response.queued, tracks: response.tracks ?? [] };
3737
3751
  }
3738
3752
  async function requeueAnalysisCommand(options) {
3739
3753
  const findings = await fetchAdminTracks({ max: options.max, order: "asc" });
@@ -4217,6 +4231,22 @@ var init_publish = __esm(() => {
4217
4231
  init_api();
4218
4232
  });
4219
4233
 
4234
+ // src/commands/capture.ts
4235
+ var exports_capture = {};
4236
+ __export(exports_capture, {
4237
+ setCaptureBudgetCommand: () => setCaptureBudgetCommand,
4238
+ captureBudgetCommand: () => captureBudgetCommand
4239
+ });
4240
+ async function captureBudgetCommand() {
4241
+ return adminApiGet("/api/admin/catalogue/capture-budget");
4242
+ }
4243
+ async function setCaptureBudgetCommand(input) {
4244
+ return adminApiPut("/api/admin/catalogue/capture-budget", input);
4245
+ }
4246
+ var init_capture = __esm(() => {
4247
+ init_api();
4248
+ });
4249
+
4220
4250
  // ../../packages/contracts/src/util/multipart.ts
4221
4251
  function planMultipart(contentLength, partSize = DEFAULT_PART_SIZE) {
4222
4252
  if (!Number.isInteger(contentLength) || contentLength <= 0) {
@@ -8096,7 +8126,7 @@ function addAdminCommands(program2) {
8096
8126
  const { captureQueueCommand: captureQueueCommand2 } = await Promise.resolve().then(() => (init_admin_tracks(), exports_admin_tracks));
8097
8127
  await runAdminCaptureQueue(options, captureQueueCommand2);
8098
8128
  });
8099
- adminTracks.command("work").description("The audio pipeline's worklist for one stage, in capture-priority order").requiredOption("--kind <kind>", "Pipeline stage: analyze | capture | embed").option("--scope <scope>", "Which half of the archive: all | catalogue | findings", "all").option("--limit <limit>", "Rows to show", "10").option("--json", "Print JSON", false).action(async (options) => {
8129
+ adminTracks.command("work").description("The audio pipeline's worklist for one stage, in capture-priority order").requiredOption("--kind <kind>", "Pipeline stage: analyze | capture | embed").option("--scope <scope>", "Which half of the archive: all | catalogue | findings", "all").option("--limit <limit>", "Rows to show", "10").option("--count", "Also report the size of the whole backlog, not just this page", false).option("--json", "Print JSON", false).action(async (options) => {
8100
8130
  const { trackWorkCommand: trackWorkCommand2 } = await Promise.resolve().then(() => (init_admin_tracks(), exports_admin_tracks));
8101
8131
  await runAdminTrackWork(options, trackWorkCommand2);
8102
8132
  });
@@ -8221,6 +8251,26 @@ function addAdminCommands(program2) {
8221
8251
  const { publishAdvancePauseCommand: publishAdvancePauseCommand2 } = await Promise.resolve().then(() => (init_publish(), exports_publish));
8222
8252
  await runPublishAdvancePause(false, options, publishAdvancePauseCommand2);
8223
8253
  });
8254
+ const adminCapture = configureCommand(admin.command("capture").description("The metered audio-capture budget and its kill switch"));
8255
+ adminCapture.action(() => {
8256
+ adminCapture.outputHelp();
8257
+ });
8258
+ 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) => {
8259
+ const { captureBudgetCommand: captureBudgetCommand2 } = await Promise.resolve().then(() => (init_capture(), exports_capture));
8260
+ await runCaptureBudget(options, captureBudgetCommand2);
8261
+ });
8262
+ adminCapture.command("pause").description("Stop all catalogue audio capture \u2014 the kill switch (operator)").option("--json", "Print JSON", false).allowExcessArguments().action(async (options) => {
8263
+ const { setCaptureBudgetCommand: setCaptureBudgetCommand2 } = await Promise.resolve().then(() => (init_capture(), exports_capture));
8264
+ await runSetCaptureBudget({ paused: true }, options, setCaptureBudgetCommand2);
8265
+ });
8266
+ adminCapture.command("resume").description("Let catalogue audio capture spend again, up to its budget (operator)").option("--json", "Print JSON", false).allowExcessArguments().action(async (options) => {
8267
+ const { setCaptureBudgetCommand: setCaptureBudgetCommand2 } = await Promise.resolve().then(() => (init_capture(), exports_capture));
8268
+ await runSetCaptureBudget({ paused: false }, options, setCaptureBudgetCommand2);
8269
+ });
8270
+ 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) => {
8271
+ const { setCaptureBudgetCommand: setCaptureBudgetCommand2 } = await Promise.resolve().then(() => (init_capture(), exports_capture));
8272
+ await runSetCaptureCaps(options, setCaptureBudgetCommand2);
8273
+ });
8224
8274
  const adminClips = configureCommand(admin.command("clips").description("Mixtape clip (Fluncle Studio) commands"));
8225
8275
  adminClips.action(() => {
8226
8276
  adminClips.outputHelp();
@@ -9373,6 +9423,60 @@ async function runPublishAdvance(options, publishAdvanceCommand2) {
9373
9423
  console.log(`Failed ${failure.platform} for ${failure.trackId} \u2014 left for the operator.`);
9374
9424
  }
9375
9425
  }
9426
+ var GB = 1073741824;
9427
+ function formatGb(bytes) {
9428
+ return `${(bytes / GB).toFixed(2)} GB`;
9429
+ }
9430
+ function printCaptureBudget(state) {
9431
+ 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" : "";
9432
+ 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.`);
9433
+ console.log(` Last ${state.windowHours}h: ${state.spend.tracks} ${state.spend.tracks === 1 ? "track" : "tracks"} \xB7 ${formatGb(state.spend.bytes)}`);
9434
+ console.log(` Budget: ${state.budget.dailyTracks} tracks \xB7 ${formatGb(state.budget.dailyBytes)} per ${state.windowHours}h`);
9435
+ console.log(` Left: ${state.remainingTracks} ${state.remainingTracks === 1 ? "track" : "tracks"} \xB7 ${formatGb(state.remainingBytes)}`);
9436
+ }
9437
+ async function runCaptureBudget(options, captureBudgetCommand2) {
9438
+ const state = await captureBudgetCommand2();
9439
+ if (options.json) {
9440
+ printJson(state);
9441
+ return;
9442
+ }
9443
+ printCaptureBudget(state);
9444
+ }
9445
+ async function runSetCaptureBudget(input, options, setCaptureBudgetCommand2) {
9446
+ const state = await setCaptureBudgetCommand2(input);
9447
+ if (options.json) {
9448
+ printJson(state);
9449
+ return;
9450
+ }
9451
+ printCaptureBudget(state);
9452
+ }
9453
+ async function runSetCaptureCaps(options, setCaptureBudgetCommand2) {
9454
+ const input = {};
9455
+ if (options.tracks !== undefined) {
9456
+ const tracks = Number(options.tracks);
9457
+ if (!Number.isInteger(tracks) || tracks < 0) {
9458
+ console.error("--tracks must be a whole number of tracks (0 or more).");
9459
+ process.exitCode = 1;
9460
+ return;
9461
+ }
9462
+ input.dailyTracks = tracks;
9463
+ }
9464
+ if (options.gb !== undefined) {
9465
+ const gb = Number(options.gb);
9466
+ if (!Number.isFinite(gb) || gb < 0) {
9467
+ console.error("--gb must be a number of gigabytes (0 or more).");
9468
+ process.exitCode = 1;
9469
+ return;
9470
+ }
9471
+ input.dailyBytes = Math.round(gb * GB);
9472
+ }
9473
+ if (input.dailyTracks === undefined && input.dailyBytes === undefined) {
9474
+ console.error("Nothing to set \u2014 pass --tracks and/or --gb.");
9475
+ process.exitCode = 1;
9476
+ return;
9477
+ }
9478
+ await runSetCaptureBudget(input, options, setCaptureBudgetCommand2);
9479
+ }
9376
9480
  async function runPublishAdvancePause(paused, options, publishAdvancePauseCommand2) {
9377
9481
  const result = await publishAdvancePauseCommand2(paused);
9378
9482
  if (options.json) {
@@ -9909,13 +10013,14 @@ async function runAdminTrackWork(options, trackWorkCommand2) {
9909
10013
  process.exitCode = 1;
9910
10014
  return;
9911
10015
  }
9912
- const tracks = await trackWorkCommand2({
10016
+ const { queued, tracks } = await trackWorkCommand2({
10017
+ count: options.count,
9913
10018
  kind,
9914
10019
  limit: parseListLimit(options.limit),
9915
10020
  scope
9916
10021
  });
9917
10022
  if (options.json) {
9918
- printJson({ ok: true, tracks });
10023
+ printJson({ ok: true, queued, tracks });
9919
10024
  return;
9920
10025
  }
9921
10026
  if (tracks.length === 0) {
@@ -9923,7 +10028,8 @@ async function runAdminTrackWork(options, trackWorkCommand2) {
9923
10028
  return;
9924
10029
  }
9925
10030
  const noun = tracks.length === 1 ? "track" : "tracks";
9926
- console.log(`${tracks.length} ${noun} to ${kind} (${scope}), in drain order:`);
10031
+ const head = queued === undefined ? `${tracks.length} ${noun} to ${kind} (${scope}), in drain order:` : `${queued} queued to ${kind} (${scope}) \u2014 showing the first ${tracks.length}, in drain order:`;
10032
+ console.log(head);
9927
10033
  for (const track of tracks) {
9928
10034
  const who = track.logId ?? `${track.trackId} \xB7 catalogue`;
9929
10035
  const rung = track.capturePriority === null ? "" : ` \xB7 p${track.capturePriority}`;
@@ -10243,6 +10349,7 @@ var stringOptions = new Set([
10243
10349
  "--footage-social",
10244
10350
  "--from",
10245
10351
  "--galaxy-id",
10352
+ "--gb",
10246
10353
  "--has-key",
10247
10354
  "--intent",
10248
10355
  "--key",
@@ -10281,6 +10388,7 @@ var stringOptions = new Set([
10281
10388
  "--title",
10282
10389
  "--token",
10283
10390
  "--tracklist-file",
10391
+ "--tracks",
10284
10392
  "--url",
10285
10393
  "--verdict",
10286
10394
  "--verdict-file",
package/package.json CHANGED
@@ -31,5 +31,5 @@
31
31
  "url": "git+https://github.com/mauricekleine/fluncle.git"
32
32
  },
33
33
  "type": "module",
34
- "version": "0.132.0"
34
+ "version": "0.134.0"
35
35
  }