fluncle 0.156.0 → 0.158.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 +120 -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.158.0".trim() ? "0.158.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.158.0".trim() ? "0.158.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
|
|
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,23 @@ 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
|
|
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",
|
|
3074
|
+
weights: { status: "hidden" }
|
|
3075
|
+
},
|
|
3076
|
+
{
|
|
3077
|
+
command: "fluncle admin albums describe --queue",
|
|
3078
|
+
exposedContent: [
|
|
3079
|
+
"auto-author the /album/<slug> voiced bio, fill-empty-only (hybrid: one claude -p call)"
|
|
3080
|
+
],
|
|
3081
|
+
kind: "cron",
|
|
3082
|
+
name: "cron.album-bio",
|
|
3083
|
+
operatorNotes: "every 30m. Hybrid --no-agent; one claude -p authors the paragraph, its grounding assembled WORKER-side (Firecrawl facts + the album's finding titles) via the draft-bio op. Never clobbers an operator bio. Live. Source: docs/agents/hermes/scripts/{entity-bio-sweep.ts,album-bio-sweep.sh}.",
|
|
3084
|
+
probeConfig: { cadenceMs: 30 * MINUTE_MS, cronName: "fluncle-album-bio", kind: "cron" },
|
|
3085
|
+
statusDescription: "writes each album's voiced bio",
|
|
3086
|
+
title: "Album bios",
|
|
3048
3087
|
weights: { status: "hidden" }
|
|
3049
3088
|
},
|
|
3050
3089
|
{
|
|
@@ -3056,6 +3095,8 @@ var init_src = __esm(() => {
|
|
|
3056
3095
|
name: "cron.triage",
|
|
3057
3096
|
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
3097
|
probeConfig: { cadenceMs: 15 * MINUTE_MS, cronName: "fluncle-triage", kind: "cron" },
|
|
3098
|
+
statusDescription: "pre-chews each crew submission's verdict",
|
|
3099
|
+
title: "Submission triage",
|
|
3059
3100
|
weights: { status: "hidden" }
|
|
3060
3101
|
},
|
|
3061
3102
|
{
|
|
@@ -3072,6 +3113,8 @@ var init_src = __esm(() => {
|
|
|
3072
3113
|
kind: "cron",
|
|
3073
3114
|
schedule: { time: "00:40", tz: "Europe/Amsterdam" }
|
|
3074
3115
|
},
|
|
3116
|
+
statusDescription: "writes each sector-day up in the Logbook",
|
|
3117
|
+
title: "Logbook author",
|
|
3075
3118
|
weights: { status: "hidden" }
|
|
3076
3119
|
},
|
|
3077
3120
|
{
|
|
@@ -3083,6 +3126,8 @@ var init_src = __esm(() => {
|
|
|
3083
3126
|
name: "cron.observation",
|
|
3084
3127
|
operatorNotes: "every 60m. Hybrid --no-agent; one claude -p authors the script, the Worker voice-gates + renders.",
|
|
3085
3128
|
probeConfig: { cadenceMs: 60 * MINUTE_MS, cronName: "fluncle-observation", kind: "cron" },
|
|
3129
|
+
statusDescription: "Fluncle's spoken field observations",
|
|
3130
|
+
title: "Audio observations",
|
|
3086
3131
|
weights: { status: "hidden" }
|
|
3087
3132
|
},
|
|
3088
3133
|
{
|
|
@@ -3092,6 +3137,8 @@ var init_src = __esm(() => {
|
|
|
3092
3137
|
name: "cron.backfill",
|
|
3093
3138
|
operatorNotes: "every 30m. Pure HTTP driving, zero LLM tokens. Agent tier.",
|
|
3094
3139
|
probeConfig: { cadenceMs: 30 * MINUTE_MS, cronName: "fluncle-backfill", kind: "cron" },
|
|
3140
|
+
statusDescription: "repairs Discogs ids and Last.fm loves",
|
|
3141
|
+
title: "Metadata backfill",
|
|
3095
3142
|
weights: { status: "hidden" }
|
|
3096
3143
|
},
|
|
3097
3144
|
{
|
|
@@ -3102,6 +3149,8 @@ var init_src = __esm(() => {
|
|
|
3102
3149
|
name: "cron.artist-sweep",
|
|
3103
3150
|
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
3151
|
probeConfig: { cadenceMs: 60 * MINUTE_MS, cronName: "fluncle-artist-sweep", kind: "cron" },
|
|
3152
|
+
statusDescription: "resolves each artist's socials and identity links",
|
|
3153
|
+
title: "Artist resolution",
|
|
3105
3154
|
weights: { status: "hidden" }
|
|
3106
3155
|
},
|
|
3107
3156
|
{
|
|
@@ -3113,6 +3162,8 @@ var init_src = __esm(() => {
|
|
|
3113
3162
|
name: "cron.social-capture",
|
|
3114
3163
|
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
3164
|
probeConfig: { cadenceMs: 10 * MINUTE_MS, cronName: "fluncle-social-capture", kind: "cron" },
|
|
3165
|
+
statusDescription: "the live YouTube and TikTok URLs for each posted video",
|
|
3166
|
+
title: "Social links",
|
|
3116
3167
|
weights: { status: "hidden" }
|
|
3117
3168
|
},
|
|
3118
3169
|
{
|
|
@@ -3123,6 +3174,8 @@ var init_src = __esm(() => {
|
|
|
3123
3174
|
name: "cron.studio-clip",
|
|
3124
3175
|
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
3176
|
probeConfig: { cadenceMs: 15 * MINUTE_MS, cronName: "fluncle-studio-clip", kind: "cron" },
|
|
3177
|
+
statusDescription: "cuts set videos into 9:16 clips",
|
|
3178
|
+
title: "Studio clips",
|
|
3126
3179
|
weights: { status: "hidden" }
|
|
3127
3180
|
},
|
|
3128
3181
|
{
|
|
@@ -3134,6 +3187,8 @@ var init_src = __esm(() => {
|
|
|
3134
3187
|
name: "cron.clip-drip",
|
|
3135
3188
|
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
3189
|
probeConfig: { cadenceMs: 20 * MINUTE_MS, cronName: "fluncle-clip-drip", kind: "cron" },
|
|
3190
|
+
statusDescription: "drip-feeds set clips to Instagram",
|
|
3191
|
+
title: "Clip drip-feed",
|
|
3137
3192
|
weights: { status: "hidden" }
|
|
3138
3193
|
},
|
|
3139
3194
|
{
|
|
@@ -3145,6 +3200,8 @@ var init_src = __esm(() => {
|
|
|
3145
3200
|
name: "cron.publish-advance",
|
|
3146
3201
|
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
3202
|
probeConfig: { cadenceMs: 30 * MINUTE_MS, cronName: "fluncle-publish-advance", kind: "cron" },
|
|
3203
|
+
statusDescription: "advances the publish queue on his own clock",
|
|
3204
|
+
title: "Publish advance",
|
|
3148
3205
|
weights: { status: "hidden" }
|
|
3149
3206
|
},
|
|
3150
3207
|
{
|
|
@@ -3156,6 +3213,8 @@ var init_src = __esm(() => {
|
|
|
3156
3213
|
name: "cron.render",
|
|
3157
3214
|
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
3215
|
probeConfig: { cadenceMs: 60 * MINUTE_MS, cronName: "fluncle-render", kind: "cron" },
|
|
3216
|
+
statusDescription: "the conductor's last run",
|
|
3217
|
+
title: "Render cron",
|
|
3159
3218
|
weights: { status: "hidden" }
|
|
3160
3219
|
},
|
|
3161
3220
|
{
|
|
@@ -3166,6 +3225,8 @@ var init_src = __esm(() => {
|
|
|
3166
3225
|
name: "cron.healthcheck",
|
|
3167
3226
|
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
3227
|
probeConfig: { cadenceMs: 10 * MINUTE_MS, cronName: "fluncle-healthcheck", kind: "cron" },
|
|
3228
|
+
statusDescription: "the prober behind this very page",
|
|
3229
|
+
title: "Healthcheck prober",
|
|
3169
3230
|
weights: { status: "hidden" }
|
|
3170
3231
|
},
|
|
3171
3232
|
{
|
|
@@ -3182,6 +3243,8 @@ var init_src = __esm(() => {
|
|
|
3182
3243
|
kind: "cron",
|
|
3183
3244
|
schedule: { time: "15:00", tz: "Europe/Amsterdam", weekday: 5 }
|
|
3184
3245
|
},
|
|
3246
|
+
statusDescription: "drafts the Friday edition",
|
|
3247
|
+
title: "Weekly newsletter",
|
|
3185
3248
|
weights: { status: "secondary" }
|
|
3186
3249
|
},
|
|
3187
3250
|
{
|
|
@@ -3197,6 +3260,8 @@ var init_src = __esm(() => {
|
|
|
3197
3260
|
kind: "cron",
|
|
3198
3261
|
schedule: { time: "03:00", tz: "Europe/Amsterdam" }
|
|
3199
3262
|
},
|
|
3263
|
+
statusDescription: "a daily off-site snapshot of the archive",
|
|
3264
|
+
title: "Database backup",
|
|
3200
3265
|
weights: { status: "secondary" }
|
|
3201
3266
|
},
|
|
3202
3267
|
{
|
|
@@ -3213,6 +3278,8 @@ var init_src = __esm(() => {
|
|
|
3213
3278
|
kind: "cron",
|
|
3214
3279
|
schedule: { time: "04:00", tz: "Europe/Amsterdam" }
|
|
3215
3280
|
},
|
|
3281
|
+
statusDescription: "counts the crew and how far the probes reached",
|
|
3282
|
+
title: "Reach snapshot",
|
|
3216
3283
|
weights: { status: "secondary" }
|
|
3217
3284
|
},
|
|
3218
3285
|
{
|
|
@@ -3228,6 +3295,8 @@ var init_src = __esm(() => {
|
|
|
3228
3295
|
kind: "cron",
|
|
3229
3296
|
schedule: { time: "01:00", tz: "Europe/Amsterdam" }
|
|
3230
3297
|
},
|
|
3298
|
+
statusDescription: "nightly one-domain codebase audit → a PR",
|
|
3299
|
+
title: "Nightly audit",
|
|
3231
3300
|
weights: { status: "secondary" }
|
|
3232
3301
|
},
|
|
3233
3302
|
{
|
|
@@ -3243,6 +3312,8 @@ var init_src = __esm(() => {
|
|
|
3243
3312
|
kind: "cron",
|
|
3244
3313
|
schedule: { time: "05:00", tz: "Europe/Amsterdam" }
|
|
3245
3314
|
},
|
|
3315
|
+
statusDescription: "reviews + merges the nightly audit PR",
|
|
3316
|
+
title: "Audit reviewer",
|
|
3246
3317
|
weights: { status: "secondary" }
|
|
3247
3318
|
}
|
|
3248
3319
|
];
|
|
@@ -5832,7 +5903,7 @@ __export(exports_admin_catalogue, {
|
|
|
5832
5903
|
async function catalogueRankCommand(options) {
|
|
5833
5904
|
const limit = options.limit ? Number.parseInt(options.limit, 10) : undefined;
|
|
5834
5905
|
const response = await adminApiPost("/api/admin/catalogue/rank", limit ? { limit } : {});
|
|
5835
|
-
return response.summary;
|
|
5906
|
+
return { summary: response.summary, telescope: response.telescope };
|
|
5836
5907
|
}
|
|
5837
5908
|
async function catalogueListCommand(options) {
|
|
5838
5909
|
const params = new URLSearchParams;
|
|
@@ -6034,6 +6105,28 @@ var init_admin_covers = __esm(() => {
|
|
|
6034
6105
|
init_api();
|
|
6035
6106
|
});
|
|
6036
6107
|
|
|
6108
|
+
// src/commands/admin-albums.ts
|
|
6109
|
+
var exports_admin_albums = {};
|
|
6110
|
+
__export(exports_admin_albums, {
|
|
6111
|
+
draftAlbumBioCommand: () => draftAlbumBioCommand,
|
|
6112
|
+
describeAlbumCommand: () => describeAlbumCommand,
|
|
6113
|
+
albumsBioQueueCommand: () => albumsBioQueueCommand
|
|
6114
|
+
});
|
|
6115
|
+
async function describeAlbumCommand(slug, options) {
|
|
6116
|
+
return adminApiPost(`/api/admin/albums/${encodeURIComponent(slug)}/bio`, buildBioBody2(options));
|
|
6117
|
+
}
|
|
6118
|
+
async function draftAlbumBioCommand(slug) {
|
|
6119
|
+
return adminApiGet(`/api/admin/albums/${encodeURIComponent(slug)}/bio-draft`);
|
|
6120
|
+
}
|
|
6121
|
+
async function albumsBioQueueCommand(limit) {
|
|
6122
|
+
const response = await adminApiGet(`/api/admin/albums/bio-queue?limit=${limit}`);
|
|
6123
|
+
return response.albums;
|
|
6124
|
+
}
|
|
6125
|
+
var init_admin_albums = __esm(() => {
|
|
6126
|
+
init_api();
|
|
6127
|
+
init_admin_artists2();
|
|
6128
|
+
});
|
|
6129
|
+
|
|
6037
6130
|
// src/commands/preview-migration.ts
|
|
6038
6131
|
var exports_preview_migration = {};
|
|
6039
6132
|
__export(exports_preview_migration, {
|
|
@@ -9226,6 +9319,23 @@ function addAdminCommands(program2) {
|
|
|
9226
9319
|
const { draftLabelBioCommand: draftLabelBioCommand2 } = await Promise.resolve().then(() => (init_admin_labels(), exports_admin_labels));
|
|
9227
9320
|
await runEntityBioDraft("label", slug, options, draftLabelBioCommand2);
|
|
9228
9321
|
});
|
|
9322
|
+
const albums = configureCommand(admin.command("albums").description("Album entity commands (the voiced bio)"));
|
|
9323
|
+
albums.action(() => {
|
|
9324
|
+
albums.outputHelp();
|
|
9325
|
+
});
|
|
9326
|
+
albums.command("describe").description("Author the voiced bio for an album (fills an empty bio only)").argument("[slug]").option("--queue", "Show the bio worklist (albums with findings but no bio), oldest first", false).option("--limit <limit>", "Number of albums to show with --queue", "50").option("--bio <text>", "The voice-gated bio paragraph").option("--bio-file <file>", "Read the bio from a file").option("--prompt-version <n>", "The prompt-registry version that authored the bio (the sweep sends this; it is the bio's provenance)").option("--dry-run", "Run the voice gate and report the verdict without storing anything", false).option("--json", "Print JSON", false).allowExcessArguments().action(async (slug, options) => {
|
|
9327
|
+
if (options.queue) {
|
|
9328
|
+
const { albumsBioQueueCommand: albumsBioQueueCommand2 } = await Promise.resolve().then(() => (init_admin_albums(), exports_admin_albums));
|
|
9329
|
+
await runEntityBioQueue("album", options, albumsBioQueueCommand2);
|
|
9330
|
+
return;
|
|
9331
|
+
}
|
|
9332
|
+
const { describeAlbumCommand: describeAlbumCommand2 } = await Promise.resolve().then(() => (init_admin_albums(), exports_admin_albums));
|
|
9333
|
+
await runEntityDescribe("album", slug, options, describeAlbumCommand2);
|
|
9334
|
+
});
|
|
9335
|
+
albums.command("draft-bio").description("Assemble the Worker-grounded bio prompt for an album (the sweep's trigger)").argument("<slug>").option("--json", "Print JSON", false).allowExcessArguments().action(async (slug, options) => {
|
|
9336
|
+
const { draftAlbumBioCommand: draftAlbumBioCommand2 } = await Promise.resolve().then(() => (init_admin_albums(), exports_admin_albums));
|
|
9337
|
+
await runEntityBioDraft("album", slug, options, draftAlbumBioCommand2);
|
|
9338
|
+
});
|
|
9229
9339
|
const migrations = configureCommand(admin.command("migrations").description("One-off operator data migrations"));
|
|
9230
9340
|
migrations.action(() => {
|
|
9231
9341
|
migrations.outputHelp();
|
|
@@ -10891,14 +11001,17 @@ async function runGalaxies(slug, options, commands) {
|
|
|
10891
11001
|
}
|
|
10892
11002
|
}
|
|
10893
11003
|
async function runCatalogueRank(options, catalogueRankCommand2) {
|
|
10894
|
-
const summary = await catalogueRankCommand2({ limit: options.limit });
|
|
11004
|
+
const { summary, telescope } = await catalogueRankCommand2({ limit: options.limit });
|
|
10895
11005
|
if (options.json) {
|
|
10896
|
-
printJson({ ok: true, summary });
|
|
11006
|
+
printJson({ ok: true, summary, telescope });
|
|
10897
11007
|
return;
|
|
10898
11008
|
}
|
|
10899
11009
|
const quarantine = summary.quarantined > 0 ? ` Quarantined ${summary.quarantined} as wrong audio.` : "";
|
|
10900
11010
|
const deduped = summary.catalogueDuplicates > 0 ? ` Marked ${summary.catalogueDuplicates} as catalogue duplicates.` : "";
|
|
10901
11011
|
console.log(`Ranked ${summary.scored} against ${summary.embeddedFindings} embedded findings; prioritized ${summary.prioritized} for capture.${quarantine}${deduped} ${summary.remaining} still stale.`);
|
|
11012
|
+
if (telescope) {
|
|
11013
|
+
console.log(telescope.ok ? `Telescope: ${telescope.size} aboard${telescope.changed ? " (updated)" : ""}.` : `Telescope: sync failed \u2014 ${telescope.reason}`);
|
|
11014
|
+
}
|
|
10902
11015
|
}
|
|
10903
11016
|
async function runCatalogueList(options, catalogueListCommand2) {
|
|
10904
11017
|
const { summary, tracks } = await catalogueListCommand2({
|
package/package.json
CHANGED