fluncle 0.35.0 → 0.37.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 +123 -4
- package/package.json +1 -1
package/bin/fluncle.mjs
CHANGED
|
@@ -3789,7 +3789,7 @@ function parseVersion(version) {
|
|
|
3789
3789
|
var currentVersion, latestReleaseUrl = "https://api.github.com/repos/mauricekleine/fluncle/releases/latest";
|
|
3790
3790
|
var init_version = __esm(() => {
|
|
3791
3791
|
init_output();
|
|
3792
|
-
currentVersion = "0.
|
|
3792
|
+
currentVersion = "0.37.0".trim() ? "0.37.0".trim() : "0.1.0";
|
|
3793
3793
|
});
|
|
3794
3794
|
|
|
3795
3795
|
// src/commands/track.ts
|
|
@@ -3799,6 +3799,7 @@ __export(exports_track, {
|
|
|
3799
3799
|
trackUpdateCommand: () => trackUpdateCommand,
|
|
3800
3800
|
trackSocialUpdateCommand: () => trackSocialUpdateCommand,
|
|
3801
3801
|
trackSocialShowCommand: () => trackSocialShowCommand,
|
|
3802
|
+
trackObserveCommand: () => trackObserveCommand,
|
|
3802
3803
|
trackGetCommand: () => trackGetCommand,
|
|
3803
3804
|
trackDraftCommand: () => trackDraftCommand
|
|
3804
3805
|
});
|
|
@@ -3892,6 +3893,25 @@ async function trackUpdateCommand(trackId, options) {
|
|
|
3892
3893
|
}
|
|
3893
3894
|
return adminApiPatch(`/api/admin/tracks/${encodeURIComponent(trackId)}`, body);
|
|
3894
3895
|
}
|
|
3896
|
+
async function trackObserveCommand(idOrLogId, options) {
|
|
3897
|
+
const body = { script: options.script };
|
|
3898
|
+
if (options.voiceId !== undefined) {
|
|
3899
|
+
body.voiceId = options.voiceId;
|
|
3900
|
+
}
|
|
3901
|
+
if (options.model !== undefined) {
|
|
3902
|
+
body.model = options.model;
|
|
3903
|
+
}
|
|
3904
|
+
if (options.durationMs !== undefined) {
|
|
3905
|
+
body.durationMs = options.durationMs;
|
|
3906
|
+
}
|
|
3907
|
+
if (options.durationTargetSec !== undefined) {
|
|
3908
|
+
body.durationTargetSec = options.durationTargetSec;
|
|
3909
|
+
}
|
|
3910
|
+
if (options.contextNote !== undefined) {
|
|
3911
|
+
body.contextNote = options.contextNote;
|
|
3912
|
+
}
|
|
3913
|
+
return adminApiPost(`/api/admin/tracks/${encodeURIComponent(idOrLogId)}/observe`, body);
|
|
3914
|
+
}
|
|
3895
3915
|
var DEFAULT_VIDEO_MODEL = "anthropic/claude-opus-4-8", DEFAULT_VIDEO_REASONING = "high", FOUND_BASE = "https://found.fluncle.com", VIDEO_FIELDS;
|
|
3896
3916
|
var init_track = __esm(() => {
|
|
3897
3917
|
init_api();
|
|
@@ -3938,10 +3958,12 @@ var init_add = __esm(() => {
|
|
|
3938
3958
|
var exports_admin_tracks = {};
|
|
3939
3959
|
__export(exports_admin_tracks, {
|
|
3940
3960
|
vehiclesCommand: () => vehiclesCommand,
|
|
3941
|
-
queueCommand: () => queueCommand
|
|
3961
|
+
queueCommand: () => queueCommand,
|
|
3962
|
+
enrichSweepCommand: () => enrichSweepCommand,
|
|
3963
|
+
enrichQueueCommand: () => enrichQueueCommand
|
|
3942
3964
|
});
|
|
3943
3965
|
async function fetchAdminTracks(options) {
|
|
3944
|
-
const { hasVideo, max, order } = options;
|
|
3966
|
+
const { hasVideo, max, order, status } = options;
|
|
3945
3967
|
const results = [];
|
|
3946
3968
|
let cursor;
|
|
3947
3969
|
do {
|
|
@@ -3949,6 +3971,9 @@ async function fetchAdminTracks(options) {
|
|
|
3949
3971
|
if (hasVideo !== undefined) {
|
|
3950
3972
|
params.set("hasVideo", String(hasVideo));
|
|
3951
3973
|
}
|
|
3974
|
+
if (status !== undefined) {
|
|
3975
|
+
params.set("status", status);
|
|
3976
|
+
}
|
|
3952
3977
|
if (cursor) {
|
|
3953
3978
|
params.set("cursor", cursor);
|
|
3954
3979
|
}
|
|
@@ -3970,6 +3995,12 @@ async function fetchAdminTracks(options) {
|
|
|
3970
3995
|
async function queueCommand(limit) {
|
|
3971
3996
|
return fetchAdminTracks({ hasVideo: false, max: limit, order: "asc" });
|
|
3972
3997
|
}
|
|
3998
|
+
async function enrichQueueCommand(limit) {
|
|
3999
|
+
return fetchAdminTracks({ max: limit, order: "asc", status: "queue" });
|
|
4000
|
+
}
|
|
4001
|
+
async function enrichSweepCommand(limit) {
|
|
4002
|
+
return adminApiPost(`/api/admin/enrich-sweep?limit=${limit}`);
|
|
4003
|
+
}
|
|
3973
4004
|
async function vehiclesCommand(limit) {
|
|
3974
4005
|
const tracks = await fetchAdminTracks({ hasVideo: true, max: limit, order: "desc" });
|
|
3975
4006
|
return tracks.map((track) => ({
|
|
@@ -4929,7 +4960,7 @@ function trackDetailLines(track) {
|
|
|
4929
4960
|
var COORD_FALLBACK2 = "—";
|
|
4930
4961
|
|
|
4931
4962
|
// src/cli.ts
|
|
4932
|
-
import { existsSync as existsSync2 } from "fs";
|
|
4963
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
4933
4964
|
import path from "path";
|
|
4934
4965
|
|
|
4935
4966
|
// ../../node_modules/.bun/commander@14.0.3/node_modules/commander/esm.mjs
|
|
@@ -5127,6 +5158,14 @@ function addAdminCommands(program2) {
|
|
|
5127
5158
|
const { queueCommand: queueCommand2 } = await Promise.resolve().then(() => (init_admin_tracks(), exports_admin_tracks));
|
|
5128
5159
|
await runAdminQueue(options, queueCommand2);
|
|
5129
5160
|
});
|
|
5161
|
+
admin.command("enrich-queue").description("Findings needing (re-)enrichment: pending, failed, or stuck processing").option("--limit <limit>", "Number of findings to show", "10").option("--json", "Print JSON", false).action(async (options) => {
|
|
5162
|
+
const { enrichQueueCommand: enrichQueueCommand2 } = await Promise.resolve().then(() => (init_admin_tracks(), exports_admin_tracks));
|
|
5163
|
+
await runAdminEnrichQueue(options, enrichQueueCommand2);
|
|
5164
|
+
});
|
|
5165
|
+
admin.command("enrich-sweep").description("Re-fire enrichment for everything in the enrich-queue (idempotent self-heal)").option("--limit <limit>", "Max findings to re-trigger", "25").option("--json", "Print JSON", false).action(async (options) => {
|
|
5166
|
+
const { enrichSweepCommand: enrichSweepCommand2 } = await Promise.resolve().then(() => (init_admin_tracks(), exports_admin_tracks));
|
|
5167
|
+
await runAdminEnrichSweep(options, enrichSweepCommand2);
|
|
5168
|
+
});
|
|
5130
5169
|
admin.command("vehicles").description("Recent video vehicles, newest first (the style ledger for diversity)").option("--limit <limit>", "Number of vehicles to show", "10").option("--json", "Print JSON", false).action(async (options) => {
|
|
5131
5170
|
const { vehiclesCommand: vehiclesCommand2 } = await Promise.resolve().then(() => (init_admin_tracks(), exports_admin_tracks));
|
|
5132
5171
|
await runAdminVehicles(options, vehiclesCommand2);
|
|
@@ -5155,6 +5194,10 @@ function addAdminCommands(program2) {
|
|
|
5155
5194
|
const { previewArchiveUploadCommand: previewArchiveUploadCommand2 } = await Promise.resolve().then(() => (init_preview_archive(), exports_preview_archive));
|
|
5156
5195
|
await runTrackPreviewArchive(idOrLogId, options, previewArchiveUploadCommand2);
|
|
5157
5196
|
});
|
|
5197
|
+
adminTrack.command("observe").description("Render Fluncle's spoken field observation for a track (ElevenLabs, Worker-side)").argument("[idOrLogId]").option("--script <text>", "The voice-gated observation script (the spoken text)").option("--script-file <file>", "Read the observation script from a file (e.g. observation.txt)").option("--voice-id <id>", "Override the configured ElevenLabs voice id").option("--model <model>", "TTS model (eleven_multilingual_v2 | eleven_v3)").option("--duration-ms <ms>", "Probed audio duration in ms (the agent runs ffprobe)").option("--duration-target-sec <sec>", "Target observation length in seconds (20\u201345)").option("--context-note <text>", "Pre-fetched factual context (else the Worker firecrawls)").option("--json", "Print JSON", false).allowExcessArguments().action(async (idOrLogId, options) => {
|
|
5198
|
+
const { trackObserveCommand: trackObserveCommand2 } = await Promise.resolve().then(() => (init_track(), exports_track));
|
|
5199
|
+
await runTrackObserve(idOrLogId, options, trackObserveCommand2);
|
|
5200
|
+
});
|
|
5158
5201
|
const adminMixtapes = configureCommand(admin.command("mixtapes").description("Mixtape admin commands"));
|
|
5159
5202
|
adminMixtapes.action(() => {
|
|
5160
5203
|
adminMixtapes.outputHelp();
|
|
@@ -5265,6 +5308,36 @@ async function runTrackPreviewArchive(idOrLogId, options, previewArchiveUploadCo
|
|
|
5265
5308
|
console.log(` source: ${result.source}`);
|
|
5266
5309
|
console.log(` mime: ${result.mime}`);
|
|
5267
5310
|
}
|
|
5311
|
+
async function runTrackObserve(idOrLogId, options, trackObserveCommand2) {
|
|
5312
|
+
const script = options.scriptFile ? readFileSync2(options.scriptFile, "utf8") : options.script;
|
|
5313
|
+
if (!idOrLogId || !script || !script.trim()) {
|
|
5314
|
+
throw new Error("Usage: fluncle admin track observe <track_id|log_id> (--script <text> | --script-file <file>) [--voice-id <id>] [--model <model>] [--duration-ms <ms>] [--context-note <text>] [--json]");
|
|
5315
|
+
}
|
|
5316
|
+
const durationMs = options.durationMs === undefined ? undefined : Number.parseInt(options.durationMs, 10);
|
|
5317
|
+
if (durationMs !== undefined && (!Number.isInteger(durationMs) || durationMs < 1)) {
|
|
5318
|
+
throw new Error("--duration-ms must be a positive integer");
|
|
5319
|
+
}
|
|
5320
|
+
const durationTargetSec = options.durationTargetSec === undefined ? undefined : Number.parseInt(options.durationTargetSec, 10);
|
|
5321
|
+
if (durationTargetSec !== undefined && (!Number.isInteger(durationTargetSec) || durationTargetSec < 1)) {
|
|
5322
|
+
throw new Error("--duration-target-sec must be a positive integer");
|
|
5323
|
+
}
|
|
5324
|
+
const result = await trackObserveCommand2(idOrLogId, {
|
|
5325
|
+
contextNote: options.contextNote,
|
|
5326
|
+
durationMs,
|
|
5327
|
+
durationTargetSec,
|
|
5328
|
+
model: options.model,
|
|
5329
|
+
script: script.trim(),
|
|
5330
|
+
voiceId: options.voiceId
|
|
5331
|
+
});
|
|
5332
|
+
if (options.json) {
|
|
5333
|
+
printJson(result);
|
|
5334
|
+
return;
|
|
5335
|
+
}
|
|
5336
|
+
console.log(`Recorded observation for ${result.logId}`);
|
|
5337
|
+
console.log(` audio: ${result.audioUrl}`);
|
|
5338
|
+
console.log(` length: ${Math.round(result.durationMs / 1000)}s`);
|
|
5339
|
+
console.log(` voice: ${result.voiceId}`);
|
|
5340
|
+
}
|
|
5268
5341
|
async function runPreviewArchiveBackfill(options, previewArchiveBackfillCommand2) {
|
|
5269
5342
|
const limit = options.limit === undefined ? undefined : Number.parseInt(options.limit, 10);
|
|
5270
5343
|
if (limit !== undefined && (!Number.isInteger(limit) || limit < 1)) {
|
|
@@ -5653,6 +5726,52 @@ async function runAdminQueue(options, queueCommand2) {
|
|
|
5653
5726
|
console.log(trackRows2(tracks).join(`
|
|
5654
5727
|
`));
|
|
5655
5728
|
}
|
|
5729
|
+
async function runAdminEnrichQueue(options, enrichQueueCommand2) {
|
|
5730
|
+
const limit = parseListLimit(options.limit);
|
|
5731
|
+
const tracks = await enrichQueueCommand2(limit);
|
|
5732
|
+
if (options.json) {
|
|
5733
|
+
printJson({
|
|
5734
|
+
ok: true,
|
|
5735
|
+
tracks
|
|
5736
|
+
});
|
|
5737
|
+
return;
|
|
5738
|
+
}
|
|
5739
|
+
if (tracks.length === 0) {
|
|
5740
|
+
console.log("Nothing awaiting enrichment. Every finding is enriched.");
|
|
5741
|
+
return;
|
|
5742
|
+
}
|
|
5743
|
+
const { trackRows: trackRows2 } = await Promise.resolve().then(() => exports_format);
|
|
5744
|
+
const noun = tracks.length === 1 ? "finding" : "findings";
|
|
5745
|
+
console.log(`${tracks.length} ${noun} needing (re-)enrichment, oldest first:`);
|
|
5746
|
+
console.log(trackRows2(tracks).join(`
|
|
5747
|
+
`));
|
|
5748
|
+
}
|
|
5749
|
+
async function runAdminEnrichSweep(options, enrichSweepCommand2) {
|
|
5750
|
+
const limit = parseListLimit(options.limit);
|
|
5751
|
+
const result = await enrichSweepCommand2(limit);
|
|
5752
|
+
if (options.json) {
|
|
5753
|
+
printJson({
|
|
5754
|
+
ok: true,
|
|
5755
|
+
reEnriched: result.reEnriched,
|
|
5756
|
+
reEnrichedCount: result.reEnrichedCount,
|
|
5757
|
+
skipped: result.skipped,
|
|
5758
|
+
skippedCount: result.skippedCount
|
|
5759
|
+
});
|
|
5760
|
+
return;
|
|
5761
|
+
}
|
|
5762
|
+
if (result.reEnrichedCount === 0 && result.skippedCount === 0) {
|
|
5763
|
+
console.log("Nothing to sweep. The enrich-queue is empty.");
|
|
5764
|
+
return;
|
|
5765
|
+
}
|
|
5766
|
+
const noun = result.reEnrichedCount === 1 ? "finding" : "findings";
|
|
5767
|
+
console.log(`Re-fired enrichment for ${result.reEnrichedCount} ${noun}.`);
|
|
5768
|
+
for (const entry of result.reEnriched) {
|
|
5769
|
+
console.log(` ${entry.logId || entry.trackId} (was ${entry.status})`);
|
|
5770
|
+
}
|
|
5771
|
+
if (result.skippedCount > 0) {
|
|
5772
|
+
console.log(`Skipped ${result.skippedCount} with no Log ID yet.`);
|
|
5773
|
+
}
|
|
5774
|
+
}
|
|
5656
5775
|
async function runAdminVehicles(options, vehiclesCommand2) {
|
|
5657
5776
|
const limit = parseListLimit(options.limit);
|
|
5658
5777
|
const vehicles = await vehiclesCommand2(limit);
|
package/package.json
CHANGED