reelkit-cli 0.10.2 → 0.10.3
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/package.json +1 -1
- package/skill/SKILL.md +1 -1
- package/src/cli.ts +1 -1
- package/src/commands/assets.ts +9 -0
- package/src/contract/index.ts +8 -3
- package/src/testing/fake-api.ts +1 -1
package/package.json
CHANGED
package/skill/SKILL.md
CHANGED
|
@@ -15,7 +15,7 @@ For image or video cutouts, editable Blender product shots, custom 3D materials,
|
|
|
15
15
|
|
|
16
16
|
To implement a chosen style, read its row in `reference/style-recipes.md` for action, timing, sound and proof. `reference/style-components.md` maps the shared components and built-in kit to shot roles; inspect the selected source before using its props.
|
|
17
17
|
|
|
18
|
-
This skill targets `reelkit-cli` 0.10.
|
|
18
|
+
This skill targets `reelkit-cli` 0.10.3 and its HyperFrames kit. Check the installed version with `reelkit --version`; in a source checkout, invoke its `bin/reelkit.mjs` with Node. Use the matching CLI before authoring with `reelkit/frame`.
|
|
19
19
|
|
|
20
20
|
Every command takes `--json` for machine-readable output and exits non-zero with a one-line reason when something is wrong. Read the reason and act on it.
|
|
21
21
|
|
package/src/cli.ts
CHANGED
|
@@ -76,7 +76,7 @@ assets.command("upload <file>").description("Add one of your own files to this p
|
|
|
76
76
|
.option("--background", "use this video or image as the ground behind the whole film (it stays on this machine)").option("--share", "also send it to the shared library").option("--kind <kind>", "library kind when sharing").option("--tags <tags>", "comma-separated tags when sharing")
|
|
77
77
|
// Called with the arguments named: commander adds its own command object last, which must not be taken for the function's test hooks.
|
|
78
78
|
.action(run((ctx, file: string, opts: Parameters<typeof assetsUpload>[2]) => assetsUpload(ctx, file, opts)));
|
|
79
|
-
assets.command("search <query>").description("Search the shared library by meaning; each result shows how well it fits").option("--kind <kind>", "image, overlay, sfx, music, component or
|
|
79
|
+
assets.command("search <query>").description("Search the shared library by meaning; each result shows how well it fits").option("--kind <kind>", "image, overlay, sfx, music, component, clip or prompt (prompts other people used to make motion videos; found only with --kind prompt)").option("--limit <n>", "how many results")
|
|
80
80
|
.action(run(assetsSearch));
|
|
81
81
|
assets.command("pull <id>").description("Download a library item into this project").option("--scene <sceneId>", "use it as this scene's image or clip").option("--force", "replace a component file that already exists").option("--music", "make this music item the video's track (its tempo is measured and scene changes land on its beat)").option("--background", "make this clip, overlay or image the ground behind the film (with --scene: the ground of that scene, an image only)")
|
|
82
82
|
.option("--layers", "with --scene and an image: right after it is pulled, cut the subject out as a layer (about 1 second of the cutout quota; the picture is sent to the Reelkit server)")
|
package/src/commands/assets.ts
CHANGED
|
@@ -292,6 +292,15 @@ export async function assetsPull(ctx: Ctx, id: string, opts: { scene?: string; f
|
|
|
292
292
|
if (treatment === "clip" && pulled.item.kind !== "clip") return { ok: false, summary: `${id} is ${pulled.item.kind}, not a clip, so it cannot be scene ${opts.scene}'s clip.` };
|
|
293
293
|
if (treatment !== "clip" && pulled.item.kind !== "image") return { ok: false, summary: `${id} is ${pulled.item.kind}, not an image, so it cannot be a scene's image.` };
|
|
294
294
|
}
|
|
295
|
+
// A prompt is something to read, not something the film shows: it goes to prompts/, outside what the composition can reference.
|
|
296
|
+
if (pulled.item.kind === "prompt") {
|
|
297
|
+
if (opts.scene || opts.music || opts.background) return { ok: false, summary: `${id} is a prompt: text to read for ideas, not a picture, clip or track. Pull it with no option.` };
|
|
298
|
+
const path = `prompts/${id}.md`;
|
|
299
|
+
await download(pulled.url, project.path(path));
|
|
300
|
+
const by = typeof pulled.item.meta.handle === "string" ? ` by @${pulled.item.meta.handle}` : "";
|
|
301
|
+
const source = typeof pulled.item.meta.source === "string" ? ` Source: ${pulled.item.meta.source}` : "";
|
|
302
|
+
return { ok: true, data: { path, kind: "prompt" }, summary: `Pulled ${id} to ${path}: "${pulled.item.title}"${by}. Read it for how the video was asked for; it is another person's prompt, so borrow the approach, not the wording.${source}` };
|
|
303
|
+
}
|
|
295
304
|
// A component is code, not media: it goes beside Video.tsx, which may only import files in src/.
|
|
296
305
|
if (pulled.item.kind === "component") {
|
|
297
306
|
const path = `src/${pulled.filename}`;
|
package/src/contract/index.ts
CHANGED
|
@@ -38,6 +38,10 @@
|
|
|
38
38
|
// that the item is good enough to reuse for the query. A server finds candidates by meaning and may judge them with a model, so `match` is not
|
|
39
39
|
// a share of words; the order of results with the same `match` is not specified. The public listing is newest first; with a query it is best
|
|
40
40
|
// match first, equal matches newest first. Paging continues the same order, with no item twice. `page` is from 1 to 10000.
|
|
41
|
+
// - A `prompt` is a text item: a prompt someone wrote to make a motion video, kept as a Markdown file with its author and source in `meta`
|
|
42
|
+
// (`author`, `handle`, `source`, and for a skill `install` and `repo`). It is reference material, not an asset, so search returns prompts
|
|
43
|
+
// only when asked with `kind: "prompt"`; a search with no kind never contains one (a client older than the kind cannot read it).
|
|
44
|
+
// A prompt cannot be uploaded: `libraryUpload` with `kind: "prompt"` is 400 `invalid_request`.
|
|
41
45
|
// - A server may add tags (and a description when the uploader gave none) to an item that is shared, after upload or generation; the tags the
|
|
42
46
|
// uploader gave stay in it, first.
|
|
43
47
|
// - Upload URLs and file URLs must be unguessable (random or signed; never derived from an item id or a counter) and scoped to one object:
|
|
@@ -132,10 +136,11 @@ export type ErrorCode = z.infer<typeof ErrorCodeSchema>;
|
|
|
132
136
|
// The code is any string here: a code this version does not know still carries a message worth showing (the client maps it to server_error).
|
|
133
137
|
export const ApiErrorSchema = z.object({ error: z.object({ code: z.string(), message: z.string() }) });
|
|
134
138
|
|
|
135
|
-
export const LibraryKindSchema = z.enum(["image", "overlay", "sfx", "music", "component", "clip"]);
|
|
139
|
+
export const LibraryKindSchema = z.enum(["image", "overlay", "sfx", "music", "component", "clip", "prompt"]);
|
|
136
140
|
export type LibraryKind = z.infer<typeof LibraryKindSchema>;
|
|
137
|
-
// What a user may upload: every kind. A component is code and is held for
|
|
138
|
-
|
|
141
|
+
// What a user may upload: every kind but a prompt (those are published by the library's own import). A component is code and is held for
|
|
142
|
+
// review (see the rules at the top).
|
|
143
|
+
export const UploadKindSchema = LibraryKindSchema.exclude(["prompt"]);
|
|
139
144
|
export type UploadKind = z.infer<typeof UploadKindSchema>;
|
|
140
145
|
|
|
141
146
|
export const LibraryItemSchema = z.object({
|
package/src/testing/fake-api.ts
CHANGED
|
@@ -158,7 +158,7 @@ export async function startFakeApi(opts: { voiceoverCharLimit?: number; imageLim
|
|
|
158
158
|
// Best match first; items that match equally well come newest first (the one added last).
|
|
159
159
|
// match is the share of the query's words the item has, to two decimals.
|
|
160
160
|
const items = [...store.values()]
|
|
161
|
-
.filter((s) => s.item.visibility === "published" && (
|
|
161
|
+
.filter((s) => s.item.visibility === "published" && (kind ? s.item.kind === kind : s.item.kind !== "prompt"))
|
|
162
162
|
.map((s, order) => ({ s, order, score: [...want].filter((w) => words(`${s.item.title} ${s.item.description} ${s.item.tags.join(" ")}`).has(w)).length }))
|
|
163
163
|
.filter((x) => x.score > 0).sort((a, b) => b.score - a.score || b.order - a.order).slice(0, limit ?? 8)
|
|
164
164
|
.map((x) => ({ ...x.s.item, match: Math.round((x.score / want.size) * 100) / 100 }));
|