fluncle 0.158.0 → 0.160.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 +87 -5
  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.158.0".trim() ? "0.158.0".trim() : "0.1.0";
564
+ currentVersion = "0.160.0".trim() ? "0.160.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.158.0".trim() ? "0.158.0".trim() : "0.1.0";
2192
+ currentVersion2 = "0.160.0".trim() ? "0.160.0".trim() : "0.1.0";
2193
2193
  });
2194
2194
 
2195
2195
  // ../../packages/registry/src/index.ts
@@ -2349,11 +2349,11 @@ var init_src = __esm(() => {
2349
2349
  {
2350
2350
  discoveryUrl: `${SITE}/llms.txt`,
2351
2351
  exposedContent: [
2352
- "/artist/:slug — one artist's page: every published finding from that artist, plus their identity links"
2352
+ "/artist/:slug — one artist's page: its findings, its identity links, and the rest of its catalogue"
2353
2353
  ],
2354
2354
  kind: "web_route",
2355
2355
  name: "web.artist",
2356
- operatorNotes: "Slug is real-name kebab-case (e.g. /artist/dbridge). Read-only; only artists with at least one published finding resolve (others 404). No probeConfig — the route is slug-parameterized, so there is no fixed URL to GET-probe.",
2356
+ operatorNotes: "Slug is real-name kebab-case (e.g. /artist/dbridge). Read-only; an artist earns a page on its CONTENT exactly as a label/album does — a row renders (a findings-free discovered artist included), a slug with no row 404s, and a page below the thin-content floor renders noindex + stays out of the sitemap (the ARTIST_INDEX_MIN_FINDINGS precedent). No probeConfig — the route is slug-parameterized, so there is no fixed URL to GET-probe.",
2357
2357
  route: "/artist",
2358
2358
  url: `${SITE}/artist`,
2359
2359
  weights: { ssh: "secondary", web: "secondary" }
@@ -2380,7 +2380,7 @@ var init_src = __esm(() => {
2380
2380
  ],
2381
2381
  kind: "web_route",
2382
2382
  name: "web.albums",
2383
- operatorNotes: "The album half of the graph, and the node that closes it: the album page carries the album → label edge (a link, plus `albumRelease.recordLabel` in its MusicAlbum JSON-LD). The INDEX is probeable (always 200); the slug page is not. Bounded by the archive, not the cataloguean album earns a page by carrying a finding (docs/album-entity.md).",
2383
+ operatorNotes: "The album half of the graph, and the node that closes it: the album page carries the album → label edge (a link, plus `albumRelease.recordLabel` in its MusicAlbum JSON-LD). The INDEX is probeable (always 200); the slug page is not. The `/albums` index stays archive-bounded (findings-joined), but a crawl-minted findings-free album is PUBLIC on its content a row renders its page, a below-floor page renders noindex + stays out of the sitemap, like a discovered label (docs/album-entity.md).",
2384
2384
  probeConfig: { cadenceMs: PROBE_CADENCE_MS, kind: "http", timeoutMs: PROBE_TIMEOUT_MS },
2385
2385
  route: "/albums",
2386
2386
  url: `${SITE}/albums`,
@@ -2969,6 +2969,23 @@ var init_src = __esm(() => {
2969
2969
  title: "Track ranking",
2970
2970
  weights: { status: "hidden" }
2971
2971
  },
2972
+ {
2973
+ command: "fluncle admin frontier refresh",
2974
+ exposedContent: [
2975
+ "re-mirror every crew member's Fluncle's Frontier playlist from their current recommendations"
2976
+ ],
2977
+ kind: "cron",
2978
+ name: "cron.frontier-refresh",
2979
+ operatorNotes: "weekly (Fri 07:00 Amsterdam), run by a rave-02 HOST systemd timer (docs/agents/hermes/frontier-refresh-timer/). E2, the public recommendation machine: every verified user can mint ONE public 'Fluncle's Frontier' playlist on Fluncle's OWN Spotify account (no per-user OAuth), holding THEIR recommendations (the E1 blend); this cron is the Discover-Weekly-style refresh that keeps each one current. The walk + the Spotify item replaces all happen inside the Worker; the sweep just fires one `fluncle admin frontier refresh`. It respects the DEFAULT-DENY `frontier.minting` kill switch (a closed switch touches nothing), skips playlists whose recommendation set is unchanged (a per-row URI-hash mirror guard), and creates no new public authority — every playlist it touches already exists, minted by its own owner. `refresh_frontier_playlists` is AGENT tier, so the box's existing agent-scoped token drives it: NO new secret. Zero LLM tokens. Source: docs/agents/hermes/scripts/frontier-refresh-sweep.*. See docs/the-ear.md § Fluncle's Frontier.",
2980
+ probeConfig: {
2981
+ cadenceMs: 7 * 24 * 60 * MINUTE_MS,
2982
+ cronName: "fluncle-frontier-refresh",
2983
+ kind: "cron"
2984
+ },
2985
+ statusDescription: "refreshes every crew member's Frontier playlist",
2986
+ title: "Frontier refresh",
2987
+ weights: { status: "hidden" }
2988
+ },
2972
2989
  {
2973
2990
  command: "fluncle admin backfills label-images",
2974
2991
  exposedContent: [
@@ -5884,6 +5901,27 @@ var init_admin_observations = __esm(() => {
5884
5901
  init_api();
5885
5902
  });
5886
5903
 
5904
+ // src/commands/admin-frontier.ts
5905
+ var exports_admin_frontier = {};
5906
+ __export(exports_admin_frontier, {
5907
+ frontierStatusCommand: () => frontierStatusCommand,
5908
+ frontierSetMintingCommand: () => frontierSetMintingCommand,
5909
+ frontierRefreshCommand: () => frontierRefreshCommand
5910
+ });
5911
+ async function frontierRefreshCommand(options) {
5912
+ const limit = options.limit ? Number.parseInt(options.limit, 10) : undefined;
5913
+ return adminApiPost("/api/admin/frontier-playlists/refresh", limit ? { limit } : {});
5914
+ }
5915
+ async function frontierStatusCommand() {
5916
+ return adminApiGet("/api/admin/frontier/minting");
5917
+ }
5918
+ async function frontierSetMintingCommand(open) {
5919
+ return adminApiPut("/api/admin/frontier/minting", { open });
5920
+ }
5921
+ var init_admin_frontier = __esm(() => {
5922
+ init_api();
5923
+ });
5924
+
5887
5925
  // src/commands/admin-catalogue.ts
5888
5926
  var exports_admin_catalogue = {};
5889
5927
  __export(exports_admin_catalogue, {
@@ -9111,6 +9149,50 @@ function addAdminCommands(program2) {
9111
9149
  const { observationGateCommand: observationGateCommand2 } = await Promise.resolve().then(() => (init_admin_observations(), exports_admin_observations));
9112
9150
  await runObservationGate(options, observationGateCommand2);
9113
9151
  });
9152
+ const frontier = configureCommand(admin.command("frontier").description("The Frontier playlists (per-user recommendations)"));
9153
+ frontier.action(() => {
9154
+ frontier.outputHelp();
9155
+ });
9156
+ frontier.command("refresh").description("Re-mirror every crew member's Frontier playlist from their recommendations").option("--limit <limit>", "Playlists per tick (default 500)").option("--json", "Print JSON", false).action(async (options) => {
9157
+ const { frontierRefreshCommand: frontierRefreshCommand2 } = await Promise.resolve().then(() => (init_admin_frontier(), exports_admin_frontier));
9158
+ const summary = await frontierRefreshCommand2(options);
9159
+ if (options.json) {
9160
+ printJson(summary);
9161
+ return;
9162
+ }
9163
+ if (summary.switchOff) {
9164
+ console.log("Frontier minting is paused (the kill switch is closed). Nothing refreshed.");
9165
+ return;
9166
+ }
9167
+ console.log(`Walked ${summary.total} playlist(s): ${summary.refreshed} refreshed, ${summary.unchanged} unchanged, ${summary.minted} minted, ${summary.skipped} skipped, ${summary.failed} failed.`);
9168
+ });
9169
+ frontier.command("status").description("Whether Frontier minting is open (the kill switch's state)").option("--json", "Print JSON", false).action(async (options) => {
9170
+ const { frontierStatusCommand: frontierStatusCommand2 } = await Promise.resolve().then(() => (init_admin_frontier(), exports_admin_frontier));
9171
+ const state = await frontierStatusCommand2();
9172
+ if (options.json) {
9173
+ printJson(state);
9174
+ return;
9175
+ }
9176
+ console.log(state.open ? "Frontier minting is OPEN." : "Frontier minting is closed.");
9177
+ });
9178
+ frontier.command("open").description("Open Frontier minting \u2014 the kill switch (operator)").option("--json", "Print JSON", false).action(async (options) => {
9179
+ const { frontierSetMintingCommand: frontierSetMintingCommand2 } = await Promise.resolve().then(() => (init_admin_frontier(), exports_admin_frontier));
9180
+ const state = await frontierSetMintingCommand2(true);
9181
+ if (options.json) {
9182
+ printJson(state);
9183
+ return;
9184
+ }
9185
+ console.log("Frontier minting is OPEN.");
9186
+ });
9187
+ frontier.command("close").description("Close Frontier minting \u2014 the kill switch (operator)").option("--json", "Print JSON", false).action(async (options) => {
9188
+ const { frontierSetMintingCommand: frontierSetMintingCommand2 } = await Promise.resolve().then(() => (init_admin_frontier(), exports_admin_frontier));
9189
+ const state = await frontierSetMintingCommand2(false);
9190
+ if (options.json) {
9191
+ printJson(state);
9192
+ return;
9193
+ }
9194
+ console.log("Frontier minting is closed.");
9195
+ });
9114
9196
  const catalogue = configureCommand(admin.command("catalogue").description("The catalogue (uncertified tracks): the crawler + its ranking"));
9115
9197
  catalogue.action(() => {
9116
9198
  catalogue.outputHelp();
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.158.0"
34
+ "version": "0.160.0"
35
35
  }