fluncle 0.34.0 → 0.36.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 +92 -2
- 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.36.0".trim() ? "0.36.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();
|
|
@@ -4618,6 +4638,38 @@ var init_mixtape_mixcloud2 = __esm(() => {
|
|
|
4618
4638
|
PICTURE_MAX_BYTES2 = 10 * 1024 * 1024;
|
|
4619
4639
|
});
|
|
4620
4640
|
|
|
4641
|
+
// src/commands/auth-lastfm.ts
|
|
4642
|
+
var exports_auth_lastfm = {};
|
|
4643
|
+
__export(exports_auth_lastfm, {
|
|
4644
|
+
authLastfmCommand: () => authLastfmCommand
|
|
4645
|
+
});
|
|
4646
|
+
async function authLastfmCommand(options) {
|
|
4647
|
+
if (options.token?.trim()) {
|
|
4648
|
+
const response2 = await adminApiPost("/api/admin/lastfm/auth/session", { token: options.token.trim() });
|
|
4649
|
+
console.log(`Last.fm connected as ${response2.name || "fluncle"}.
|
|
4650
|
+
|
|
4651
|
+
Set this as the Worker secret LASTFM_SESSION_KEY (it does not expire):
|
|
4652
|
+
|
|
4653
|
+
${response2.sessionKey}
|
|
4654
|
+
|
|
4655
|
+
bun run --cwd apps/web wrangler secret put LASTFM_SESSION_KEY
|
|
4656
|
+
|
|
4657
|
+
Also store it in 1Password (Fluncle vault) alongside the API key + shared secret.`);
|
|
4658
|
+
return;
|
|
4659
|
+
}
|
|
4660
|
+
const response = await adminApiGet("/api/admin/lastfm/auth/start");
|
|
4661
|
+
console.log(`Open this Last.fm authorization URL (logged in as fluncle) and click "Yes, allow access":
|
|
4662
|
+
|
|
4663
|
+
${response.authUrl}
|
|
4664
|
+
|
|
4665
|
+
After approving, run this to mint the durable session key:
|
|
4666
|
+
|
|
4667
|
+
fluncle admin auth lastfm --token ${response.token}`);
|
|
4668
|
+
}
|
|
4669
|
+
var init_auth_lastfm = __esm(() => {
|
|
4670
|
+
init_api();
|
|
4671
|
+
});
|
|
4672
|
+
|
|
4621
4673
|
// src/interactive.ts
|
|
4622
4674
|
var exports_interactive = {};
|
|
4623
4675
|
__export(exports_interactive, {
|
|
@@ -4897,7 +4949,7 @@ function trackDetailLines(track) {
|
|
|
4897
4949
|
var COORD_FALLBACK2 = "—";
|
|
4898
4950
|
|
|
4899
4951
|
// src/cli.ts
|
|
4900
|
-
import { existsSync as existsSync2 } from "fs";
|
|
4952
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
4901
4953
|
import path from "path";
|
|
4902
4954
|
|
|
4903
4955
|
// ../../node_modules/.bun/commander@14.0.3/node_modules/commander/esm.mjs
|
|
@@ -5123,6 +5175,10 @@ function addAdminCommands(program2) {
|
|
|
5123
5175
|
const { previewArchiveUploadCommand: previewArchiveUploadCommand2 } = await Promise.resolve().then(() => (init_preview_archive(), exports_preview_archive));
|
|
5124
5176
|
await runTrackPreviewArchive(idOrLogId, options, previewArchiveUploadCommand2);
|
|
5125
5177
|
});
|
|
5178
|
+
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) => {
|
|
5179
|
+
const { trackObserveCommand: trackObserveCommand2 } = await Promise.resolve().then(() => (init_track(), exports_track));
|
|
5180
|
+
await runTrackObserve(idOrLogId, options, trackObserveCommand2);
|
|
5181
|
+
});
|
|
5126
5182
|
const adminMixtapes = configureCommand(admin.command("mixtapes").description("Mixtape admin commands"));
|
|
5127
5183
|
adminMixtapes.action(() => {
|
|
5128
5184
|
adminMixtapes.outputHelp();
|
|
@@ -5202,6 +5258,10 @@ function addAdminCommands(program2) {
|
|
|
5202
5258
|
const { authMixcloudCommand: authMixcloudCommand3 } = await Promise.resolve().then(() => (init_mixtape_mixcloud2(), exports_mixtape_mixcloud2));
|
|
5203
5259
|
await authMixcloudCommand3();
|
|
5204
5260
|
});
|
|
5261
|
+
auth.command("lastfm").description("Authorize Last.fm access (love-on-add). Run once for the URL, then again with --token").option("--token <token>", "The approved request token, to mint the session key").action(async (options) => {
|
|
5262
|
+
const { authLastfmCommand: authLastfmCommand2 } = await Promise.resolve().then(() => (init_auth_lastfm(), exports_auth_lastfm));
|
|
5263
|
+
await authLastfmCommand2(options);
|
|
5264
|
+
});
|
|
5205
5265
|
const backfill = configureCommand(admin.command("backfill").description("Backfill operator-only archives"));
|
|
5206
5266
|
backfill.action(() => {
|
|
5207
5267
|
backfill.outputHelp();
|
|
@@ -5229,6 +5289,36 @@ async function runTrackPreviewArchive(idOrLogId, options, previewArchiveUploadCo
|
|
|
5229
5289
|
console.log(` source: ${result.source}`);
|
|
5230
5290
|
console.log(` mime: ${result.mime}`);
|
|
5231
5291
|
}
|
|
5292
|
+
async function runTrackObserve(idOrLogId, options, trackObserveCommand2) {
|
|
5293
|
+
const script = options.scriptFile ? readFileSync2(options.scriptFile, "utf8") : options.script;
|
|
5294
|
+
if (!idOrLogId || !script || !script.trim()) {
|
|
5295
|
+
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]");
|
|
5296
|
+
}
|
|
5297
|
+
const durationMs = options.durationMs === undefined ? undefined : Number.parseInt(options.durationMs, 10);
|
|
5298
|
+
if (durationMs !== undefined && (!Number.isInteger(durationMs) || durationMs < 1)) {
|
|
5299
|
+
throw new Error("--duration-ms must be a positive integer");
|
|
5300
|
+
}
|
|
5301
|
+
const durationTargetSec = options.durationTargetSec === undefined ? undefined : Number.parseInt(options.durationTargetSec, 10);
|
|
5302
|
+
if (durationTargetSec !== undefined && (!Number.isInteger(durationTargetSec) || durationTargetSec < 1)) {
|
|
5303
|
+
throw new Error("--duration-target-sec must be a positive integer");
|
|
5304
|
+
}
|
|
5305
|
+
const result = await trackObserveCommand2(idOrLogId, {
|
|
5306
|
+
contextNote: options.contextNote,
|
|
5307
|
+
durationMs,
|
|
5308
|
+
durationTargetSec,
|
|
5309
|
+
model: options.model,
|
|
5310
|
+
script: script.trim(),
|
|
5311
|
+
voiceId: options.voiceId
|
|
5312
|
+
});
|
|
5313
|
+
if (options.json) {
|
|
5314
|
+
printJson(result);
|
|
5315
|
+
return;
|
|
5316
|
+
}
|
|
5317
|
+
console.log(`Recorded observation for ${result.logId}`);
|
|
5318
|
+
console.log(` audio: ${result.audioUrl}`);
|
|
5319
|
+
console.log(` length: ${Math.round(result.durationMs / 1000)}s`);
|
|
5320
|
+
console.log(` voice: ${result.voiceId}`);
|
|
5321
|
+
}
|
|
5232
5322
|
async function runPreviewArchiveBackfill(options, previewArchiveBackfillCommand2) {
|
|
5233
5323
|
const limit = options.limit === undefined ? undefined : Number.parseInt(options.limit, 10);
|
|
5234
5324
|
if (limit !== undefined && (!Number.isInteger(limit) || limit < 1)) {
|
package/package.json
CHANGED