fluncle 0.88.0 → 0.89.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 +59 -12
- package/package.json +1 -1
package/bin/fluncle.mjs
CHANGED
|
@@ -538,7 +538,7 @@ function parseVersion(version) {
|
|
|
538
538
|
var currentVersion;
|
|
539
539
|
var init_version = __esm(() => {
|
|
540
540
|
init_output();
|
|
541
|
-
currentVersion = "0.
|
|
541
|
+
currentVersion = "0.89.0".trim() ? "0.89.0".trim() : "0.1.0";
|
|
542
542
|
});
|
|
543
543
|
|
|
544
544
|
// src/update-notifier.ts
|
|
@@ -2168,7 +2168,7 @@ function parseVersion2(version) {
|
|
|
2168
2168
|
var currentVersion2, latestReleaseUrl = "https://api.github.com/repos/mauricekleine/fluncle/releases/latest";
|
|
2169
2169
|
var init_version2 = __esm(() => {
|
|
2170
2170
|
init_output();
|
|
2171
|
-
currentVersion2 = "0.
|
|
2171
|
+
currentVersion2 = "0.89.0".trim() ? "0.89.0".trim() : "0.1.0";
|
|
2172
2172
|
});
|
|
2173
2173
|
|
|
2174
2174
|
// ../../packages/registry/src/index.ts
|
|
@@ -2894,16 +2894,41 @@ __export(exports_track, {
|
|
|
2894
2894
|
trackNoteCommand: () => trackNoteCommand,
|
|
2895
2895
|
trackGetCommand: () => trackGetCommand,
|
|
2896
2896
|
trackDraftCommand: () => trackDraftCommand,
|
|
2897
|
-
trackContextCommand: () => trackContextCommand
|
|
2897
|
+
trackContextCommand: () => trackContextCommand,
|
|
2898
|
+
checkBundleCompleteness: () => checkBundleCompleteness
|
|
2898
2899
|
});
|
|
2899
2900
|
async function trackGetCommand(idOrLogId) {
|
|
2900
2901
|
return publicApiGet(`/api/tracks/${encodeURIComponent(idOrLogId)}`);
|
|
2901
2902
|
}
|
|
2902
|
-
|
|
2903
|
+
function checkBundleCompleteness(files) {
|
|
2904
|
+
const uploadingFootage = FOOTAGE_FIELDS.some((option) => Boolean(files[option]));
|
|
2905
|
+
const missingFrom = (specs) => uploadingFootage ? specs.filter((spec) => !files[spec.option]).map((spec) => spec.file) : [];
|
|
2906
|
+
return {
|
|
2907
|
+
missingAdvisory: missingFrom(RERENDER_ADVISORY_FIELDS),
|
|
2908
|
+
missingContract: missingFrom(RERENDER_CONTRACT_FIELDS),
|
|
2909
|
+
uploadingFootage
|
|
2910
|
+
};
|
|
2911
|
+
}
|
|
2912
|
+
async function trackVideoCommand(idOrLogId, files, onProgress, options = {}) {
|
|
2913
|
+
const completeness = checkBundleCompleteness(files);
|
|
2914
|
+
if (completeness.uploadingFootage && completeness.missingContract.length > 0 && !options.allowPartial) {
|
|
2915
|
+
throw new CliError2("bundle_incomplete", `Refusing to upload a PARTIAL bundle: footage is being uploaded but the re-render contract is missing ${completeness.missingContract.join(", ")}. ` + `A footage-only upload leaves composition.tsx/props.json/render.json stale on R2 and desyncs the render.json from the DB ledger. ` + `Ship the complete bundle (re-run \`ship\` and upload with --dir), or pass --allow-partial for a deliberate partial refresh (e.g. poster-only).`);
|
|
2916
|
+
}
|
|
2917
|
+
if (completeness.uploadingFootage) {
|
|
2918
|
+
if (completeness.missingContract.length > 0) {
|
|
2919
|
+
onProgress?.(`warning: --allow-partial — uploading WITHOUT the re-render contract (${completeness.missingContract.join(", ")}); the R2 bundle will NOT be re-renderable`);
|
|
2920
|
+
}
|
|
2921
|
+
for (const missing of completeness.missingAdvisory) {
|
|
2922
|
+
onProgress?.(`warning: ${missing} missing (provenance/eval only) — shipping without it`);
|
|
2923
|
+
}
|
|
2924
|
+
}
|
|
2903
2925
|
const present = VIDEO_FIELDS.map((spec) => ({
|
|
2904
2926
|
field: spec.field,
|
|
2905
2927
|
path: files[spec.option]
|
|
2906
2928
|
})).filter((spec) => Boolean(spec.path));
|
|
2929
|
+
if (present.length === 0) {
|
|
2930
|
+
throw new CliError2("nothing_to_upload", "No bundle files resolved to upload (pass --dir <bundle> or explicit file flags).");
|
|
2931
|
+
}
|
|
2907
2932
|
const presign = await adminApiPost(`/api/admin/tracks/${encodeURIComponent(idOrLogId)}/video/uploads`, { fields: present.map((spec) => spec.field) });
|
|
2908
2933
|
const byField = new Map(presign.uploads.map((upload) => [upload.field, upload]));
|
|
2909
2934
|
const urls = {};
|
|
@@ -3033,7 +3058,7 @@ async function trackNoteCommand(idOrLogId, options) {
|
|
|
3033
3058
|
const body = { note: options.note };
|
|
3034
3059
|
return adminApiPost(`/api/admin/tracks/${encodeURIComponent(idOrLogId)}/note`, body);
|
|
3035
3060
|
}
|
|
3036
|
-
var DEFAULT_VIDEO_MODEL = "anthropic/claude-opus-4-8", DEFAULT_VIDEO_REASONING = "high", FOUND_BASE = "https://found.fluncle.com", VIDEO_FIELDS;
|
|
3061
|
+
var DEFAULT_VIDEO_MODEL = "anthropic/claude-opus-4-8", DEFAULT_VIDEO_REASONING = "high", FOUND_BASE = "https://found.fluncle.com", VIDEO_FIELDS, RERENDER_CONTRACT_FIELDS, RERENDER_ADVISORY_FIELDS, FOOTAGE_FIELDS;
|
|
3037
3062
|
var init_track = __esm(() => {
|
|
3038
3063
|
init_api();
|
|
3039
3064
|
init_output();
|
|
@@ -3050,7 +3075,25 @@ var init_track = __esm(() => {
|
|
|
3050
3075
|
{ field: "props", option: "props" },
|
|
3051
3076
|
{ field: "render", option: "render" },
|
|
3052
3077
|
{ field: "intent", option: "intent" },
|
|
3053
|
-
{ field: "metrics", option: "metrics" }
|
|
3078
|
+
{ field: "metrics", option: "metrics" },
|
|
3079
|
+
{ field: "scene", option: "scene" }
|
|
3080
|
+
];
|
|
3081
|
+
RERENDER_CONTRACT_FIELDS = [
|
|
3082
|
+
{ file: "composition.tsx", option: "composition" },
|
|
3083
|
+
{ file: "props.json", option: "props" },
|
|
3084
|
+
{ file: "render.json", option: "render" }
|
|
3085
|
+
];
|
|
3086
|
+
RERENDER_ADVISORY_FIELDS = [
|
|
3087
|
+
{ file: "intent.json", option: "intent" },
|
|
3088
|
+
{ file: "metrics.json", option: "metrics" },
|
|
3089
|
+
{ file: "scene.json", option: "scene" }
|
|
3090
|
+
];
|
|
3091
|
+
FOOTAGE_FIELDS = [
|
|
3092
|
+
"footage",
|
|
3093
|
+
"footageSocial",
|
|
3094
|
+
"footageNotext",
|
|
3095
|
+
"footageLandscape",
|
|
3096
|
+
"footageLandscapeSocial"
|
|
3054
3097
|
];
|
|
3055
3098
|
});
|
|
3056
3099
|
|
|
@@ -7229,7 +7272,7 @@ function addAdminCommands(program2) {
|
|
|
7229
7272
|
const { trackUpdateCommand: trackUpdateCommand2 } = await Promise.resolve().then(() => (init_track(), exports_track));
|
|
7230
7273
|
await runTrackUpdate(trackId, options, trackUpdateCommand2);
|
|
7231
7274
|
});
|
|
7232
|
-
adminTrack.command("video").description("Upload a track's video bundle to R2 and link it").argument("[idOrLogId]").option("--composition <file>", "Composition source file").option("--cover <file>", "Cover image").option("--dir <dir>", "Bundle directory").option("--footage <file>", "Video footage (square crop source)").option("--footage-landscape <file>", "Clean landscape cut (optional escape hatch)").option("--footage-landscape-social <file>", "Landscape cut with baked text (optional)").option("--footage-notext <file>", "Portrait cut without the type layer (optional)").option("--footage-social <file>", "Portrait social cut (baked text)").option("--intent <file>", "Render-intent JSON (optional)").option("--json", "Print JSON", false).option("--metrics <file>", "Gate metrics JSON (optional)").option("--model <model>", "Authoring AI model (<provider>/<model>)").option("--note <file>", "Note file").option("--poster <file>", "Poster image").option("--props <file>", "Render props JSON").option("--reasoning <level>", "Authoring model reasoning effort (e.g. high)").option("--render <file>", "Render metadata JSON").allowExcessArguments().action(async (idOrLogId, options) => {
|
|
7275
|
+
adminTrack.command("video").description("Upload a track's video bundle to R2 and link it").argument("[idOrLogId]").option("--allow-partial", "Allow an intentionally partial upload (skip the re-render-contract check; e.g. poster-only)", false).option("--composition <file>", "Composition source file").option("--cover <file>", "Cover image").option("--dir <dir>", "Bundle directory").option("--footage <file>", "Video footage (square crop source)").option("--footage-landscape <file>", "Clean landscape cut (optional escape hatch)").option("--footage-landscape-social <file>", "Landscape cut with baked text (optional)").option("--footage-notext <file>", "Portrait cut without the type layer (optional)").option("--footage-social <file>", "Portrait social cut (baked text)").option("--intent <file>", "Render-intent JSON (optional)").option("--json", "Print JSON", false).option("--metrics <file>", "Gate metrics JSON (optional)").option("--model <model>", "Authoring AI model (<provider>/<model>)").option("--note <file>", "Note file").option("--poster <file>", "Poster image").option("--props <file>", "Render props JSON").option("--reasoning <level>", "Authoring model reasoning effort (e.g. high)").option("--render <file>", "Render metadata JSON").option("--scene <file>", "Scene replay manifest JSON (fluncle.scene/1, optional)").allowExcessArguments().action(async (idOrLogId, options) => {
|
|
7233
7276
|
const { trackVideoCommand: trackVideoCommand2 } = await Promise.resolve().then(() => (init_track(), exports_track));
|
|
7234
7277
|
await runTrackVideo(idOrLogId, options, trackVideoCommand2);
|
|
7235
7278
|
});
|
|
@@ -7654,7 +7697,7 @@ async function runBackfillDiscogs(options, backfillDiscogsCommand2) {
|
|
|
7654
7697
|
}
|
|
7655
7698
|
async function runTrackVideo(idOrLogId, options, trackVideoCommand2) {
|
|
7656
7699
|
if (!idOrLogId) {
|
|
7657
|
-
throw new Error("Missing id. Usage: fluncle admin tracks video <track_id|log_id> (--dir <dir> | --footage <file> [--footage-social <file>] [--footage-notext <file>] [--footage-landscape <file>] [--footage-landscape-social <file>] [--poster <file>] [--cover <file>] [--note <file>] [--composition <file>] [--props <file>] [--render <file>] [--intent <file>] [--metrics <file>])");
|
|
7700
|
+
throw new Error("Missing id. Usage: fluncle admin tracks video <track_id|log_id> (--dir <dir> | --footage <file> [--footage-social <file>] [--footage-notext <file>] [--footage-landscape <file>] [--footage-landscape-social <file>] [--poster <file>] [--cover <file>] [--note <file>] [--composition <file>] [--props <file>] [--render <file>] [--intent <file>] [--metrics <file>] [--scene <file>]) [--allow-partial]");
|
|
7658
7701
|
}
|
|
7659
7702
|
const dir = options.dir ? path2.resolve(process.cwd(), options.dir) : undefined;
|
|
7660
7703
|
const fromDir = (name) => {
|
|
@@ -7685,13 +7728,16 @@ async function runTrackVideo(idOrLogId, options, trackVideoCommand2) {
|
|
|
7685
7728
|
poster: resolveFile(options.poster, "poster.jpg"),
|
|
7686
7729
|
props: resolveFile(options.props, "props.json"),
|
|
7687
7730
|
reasoning: options.reasoning,
|
|
7688
|
-
render: resolveFile(options.render, "render.json")
|
|
7731
|
+
render: resolveFile(options.render, "render.json"),
|
|
7732
|
+
scene: resolveFile(options.scene, "scene.json")
|
|
7689
7733
|
};
|
|
7690
|
-
if (!files.footage) {
|
|
7691
|
-
throw new Error("A footage cut is required (--footage <file>, or --dir containing footage.mp4)");
|
|
7734
|
+
if (!files.footage && !options.allowPartial) {
|
|
7735
|
+
throw new Error("A footage cut is required (--footage <file>, or --dir containing footage.mp4). Pass --allow-partial for a deliberate partial refresh (e.g. poster-only).");
|
|
7692
7736
|
}
|
|
7693
7737
|
const onProgress = options.json ? undefined : (message) => console.log(message);
|
|
7694
|
-
const result = await trackVideoCommand2(idOrLogId, files, onProgress
|
|
7738
|
+
const result = await trackVideoCommand2(idOrLogId, files, onProgress, {
|
|
7739
|
+
allowPartial: options.allowPartial
|
|
7740
|
+
});
|
|
7695
7741
|
if (options.json) {
|
|
7696
7742
|
printJson(result);
|
|
7697
7743
|
return;
|
|
@@ -8491,6 +8537,7 @@ var stringOptions = new Set([
|
|
|
8491
8537
|
"--query",
|
|
8492
8538
|
"--recorded-at",
|
|
8493
8539
|
"--render",
|
|
8540
|
+
"--scene",
|
|
8494
8541
|
"--scheduled-for",
|
|
8495
8542
|
"--soundcloud-url",
|
|
8496
8543
|
"--source",
|
package/package.json
CHANGED