@hypit/hypit 0.1.5 → 0.1.7
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/README.md +1 -1
- package/examples/semantic-composition/README.md +2 -1
- package/examples/semantic-composition/chat.svml +1 -1
- package/examples/semantic-composition/hypit.runtime.json +1 -1
- package/package.json +4 -1
- package/packages/caption-fine/README.md +7 -0
- package/packages/cli/src/view.ts +4 -3
- package/packages/film/src/surface.ts +4 -1
- package/packages/provider-hypihub/README.md +17 -3
- package/packages/provider-hypihub/src/oauth.ts +1 -1
- package/packages/provider-hypihub/src/provider.ts +35 -9
- package/packages/provider-hypihub/src/upload.ts +37 -4
- package/packages/runtime-local/README.md +17 -0
- package/packages/script/README.md +15 -3
- package/packages/script/src/manifest.ts +2 -1
- package/packages/script/src/parser.ts +45 -6
- package/packages/studio/LOCALIZATION.md +98 -0
- package/packages/studio/README.md +13 -0
- package/packages/studio/locales/en.json +197 -0
- package/packages/studio/locales/zh-CN.json +191 -0
- package/packages/studio/src/localization-node.ts +46 -0
- package/packages/studio/src/localization.ts +85 -0
- package/packages/studio/src/style.css +15 -3
- package/packages/studio/src/ui/artifact-name.ts +8 -6
- package/packages/studio/src/ui/artifact-preview.ts +5 -4
- package/packages/studio/src/ui/code.ts +17 -16
- package/packages/studio/src/ui/comments.ts +26 -25
- package/packages/studio/src/ui/dropdown.ts +68 -0
- package/packages/studio/src/ui/i18n.ts +109 -0
- package/packages/studio/src/ui/icons.ts +1 -0
- package/packages/studio/src/ui/library.ts +76 -65
- package/packages/studio/src/ui/main.ts +84 -131
- package/packages/studio/src/ui/scrub-preview.ts +8 -6
- package/packages/studio/src/ui/stage.ts +28 -27
- package/packages/studio/src/ui/timeline.ts +17 -14
- package/packages/studio/start.ts +39 -22
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { uiLabel, uiAttribute, uiText, uiAttr, userText } from "./i18n.js";
|
|
1
2
|
import { createArtifactPreview } from "./artifact-preview.js";
|
|
2
3
|
import type { StudioArtifactView, StudioSnapshot } from "../shared.js";
|
|
3
4
|
import { createOverlay } from "./overlay.js";
|
|
@@ -31,31 +32,31 @@ export function createStage(store: Store, selectedArtifact: (id: string | undefi
|
|
|
31
32
|
element.className = "stage";
|
|
32
33
|
element.innerHTML = `
|
|
33
34
|
<div class="stage-heading">
|
|
34
|
-
<div class="stage-title">${icon("preview")}<strong
|
|
35
|
-
<button type="button" class="stage-return" hidden
|
|
35
|
+
<div class="stage-title">${icon("preview")}<strong>${uiLabel("player.preview")}</strong></div>
|
|
36
|
+
<button type="button" class="stage-return" hidden>${uiLabel("player.back-to-composition")}</button>
|
|
36
37
|
</div>
|
|
37
38
|
<div class="stage-viewport">
|
|
38
39
|
<div class="stage-scaler">
|
|
39
|
-
<iframe title
|
|
40
|
+
<iframe ${uiAttribute("title", "player.preview")} sandbox="allow-scripts allow-same-origin" allow="autoplay"></iframe>
|
|
40
41
|
</div>
|
|
41
42
|
</div>
|
|
42
43
|
<div class="stage-progress" hidden>
|
|
43
|
-
<input class="stage-scrubber" type="range" min="0" max="0" value="0" step="0.01" aria-label
|
|
44
|
+
<input class="stage-scrubber" type="range" min="0" max="0" value="0" step="0.01" ${uiAttribute("aria-label", "player.media-time")} hidden>
|
|
44
45
|
</div>
|
|
45
46
|
<div class="stage-bar">
|
|
46
47
|
<span class="stage-time" hidden></span>
|
|
47
48
|
<div class="stage-transport">
|
|
48
|
-
<button type="button" data-previous aria-label
|
|
49
|
+
<button type="button" data-previous ${uiAttribute("aria-label", "player.previous-frame")} ${uiAttribute("title", "player.previous-frame")}>
|
|
49
50
|
${icon("previous")}
|
|
50
51
|
</button>
|
|
51
|
-
<button type="button" data-play aria-label
|
|
52
|
+
<button type="button" data-play ${uiAttribute("aria-label", "player.play")}>
|
|
52
53
|
<span data-icon>${icon("play")}</span>
|
|
53
54
|
</button>
|
|
54
|
-
<button type="button" data-next aria-label
|
|
55
|
+
<button type="button" data-next ${uiAttribute("aria-label", "player.next-frame")} ${uiAttribute("title", "player.next-frame")}>
|
|
55
56
|
${icon("next")}
|
|
56
57
|
</button>
|
|
57
58
|
</div>
|
|
58
|
-
<button type="button" data-mute aria-label
|
|
59
|
+
<button type="button" data-mute ${uiAttribute("aria-label", "player.mute")} class="stage-mute">
|
|
59
60
|
<span data-mute-icon>${icon("volume")}</span>
|
|
60
61
|
</button>
|
|
61
62
|
</div>`;
|
|
@@ -124,7 +125,7 @@ export function createStage(store: Store, selectedArtifact: (id: string | undefi
|
|
|
124
125
|
event.preventDefault(); stop(); closeSelectionMenu();
|
|
125
126
|
const menu = document.createElement("div");
|
|
126
127
|
menu.className = "selection-menu";
|
|
127
|
-
menu.setAttribute("role", "menu"); menu
|
|
128
|
+
menu.setAttribute("role", "menu"); uiAttr(menu, "aria-label", "player.elements-at-this-point");
|
|
128
129
|
for (const hit of hits) {
|
|
129
130
|
const option = document.createElement("button"); option.type = "button";
|
|
130
131
|
option.setAttribute("role", "menuitem"); option.textContent = hit.display.title;
|
|
@@ -204,7 +205,7 @@ export function createStage(store: Store, selectedArtifact: (id: string | undefi
|
|
|
204
205
|
const wasPlaying = playing;
|
|
205
206
|
playing = false;
|
|
206
207
|
setIcon(playIcon, "play");
|
|
207
|
-
play
|
|
208
|
+
uiAttr(play, "aria-label", "player.play");
|
|
208
209
|
if (raf !== 0) cancelAnimationFrame(raf);
|
|
209
210
|
raf = 0;
|
|
210
211
|
// Settle the picture on the frame the transport stopped at.
|
|
@@ -219,7 +220,7 @@ export function createStage(store: Store, selectedArtifact: (id: string | undefi
|
|
|
219
220
|
if (playing) { stop(); return; }
|
|
220
221
|
playing = true;
|
|
221
222
|
setIcon(playIcon, "pause");
|
|
222
|
-
play
|
|
223
|
+
uiAttr(play, "aria-label", "player.pause");
|
|
223
224
|
const total = state.snapshot.space.frameCount;
|
|
224
225
|
const rate = fps(state.snapshot);
|
|
225
226
|
fromFrame = state.playhead.frame >= total - 1 ? 0 : state.playhead.frame;
|
|
@@ -245,7 +246,7 @@ export function createStage(store: Store, selectedArtifact: (id: string | undefi
|
|
|
245
246
|
|
|
246
247
|
const applyMuted = (): void => {
|
|
247
248
|
setIcon(muteIcon, muted ? "muted" : "volume");
|
|
248
|
-
mute
|
|
249
|
+
uiAttr(mute, "aria-label", muted ? "player.unmute" : "player.mute");
|
|
249
250
|
if (artifactPreview.media !== undefined) artifactPreview.media.muted = muted;
|
|
250
251
|
(iframe.contentWindow as SeekWindow | null)?.__hypitSetMuted?.(muted);
|
|
251
252
|
};
|
|
@@ -286,12 +287,12 @@ export function createStage(store: Store, selectedArtifact: (id: string | undefi
|
|
|
286
287
|
previous.disabled = next.disabled = play.disabled;
|
|
287
288
|
scrubber.disabled = duration <= 0;
|
|
288
289
|
scrubber.step = "0.01";
|
|
289
|
-
scrubber
|
|
290
|
+
uiAttr(scrubber, "aria-label", "player.media-time");
|
|
290
291
|
scrubber.max = String(duration);
|
|
291
292
|
scrubber.value = String(media?.currentTime ?? 0);
|
|
292
293
|
time.textContent = `${clock(media?.currentTime ?? 0)} / ${clock(duration)}`;
|
|
293
294
|
setIcon(playIcon, media !== undefined && !media.paused ? "pause" : "play");
|
|
294
|
-
play
|
|
295
|
+
uiAttr(play, "aria-label", media !== undefined && !media.paused ? "player.pause" : "player.play");
|
|
295
296
|
});
|
|
296
297
|
viewport.append(artifactPreview.element);
|
|
297
298
|
const compositionTime = (): void => {
|
|
@@ -302,7 +303,7 @@ export function createStage(store: Store, selectedArtifact: (id: string | undefi
|
|
|
302
303
|
scrubber.step = String(1 / rate);
|
|
303
304
|
scrubber.max = String(Math.max(0, state.snapshot.space.frameCount - 1) / rate);
|
|
304
305
|
scrubber.value = String(state.playhead.frame / rate);
|
|
305
|
-
scrubber
|
|
306
|
+
uiAttr(scrubber, "aria-label", "player.composition-time");
|
|
306
307
|
time.textContent = `${clock(state.playhead.frame / rate)} / ${clock(state.snapshot.space.frameCount / rate)}`;
|
|
307
308
|
};
|
|
308
309
|
scrubber.addEventListener("input", () => {
|
|
@@ -318,14 +319,14 @@ export function createStage(store: Store, selectedArtifact: (id: string | undefi
|
|
|
318
319
|
compositionTime();
|
|
319
320
|
transport.hidden = mute.hidden = false;
|
|
320
321
|
play.disabled = previous.disabled = next.disabled = false;
|
|
321
|
-
previous
|
|
322
|
-
previous
|
|
323
|
-
next
|
|
324
|
-
next
|
|
325
|
-
title
|
|
322
|
+
uiAttr(previous, "title", "player.previous-frame");
|
|
323
|
+
uiAttr(previous, "aria-label", "player.previous-frame");
|
|
324
|
+
uiAttr(next, "title", "player.next-frame");
|
|
325
|
+
uiAttr(next, "aria-label", "player.next-frame");
|
|
326
|
+
uiText(title, "player.preview");
|
|
326
327
|
title.removeAttribute("title");
|
|
327
328
|
setIcon(playIcon, "play");
|
|
328
|
-
play
|
|
329
|
+
uiAttr(play, "aria-label", "player.play");
|
|
329
330
|
fit();
|
|
330
331
|
if (state !== undefined && ready) seekPicture(state.playhead.frame);
|
|
331
332
|
};
|
|
@@ -335,12 +336,12 @@ export function createStage(store: Store, selectedArtifact: (id: string | undefi
|
|
|
335
336
|
stop();
|
|
336
337
|
scaler.hidden = true;
|
|
337
338
|
back.hidden = false;
|
|
338
|
-
title
|
|
339
|
+
userText(title, artifact.displayName ?? artifact.output);
|
|
339
340
|
title.title = artifact.output;
|
|
340
|
-
previous
|
|
341
|
-
next
|
|
342
|
-
previous
|
|
343
|
-
next
|
|
341
|
+
uiAttr(previous, "title", "player.back-5-seconds");
|
|
342
|
+
uiAttr(next, "title", "player.forward-5-seconds");
|
|
343
|
+
uiAttr(previous, "aria-label", "player.back-5-seconds");
|
|
344
|
+
uiAttr(next, "aria-label", "player.forward-5-seconds");
|
|
344
345
|
artifactPreview.open(artifact, muted);
|
|
345
346
|
selectedArtifact(artifact.id);
|
|
346
347
|
};
|
|
@@ -404,7 +405,7 @@ export function createStage(store: Store, selectedArtifact: (id: string | undefi
|
|
|
404
405
|
showComposition() { if (artifactPreview.selected !== undefined) returnToComposition(); },
|
|
405
406
|
renameArtifact(artifact) {
|
|
406
407
|
const selected = artifactPreview.selected;
|
|
407
|
-
if (selected?.build === artifact.build && selected.output === artifact.output) title
|
|
408
|
+
if (selected?.build === artifact.build && selected.output === artifact.output) userText(title, artifact.displayName ?? artifact.output);
|
|
408
409
|
},
|
|
409
410
|
};
|
|
410
411
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { userText, uiAttribute, uiText, uiAttr } from "./i18n.js";
|
|
1
2
|
import type {
|
|
2
3
|
SemanticToken,
|
|
3
4
|
StudioSnapshot,
|
|
@@ -89,13 +90,13 @@ export function createTimeline(store: Store): Timeline {
|
|
|
89
90
|
element.innerHTML = `
|
|
90
91
|
<div class="timeline-toolbar">
|
|
91
92
|
<div class="timeline-tools">
|
|
92
|
-
<button type="button" class="tool-button active" aria-label
|
|
93
|
+
<button type="button" class="tool-button active" ${uiAttribute("aria-label", "timeline.select")} ${uiAttribute("title", "timeline.select")}>${icon("select")}</button>
|
|
93
94
|
</div>
|
|
94
95
|
<div class="timeline-time" data-timeline-time>00:00:00</div>
|
|
95
96
|
<div class="timeline-view-actions">
|
|
96
|
-
<button type="button" class="icon-button" data-zoom-out aria-label
|
|
97
|
-
<button type="button" class="icon-button" data-zoom-fit aria-label
|
|
98
|
-
<button type="button" class="icon-button" data-zoom-in aria-label
|
|
97
|
+
<button type="button" class="icon-button" data-zoom-out ${uiAttribute("aria-label", "timeline.zoom-out")} ${uiAttribute("title", "timeline.zoom-out")}>${icon("minus")}</button>
|
|
98
|
+
<button type="button" class="icon-button" data-zoom-fit ${uiAttribute("aria-label", "timeline.fit-timeline")} ${uiAttribute("title", "timeline.fit-timeline")}>${icon("fit")}</button>
|
|
99
|
+
<button type="button" class="icon-button" data-zoom-in ${uiAttribute("aria-label", "timeline.zoom-in")} ${uiAttribute("title", "timeline.zoom-in")}>${icon("plus")}</button>
|
|
99
100
|
</div>
|
|
100
101
|
</div>
|
|
101
102
|
<div class="timeline-body" data-timeline-body>
|
|
@@ -138,8 +139,8 @@ export function createTimeline(store: Store): Timeline {
|
|
|
138
139
|
remember: "hypit-studio.v4.timeline-label-width",
|
|
139
140
|
});
|
|
140
141
|
labelHandle.classList.add("timeline-label-handle");
|
|
141
|
-
labelHandle
|
|
142
|
-
labelHandle
|
|
142
|
+
uiAttr(labelHandle, "aria-label", "timeline.resize-timeline-track-labels");
|
|
143
|
+
uiAttr(labelHandle, "title", "timeline.resize-track-labels");
|
|
143
144
|
body.insertBefore(labelHandle, lanes);
|
|
144
145
|
|
|
145
146
|
let state: State | undefined;
|
|
@@ -501,12 +502,14 @@ export function createTimeline(store: Store): Timeline {
|
|
|
501
502
|
];
|
|
502
503
|
const laneHeight = bands.reduce((height, band) => height + band.height, itemMetrics.insetYPx * 2);
|
|
503
504
|
const label = createTrackLabel(
|
|
504
|
-
presentation.label ?? "
|
|
505
|
+
presentation.label ?? "",
|
|
505
506
|
presentation.tone,
|
|
506
507
|
presentation.icon,
|
|
507
|
-
|
|
508
|
+
"",
|
|
508
509
|
laneHeight,
|
|
509
510
|
);
|
|
511
|
+
if (presentation.label === undefined) uiText(label.querySelector("strong")!, "inspector.timeline");
|
|
512
|
+
uiAttr(label, "title", "timeline.segment-count", { count: snapshot.semantic.segments.length });
|
|
510
513
|
label.classList.add("track-label-semantic");
|
|
511
514
|
label.style.height = `calc(var(--timeline-ruler-height) + ${laneHeight}px)`;
|
|
512
515
|
labels.append(label);
|
|
@@ -529,7 +532,7 @@ export function createTimeline(store: Store): Timeline {
|
|
|
529
532
|
band.className = `semantic-band semantic-band-${kind}`;
|
|
530
533
|
band.style.top = `${bandTop}px`;
|
|
531
534
|
band.style.setProperty("--semantic-band-height", `${height}px`);
|
|
532
|
-
band
|
|
535
|
+
uiAttr(band, "aria-label", kind === "intent" ? "timeline.selections-and-moments" : kind === "word" ? "timeline.words" : "timeline.segments");
|
|
533
536
|
lane.append(band);
|
|
534
537
|
bandTop += height;
|
|
535
538
|
}
|
|
@@ -546,7 +549,7 @@ export function createTimeline(store: Store): Timeline {
|
|
|
546
549
|
node.className = "semantic-cell semantic-segment";
|
|
547
550
|
node.tabIndex = 0;
|
|
548
551
|
node.setAttribute("role", "button");
|
|
549
|
-
node
|
|
552
|
+
uiAttr(node, "aria-label", "timeline.segment-name", { name: segment.id });
|
|
550
553
|
node.dataset.semanticSegment = segment.id;
|
|
551
554
|
node.style.left = `${from * 100}%`;
|
|
552
555
|
const segmentWidth = Math.max(0, to - from) * 100;
|
|
@@ -626,7 +629,7 @@ export function createTimeline(store: Store): Timeline {
|
|
|
626
629
|
node.type = "button";
|
|
627
630
|
node.className = "semantic-cell semantic-selection";
|
|
628
631
|
node.tabIndex = 0;
|
|
629
|
-
node
|
|
632
|
+
uiAttr(node, "aria-label", "timeline.selection-name", { name: selection.id });
|
|
630
633
|
node.style.left = `${from * 100}%`;
|
|
631
634
|
node.style.width = `max(2px, ${Math.max(0, to - from) * 100}%)`;
|
|
632
635
|
node.title = selection.id;
|
|
@@ -652,7 +655,7 @@ export function createTimeline(store: Store): Timeline {
|
|
|
652
655
|
node.type = "button";
|
|
653
656
|
node.className = "semantic-moment";
|
|
654
657
|
node.tabIndex = 0;
|
|
655
|
-
node
|
|
658
|
+
uiAttr(node, "aria-label", "timeline.moment-name", { name: moment.id });
|
|
656
659
|
node.style.left = `${at * 100}%`;
|
|
657
660
|
node.title = moment.id;
|
|
658
661
|
node.addEventListener("click", (event) => {
|
|
@@ -674,7 +677,7 @@ export function createTimeline(store: Store): Timeline {
|
|
|
674
677
|
const menu = document.createElement("div");
|
|
675
678
|
menu.className = "timeline-overlap-menu";
|
|
676
679
|
menu.setAttribute("role", "menu");
|
|
677
|
-
menu
|
|
680
|
+
uiAttr(menu, "aria-label", "timeline.overlapping-timeline-objects");
|
|
678
681
|
for (const hit of [...hits].reverse()) {
|
|
679
682
|
const option = document.createElement("button");
|
|
680
683
|
option.type = "button";
|
|
@@ -835,7 +838,7 @@ export function createTimeline(store: Store): Timeline {
|
|
|
835
838
|
semanticNodes = [];
|
|
836
839
|
const corner = document.createElement("div");
|
|
837
840
|
corner.className = "label-corner";
|
|
838
|
-
corner
|
|
841
|
+
userText(corner, "");
|
|
839
842
|
if (snapshot.semantic === undefined || snapshot.semantic.segments.length === 0) labels.append(corner);
|
|
840
843
|
buildSemanticLane(snapshot);
|
|
841
844
|
const nextClipNodes: { node: HTMLElement; start: number; end: number; id: string; selectionGroup?: string }[] = [];
|
package/packages/studio/start.ts
CHANGED
|
@@ -10,6 +10,14 @@ Open a Run in the browser to inspect its composition, Sources and Results.
|
|
|
10
10
|
|
|
11
11
|
hypit studio --run <build.svrun> [--runtime <hypit.runtime.json>]
|
|
12
12
|
[--port <number>] [--workspace <directory>] [--package-root <directory>]
|
|
13
|
+
[--locale-pack <./language.json | installed-package/language.json>]...
|
|
14
|
+
|
|
15
|
+
hypit studio --check-locale <./language.json | installed-package/language.json>
|
|
16
|
+
[--package-root <directory>]
|
|
17
|
+
|
|
18
|
+
Language packs are explicit JSON data. Relative files use the current directory;
|
|
19
|
+
package exports resolve from --package-root (the project by default).
|
|
20
|
+
--check-locale lists missing translations and unknown IDs without opening a Run.
|
|
13
21
|
|
|
14
22
|
Relative command-line paths start at the current directory; --workspace selects
|
|
15
23
|
the project, without rebasing those paths. Otherwise the nearest package.json
|
|
@@ -24,9 +32,9 @@ function invalidArguments(message: string): never {
|
|
|
24
32
|
throw new Error(`${message}. See hypit studio --help.`);
|
|
25
33
|
}
|
|
26
34
|
|
|
27
|
-
function argumentsByName(argv: readonly string[]): ReadonlyMap<string, string> {
|
|
28
|
-
const accepted = new Set(["run", "runtime", "port", "workspace", "package-root"]);
|
|
29
|
-
const result = new Map<string, string>();
|
|
35
|
+
function argumentsByName(argv: readonly string[]): ReadonlyMap<string, readonly string[]> {
|
|
36
|
+
const accepted = new Set(["run", "runtime", "port", "workspace", "package-root", "locale-pack", "check-locale"]);
|
|
37
|
+
const result = new Map<string, string[]>();
|
|
30
38
|
for (let index = 0; index < argv.length; index += 2) {
|
|
31
39
|
const flag = argv[index];
|
|
32
40
|
const value = argv[index + 1];
|
|
@@ -35,7 +43,7 @@ function argumentsByName(argv: readonly string[]): ReadonlyMap<string, string> {
|
|
|
35
43
|
}
|
|
36
44
|
const name = flag.slice(2);
|
|
37
45
|
if (!accepted.has(name)) invalidArguments(`Unknown option --${name}`);
|
|
38
|
-
result.set(name, value);
|
|
46
|
+
result.set(name, [...result.get(name) ?? [], value]);
|
|
39
47
|
}
|
|
40
48
|
return result;
|
|
41
49
|
}
|
|
@@ -47,22 +55,12 @@ export async function runStudio(argv: readonly string[], io: Pick<CliIo, "write"
|
|
|
47
55
|
}
|
|
48
56
|
const values = argumentsByName(argv[0] === "--" ? argv.slice(1) : argv);
|
|
49
57
|
const invokedFrom = process.env.INIT_CWD ?? process.cwd();
|
|
50
|
-
const runArgument = values.get("run");
|
|
51
|
-
|
|
52
|
-
const { createServer } = await import("vite");
|
|
58
|
+
const runArgument = values.get("run")?.at(-1);
|
|
59
|
+
|
|
53
60
|
const { findRuntimeProfile, resolveProjectRoot } = await import("@hypit/project-context-node");
|
|
54
|
-
|
|
55
|
-
const
|
|
56
|
-
const
|
|
57
|
-
const { loadStudioCompanionRegistry } = await import("./src/companion-assembly.js");
|
|
58
|
-
const { loadStudioDomain } = await import("./src/domain.js");
|
|
59
|
-
const { loadStudioRun } = await import("./src/run.js");
|
|
60
|
-
const { studioPlugin } = await import("./src/server.js");
|
|
61
|
-
const { studioFeedbackPlugin } = await import("./src/feedback-server.js");
|
|
62
|
-
const { inspectStudioRun } = await import("./src/studio-preflight.js");
|
|
63
|
-
const runPath = resolve(invokedFrom, runArgument);
|
|
64
|
-
const packageRootArgument = values.get("package-root");
|
|
65
|
-
const workspaceArgument = values.get("workspace");
|
|
61
|
+
|
|
62
|
+
const packageRootArgument = values.get("package-root")?.at(-1);
|
|
63
|
+
const workspaceArgument = values.get("workspace")?.at(-1);
|
|
66
64
|
const requestedWorkspaceRoot = workspaceArgument === undefined
|
|
67
65
|
? undefined
|
|
68
66
|
: resolve(invokedFrom, workspaceArgument);
|
|
@@ -73,7 +71,26 @@ export async function runStudio(argv: readonly string[], io: Pick<CliIo, "write"
|
|
|
73
71
|
const packageRoot = packageRootArgument === undefined
|
|
74
72
|
? workspaceRoot
|
|
75
73
|
: resolve(invokedFrom, packageRootArgument);
|
|
76
|
-
const
|
|
74
|
+
const { describeLanguagePack, loadLanguagePack, studioLanguages, studioLocalizationPlugin } = await import("./src/localization-node.js");
|
|
75
|
+
const checkLocale = values.get("check-locale")?.at(-1);
|
|
76
|
+
if (checkLocale !== undefined) {
|
|
77
|
+
io.write(describeLanguagePack(await loadLanguagePack(checkLocale, invokedFrom, packageRoot)) + "\n");
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
if (runArgument === undefined || runArgument.trim().length === 0) invalidArguments("Missing --run");
|
|
81
|
+
const runPath = resolve(invokedFrom, runArgument);
|
|
82
|
+
const { createServer } = await import("vite");
|
|
83
|
+
const { resolveDistributionPackageImport } = await import("@hypit/package-loader-node");
|
|
84
|
+
const { videoCliDistribution, videoStudioCompanionPackages } = await import("@hypit/video-cli");
|
|
85
|
+
const { openStudioBuildLibrary } = await import("./src/build-library.js");
|
|
86
|
+
const { loadStudioCompanionRegistry } = await import("./src/companion-assembly.js");
|
|
87
|
+
const { loadStudioDomain } = await import("./src/domain.js");
|
|
88
|
+
const { loadStudioRun } = await import("./src/run.js");
|
|
89
|
+
const { studioPlugin } = await import("./src/server.js");
|
|
90
|
+
const { studioFeedbackPlugin } = await import("./src/feedback-server.js");
|
|
91
|
+
const { inspectStudioRun } = await import("./src/studio-preflight.js");
|
|
92
|
+
const languages = await studioLanguages(values.get("locale-pack") ?? [], invokedFrom, packageRoot);
|
|
93
|
+
const runtimeArgument = values.get("runtime")?.at(-1);
|
|
77
94
|
const selectedRuntime = runtimeArgument === undefined
|
|
78
95
|
? await findRuntimeProfile(workspaceRoot)
|
|
79
96
|
: undefined;
|
|
@@ -89,7 +106,7 @@ export async function runStudio(argv: readonly string[], io: Pick<CliIo, "write"
|
|
|
89
106
|
...(packageRoot === workspaceRoot ? [] : [` Package root ${packageRoot}`]),
|
|
90
107
|
"",
|
|
91
108
|
].join("\n"));
|
|
92
|
-
const port = Number(values.get("port") ?? "5179");
|
|
109
|
+
const port = Number(values.get("port")?.at(-1) ?? "5179");
|
|
93
110
|
if (!Number.isSafeInteger(port) || port <= 0) invalidArguments("--port must be a positive integer");
|
|
94
111
|
|
|
95
112
|
const distributionPackageRoot = videoCliDistribution.packageRoot ?? resolve(here, "../..");
|
|
@@ -137,7 +154,7 @@ export async function runStudio(argv: readonly string[], io: Pick<CliIo, "write"
|
|
|
137
154
|
// available for Source and material previews.
|
|
138
155
|
fs: { allow: [workspaceRoot, packageRoot, distributionPackageRoot, here] },
|
|
139
156
|
},
|
|
140
|
-
plugins: [distributionImports, studioFeedbackPlugin(workspaceRoot, runPath), studioPlugin({
|
|
157
|
+
plugins: [distributionImports, studioLocalizationPlugin(languages), studioFeedbackPlugin(workspaceRoot, runPath), studioPlugin({
|
|
141
158
|
source,
|
|
142
159
|
runPath,
|
|
143
160
|
workspaceRoot,
|