fluncle 0.56.0 → 0.58.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 +119 -8
  2. package/package.json +1 -1
package/bin/fluncle.mjs CHANGED
@@ -423,7 +423,7 @@ function parseVersion(version) {
423
423
  var currentVersion;
424
424
  var init_version = __esm(() => {
425
425
  init_output();
426
- currentVersion = "0.56.0".trim() ? "0.56.0".trim() : "0.1.0";
426
+ currentVersion = "0.58.0".trim() ? "0.58.0".trim() : "0.1.0";
427
427
  });
428
428
 
429
429
  // src/update-notifier.ts
@@ -782,6 +782,7 @@ function mapTrack(track) {
782
782
  title: track.title,
783
783
  trackId: track.trackId,
784
784
  type: "finding",
785
+ videoGrain: track.videoGrain,
785
786
  videoModel: track.videoModel,
786
787
  videoModelReasoning: track.videoModelReasoning,
787
788
  videoUrl: track.videoUrl,
@@ -1531,6 +1532,7 @@ function mapTrack2(track) {
1531
1532
  title: track.title,
1532
1533
  trackId: track.trackId,
1533
1534
  type: "finding",
1535
+ videoGrain: track.videoGrain,
1534
1536
  videoModel: track.videoModel,
1535
1537
  videoModelReasoning: track.videoModelReasoning,
1536
1538
  videoUrl: track.videoUrl,
@@ -1912,7 +1914,7 @@ function parseVersion2(version) {
1912
1914
  var currentVersion2, latestReleaseUrl = "https://api.github.com/repos/mauricekleine/fluncle/releases/latest";
1913
1915
  var init_version2 = __esm(() => {
1914
1916
  init_output();
1915
- currentVersion2 = "0.56.0".trim() ? "0.56.0".trim() : "0.1.0";
1917
+ currentVersion2 = "0.58.0".trim() ? "0.58.0".trim() : "0.1.0";
1916
1918
  });
1917
1919
 
1918
1920
  // src/commands/track.ts
@@ -1922,7 +1924,10 @@ __export(exports_track, {
1922
1924
  trackUpdateCommand: () => trackUpdateCommand,
1923
1925
  trackSocialUpdateCommand: () => trackSocialUpdateCommand,
1924
1926
  trackSocialShowCommand: () => trackSocialShowCommand,
1927
+ trackRequeueVideoCommand: () => trackRequeueVideoCommand,
1928
+ trackPurgeVideoCommand: () => trackPurgeVideoCommand,
1925
1929
  trackObserveCommand: () => trackObserveCommand,
1930
+ trackNoteCommand: () => trackNoteCommand,
1926
1931
  trackGetCommand: () => trackGetCommand,
1927
1932
  trackDraftCommand: () => trackDraftCommand,
1928
1933
  trackContextCommand: () => trackContextCommand
@@ -1963,7 +1968,8 @@ async function trackVideoCommand(idOrLogId, files, onProgress) {
1963
1968
  videoModel,
1964
1969
  videoModelReasoning,
1965
1970
  ...squared ? { squared: true } : {},
1966
- ...manifest.vehicle ? { videoVehicle: manifest.vehicle } : {}
1971
+ ...manifest.vehicle ? { videoVehicle: manifest.vehicle } : {},
1972
+ ...manifest.grain ? { videoGrain: manifest.grain } : {}
1967
1973
  });
1968
1974
  return { logId: finalize.logId, ok: true, trackId: finalize.trackId, urls };
1969
1975
  }
@@ -1971,7 +1977,7 @@ async function readManifestFields(renderPath) {
1971
1977
  try {
1972
1978
  const manifest = await Bun.file(renderPath).json();
1973
1979
  const result = {};
1974
- for (const key of ["vehicle", "model", "reasoning"]) {
1980
+ for (const key of ["vehicle", "grain", "model", "reasoning"]) {
1975
1981
  const value = manifest[key];
1976
1982
  if (typeof value === "string" && value.trim()) {
1977
1983
  result[key] = value.trim().slice(0, 120);
@@ -2019,6 +2025,12 @@ async function trackUpdateCommand(trackId, options) {
2019
2025
  }
2020
2026
  return adminApiPatch(`/api/admin/tracks/${encodeURIComponent(trackId)}`, body);
2021
2027
  }
2028
+ async function trackRequeueVideoCommand(idOrLogId) {
2029
+ return adminApiPost(`/api/admin/tracks/${encodeURIComponent(idOrLogId)}/video/requeue`);
2030
+ }
2031
+ async function trackPurgeVideoCommand(idOrLogId) {
2032
+ return adminApiPost(`/api/admin/tracks/${encodeURIComponent(idOrLogId)}/video/purge`);
2033
+ }
2022
2034
  async function trackObserveCommand(idOrLogId, options) {
2023
2035
  const body = { script: options.script };
2024
2036
  if (options.voiceId !== undefined) {
@@ -2043,8 +2055,15 @@ async function trackContextCommand(idOrLogId, options = {}) {
2043
2055
  if (options.query !== undefined) {
2044
2056
  body.query = options.query;
2045
2057
  }
2058
+ if (options.refresh) {
2059
+ body.refresh = true;
2060
+ }
2046
2061
  return adminApiPost(`/api/admin/tracks/${encodeURIComponent(idOrLogId)}/context`, body);
2047
2062
  }
2063
+ async function trackNoteCommand(idOrLogId, options) {
2064
+ const body = { note: options.note };
2065
+ return adminApiPost(`/api/admin/tracks/${encodeURIComponent(idOrLogId)}/note`, body);
2066
+ }
2048
2067
  var DEFAULT_VIDEO_MODEL = "anthropic/claude-opus-4-8", DEFAULT_VIDEO_REASONING = "high", FOUND_BASE = "https://found.fluncle.com", VIDEO_FIELDS;
2049
2068
  var init_track = __esm(() => {
2050
2069
  init_api();
@@ -2094,6 +2113,7 @@ __export(exports_admin_tracks, {
2094
2113
  vehiclesCommand: () => vehiclesCommand,
2095
2114
  queueCommand: () => queueCommand,
2096
2115
  observeQueueCommand: () => observeQueueCommand,
2116
+ noteQueueCommand: () => noteQueueCommand,
2097
2117
  enrichQueueCommand: () => enrichQueueCommand,
2098
2118
  contextQueueCommand: () => contextQueueCommand,
2099
2119
  backfillLastfmCommand: () => backfillLastfmCommand,
@@ -2101,7 +2121,7 @@ __export(exports_admin_tracks, {
2101
2121
  backfillAlignmentCommand: () => backfillAlignmentCommand
2102
2122
  });
2103
2123
  async function fetchAdminTracks(options) {
2104
- const { hasContext, hasObservation, hasVideo, max, order, status } = options;
2124
+ const { hasContext, hasNote, hasObservation, hasVideo, max, order, status } = options;
2105
2125
  const results = [];
2106
2126
  let cursor;
2107
2127
  do {
@@ -2112,6 +2132,9 @@ async function fetchAdminTracks(options) {
2112
2132
  if (hasContext !== undefined) {
2113
2133
  params.set("hasContext", String(hasContext));
2114
2134
  }
2135
+ if (hasNote !== undefined) {
2136
+ params.set("hasNote", String(hasNote));
2137
+ }
2115
2138
  if (hasObservation !== undefined) {
2116
2139
  params.set("hasObservation", String(hasObservation));
2117
2140
  }
@@ -2159,6 +2182,14 @@ async function observeQueueCommand(limit) {
2159
2182
  order: "asc"
2160
2183
  });
2161
2184
  }
2185
+ async function noteQueueCommand(limit) {
2186
+ return fetchAdminTracks({
2187
+ hasContext: true,
2188
+ hasNote: false,
2189
+ max: limit,
2190
+ order: "asc"
2191
+ });
2192
+ }
2162
2193
  async function backfillLastfmCommand(limit, dryRun, cursor) {
2163
2194
  const params = new URLSearchParams({ dryRun: String(dryRun), limit: String(limit) });
2164
2195
  if (cursor) {
@@ -2185,6 +2216,7 @@ async function vehiclesCommand(limit) {
2185
2216
  return tracks.map((track) => ({
2186
2217
  addedAt: track.addedAt,
2187
2218
  artists: track.artists,
2219
+ grain: track.videoGrain,
2188
2220
  logId: track.logId,
2189
2221
  title: track.title,
2190
2222
  vehicle: track.videoVehicle
@@ -5470,6 +5502,14 @@ function addAdminCommands(program2) {
5470
5502
  const { trackVideoCommand: trackVideoCommand2 } = await Promise.resolve().then(() => (init_track(), exports_track));
5471
5503
  await runTrackVideo(idOrLogId, options, trackVideoCommand2);
5472
5504
  });
5505
+ adminTrack.command("requeue-video").description("Clear a finding's video so it re-enters the render queue (operator)").argument("[idOrLogId]").option("--json", "Print JSON", false).allowExcessArguments().action(async (idOrLogId, options) => {
5506
+ const { trackRequeueVideoCommand: trackRequeueVideoCommand2 } = await Promise.resolve().then(() => (init_track(), exports_track));
5507
+ await runTrackRequeueVideo(idOrLogId, options, trackRequeueVideoCommand2);
5508
+ });
5509
+ adminTrack.command("purge-video").description("Purge a finding's stale Cloudflare video renditions from the edge (operator)").argument("[idOrLogId]").option("--json", "Print JSON", false).allowExcessArguments().action(async (idOrLogId, options) => {
5510
+ const { trackPurgeVideoCommand: trackPurgeVideoCommand2 } = await Promise.resolve().then(() => (init_track(), exports_track));
5511
+ await runTrackPurgeVideo(idOrLogId, options, trackPurgeVideoCommand2);
5512
+ });
5473
5513
  adminTrack.command("draft").description("Push the video to a platform as a draft").argument("[idOrLogId]").option("--json", "Print JSON", false).option("--platform <platform>", "Publishing platform").allowExcessArguments().action(async (idOrLogId, options) => {
5474
5514
  const { trackDraftCommand: trackDraftCommand2 } = await Promise.resolve().then(() => (init_track(), exports_track));
5475
5515
  await runTrackDraft(idOrLogId, options, trackDraftCommand2);
@@ -5491,7 +5531,7 @@ function addAdminCommands(program2) {
5491
5531
  const { trackObserveCommand: trackObserveCommand2 } = await Promise.resolve().then(() => (init_track(), exports_track));
5492
5532
  await runTrackObserve(idOrLogId, options, trackObserveCommand2);
5493
5533
  });
5494
- adminTrack.command("context").description("Gather the field notes for a finding (facts only; observe speaks from them)").argument("[idOrLogId]").option("--queue", "Show the context worklist (findings missing field notes), oldest first", false).option("--limit <limit>", "Number of findings to show with --queue", "10").option("--query <text>", "Override the fact-search query (else the Worker builds one)").option("--json", "Print JSON", false).allowExcessArguments().action(async (idOrLogId, options) => {
5534
+ adminTrack.command("context").description("Gather the field notes for a finding (facts only; observe speaks from them)").argument("[idOrLogId]").option("--queue", "Show the context worklist (findings missing field notes), oldest first", false).option("--limit <limit>", "Number of findings to show with --queue", "10").option("--query <text>", "Override the fact-search query (else the Worker builds one)").option("--refresh", "Re-run the fetch even if a note exists (backfill/sharpen)", false).option("--json", "Print JSON", false).allowExcessArguments().action(async (idOrLogId, options) => {
5495
5535
  if (options.queue) {
5496
5536
  const { contextQueueCommand: contextQueueCommand2 } = await Promise.resolve().then(() => (init_admin_tracks(), exports_admin_tracks));
5497
5537
  await runAdminContextQueue(options, contextQueueCommand2);
@@ -5500,6 +5540,15 @@ function addAdminCommands(program2) {
5500
5540
  const { trackContextCommand: trackContextCommand2 } = await Promise.resolve().then(() => (init_track(), exports_track));
5501
5541
  await runTrackContext(idOrLogId, options, trackContextCommand2);
5502
5542
  });
5543
+ adminTrack.command("note").description("Author the editorial note for a finding (fills an empty note only)").argument("[idOrLogId]").option("--queue", "Show the note worklist (context'd findings with no note yet), oldest first", false).option("--limit <limit>", "Number of findings to show with --queue", "10").option("--script <text>", "The voice-gated editorial note").option("--script-file <file>", "Read the editorial note from a file").option("--json", "Print JSON", false).allowExcessArguments().action(async (idOrLogId, options) => {
5544
+ if (options.queue) {
5545
+ const { noteQueueCommand: noteQueueCommand2 } = await Promise.resolve().then(() => (init_admin_tracks(), exports_admin_tracks));
5546
+ await runAdminNoteQueue(options, noteQueueCommand2);
5547
+ return;
5548
+ }
5549
+ const { trackNoteCommand: trackNoteCommand2 } = await Promise.resolve().then(() => (init_track(), exports_track));
5550
+ await runTrackNote(idOrLogId, options, trackNoteCommand2);
5551
+ });
5503
5552
  const adminMixtapes = configureCommand(admin.command("mixtapes").description("Mixtape admin commands"));
5504
5553
  adminMixtapes.action(() => {
5505
5554
  adminMixtapes.outputHelp();
@@ -5674,9 +5723,12 @@ async function runTrackObserve(idOrLogId, options, trackObserveCommand2) {
5674
5723
  }
5675
5724
  async function runTrackContext(idOrLogId, options, trackContextCommand2) {
5676
5725
  if (!idOrLogId) {
5677
- throw new Error("Usage: fluncle admin tracks context <track_id|log_id> [--query <text>] [--json]");
5726
+ throw new Error("Usage: fluncle admin tracks context <track_id|log_id> [--query <text>] [--refresh] [--json]");
5678
5727
  }
5679
- const result = await trackContextCommand2(idOrLogId, { query: options.query });
5728
+ const result = await trackContextCommand2(idOrLogId, {
5729
+ query: options.query,
5730
+ refresh: options.refresh
5731
+ });
5680
5732
  if (options.json) {
5681
5733
  printJson(result);
5682
5734
  return;
@@ -5695,6 +5747,23 @@ async function runTrackContext(idOrLogId, options, trackContextCommand2) {
5695
5747
  console.log(` sources: ${result.sources.join(", ")}`);
5696
5748
  }
5697
5749
  }
5750
+ async function runTrackNote(idOrLogId, options, trackNoteCommand2) {
5751
+ const note = options.scriptFile ? readFileSync3(options.scriptFile, "utf8") : options.script;
5752
+ if (!idOrLogId || !note || !note.trim()) {
5753
+ throw new Error("Usage: fluncle admin tracks note <track_id|log_id> (--script <text> | --script-file <file>) [--json]");
5754
+ }
5755
+ const result = await trackNoteCommand2(idOrLogId, { note: note.trim() });
5756
+ if (options.json) {
5757
+ printJson(result);
5758
+ return;
5759
+ }
5760
+ if (result.skipped) {
5761
+ console.log(`A note is already on file for ${result.logId}. The operator's note stands.`);
5762
+ return;
5763
+ }
5764
+ console.log(`Authored the note for ${result.logId}:`);
5765
+ console.log(` ${result.note}`);
5766
+ }
5698
5767
  async function runPreviewArchiveBackfill(options, previewArchiveBackfillCommand2) {
5699
5768
  const limit = options.limit === undefined ? undefined : Number.parseInt(options.limit, 10);
5700
5769
  if (limit !== undefined && (!Number.isInteger(limit) || limit < 1)) {
@@ -5990,6 +6059,28 @@ async function runTrackUpdate(trackId, options, trackUpdateCommand2) {
5990
6059
  }
5991
6060
  console.log(`Updated ${result.trackId}: ${result.fields.join(", ")}`);
5992
6061
  }
6062
+ async function runTrackRequeueVideo(idOrLogId, options, trackRequeueVideoCommand2) {
6063
+ if (!idOrLogId) {
6064
+ throw new Error("Missing id. Usage: fluncle admin tracks requeue-video <track_id|log_id>");
6065
+ }
6066
+ const result = await trackRequeueVideoCommand2(idOrLogId);
6067
+ if (options.json) {
6068
+ printJson(result);
6069
+ return;
6070
+ }
6071
+ console.log(result.alreadyClear ? `${result.logId} already had no video \u2014 nothing to clear.` : `Cleared the video for ${result.logId}. It's back on the render queue (and off radio until re-rendered).`);
6072
+ }
6073
+ async function runTrackPurgeVideo(idOrLogId, options, trackPurgeVideoCommand2) {
6074
+ if (!idOrLogId) {
6075
+ throw new Error("Missing id. Usage: fluncle admin tracks purge-video <track_id|log_id>");
6076
+ }
6077
+ const result = await trackPurgeVideoCommand2(idOrLogId);
6078
+ if (options.json) {
6079
+ printJson(result);
6080
+ return;
6081
+ }
6082
+ console.log(result.noVideo ? `${result.logId} has no video \u2014 nothing to purge.` : `Purging the stale renditions for ${result.logId} from the edge. The next play picks up the fresh render.`);
6083
+ }
5993
6084
  async function runMixtapeCreate(options, mixtapeCreateCommand2) {
5994
6085
  const result = await mixtapeCreateCommand2(options);
5995
6086
  if (options.json) {
@@ -6307,6 +6398,26 @@ async function runAdminObserveQueue(options, observeQueueCommand2) {
6307
6398
  console.log(trackRows2(tracks).join(`
6308
6399
  `));
6309
6400
  }
6401
+ async function runAdminNoteQueue(options, noteQueueCommand2) {
6402
+ const limit = parseListLimit(options.limit);
6403
+ const tracks = await noteQueueCommand2(limit);
6404
+ if (options.json) {
6405
+ printJson({
6406
+ ok: true,
6407
+ tracks
6408
+ });
6409
+ return;
6410
+ }
6411
+ if (tracks.length === 0) {
6412
+ console.log("Every context'd finding has a note. Nothing waiting on the uncle's words.");
6413
+ return;
6414
+ }
6415
+ const { trackRows: trackRows2 } = await Promise.resolve().then(() => (init_format2(), exports_format));
6416
+ const noun = tracks.length === 1 ? "finding" : "findings";
6417
+ console.log(`${tracks.length} ${noun} awaiting a note, oldest first:`);
6418
+ console.log(trackRows2(tracks).join(`
6419
+ `));
6420
+ }
6310
6421
  async function runAdminEnrichQueue(options, enrichQueueCommand2) {
6311
6422
  const limit = parseListLimit(options.limit);
6312
6423
  const tracks = await enrichQueueCommand2(limit);
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.56.0"
34
+ "version": "0.58.0"
35
35
  }