fluncle 0.265.0 → 0.267.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 +87 -8
- package/package.json +1 -1
package/bin/fluncle.mjs
CHANGED
|
@@ -386,12 +386,16 @@ __export(exports_env, {
|
|
|
386
386
|
loadEnv: () => loadEnv,
|
|
387
387
|
readOptionalEnv: () => readOptionalEnv
|
|
388
388
|
});
|
|
389
|
+
import { execFileSync } from "node:child_process";
|
|
389
390
|
import { homedir } from "node:os";
|
|
390
391
|
import { join } from "node:path";
|
|
391
392
|
function loadEnv(keys) {
|
|
392
393
|
loadConfig();
|
|
393
394
|
const result = {};
|
|
394
395
|
const missing = [];
|
|
396
|
+
if (keys.includes("FLUNCLE_API_TOKEN")) {
|
|
397
|
+
resolveTokenRef();
|
|
398
|
+
}
|
|
395
399
|
for (const key of keys) {
|
|
396
400
|
const value = process.env[key];
|
|
397
401
|
if (value === undefined) {
|
|
@@ -413,6 +417,21 @@ function getApiBaseUrl() {
|
|
|
413
417
|
loadConfig();
|
|
414
418
|
return (process.env.FLUNCLE_API_BASE_URL ?? "https://www.fluncle.com").replace(/\/+$/, "");
|
|
415
419
|
}
|
|
420
|
+
function resolveTokenRef() {
|
|
421
|
+
const ref = process.env.FLUNCLE_API_TOKEN_REF;
|
|
422
|
+
if (process.env.FLUNCLE_API_TOKEN !== undefined || !ref || false) {
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
try {
|
|
426
|
+
const secretRef = ref.startsWith("op://") ? ref : `op://${ref}`;
|
|
427
|
+
process.env.FLUNCLE_API_TOKEN = execFileSync("op", ["read", "--no-newline", secretRef], {
|
|
428
|
+
encoding: "utf8",
|
|
429
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
430
|
+
});
|
|
431
|
+
} catch {
|
|
432
|
+
throw new Error(`Could not read FLUNCLE_API_TOKEN_REF (${ref}) with op.`);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
416
435
|
function loadConfig() {
|
|
417
436
|
const profile = getEnvProfile();
|
|
418
437
|
if (loadedProfile === profile) {
|
|
@@ -632,7 +651,7 @@ function parseVersion(version) {
|
|
|
632
651
|
var currentVersion;
|
|
633
652
|
var init_version = __esm(() => {
|
|
634
653
|
init_output();
|
|
635
|
-
currentVersion = "0.
|
|
654
|
+
currentVersion = "0.267.0".trim() ? "0.267.0".trim() : "0.1.0";
|
|
636
655
|
});
|
|
637
656
|
|
|
638
657
|
// src/update-notifier.ts
|
|
@@ -2345,7 +2364,7 @@ function parseVersion2(version) {
|
|
|
2345
2364
|
var currentVersion2, latestReleaseUrl = "https://api.github.com/repos/mauricekleine/fluncle/releases/latest";
|
|
2346
2365
|
var init_version2 = __esm(() => {
|
|
2347
2366
|
init_output();
|
|
2348
|
-
currentVersion2 = "0.
|
|
2367
|
+
currentVersion2 = "0.267.0".trim() ? "0.267.0".trim() : "0.1.0";
|
|
2349
2368
|
});
|
|
2350
2369
|
|
|
2351
2370
|
// ../../packages/registry/src/index.ts
|
|
@@ -3725,13 +3744,15 @@ var init_src = __esm(() => {
|
|
|
3725
3744
|
},
|
|
3726
3745
|
{
|
|
3727
3746
|
command: "fluncle admin labels list --seed-state undecided",
|
|
3728
|
-
exposedContent: [
|
|
3747
|
+
exposedContent: [
|
|
3748
|
+
"read the undecided crawl-seed pile and, once a round is due, research it into proposals"
|
|
3749
|
+
],
|
|
3729
3750
|
kind: "cron",
|
|
3730
3751
|
name: "cron.label-triage",
|
|
3731
|
-
operatorNotes: "daily.
|
|
3752
|
+
operatorNotes: "daily. The gate is one countless admin read and a sort; it fires only when 40+ NEVER-LOOKED labels with a MusicBrainz identity and no artist rules have accumulated, and stale ones ride along. A fired round runs one claude -p per batch of 10 labels (capped at 3 batches and 30 labels) whose only fetcher is `fluncle admin labels evidence`; the model holds no Fluncle token, and the script records each verdict with record_label_triage (agent tier). It cannot rule: update_label is operator tier and 403s the box token. Labels a round left unfinished (a failed batch, or past the cap) are carried and fire the next day. The model runs --restricted with dontAsk permissions, confined to its batch directory and the skill. A fired round that records zero proposals, or any failed batch, exits non-zero, reads failed on /status and posts to Discord. Source: docs/agents/hermes/scripts/{label-triage-sweep.ts,label-triage-sweep.sh}.",
|
|
3732
3753
|
probeConfig: { cadenceMs: 24 * 60 * MINUTE_MS, cronName: "fluncle-label-triage", kind: "cron" },
|
|
3733
|
-
statusDescription: "
|
|
3734
|
-
title: "Label triage
|
|
3754
|
+
statusDescription: "researches the label pile when it needs a round",
|
|
3755
|
+
title: "Label triage",
|
|
3735
3756
|
weights: { status: "hidden" }
|
|
3736
3757
|
},
|
|
3737
3758
|
{
|
|
@@ -11190,7 +11211,7 @@ var init_admin_albums = __esm(() => {
|
|
|
11190
11211
|
});
|
|
11191
11212
|
|
|
11192
11213
|
// ../../packages/contracts/src/orpc/admin-artifacts.ts
|
|
11193
|
-
var ARTIFACT_CHANGE_API_MAX_LIMIT = 500, ARTIFACT_SNAPSHOT_API_MAX_LIMIT = 200, ARTIFACT_COMPACTION_API_MAX_LIMIT = 1000, ARTIFACT_SUPPORTED_CONTRACTS, ArtifactStreamSchema, ArtifactContractSchema, ConsumerIdSchema, DigestSchema, SequenceSchema, ArtifactRebuildCheckpointSchema, ArtifactConsumerStatusSchema, ArtifactChangeEventSchema, ArtifactSnapshotItemSchema, ArtifactSnapshotPageSchema, ArtifactChangePageSchema, ArtifactCompactionResultSchema, registerArtifactConsumer, getArtifactConsumer, listArtifactSnapshot, checkpointArtifactRebuild, activateArtifactConsumer, listArtifactChanges, acknowledgeArtifactChanges, inactivateArtifactConsumer, compactArtifactChanges, adminArtifactsContract;
|
|
11214
|
+
var ARTIFACT_CHANGE_API_MAX_LIMIT = 500, ARTIFACT_SNAPSHOT_API_MAX_LIMIT = 200, ARTIFACT_COMPACTION_API_MAX_LIMIT = 1000, ARTIFACT_SUPPORTED_CONTRACTS, ArtifactStreamSchema, ArtifactContractSchema, ConsumerIdSchema, DigestSchema, SequenceSchema, ArtifactRebuildCheckpointSchema, ArtifactConsumerStatusSchema, ArtifactChangeEventSchema, ArtifactSnapshotItemSchema, ArtifactSnapshotPageSchema, ArtifactChangePageSchema, ArtifactCompactionResultSchema, SonarSourceAfterSchema, SonarSourceLimitSchema, SonarSourceIdsSchema, listSonarTrackDigests, listSonarTracks, listSonarCentroidDigests, listSonarCentroids, registerArtifactConsumer, getArtifactConsumer, listArtifactSnapshot, checkpointArtifactRebuild, activateArtifactConsumer, listArtifactChanges, acknowledgeArtifactChanges, inactivateArtifactConsumer, compactArtifactChanges, adminArtifactsContract;
|
|
11194
11215
|
var init_admin_artifacts = __esm(() => {
|
|
11195
11216
|
init_dist3();
|
|
11196
11217
|
init_zod();
|
|
@@ -11304,6 +11325,57 @@ var init_admin_artifacts = __esm(() => {
|
|
|
11304
11325
|
ok: literal(true),
|
|
11305
11326
|
reason: _enum(["compacted", "empty", "no_safe_barrier"])
|
|
11306
11327
|
});
|
|
11328
|
+
SonarSourceAfterSchema = string2().min(1).max(1024).optional();
|
|
11329
|
+
SonarSourceLimitSchema = number3().int().min(1).max(2000).default(1000);
|
|
11330
|
+
SonarSourceIdsSchema = array(string2().min(1).max(1024)).min(1).max(200).refine((ids) => new Set(ids).size === ids.length);
|
|
11331
|
+
listSonarTrackDigests = oc.route({
|
|
11332
|
+
method: "GET",
|
|
11333
|
+
operationId: "listSonarTrackDigests",
|
|
11334
|
+
path: "/admin/sonar/source/tracks",
|
|
11335
|
+
summary: "List source track digests and revisions",
|
|
11336
|
+
tags: ["Admin"]
|
|
11337
|
+
}).input(strictObject({ after: SonarSourceAfterSchema, limit: SonarSourceLimitSchema })).output(strictObject({
|
|
11338
|
+
items: array(strictObject({
|
|
11339
|
+
payloadDigest: DigestSchema,
|
|
11340
|
+
revision: SequenceSchema,
|
|
11341
|
+
subjectId: string2().min(1).max(1024)
|
|
11342
|
+
})),
|
|
11343
|
+
nextAfter: string2().nullable(),
|
|
11344
|
+
ok: literal(true)
|
|
11345
|
+
}));
|
|
11346
|
+
listSonarTracks = oc.route({
|
|
11347
|
+
method: "POST",
|
|
11348
|
+
operationId: "listSonarTracks",
|
|
11349
|
+
path: "/admin/sonar/source/tracks/items",
|
|
11350
|
+
summary: "Read selected source tracks",
|
|
11351
|
+
tags: ["Admin"]
|
|
11352
|
+
}).input(strictObject({ subjectIds: SonarSourceIdsSchema })).output(strictObject({
|
|
11353
|
+
absentIds: array(string2()),
|
|
11354
|
+
items: array(ArtifactSnapshotItemSchema.extend({ revision: SequenceSchema })),
|
|
11355
|
+
ok: literal(true)
|
|
11356
|
+
}));
|
|
11357
|
+
listSonarCentroidDigests = oc.route({
|
|
11358
|
+
method: "GET",
|
|
11359
|
+
operationId: "listSonarCentroidDigests",
|
|
11360
|
+
path: "/admin/sonar/source/centroids",
|
|
11361
|
+
summary: "List source artist centroid digests",
|
|
11362
|
+
tags: ["Admin"]
|
|
11363
|
+
}).input(strictObject({ after: SonarSourceAfterSchema, limit: SonarSourceLimitSchema })).output(strictObject({
|
|
11364
|
+
items: array(strictObject({ artistId: string2(), digest: DigestSchema })),
|
|
11365
|
+
nextAfter: string2().nullable(),
|
|
11366
|
+
ok: literal(true)
|
|
11367
|
+
}));
|
|
11368
|
+
listSonarCentroids = oc.route({
|
|
11369
|
+
method: "POST",
|
|
11370
|
+
operationId: "listSonarCentroids",
|
|
11371
|
+
path: "/admin/sonar/source/centroids/items",
|
|
11372
|
+
summary: "Read selected artist centroids",
|
|
11373
|
+
tags: ["Admin"]
|
|
11374
|
+
}).input(strictObject({ artistIds: SonarSourceIdsSchema })).output(strictObject({
|
|
11375
|
+
absentIds: array(string2()),
|
|
11376
|
+
items: array(strictObject({ artistId: string2(), blobBase64: string2(), digest: DigestSchema })),
|
|
11377
|
+
ok: literal(true)
|
|
11378
|
+
}));
|
|
11307
11379
|
registerArtifactConsumer = oc.route({
|
|
11308
11380
|
method: "POST",
|
|
11309
11381
|
operationId: "registerArtifactConsumer",
|
|
@@ -11364,6 +11436,7 @@ var init_admin_artifacts = __esm(() => {
|
|
|
11364
11436
|
tags: ["Admin"]
|
|
11365
11437
|
}).input(strictObject({
|
|
11366
11438
|
consumerId: ConsumerIdSchema,
|
|
11439
|
+
fromSeq: number3().int().nonnegative().optional(),
|
|
11367
11440
|
limit: number3().int().min(1).max(ARTIFACT_CHANGE_API_MAX_LIMIT).default(100)
|
|
11368
11441
|
})).output(ArtifactChangePageSchema);
|
|
11369
11442
|
acknowledgeArtifactChanges = oc.route({
|
|
@@ -11404,6 +11477,10 @@ var init_admin_artifacts = __esm(() => {
|
|
|
11404
11477
|
inactivate_artifact_consumer: inactivateArtifactConsumer,
|
|
11405
11478
|
list_artifact_changes: listArtifactChanges,
|
|
11406
11479
|
list_artifact_snapshot: listArtifactSnapshot,
|
|
11480
|
+
list_sonar_centroid_digests: listSonarCentroidDigests,
|
|
11481
|
+
list_sonar_centroids: listSonarCentroids,
|
|
11482
|
+
list_sonar_track_digests: listSonarTrackDigests,
|
|
11483
|
+
list_sonar_tracks: listSonarTracks,
|
|
11407
11484
|
register_artifact_consumer: registerArtifactConsumer
|
|
11408
11485
|
};
|
|
11409
11486
|
});
|
|
@@ -14033,6 +14110,7 @@ var init_admin_labels = __esm(() => {
|
|
|
14033
14110
|
LabelSeedStateSchema = _enum(["disabled", "enabled", "undecided"]).meta({ id: "LabelSeedState" });
|
|
14034
14111
|
LabelTriageVerdictSchema = _enum(["dnb", "dnb_partial", "not_dnb", "unclear"]).meta({ id: "LabelTriageVerdict" });
|
|
14035
14112
|
LabelAdminItemSchema = object({
|
|
14113
|
+
carriesArtistRules: boolean2().optional(),
|
|
14036
14114
|
createdAt: string2(),
|
|
14037
14115
|
disambiguation: string2().nullable().optional(),
|
|
14038
14116
|
findingCount: number2(),
|
|
@@ -25013,7 +25091,8 @@ JSON field reference:
|
|
|
25013
25091
|
}
|
|
25014
25092
|
for (const label of labels) {
|
|
25015
25093
|
const looked = label.triageCheckedAt ? label.triageVerdict : "never looked";
|
|
25016
|
-
|
|
25094
|
+
const rules = label.carriesArtistRules ? " artist rules" : "";
|
|
25095
|
+
console.log(`${label.slug} ${label.seedState} ${looked ?? ""}${rules}`.trimEnd());
|
|
25017
25096
|
}
|
|
25018
25097
|
});
|
|
25019
25098
|
labels.command("evidence").description("Gather a label's MusicBrainz, Discogs, Beatport and Apple evidence for triage (cached, rate-limited)").argument("<label>", "The label's MusicBrainz MBID, slug, or lbl_\u2026 id").option("--census", "Also count FIRST credits per recording over the label's releases", false).option("--census-pages <n>", "MusicBrainz pages the census may read, 1-5", "5").option("--sources <list>", "Comma list of musicbrainz,discogs,beatport,apple (default all)").option("--refresh", "Ignore cached responses and fetch fresh", false).option("--json", "Print JSON", false).action(async (input, options) => {
|
package/package.json
CHANGED