fluncle 0.156.0 → 0.157.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 +68 -7
  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.156.0".trim() ? "0.156.0".trim() : "0.1.0";
564
+ currentVersion = "0.157.0".trim() ? "0.157.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.156.0".trim() ? "0.156.0".trim() : "0.1.0";
2192
+ currentVersion2 = "0.157.0".trim() ? "0.157.0".trim() : "0.1.0";
2193
2193
  });
2194
2194
 
2195
2195
  // ../../packages/registry/src/index.ts
@@ -2913,6 +2913,8 @@ var init_src = __esm(() => {
2913
2913
  name: "cron.enrich",
2914
2914
  operatorNotes: "every 5m. Pure compute, zero LLM tokens. Source: docs/agents/hermes/scripts/enrich-sweep.*",
2915
2915
  probeConfig: { cadenceMs: 5 * MINUTE_MS, cronName: "fluncle-enrich", kind: "cron" },
2916
+ statusDescription: "BPM, key, and the spectral fingerprint",
2917
+ title: "Audio enrichment",
2916
2918
  weights: { status: "hidden" }
2917
2919
  },
2918
2920
  {
@@ -2924,6 +2926,8 @@ var init_src = __esm(() => {
2924
2926
  name: "cron.embed",
2925
2927
  operatorNotes: "every 5m. On-box MuQ (torch, ~16s/track), zero LLM tokens. Writes the vector via the agent-tier update_track. Source: docs/agents/hermes/scripts/embed-sweep.* + embed-track.py. See docs/track-lifecycle.md.",
2926
2928
  probeConfig: { cadenceMs: 5 * MINUTE_MS, cronName: "fluncle-embed", kind: "cron" },
2929
+ statusDescription: "MuQ vectors for sonic similarity",
2930
+ title: "Audio embeddings",
2927
2931
  weights: { status: "hidden" }
2928
2932
  },
2929
2933
  {
@@ -2935,6 +2939,8 @@ var init_src = __esm(() => {
2935
2939
  name: "cron.cluster",
2936
2940
  operatorNotes: "nightly (02:20 Amsterdam), run by a rave-02 HOST systemd timer (docs/agents/hermes/cluster-timer/). Assignment-ONLY + idempotent (a no-op on an unchanged corpus): assign each finding to its nearest stored centroid, recompute centroids as members' means, retire an emptied galaxy, consume an operator split_requested_at (a k=2 fit). Zero LLM tokens; sub-second CPU. A full k=9 fit is an OPERATOR act (--cold-start / --remint), never scheduled. Source: docs/agents/hermes/scripts/cluster-sweep.* + cluster.py. See docs/agents/cluster-engine.md.",
2937
2941
  probeConfig: { cadenceMs: 24 * 60 * MINUTE_MS, cronName: "fluncle-cluster", kind: "cron" },
2942
+ statusDescription: "groups the archive into sonic galaxies",
2943
+ title: "Sonic galaxies",
2938
2944
  weights: { status: "hidden" }
2939
2945
  },
2940
2946
  {
@@ -2946,6 +2952,8 @@ var init_src = __esm(() => {
2946
2952
  name: "cron.crawl",
2947
2953
  operatorNotes: "every 10m, run by a rave-02 HOST systemd timer (docs/agents/hermes/crawl-timer/). METADATA ONLY — it writes a `tracks` row with no `findings` row, so it certifies nothing (no Log ID, no note, no video, no public surface) and it captures no audio. Worker-paced (the box holds no MusicBrainz budget): one bounded pass per tick over the durable `crawl_frontier`, so a crawl is a marathon the SCHEDULE finishes and a reboot mid-label costs one node, not one crawl. The boundary gate is the operator's seed-label allowlist + graph distance (hop 0-2), never genre inference; a label the walk discovers enters `undecided` and is NOT crawled until he rules on it. Zero LLM tokens. Source: docs/agents/hermes/scripts/crawl-sweep.*. See docs/catalogue-crawler.md.",
2948
2954
  probeConfig: { cadenceMs: 10 * MINUTE_MS, cronName: "fluncle-crawl", kind: "cron" },
2955
+ statusDescription: "charts new tracks from the wider label graph",
2956
+ title: "Track crawler",
2949
2957
  weights: { status: "hidden" }
2950
2958
  },
2951
2959
  {
@@ -2957,6 +2965,8 @@ var init_src = __esm(() => {
2957
2965
  name: "cron.rank",
2958
2966
  operatorNotes: "every 30m, run by a rave-02 HOST systemd timer (docs/agents/hermes/rank-timer/). THE EAR's schedule, and it lands with the crawler on purpose: a timer ranking an empty table would be a /status row that means nothing, and the crawler is what creates rows. All the vector arithmetic runs in SQL inside the Worker; the sweep DRAINS (it loops while `remaining > 0` up to a tick budget), so a crawl that just landed 700 rows is ranked by the next tick. Self-healing: staleness is a fingerprint of the finding corpus, so logging or embedding a finding re-ranks the catalogue with no invalidation call. Writes DERIVED columns on catalogue rows only — it cannot certify. Zero LLM tokens. Source: docs/agents/hermes/scripts/rank-sweep.*. See docs/the-ear.md.",
2959
2967
  probeConfig: { cadenceMs: 30 * MINUTE_MS, cronName: "fluncle-rank", kind: "cron" },
2968
+ statusDescription: "ranks unvisited tracks by nearness to the archive",
2969
+ title: "Track ranking",
2960
2970
  weights: { status: "hidden" }
2961
2971
  },
2962
2972
  {
@@ -2968,6 +2978,8 @@ var init_src = __esm(() => {
2968
2978
  name: "cron.label-images",
2969
2979
  operatorNotes: "every 60m, run by a rave-02 HOST systemd timer (docs/agents/hermes/label-images-timer/). The DURABLE other half of the label entity: the crawler MINTS new labels every few minutes (each `image_state='pending'`) and the one-shot operator backfill only seeded the labels that already existed, so this cron is what gives every freshly-minted label its OWN logo instead of a borrowed album cover. METADATA ONLY — a label logo is internal, reversible, nominative-use trademark (the album-art posture); it certifies nothing and publishes nothing (agent tier, the `backfill_discogs` precedent). Worker-paced (the box holds no Discogs key / MusicBrainz budget): one bounded batch per tick walks each label's MB identity → its curated Discogs/Wikidata url-rels → downloads the logo once into R2, up the ladder Discogs → Wikidata → none (the freshest-cover floor). The `labels` row carries the durable reliability state (image_state/image_attempted_at/image_failures), so a resolved/none label is terminal and a vendor throttle just circuit-breaks and resumes next tick. Zero LLM tokens. Source: docs/agents/hermes/scripts/label-images-sweep.*. See docs/label-entity.md.",
2970
2980
  probeConfig: { cadenceMs: 60 * MINUTE_MS, cronName: "fluncle-label-images", kind: "cron" },
2981
+ statusDescription: "resolves each label's own mark",
2982
+ title: "Label logos",
2971
2983
  weights: { status: "hidden" }
2972
2984
  },
2973
2985
  {
@@ -2979,6 +2991,8 @@ var init_src = __esm(() => {
2979
2991
  name: "cron.cover-masters",
2980
2992
  operatorNotes: "every 60m, run by a rave-02 HOST systemd timer (docs/agents/hermes/cover-masters-timer/). The DURABLE other half of the album/artist cover (RFC musickit-second-authority U3b): the publish path + catalogue crawl MINT albums/artists (each `image_state='pending'`) and this cron gives each its OWN ≤1200²-capped cover derivative in R2 (found.fluncle.com, `albums/<slug>.<ext>` / `artists/<slug>.<ext>`) instead of hotlinking a third party — the label-logo posture, two entities over. IMAGE ONLY — a downscaled display derivative, reversible, the REF-05-conscious 1200 line (docs/album-artwork.md); it certifies nothing and publishes nothing (agent tier, the `backfill_label_images` precedent). Worker-paced: one bounded batch of albums (Apple template → Cover Art Archive → Spotify floor), then one of artists (Spotify floor), per tick; every rung requests a ≤1200 rendition and a byte read enforces the cap before the R2 put, so no un-downscaled original is ever stored. The `albums`/`artists` row carries the durable reliability state (image_state/image_attempted_at/image_failures), so a resolved/none entity is terminal. Served via Cloudflare Images `/cdn-cgi/image/…` (decision B). Zero LLM tokens. Source: docs/agents/hermes/scripts/cover-masters-sweep.*. See docs/album-artwork.md.",
2981
2993
  probeConfig: { cadenceMs: 60 * MINUTE_MS, cronName: "fluncle-cover-masters", kind: "cron" },
2994
+ statusDescription: "owns each album and artist its cover master",
2995
+ title: "Cover masters",
2982
2996
  weights: { status: "hidden" }
2983
2997
  },
2984
2998
  {
@@ -2990,6 +3004,8 @@ var init_src = __esm(() => {
2990
3004
  name: "cron.capture",
2991
3005
  operatorNotes: "every 5m, run by a rave-02 HOST systemd timer (docs/agents/hermes/capture-timer/) — NOT a gateway cron: a proxied yt-dlp fetch has an unbounded tail that would starve the 5-min enrich/context/note sweeps on the shared serial runner. A NON-BLOCKING side-channel (never gates enrich/embed). Runs yt-dlp through a residential proxy on a per-track sticky session, duration-guards the match, stores the full song in the PRIVATE fluncle-source-audio bucket (S3-direct), and writes back via the agent-tier update_track (with per-finding backoff). yt-dlp + ffprobe are a box deploy prereq. Newest-first so a fresh add jumps the backfill. Source: docs/agents/hermes/scripts/capture-sweep.*. See docs/track-lifecycle.md.",
2992
3006
  probeConfig: { cadenceMs: 5 * MINUTE_MS, cronName: "fluncle-capture", kind: "cron" },
3007
+ statusDescription: "captures each finding's full song once",
3008
+ title: "Full-song capture",
2993
3009
  weights: { status: "hidden" }
2994
3010
  },
2995
3011
  {
@@ -3001,6 +3017,8 @@ var init_src = __esm(() => {
3001
3017
  name: "cron.verify-captures",
3002
3018
  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.",
3003
3019
  probeConfig: { cadenceMs: 30 * MINUTE_MS, cronName: "fluncle-verify-captures", kind: "cron" },
3020
+ statusDescription: "checks each captured song against its official preview",
3021
+ title: "Capture verification",
3004
3022
  weights: { status: "hidden" }
3005
3023
  },
3006
3024
  {
@@ -3012,6 +3030,8 @@ var init_src = __esm(() => {
3012
3030
  name: "cron.context-note",
3013
3031
  operatorNotes: "every 5m. --no-agent trigger; the Worker does the Firecrawl + Haiku distill. Zero on-box tokens.",
3014
3032
  probeConfig: { cadenceMs: 5 * MINUTE_MS, cronName: "fluncle-context-note", kind: "cron" },
3033
+ statusDescription: "distills the facts behind each finding",
3034
+ title: "Context notes",
3015
3035
  weights: { status: "hidden" }
3016
3036
  },
3017
3037
  {
@@ -3023,6 +3043,8 @@ var init_src = __esm(() => {
3023
3043
  name: "cron.note",
3024
3044
  operatorNotes: "every 10m. Hybrid --no-agent; one claude -p authors the line. Never clobbers an operator note.",
3025
3045
  probeConfig: { cadenceMs: 10 * MINUTE_MS, cronName: "fluncle-note", kind: "cron" },
3046
+ statusDescription: "writes each finding's editorial note",
3047
+ title: "Editorial notes",
3026
3048
  weights: { status: "hidden" }
3027
3049
  },
3028
3050
  {
@@ -3032,8 +3054,10 @@ var init_src = __esm(() => {
3032
3054
  ],
3033
3055
  kind: "cron",
3034
3056
  name: "cron.artist-bio",
3035
- operatorNotes: "every 30m. Hybrid --no-agent; one claude -p authors the paragraph off best-effort Firecrawl facts + identity. Never clobbers an operator bio. Box activation operator-gated. Source: docs/agents/hermes/scripts/{entity-bio-sweep.ts,artist-bio-sweep.sh}.",
3057
+ operatorNotes: "every 30m. Hybrid --no-agent; one claude -p authors the paragraph, its grounding assembled WORKER-side (Firecrawl facts + the artist's finding titles) via the draft-bio op. Never clobbers an operator bio. Live. Source: docs/agents/hermes/scripts/{entity-bio-sweep.ts,artist-bio-sweep.sh}.",
3036
3058
  probeConfig: { cadenceMs: 30 * MINUTE_MS, cronName: "fluncle-artist-bio", kind: "cron" },
3059
+ statusDescription: "writes each artist's voiced bio",
3060
+ title: "Artist bios",
3037
3061
  weights: { status: "hidden" }
3038
3062
  },
3039
3063
  {
@@ -3043,8 +3067,10 @@ var init_src = __esm(() => {
3043
3067
  ],
3044
3068
  kind: "cron",
3045
3069
  name: "cron.label-bio",
3046
- operatorNotes: "every 30m. Hybrid --no-agent; one claude -p authors the paragraph off best-effort Firecrawl facts + identity. Never clobbers an operator bio. Box activation operator-gated. Source: docs/agents/hermes/scripts/{entity-bio-sweep.ts,label-bio-sweep.sh}.",
3070
+ operatorNotes: "every 30m. Hybrid --no-agent; one claude -p authors the paragraph, its grounding assembled WORKER-side (Firecrawl facts + the label's finding titles) via the draft-bio op. Never clobbers an operator bio. Live. Source: docs/agents/hermes/scripts/{entity-bio-sweep.ts,label-bio-sweep.sh}.",
3047
3071
  probeConfig: { cadenceMs: 30 * MINUTE_MS, cronName: "fluncle-label-bio", kind: "cron" },
3072
+ statusDescription: "writes each label's voiced bio",
3073
+ title: "Label bios",
3048
3074
  weights: { status: "hidden" }
3049
3075
  },
3050
3076
  {
@@ -3056,6 +3082,8 @@ var init_src = __esm(() => {
3056
3082
  name: "cron.triage",
3057
3083
  operatorNotes: "every 15m. Hybrid --no-agent; a deterministic archive dedupe + DnB-plausibility heuristic feeds one claude -p phrasing, length-gated. Writes the verdict onto a PENDING submission so it lands in the /admin attention queue already assessed; approve/reject stays operator tier. Source: docs/agents/hermes/scripts/triage-sweep.{sh,ts}.",
3058
3084
  probeConfig: { cadenceMs: 15 * MINUTE_MS, cronName: "fluncle-triage", kind: "cron" },
3085
+ statusDescription: "pre-chews each crew submission's verdict",
3086
+ title: "Submission triage",
3059
3087
  weights: { status: "hidden" }
3060
3088
  },
3061
3089
  {
@@ -3072,6 +3100,8 @@ var init_src = __esm(() => {
3072
3100
  kind: "cron",
3073
3101
  schedule: { time: "00:40", tz: "Europe/Amsterdam" }
3074
3102
  },
3103
+ statusDescription: "writes each sector-day up in the Logbook",
3104
+ title: "Logbook author",
3075
3105
  weights: { status: "hidden" }
3076
3106
  },
3077
3107
  {
@@ -3083,6 +3113,8 @@ var init_src = __esm(() => {
3083
3113
  name: "cron.observation",
3084
3114
  operatorNotes: "every 60m. Hybrid --no-agent; one claude -p authors the script, the Worker voice-gates + renders.",
3085
3115
  probeConfig: { cadenceMs: 60 * MINUTE_MS, cronName: "fluncle-observation", kind: "cron" },
3116
+ statusDescription: "Fluncle's spoken field observations",
3117
+ title: "Audio observations",
3086
3118
  weights: { status: "hidden" }
3087
3119
  },
3088
3120
  {
@@ -3092,6 +3124,8 @@ var init_src = __esm(() => {
3092
3124
  name: "cron.backfill",
3093
3125
  operatorNotes: "every 30m. Pure HTTP driving, zero LLM tokens. Agent tier.",
3094
3126
  probeConfig: { cadenceMs: 30 * MINUTE_MS, cronName: "fluncle-backfill", kind: "cron" },
3127
+ statusDescription: "repairs Discogs ids and Last.fm loves",
3128
+ title: "Metadata backfill",
3095
3129
  weights: { status: "hidden" }
3096
3130
  },
3097
3131
  {
@@ -3102,6 +3136,8 @@ var init_src = __esm(() => {
3102
3136
  name: "cron.artist-sweep",
3103
3137
  operatorNotes: "every 60m. --no-agent trigger; the Worker does the MB walk + Firecrawl /v2/extract + YouTube channel resolution. Zero on-box tokens. MB rows land as status=auto (trusted); Firecrawl rows as status=candidate (operator-confirm before public). Source: docs/agents/hermes/scripts/artist-sweep.*",
3104
3138
  probeConfig: { cadenceMs: 60 * MINUTE_MS, cronName: "fluncle-artist-sweep", kind: "cron" },
3139
+ statusDescription: "resolves each artist's socials and identity links",
3140
+ title: "Artist resolution",
3105
3141
  weights: { status: "hidden" }
3106
3142
  },
3107
3143
  {
@@ -3113,6 +3149,8 @@ var init_src = __esm(() => {
3113
3149
  name: "cron.social-capture",
3114
3150
  operatorNotes: "every 10m. Pure HTTP trigger, zero LLM tokens. Agent tier (fills the public URL only — publishes nothing). The box's baked CLI predates the `--capture` verb, so the cron curls POST /api/admin/social/posts/capture directly; the Worker polls Postiz and writes back. Source: docs/agents/hermes/scripts/social-capture-sweep.sh. Probed on /status as cron.social-capture.",
3115
3151
  probeConfig: { cadenceMs: 10 * MINUTE_MS, cronName: "fluncle-social-capture", kind: "cron" },
3152
+ statusDescription: "the live YouTube and TikTok URLs for each posted video",
3153
+ title: "Social links",
3116
3154
  weights: { status: "hidden" }
3117
3155
  },
3118
3156
  {
@@ -3123,6 +3161,8 @@ var init_src = __esm(() => {
3123
3161
  name: "cron.studio-clip",
3124
3162
  operatorNotes: "every 15m. Pure-trigger, zero LLM tokens: a deterministic ffmpeg cut driven by the fluncle CLI (`admin clips list` → `admin clips cut`), agent-scoped (list_clips + the agent-tier presign_clip_upload / finalize_clip_cut). Cuts the operator-framed 9:16 clips from the /admin/studio editor (keyed by Log ID) out of the set video → ships `<clipId>/footage.mp4` to R2 for the /admin/clips library + the clip drip-feed. The box runs the standalone bun BINARY (the npm thin client can't spawn ffmpeg). Source: docs/agents/hermes/scripts/clip-sweep.sh. Probed on /status as cron.studio-clip.",
3125
3163
  probeConfig: { cadenceMs: 15 * MINUTE_MS, cronName: "fluncle-studio-clip", kind: "cron" },
3164
+ statusDescription: "cuts set videos into 9:16 clips",
3165
+ title: "Studio clips",
3126
3166
  weights: { status: "hidden" }
3127
3167
  },
3128
3168
  {
@@ -3134,6 +3174,8 @@ var init_src = __esm(() => {
3134
3174
  name: "cron.clip-drip",
3135
3175
  operatorNotes: "every 20m. Pure HTTP trigger, zero LLM tokens. Admin tier (needs the Worker's Postiz key, which the box never sees — the box only triggers; the `finalize_clip_cut` / `record_health` precedent). The Worker checks the global kill switch FIRST (paused → no-op), then posts due clips bounded by a per-tick cap AND a rolling-24h IG cap. Every clip auto-enters the schedule at a jittered ~23-25h after the queue tail. The operator pauses/resumes with `fluncle admin clips drip-pause` / `drip-resume`. Source: docs/agents/hermes/scripts/clip-drip-sweep.sh. Probed on /status as cron.clip-drip.",
3136
3176
  probeConfig: { cadenceMs: 20 * MINUTE_MS, cronName: "fluncle-clip-drip", kind: "cron" },
3177
+ statusDescription: "drip-feeds set clips to Instagram",
3178
+ title: "Clip drip-feed",
3137
3179
  weights: { status: "hidden" }
3138
3180
  },
3139
3181
  {
@@ -3145,6 +3187,8 @@ var init_src = __esm(() => {
3145
3187
  name: "cron.publish-advance",
3146
3188
  operatorNotes: "every 30m. Pure HTTP trigger, zero LLM tokens. The last autonomy gap: render finishes → this pushes, with no operator beat between. Admin tier (needs the Worker's Postiz key, which the box never sees — the box only triggers; the `drip_clips` / `capture_post_urls` precedent). SHIPS DARK: the Worker's kill switch is DEFAULT-DENY (only an explicit `false` in the `publish_advance_paused` setting runs it), so the timer ticks and posts nothing until `fluncle admin publish resume`. The Worker reads the switch FIRST, then advances at most ONE ready finding — both masters finalized, 15m settled, the whole bundle served on R2, the (track, platform) row CLAIMED atomically before any Postiz call, a rolling-24h cap of 6 pushes. A failed push is left `failed` for the operator and never auto-retried. Source: docs/agents/hermes/scripts/publish-advance-sweep.sh. Probed on /status as cron.publish-advance.",
3147
3189
  probeConfig: { cadenceMs: 30 * MINUTE_MS, cronName: "fluncle-publish-advance", kind: "cron" },
3190
+ statusDescription: "advances the publish queue on his own clock",
3191
+ title: "Publish advance",
3148
3192
  weights: { status: "hidden" }
3149
3193
  },
3150
3194
  {
@@ -3156,6 +3200,8 @@ var init_src = __esm(() => {
3156
3200
  name: "cron.render",
3157
3201
  operatorNotes: "every 60m. A conductor: triggers a detached @fluncle-video render on a scale-to-zero box.ascii box (rave-03). Never posts to social (operator-tier 403). Probed on /status as service `cron.render` (its own last-run freshness); the box's reachability is the SEPARATE `render-box` probe (the conductor state file).",
3158
3202
  probeConfig: { cadenceMs: 60 * MINUTE_MS, cronName: "fluncle-render", kind: "cron" },
3203
+ statusDescription: "the conductor's last run",
3204
+ title: "Render cron",
3159
3205
  weights: { status: "hidden" }
3160
3206
  },
3161
3207
  {
@@ -3166,6 +3212,8 @@ var init_src = __esm(() => {
3166
3212
  name: "cron.healthcheck",
3167
3213
  operatorNotes: "every 10m, run by a rave-02 host systemd timer (docs/agents/hermes/healthcheck-timer/) — decoupled from the Hermes cron gateway so the prober isn't starved by the scheduler it monitors. Pure probing, zero LLM tokens. POSTs to the agent-tier record_health op that /status reads.",
3168
3214
  probeConfig: { cadenceMs: 10 * MINUTE_MS, cronName: "fluncle-healthcheck", kind: "cron" },
3215
+ statusDescription: "the prober behind this very page",
3216
+ title: "Healthcheck prober",
3169
3217
  weights: { status: "hidden" }
3170
3218
  },
3171
3219
  {
@@ -3182,6 +3230,8 @@ var init_src = __esm(() => {
3182
3230
  kind: "cron",
3183
3231
  schedule: { time: "15:00", tz: "Europe/Amsterdam", weekday: 5 }
3184
3232
  },
3233
+ statusDescription: "drafts the Friday edition",
3234
+ title: "Weekly newsletter",
3185
3235
  weights: { status: "secondary" }
3186
3236
  },
3187
3237
  {
@@ -3197,6 +3247,8 @@ var init_src = __esm(() => {
3197
3247
  kind: "cron",
3198
3248
  schedule: { time: "03:00", tz: "Europe/Amsterdam" }
3199
3249
  },
3250
+ statusDescription: "a daily off-site snapshot of the archive",
3251
+ title: "Database backup",
3200
3252
  weights: { status: "secondary" }
3201
3253
  },
3202
3254
  {
@@ -3213,6 +3265,8 @@ var init_src = __esm(() => {
3213
3265
  kind: "cron",
3214
3266
  schedule: { time: "04:00", tz: "Europe/Amsterdam" }
3215
3267
  },
3268
+ statusDescription: "counts the crew and how far the probes reached",
3269
+ title: "Reach snapshot",
3216
3270
  weights: { status: "secondary" }
3217
3271
  },
3218
3272
  {
@@ -3228,6 +3282,8 @@ var init_src = __esm(() => {
3228
3282
  kind: "cron",
3229
3283
  schedule: { time: "01:00", tz: "Europe/Amsterdam" }
3230
3284
  },
3285
+ statusDescription: "nightly one-domain codebase audit → a PR",
3286
+ title: "Nightly audit",
3231
3287
  weights: { status: "secondary" }
3232
3288
  },
3233
3289
  {
@@ -3243,6 +3299,8 @@ var init_src = __esm(() => {
3243
3299
  kind: "cron",
3244
3300
  schedule: { time: "05:00", tz: "Europe/Amsterdam" }
3245
3301
  },
3302
+ statusDescription: "reviews + merges the nightly audit PR",
3303
+ title: "Audit reviewer",
3246
3304
  weights: { status: "secondary" }
3247
3305
  }
3248
3306
  ];
@@ -5832,7 +5890,7 @@ __export(exports_admin_catalogue, {
5832
5890
  async function catalogueRankCommand(options) {
5833
5891
  const limit = options.limit ? Number.parseInt(options.limit, 10) : undefined;
5834
5892
  const response = await adminApiPost("/api/admin/catalogue/rank", limit ? { limit } : {});
5835
- return response.summary;
5893
+ return { summary: response.summary, telescope: response.telescope };
5836
5894
  }
5837
5895
  async function catalogueListCommand(options) {
5838
5896
  const params = new URLSearchParams;
@@ -10891,14 +10949,17 @@ async function runGalaxies(slug, options, commands) {
10891
10949
  }
10892
10950
  }
10893
10951
  async function runCatalogueRank(options, catalogueRankCommand2) {
10894
- const summary = await catalogueRankCommand2({ limit: options.limit });
10952
+ const { summary, telescope } = await catalogueRankCommand2({ limit: options.limit });
10895
10953
  if (options.json) {
10896
- printJson({ ok: true, summary });
10954
+ printJson({ ok: true, summary, telescope });
10897
10955
  return;
10898
10956
  }
10899
10957
  const quarantine = summary.quarantined > 0 ? ` Quarantined ${summary.quarantined} as wrong audio.` : "";
10900
10958
  const deduped = summary.catalogueDuplicates > 0 ? ` Marked ${summary.catalogueDuplicates} as catalogue duplicates.` : "";
10901
10959
  console.log(`Ranked ${summary.scored} against ${summary.embeddedFindings} embedded findings; prioritized ${summary.prioritized} for capture.${quarantine}${deduped} ${summary.remaining} still stale.`);
10960
+ if (telescope) {
10961
+ console.log(telescope.ok ? `Telescope: ${telescope.size} aboard${telescope.changed ? " (updated)" : ""}.` : `Telescope: sync failed \u2014 ${telescope.reason}`);
10962
+ }
10902
10963
  }
10903
10964
  async function runCatalogueList(options, catalogueListCommand2) {
10904
10965
  const { summary, tracks } = await catalogueListCommand2({
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.156.0"
34
+ "version": "0.157.0"
35
35
  }