@slatesvideo/shared 0.7.0 → 0.7.2
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/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/manual/content.d.ts +1 -1
- package/dist/manual/content.js +1 -1
- package/dist/manual/index.d.ts +11 -2
- package/dist/manual/index.js +178 -14
- package/dist/operations/index.d.ts +200 -1
- package/dist/operations/index.js +719 -70
- package/dist/operations/surface.d.ts +2 -1
- package/dist/operations/surface.js +14 -4
- package/dist/prompts/agent-doctrine.js +24 -3
- package/package.json +3 -3
package/dist/manual/index.d.ts
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
import { APP_MANUAL } from './content.js';
|
|
2
2
|
export { APP_MANUAL };
|
|
3
|
-
/**
|
|
4
|
-
|
|
3
|
+
/**
|
|
4
|
+
* A reader over one manual text. The package's own reads go through the shipped manual below; the
|
|
5
|
+
* retrieval check (`scripts/app-manual-retrieval-check.mjs`) reads slate's source manual the same way,
|
|
6
|
+
* before the generator has copied it here.
|
|
7
|
+
*/
|
|
8
|
+
export declare function manualReader(manual: string): {
|
|
9
|
+
index: () => string;
|
|
10
|
+
sections: (query?: string) => string;
|
|
11
|
+
};
|
|
12
|
+
export declare const appManualIndex: () => string;
|
|
13
|
+
export declare const appManualSections: (query?: string) => string;
|
|
5
14
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/manual/index.js
CHANGED
|
@@ -1,20 +1,184 @@
|
|
|
1
1
|
import { APP_MANUAL } from './content.js';
|
|
2
2
|
export { APP_MANUAL };
|
|
3
|
-
/**
|
|
4
|
-
|
|
3
|
+
/** Stop here when two sections are returned together (~1.5k tokens). */
|
|
4
|
+
const PAIR_CAP_CHARS = 6000;
|
|
5
|
+
const STOP = new Set(
|
|
6
|
+
// Question words and filler: "that has no video yet" should not steer toward a heading that says "yet".
|
|
7
|
+
'a an and are as at be by can could do does don doesn for from get got had has have how i in into is isn it its just ll me my of on or re s should t than that the then there this to ve what when where which while who why will with won would you your'.split(' '));
|
|
8
|
+
/**
|
|
9
|
+
* One form per word, so the question's word meets the manual's: "saved", "saves" and "save" are one, as
|
|
10
|
+
* are "running" and "run", "categories" and "category". A light stemmer, not Porter: plural, then -ing or
|
|
11
|
+
* -ed, then a doubled final consonant, then a final e. Both sides go through it, so a crude root is fine.
|
|
12
|
+
*/
|
|
13
|
+
function stem(word) {
|
|
14
|
+
let w = word;
|
|
15
|
+
if (w.length > 4 && w.endsWith('ies'))
|
|
16
|
+
w = `${w.slice(0, -3)}y`;
|
|
17
|
+
else if (w.length > 3 && w.endsWith('s') && !w.endsWith('ss'))
|
|
18
|
+
w = w.slice(0, -1);
|
|
19
|
+
if (w.length > 5 && w.endsWith('ing'))
|
|
20
|
+
w = w.slice(0, -3);
|
|
21
|
+
else if (w.length > 4 && w.endsWith('ed'))
|
|
22
|
+
w = w.slice(0, -2);
|
|
23
|
+
const last = w[w.length - 1];
|
|
24
|
+
if (w.length > 3 && last === w[w.length - 2] && !'lsz'.includes(last) && !/[aeiou0-9]/.test(last))
|
|
25
|
+
w = w.slice(0, -1);
|
|
26
|
+
if (w.length > 3 && w.endsWith('e'))
|
|
27
|
+
w = w.slice(0, -1);
|
|
28
|
+
return w;
|
|
29
|
+
}
|
|
30
|
+
/** Lowercase, split, drop stop words, stem. */
|
|
31
|
+
function terms(text) {
|
|
32
|
+
return (text.toLowerCase().match(/[\p{L}\p{N}]+/gu) ?? []).filter((w) => !STOP.has(w)).map(stem);
|
|
33
|
+
}
|
|
34
|
+
const pairs = (list) => new Set(list.slice(1).map((w, i) => `${list[i]} ${w}`));
|
|
35
|
+
const counts = (list) => {
|
|
36
|
+
const m = new Map();
|
|
37
|
+
for (const w of list)
|
|
38
|
+
m.set(w, (m.get(w) ?? 0) + 1);
|
|
39
|
+
return m;
|
|
40
|
+
};
|
|
41
|
+
const clean = (text) => text.replace(/<!--[\s\S]*?-->\n?/g, '').replace(/\n{3,}/g, '\n\n').trim();
|
|
42
|
+
const bare = (heading) => heading.replace(/^#+\s*/, '').trim();
|
|
43
|
+
/** The manual's sections, parsed once per text. */
|
|
44
|
+
function parse(manual) {
|
|
45
|
+
const start = manual.indexOf('<slates_reference>');
|
|
46
|
+
const end = manual.lastIndexOf('</slates_reference>');
|
|
47
|
+
const body = start >= 0 && end > start ? manual.slice(start + '<slates_reference>'.length, end) : manual;
|
|
48
|
+
const out = [];
|
|
49
|
+
let parent = null;
|
|
50
|
+
let current = null;
|
|
51
|
+
let fenced = false;
|
|
52
|
+
const flush = () => {
|
|
53
|
+
if (!current)
|
|
54
|
+
return;
|
|
55
|
+
const text = clean(current.lines.join('\n'));
|
|
56
|
+
const words = new Map();
|
|
57
|
+
for (const w of terms(text))
|
|
58
|
+
words.set(w, (words.get(w) ?? 0) + 1);
|
|
59
|
+
out.push({
|
|
60
|
+
heading: current.heading,
|
|
61
|
+
parent: current.parent,
|
|
62
|
+
level: current.level,
|
|
63
|
+
body: text,
|
|
64
|
+
words,
|
|
65
|
+
headingWords: counts(terms(current.heading)),
|
|
66
|
+
headingPairs: pairs(terms(current.heading)),
|
|
67
|
+
parentWords: new Set(terms(current.parent ?? '')),
|
|
68
|
+
});
|
|
69
|
+
};
|
|
70
|
+
for (const line of body.split(/\r?\n/)) {
|
|
71
|
+
if (/^\s*```/.test(line))
|
|
72
|
+
fenced = !fenced;
|
|
73
|
+
const m = fenced ? null : /^(#{1,4}) (.+)$/.exec(line);
|
|
74
|
+
// `#` (the version header) and `####` (a sub-point) stay inside the section they sit in.
|
|
75
|
+
if (m && (m[1].length === 2 || m[1].length === 3)) {
|
|
76
|
+
flush();
|
|
77
|
+
const level = m[1].length;
|
|
78
|
+
if (level === 2)
|
|
79
|
+
parent = m[2].trim();
|
|
80
|
+
current = { heading: m[2].trim(), level, parent: level === 3 ? parent : null, lines: [line] };
|
|
81
|
+
}
|
|
82
|
+
else if (current)
|
|
83
|
+
current.lines.push(line);
|
|
84
|
+
}
|
|
85
|
+
flush();
|
|
86
|
+
return out.filter((s) => s.body.replace(/^#+ .*$/m, '').trim().length > 0);
|
|
87
|
+
}
|
|
88
|
+
/** A `###` heading without its trailing synonyms: "Timeline: markers (add a marker, …)" is "Timeline: markers", which asks for it. */
|
|
89
|
+
const shortHeading = (heading) => heading.replace(/\s*\([^)]*\)\s*$/, '').trim() || heading;
|
|
90
|
+
/**
|
|
91
|
+
* The map, step one: every `##` surface on one line with the words it answers. Asking for a surface by
|
|
92
|
+
* the words before its dash returns its opening and its sections (step two); asking with the words of a
|
|
93
|
+
* question returns the one section that answers it. Each step is small.
|
|
94
|
+
*/
|
|
95
|
+
function indexOf(all) {
|
|
96
|
+
const lines = [
|
|
97
|
+
'Slates app manual. Ask with the words of the question for the section that answers it, or ask for a surface by its name (the words before the —) for its list of sections.',
|
|
98
|
+
'',
|
|
99
|
+
];
|
|
100
|
+
for (const s of all)
|
|
101
|
+
if (s.level === 2)
|
|
102
|
+
lines.push(`## ${s.heading}`);
|
|
103
|
+
return lines.join('\n');
|
|
104
|
+
}
|
|
105
|
+
/** A surface's own sections, short, for step two. */
|
|
106
|
+
const sectionList = (all, surface) => all.filter((s) => s.parent === surface.heading).map((s) => shortHeading(s.heading)).join(' · ');
|
|
107
|
+
function score(s, qTerms, idf, phrase) {
|
|
108
|
+
let n = 0;
|
|
109
|
+
for (const t of new Set(qTerms)) {
|
|
110
|
+
const w = idf.get(t) ?? 0;
|
|
111
|
+
if (!w)
|
|
112
|
+
continue;
|
|
113
|
+
// A heading word counts 4, a second mention of it 2 more; the surface's words 1; the body up to 1.5.
|
|
114
|
+
const h = s.headingWords.get(t) ?? 0;
|
|
115
|
+
n += w * ((h ? 4 : 0) + (h > 1 ? 2 : 0) + (s.parentWords.has(t) ? 1 : 0) + Math.min(s.words.get(t) ?? 0, 3) * 0.5);
|
|
116
|
+
}
|
|
117
|
+
// Two question words side by side in the heading ("new project", "video from a picture") are the
|
|
118
|
+
// phrasing the heading was written for.
|
|
119
|
+
for (let i = 1; i < qTerms.length; i++) {
|
|
120
|
+
if (s.headingPairs.has(`${qTerms[i - 1]} ${qTerms[i]}`))
|
|
121
|
+
n += 2 * ((idf.get(qTerms[i - 1]) ?? 0) + (idf.get(qTerms[i]) ?? 0));
|
|
122
|
+
}
|
|
123
|
+
if (phrase.length > 3) {
|
|
124
|
+
if (s.heading.toLowerCase().includes(phrase))
|
|
125
|
+
n += 6;
|
|
126
|
+
else if (s.body.toLowerCase().includes(phrase))
|
|
127
|
+
n += 2;
|
|
128
|
+
}
|
|
129
|
+
return n;
|
|
130
|
+
}
|
|
131
|
+
const withContext = (s) => (s.parent ? `## ${s.parent}\n\n${s.body}` : s.body);
|
|
132
|
+
/**
|
|
133
|
+
* With no query, the whole manual. With a query, the best section (a second when it scores within 15%
|
|
134
|
+
* and both fit ~1.5k tokens), then the next headings to ask for. Whole sections only: never a cut
|
|
135
|
+
* sentence, never an invented step.
|
|
136
|
+
*/
|
|
137
|
+
function sectionsFor(manual, all, query) {
|
|
5
138
|
if (!query?.trim())
|
|
6
|
-
return
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
139
|
+
return manual;
|
|
140
|
+
const q = query.trim().toLowerCase();
|
|
141
|
+
const asked = q.replace(/^#+\s*/, '');
|
|
142
|
+
const exact = all.find((s) => s.heading.toLowerCase() === q || bare(s.heading).toLowerCase() === asked) ??
|
|
143
|
+
// A heading without its synonyms ("Timeline: markers"), or a surface by the words before its dash.
|
|
144
|
+
all.find((s) => s.heading.toLowerCase().replace(/\s*\([^)]*\)\s*$/, '') === asked) ??
|
|
145
|
+
all.find((s) => s.level === 2 && s.heading.split(' — ')[0].toLowerCase() === asked);
|
|
146
|
+
if (exact?.level === 3)
|
|
147
|
+
return withContext(exact);
|
|
148
|
+
if (exact) {
|
|
149
|
+
const list = sectionList(all, exact);
|
|
150
|
+
return list ? `${exact.body}\n\nIts sections (ask for one by name, or with the question's words): ${list}` : exact.body;
|
|
151
|
+
}
|
|
152
|
+
const qTerms = terms(query);
|
|
153
|
+
const df = new Map();
|
|
154
|
+
for (const t of new Set(qTerms))
|
|
155
|
+
df.set(t, all.filter((s) => s.words.has(t) || s.headingWords.has(t)).length);
|
|
156
|
+
const idf = new Map([...df].map(([t, d]) => [t, d ? Math.log(1 + all.length / d) : 0]));
|
|
157
|
+
const ranked = all
|
|
158
|
+
.map((s, index) => ({ s, index, score: score(s, qTerms, idf, q) }))
|
|
159
|
+
.filter((r) => r.score > 0)
|
|
160
|
+
.sort((a, b) => b.score - a.score || a.s.body.length - b.s.body.length || a.index - b.index);
|
|
15
161
|
if (!ranked.length)
|
|
16
|
-
return
|
|
17
|
-
|
|
18
|
-
|
|
162
|
+
return `No manual section matches "${query}". Available headings:\n\n${indexOf(all)}`;
|
|
163
|
+
const [best, second] = ranked;
|
|
164
|
+
const picked = [best];
|
|
165
|
+
if (second && second.score >= best.score * 0.85 && best.s.body.length + second.s.body.length <= PAIR_CAP_CHARS)
|
|
166
|
+
picked.push(second);
|
|
167
|
+
const related = ranked.slice(picked.length, picked.length + 4).map((r) => r.s.heading);
|
|
168
|
+
const text = picked.map((r) => withContext(r.s)).join('\n\n');
|
|
169
|
+
return related.length ? `${text}\n\nRelated sections (ask by heading): ${related.join(' · ')}` : text;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* A reader over one manual text. The package's own reads go through the shipped manual below; the
|
|
173
|
+
* retrieval check (`scripts/app-manual-retrieval-check.mjs`) reads slate's source manual the same way,
|
|
174
|
+
* before the generator has copied it here.
|
|
175
|
+
*/
|
|
176
|
+
export function manualReader(manual) {
|
|
177
|
+
let all = null;
|
|
178
|
+
const parsed = () => (all ??= parse(manual));
|
|
179
|
+
return { index: () => indexOf(parsed()), sections: (query) => sectionsFor(manual, parsed(), query) };
|
|
19
180
|
}
|
|
181
|
+
const shipped = manualReader(APP_MANUAL);
|
|
182
|
+
export const appManualIndex = () => shipped.index();
|
|
183
|
+
export const appManualSections = (query) => shipped.sections(query);
|
|
20
184
|
//# sourceMappingURL=index.js.map
|
|
@@ -159,9 +159,25 @@ export declare const getWorkspaceState: Operation<{
|
|
|
159
159
|
* up at request time. Exists so "make these into videos" needs no codes typed.
|
|
160
160
|
*/
|
|
161
161
|
export declare const getSelection: Operation<Record<string, never>>;
|
|
162
|
+
declare const SELECTION_TARGETS: readonly ["media", "board"];
|
|
163
|
+
declare const SELECTION_MODES: readonly ["replace", "add", "remove", "clear", "all"];
|
|
164
|
+
/**
|
|
165
|
+
* SET what is selected, as the user's clicks do: the cards ticked in Media, the Shots ticked on the Board.
|
|
166
|
+
* Pairs with `slates_get_selection`, which reads it: "tick the shots with no clip, then price them" is this op
|
|
167
|
+
* and then the quote. The desktop applies it through the stores the grids write and answers with what SETTLED.
|
|
168
|
+
*/
|
|
169
|
+
export declare const setSelection: Operation<{
|
|
170
|
+
surface: (typeof SELECTION_TARGETS)[number];
|
|
171
|
+
mode: (typeof SELECTION_MODES)[number];
|
|
172
|
+
ids?: string[];
|
|
173
|
+
}>;
|
|
162
174
|
declare const VIEW_LENSES: readonly ["board", "media", "script"];
|
|
163
175
|
declare const VIEW_CUT_SIDES: readonly ["bottom", "left", "right"];
|
|
164
176
|
declare const VIEW_DOCK_SECTIONS: readonly ["storyboards", "library", "folders", "pinned"];
|
|
177
|
+
declare const VIEW_BOARD_LEVELS: readonly ["film", "scenes", "shot"];
|
|
178
|
+
declare const VIEW_BOARD_FILTERS: readonly ["all", "with-clip", "without-clip"];
|
|
179
|
+
declare const VIEW_MEDIA_TABS: readonly ["all", "images", "videos", "audio"];
|
|
180
|
+
declare const VIEW_SETTINGS_PANES: readonly ["account", "ai", "storage", "logs", "general", "keys"];
|
|
165
181
|
type DockSection = (typeof VIEW_DOCK_SECTIONS)[number];
|
|
166
182
|
/**
|
|
167
183
|
* How the Slates window is ARRANGED right now — which lens is showing, where
|
|
@@ -180,6 +196,7 @@ export declare const getView: Operation<Record<string, never>>;
|
|
|
180
196
|
* the timeline full-screen instead, and says so.
|
|
181
197
|
*/
|
|
182
198
|
export declare const setView: Operation<{
|
|
199
|
+
projectId?: string | null;
|
|
183
200
|
lens?: (typeof VIEW_LENSES)[number];
|
|
184
201
|
cut?: {
|
|
185
202
|
open?: boolean;
|
|
@@ -187,6 +204,7 @@ export declare const setView: Operation<{
|
|
|
187
204
|
side?: (typeof VIEW_CUT_SIDES)[number];
|
|
188
205
|
height?: number;
|
|
189
206
|
width?: number;
|
|
207
|
+
timelineId?: string;
|
|
190
208
|
};
|
|
191
209
|
leftDock?: {
|
|
192
210
|
open?: boolean;
|
|
@@ -199,8 +217,145 @@ export declare const setView: Operation<{
|
|
|
199
217
|
};
|
|
200
218
|
script?: {
|
|
201
219
|
details?: boolean;
|
|
220
|
+
textScale?: number;
|
|
221
|
+
panelShotId?: string | null;
|
|
222
|
+
};
|
|
223
|
+
board?: {
|
|
224
|
+
id?: string;
|
|
225
|
+
sceneId?: string;
|
|
226
|
+
level?: (typeof VIEW_BOARD_LEVELS)[number];
|
|
227
|
+
cardWidth?: number;
|
|
228
|
+
filter?: (typeof VIEW_BOARD_FILTERS)[number];
|
|
229
|
+
linkedClips?: boolean;
|
|
230
|
+
scriptFollowsDrag?: boolean;
|
|
231
|
+
collapsedSceneIds?: string[];
|
|
232
|
+
};
|
|
233
|
+
media?: {
|
|
234
|
+
tab?: (typeof VIEW_MEDIA_TABS)[number];
|
|
235
|
+
folderId?: string | null;
|
|
236
|
+
unfiledOnly?: boolean;
|
|
237
|
+
search?: string;
|
|
238
|
+
favoritesOnly?: boolean;
|
|
239
|
+
linkedOnly?: boolean;
|
|
240
|
+
rounds?: boolean;
|
|
241
|
+
cardSize?: number;
|
|
242
|
+
revealAssetId?: string;
|
|
243
|
+
};
|
|
244
|
+
library?: {
|
|
245
|
+
categoryId: string | null;
|
|
246
|
+
};
|
|
247
|
+
viewer?: {
|
|
248
|
+
assetId: string | null;
|
|
249
|
+
};
|
|
250
|
+
compare?: {
|
|
251
|
+
open?: boolean;
|
|
252
|
+
assetIds?: string[];
|
|
253
|
+
};
|
|
254
|
+
animatic?: {
|
|
255
|
+
open: boolean;
|
|
256
|
+
fromShotId?: string;
|
|
257
|
+
};
|
|
258
|
+
settings?: {
|
|
259
|
+
open: boolean;
|
|
260
|
+
pane?: (typeof VIEW_SETTINGS_PANES)[number];
|
|
261
|
+
};
|
|
262
|
+
composer?: {
|
|
263
|
+
open: boolean;
|
|
202
264
|
};
|
|
203
265
|
}>;
|
|
266
|
+
/**
|
|
267
|
+
* SHOW AND POINT (1.6.1). The manual's pictures and a ring around a live control, so an agent can
|
|
268
|
+
* answer "where is it?" with the thing itself instead of a paragraph. Neither changes the project or
|
|
269
|
+
* the view. The pictures come from the INSTALLED app (it ships them), so they show the user's version;
|
|
270
|
+
* the public URL is for a client that renders only links. Decisions 13-16 in second-brain
|
|
271
|
+
* plans/2026-09-30-slates-manual-for-llms-1-6-1-decisions.md.
|
|
272
|
+
*/
|
|
273
|
+
export declare const getManualPicture: Operation<{
|
|
274
|
+
id?: string;
|
|
275
|
+
}>;
|
|
276
|
+
export declare const highlightControl: Operation<{
|
|
277
|
+
target?: string;
|
|
278
|
+
caption?: string;
|
|
279
|
+
list?: boolean;
|
|
280
|
+
}>;
|
|
281
|
+
export declare const getComposer: Operation<Record<string, never>>;
|
|
282
|
+
export declare const setComposer: Operation<{
|
|
283
|
+
projectId?: string;
|
|
284
|
+
bindShotId?: string | null;
|
|
285
|
+
clear?: boolean;
|
|
286
|
+
restoreDraft?: boolean;
|
|
287
|
+
restoreSetup?: boolean;
|
|
288
|
+
fromAssetId?: string;
|
|
289
|
+
editSourceAssetId?: string;
|
|
290
|
+
lane?: 'image' | 'video' | 'audio';
|
|
291
|
+
model?: string;
|
|
292
|
+
prompt?: string;
|
|
293
|
+
addMentions?: string[];
|
|
294
|
+
attach?: Array<{
|
|
295
|
+
assetId: string;
|
|
296
|
+
role?: string;
|
|
297
|
+
}>;
|
|
298
|
+
detach?: string[];
|
|
299
|
+
setRole?: Array<{
|
|
300
|
+
assetId: string;
|
|
301
|
+
role: string;
|
|
302
|
+
}>;
|
|
303
|
+
params?: Record<string, string | number | boolean>;
|
|
304
|
+
voice?: {
|
|
305
|
+
presetId: string;
|
|
306
|
+
} | {
|
|
307
|
+
clipAssetId: string;
|
|
308
|
+
} | {
|
|
309
|
+
description: string;
|
|
310
|
+
};
|
|
311
|
+
tool?: {
|
|
312
|
+
sourceAssetId?: string | null;
|
|
313
|
+
speechText?: string;
|
|
314
|
+
drivingVideoAssetId?: string | null;
|
|
315
|
+
characterImageAssetId?: string | null;
|
|
316
|
+
};
|
|
317
|
+
}>;
|
|
318
|
+
/**
|
|
319
|
+
* AGENT PARITY (1.6.1): what a user could do in the window and an agent could not. Each calls a desktop
|
|
320
|
+
* route that runs the window's own function (`slate/src/main/agent/routes-parity.ts`). Plan step 5b,
|
|
321
|
+
* second-brain plans/2026-09-30-slates-manual-for-llms-1-6-1.md.
|
|
322
|
+
*/
|
|
323
|
+
export declare const reorderFolders: Operation<{
|
|
324
|
+
projectId: string;
|
|
325
|
+
folderIds: string[];
|
|
326
|
+
}>;
|
|
327
|
+
export declare const reorderPins: Operation<{
|
|
328
|
+
projectId: string;
|
|
329
|
+
assetIds: string[];
|
|
330
|
+
}>;
|
|
331
|
+
export declare const getUsage: Operation<{
|
|
332
|
+
period?: 'week' | 'month' | 'all';
|
|
333
|
+
}>;
|
|
334
|
+
export declare const getAppSettings: Operation<Record<string, never>>;
|
|
335
|
+
type AppSettingsPatch = {
|
|
336
|
+
newProjectLens?: 'media' | 'script' | 'board';
|
|
337
|
+
chatGptImagesEnabled?: boolean;
|
|
338
|
+
studioAgentHost?: 'slates' | 'codex' | 'claude';
|
|
339
|
+
studioAgentCodexModel?: string;
|
|
340
|
+
studioAgentCodexEffort?: string;
|
|
341
|
+
studioAgentClaudeModel?: string;
|
|
342
|
+
studioAgentClaudeEffort?: string;
|
|
343
|
+
};
|
|
344
|
+
export declare const setAppSettings: Operation<AppSettingsPatch>;
|
|
345
|
+
export declare const getAsset: Operation<{
|
|
346
|
+
projectId: string;
|
|
347
|
+
assetId: string;
|
|
348
|
+
}>;
|
|
349
|
+
export declare const linkAssetSource: Operation<{
|
|
350
|
+
projectId: string;
|
|
351
|
+
assetId: string;
|
|
352
|
+
imageAssetId: string | null;
|
|
353
|
+
}>;
|
|
354
|
+
export declare const extractVideoFrame: Operation<{
|
|
355
|
+
projectId: string;
|
|
356
|
+
assetId: string;
|
|
357
|
+
at?: 'first' | 'last' | number;
|
|
358
|
+
}>;
|
|
204
359
|
export declare const getMe: Operation<Record<string, never>>;
|
|
205
360
|
export declare const getCreditBalance: Operation<Record<string, never>>;
|
|
206
361
|
export declare const listAvailableModels: Operation<{
|
|
@@ -265,6 +420,7 @@ export declare const generateChatGptImage: Operation<{
|
|
|
265
420
|
aspectRatio?: string;
|
|
266
421
|
referenceAssetIds?: string[];
|
|
267
422
|
background?: boolean;
|
|
423
|
+
folderId?: string | null;
|
|
268
424
|
}>;
|
|
269
425
|
export declare const saveExternalImage: Operation<{
|
|
270
426
|
projectId: string;
|
|
@@ -283,6 +439,7 @@ export declare const uploadReferenceImage: Operation<{
|
|
|
283
439
|
filePath?: string;
|
|
284
440
|
dataUrl?: string;
|
|
285
441
|
type?: 'image' | 'video' | 'audio';
|
|
442
|
+
folderId?: string | null;
|
|
286
443
|
}>;
|
|
287
444
|
export declare const listFolders: Operation<{
|
|
288
445
|
projectId: string;
|
|
@@ -435,6 +592,7 @@ export declare const generateImage: Operation<{
|
|
|
435
592
|
referenceAssetIds?: string[];
|
|
436
593
|
background?: boolean;
|
|
437
594
|
confirm?: boolean;
|
|
595
|
+
folderId?: string | null;
|
|
438
596
|
}>;
|
|
439
597
|
export declare const editImage: Operation<{
|
|
440
598
|
projectId: string;
|
|
@@ -449,6 +607,27 @@ export declare const editImage: Operation<{
|
|
|
449
607
|
confirm?: boolean;
|
|
450
608
|
background?: boolean;
|
|
451
609
|
}>;
|
|
610
|
+
/**
|
|
611
|
+
* The picture viewer's EXTRACT (its Cells tab): a 2x2 or 3x3 grid picture, cells cropped out and re-rendered
|
|
612
|
+
* at full resolution, each as its own new picture. BILLABLE, and priced by the DESKTOP: its quote is the
|
|
613
|
+
* `imageCost` the viewer's Extract button prints, for this seat, rung and cell count, so the price an agent
|
|
614
|
+
* is shown cannot differ from the button's. The confirm gate is every billable op's: above CONFIRM_CREDITS
|
|
615
|
+
* with no `confirm`, the op answers with the price and the exact prompt, and spends nothing.
|
|
616
|
+
*/
|
|
617
|
+
/** The seats the viewer's Cells box offers. Mirrors slate's `GRID_EXTRACT_MODELS` (`shared/prompts/storyboard-grids.ts`), which this package cannot import. */
|
|
618
|
+
declare const GRID_EXTRACT_SEATS: readonly ["nano-banana-2", "flux-2-max", "seedream-5-lite"];
|
|
619
|
+
export declare const extractGridCells: Operation<{
|
|
620
|
+
projectId: string;
|
|
621
|
+
assetId: string;
|
|
622
|
+
cells: string[];
|
|
623
|
+
model?: (typeof GRID_EXTRACT_SEATS)[number];
|
|
624
|
+
resolution?: '1k' | '2k' | '3k' | '4k';
|
|
625
|
+
aspectRatio?: string;
|
|
626
|
+
prompt?: string;
|
|
627
|
+
referenceAssetIds?: string[];
|
|
628
|
+
confirm?: boolean;
|
|
629
|
+
background?: boolean;
|
|
630
|
+
}>;
|
|
452
631
|
export declare function videoCostKey(input: {
|
|
453
632
|
model: VideoModel;
|
|
454
633
|
duration: number;
|
|
@@ -522,6 +701,7 @@ export declare const generateVideo: Operation<{
|
|
|
522
701
|
negativePrompt?: string;
|
|
523
702
|
background?: boolean;
|
|
524
703
|
confirm?: boolean;
|
|
704
|
+
folderId?: string | null;
|
|
525
705
|
}>;
|
|
526
706
|
/**
|
|
527
707
|
* AGENT PARITY for the voice picker. The desktop browses stock voices by
|
|
@@ -554,6 +734,7 @@ export declare const generateAudio: Operation<{
|
|
|
554
734
|
imageReferenceAssetId?: string;
|
|
555
735
|
background?: boolean;
|
|
556
736
|
confirm?: boolean;
|
|
737
|
+
folderId?: string | null;
|
|
557
738
|
}>;
|
|
558
739
|
export declare const generateLipSync: Operation<{
|
|
559
740
|
projectId: string;
|
|
@@ -593,12 +774,18 @@ export declare const editVideo: Operation<{
|
|
|
593
774
|
seedanceFace?: boolean;
|
|
594
775
|
background?: boolean;
|
|
595
776
|
confirm?: boolean;
|
|
777
|
+
folderId?: string | null;
|
|
596
778
|
}>;
|
|
597
779
|
export declare const trimVideo: Operation<{
|
|
598
780
|
projectId: string;
|
|
599
781
|
assetId: string;
|
|
600
782
|
inSec?: number;
|
|
601
783
|
outSec: number;
|
|
784
|
+
pieces?: {
|
|
785
|
+
splitsAtSec?: number[];
|
|
786
|
+
longestSec?: number;
|
|
787
|
+
shareSec?: number;
|
|
788
|
+
};
|
|
602
789
|
}>;
|
|
603
790
|
export declare const getGenerationStatus: Operation<{
|
|
604
791
|
generationId: string;
|
|
@@ -878,6 +1065,7 @@ export declare const updateFrame: Operation<{
|
|
|
878
1065
|
assetId?: string | null;
|
|
879
1066
|
sceneId?: string | null;
|
|
880
1067
|
position?: number;
|
|
1068
|
+
preferredClipId?: string | null;
|
|
881
1069
|
}>;
|
|
882
1070
|
/**
|
|
883
1071
|
* Batch form of `slates_update_frame`.
|
|
@@ -900,6 +1088,7 @@ export declare const batchUpdateFrames: Operation<{
|
|
|
900
1088
|
assetId?: string | null;
|
|
901
1089
|
sceneId?: string | null;
|
|
902
1090
|
position?: number;
|
|
1091
|
+
preferredClipId?: string | null;
|
|
903
1092
|
}[];
|
|
904
1093
|
}>;
|
|
905
1094
|
export declare const deleteFrame: Operation<{
|
|
@@ -934,7 +1123,8 @@ type ShotOpParams = Omit<ShotParams, 'aspectRatio' | 'videoResolution' | 'imageR
|
|
|
934
1123
|
export declare const createShot: Operation<ShotOpRefs & ShotOpScript & {
|
|
935
1124
|
projectId: string;
|
|
936
1125
|
name?: string;
|
|
937
|
-
prompt
|
|
1126
|
+
prompt?: string;
|
|
1127
|
+
fromAssetId?: string;
|
|
938
1128
|
model?: string;
|
|
939
1129
|
params?: ShotOpParams;
|
|
940
1130
|
frameId?: string;
|
|
@@ -969,6 +1159,15 @@ export declare const listShots: Operation<{
|
|
|
969
1159
|
export declare const getShot: Operation<{
|
|
970
1160
|
shotId: string;
|
|
971
1161
|
}>;
|
|
1162
|
+
/**
|
|
1163
|
+
* The Board's "Use pictures as first frames": each video Shot with a picture and no first frame starts its
|
|
1164
|
+
* video from that picture. The desktop runs the command's own pick and write (`firstFrameCandidate`,
|
|
1165
|
+
* `withFirstFrame`), so the recipe changes exactly as a click changes it. Free: nothing is generated.
|
|
1166
|
+
*/
|
|
1167
|
+
export declare const usePicturesAsFirstFrames: Operation<{
|
|
1168
|
+
projectId: string;
|
|
1169
|
+
shotIds?: string[];
|
|
1170
|
+
}>;
|
|
972
1171
|
/**
|
|
973
1172
|
* SPLIT and MERGE — the chop decision, and the only two cross-row operations on
|
|
974
1173
|
* this surface.
|