@neta-art/cohub-cli 10.4.1 → 10.4.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/dist/board-kernel.js
CHANGED
|
@@ -6821,20 +6821,20 @@ const CAMERA_PROPERTIES = {
|
|
|
6821
6821
|
y: number$1().finite(),
|
|
6822
6822
|
width: number$1().finite().positive(),
|
|
6823
6823
|
height: number$1().finite().positive()
|
|
6824
|
-
}).strict()])
|
|
6824
|
+
}).strict()]).describe("Item id or world-space rect to fit with 48 px padding; holds until the next focus keyframe.")
|
|
6825
6825
|
},
|
|
6826
6826
|
zoom: {
|
|
6827
6827
|
kind: "number",
|
|
6828
|
-
schema: number$1().finite().positive(),
|
|
6828
|
+
schema: number$1().finite().positive().describe("Pixels per world unit; overrides the zoom computed by focus."),
|
|
6829
6829
|
multiplicative: true
|
|
6830
6830
|
},
|
|
6831
6831
|
center: {
|
|
6832
6832
|
kind: "vec2",
|
|
6833
|
-
schema: BoardVec2Schema$1
|
|
6833
|
+
schema: BoardVec2Schema$1.describe("World-space viewport center; overrides focus positioning using the resolved zoom.")
|
|
6834
6834
|
},
|
|
6835
6835
|
shake: {
|
|
6836
6836
|
kind: "number",
|
|
6837
|
-
schema: number$1().finite().nonnegative()
|
|
6837
|
+
schema: number$1().finite().nonnegative().describe("Shake amplitude in screen pixels, applied after focus, zoom and center.")
|
|
6838
6838
|
}
|
|
6839
6839
|
};
|
|
6840
6840
|
const ANIMATION_PROPERTIES = { time: {
|
|
@@ -7338,6 +7338,86 @@ function parseBoardDocument(input) {
|
|
|
7338
7338
|
} : result;
|
|
7339
7339
|
}
|
|
7340
7340
|
//#endregion
|
|
7341
|
+
//#region ../protocol/src/board.ts
|
|
7342
|
+
const BOARD_EXTENSION = ".board";
|
|
7343
|
+
const BOARD_MIME_TYPE = "application/json";
|
|
7344
|
+
object({
|
|
7345
|
+
kind: literal("cohub.board.manifest"),
|
|
7346
|
+
version: literal(1),
|
|
7347
|
+
boardId: string().uuid(),
|
|
7348
|
+
title: string().min(1).max(255)
|
|
7349
|
+
});
|
|
7350
|
+
const BOARD_READ_SECTIONS = ["items", "animations"];
|
|
7351
|
+
const rectSchema = object({
|
|
7352
|
+
x: number$1().finite(),
|
|
7353
|
+
y: number$1().finite(),
|
|
7354
|
+
width: number$1().finite().positive(),
|
|
7355
|
+
height: number$1().finite().positive()
|
|
7356
|
+
}).strict();
|
|
7357
|
+
object({
|
|
7358
|
+
only: array(_enum(BOARD_READ_SECTIONS)).optional(),
|
|
7359
|
+
rect: rectSchema.optional(),
|
|
7360
|
+
within: BoardIdSchema$1.optional(),
|
|
7361
|
+
items: array(string().min(1)).max(5e4).optional(),
|
|
7362
|
+
animations: array(string().min(1)).max(1e4).optional(),
|
|
7363
|
+
limit: number$1().int().min(1).max(5e4).optional(),
|
|
7364
|
+
cursor: string().min(1).optional()
|
|
7365
|
+
}).strict().refine((read) => !(read.cursor && (read.rect || read.within)), {
|
|
7366
|
+
path: ["cursor"],
|
|
7367
|
+
message: "cursor pages by id, so it cannot be combined with rect or within"
|
|
7368
|
+
});
|
|
7369
|
+
object({
|
|
7370
|
+
patch: BoardPatchSchema$1,
|
|
7371
|
+
replace: boolean().default(false),
|
|
7372
|
+
cascade: boolean().default(false),
|
|
7373
|
+
dryRun: boolean().default(false),
|
|
7374
|
+
baseVersion: number$1().int().nonnegative().optional(),
|
|
7375
|
+
mutationId: string().min(1).max(160).optional(),
|
|
7376
|
+
clientId: string().min(1).max(160).optional()
|
|
7377
|
+
}).strict();
|
|
7378
|
+
object({
|
|
7379
|
+
path: string().min(1),
|
|
7380
|
+
title: string().min(1).max(255).optional(),
|
|
7381
|
+
document: BoardPatchSchema$1.optional(),
|
|
7382
|
+
mutationId: string().max(160).optional()
|
|
7383
|
+
}).strict();
|
|
7384
|
+
object({
|
|
7385
|
+
before: number$1().int().positive().optional(),
|
|
7386
|
+
limit: number$1().int().min(1).max(500).default(200)
|
|
7387
|
+
}).strict();
|
|
7388
|
+
const commandId = string().min(1).max(160);
|
|
7389
|
+
discriminatedUnion("type", [
|
|
7390
|
+
object({
|
|
7391
|
+
commandId,
|
|
7392
|
+
type: literal("play"),
|
|
7393
|
+
animationId: string().min(1),
|
|
7394
|
+
position: number$1().finite().nonnegative().optional(),
|
|
7395
|
+
timeScale: number$1().finite().positive().max(4).optional(),
|
|
7396
|
+
seed: string().min(1).max(160).optional()
|
|
7397
|
+
}).strict(),
|
|
7398
|
+
object({
|
|
7399
|
+
commandId,
|
|
7400
|
+
type: literal("pause")
|
|
7401
|
+
}).strict(),
|
|
7402
|
+
object({
|
|
7403
|
+
commandId,
|
|
7404
|
+
type: literal("resume")
|
|
7405
|
+
}).strict(),
|
|
7406
|
+
object({
|
|
7407
|
+
commandId,
|
|
7408
|
+
type: literal("seek"),
|
|
7409
|
+
position: number$1().finite().nonnegative()
|
|
7410
|
+
}).strict(),
|
|
7411
|
+
object({
|
|
7412
|
+
commandId,
|
|
7413
|
+
type: literal("next")
|
|
7414
|
+
}).strict(),
|
|
7415
|
+
object({
|
|
7416
|
+
commandId,
|
|
7417
|
+
type: literal("stop")
|
|
7418
|
+
}).strict()
|
|
7419
|
+
]);
|
|
7420
|
+
//#endregion
|
|
7341
7421
|
//#region ../protocol/src/board-task.ts
|
|
7342
7422
|
function artifactScore(artifact) {
|
|
7343
7423
|
const kind = {
|
|
@@ -7374,6 +7454,117 @@ function taskArtifactPreviewUrl(artifact) {
|
|
|
7374
7454
|
if (artifact?.type === "video" || artifact?.type === "audio") return artifact.previewUrl;
|
|
7375
7455
|
}
|
|
7376
7456
|
//#endregion
|
|
7457
|
+
//#region ../protocol/src/fs/mime.ts
|
|
7458
|
+
const MIME_BY_EXTENSION = {
|
|
7459
|
+
".txt": "text/plain",
|
|
7460
|
+
".md": "text/markdown",
|
|
7461
|
+
".markdown": "text/markdown",
|
|
7462
|
+
".json": "application/json",
|
|
7463
|
+
".jsonl": "application/x-ndjson",
|
|
7464
|
+
".csv": "text/csv",
|
|
7465
|
+
[BOARD_EXTENSION]: BOARD_MIME_TYPE,
|
|
7466
|
+
".js": "text/javascript",
|
|
7467
|
+
".mjs": "text/javascript",
|
|
7468
|
+
".cjs": "text/javascript",
|
|
7469
|
+
".ts": "text/typescript",
|
|
7470
|
+
".tsx": "text/tsx",
|
|
7471
|
+
".jsx": "text/jsx",
|
|
7472
|
+
".svelte": "text/x-svelte",
|
|
7473
|
+
".css": "text/css",
|
|
7474
|
+
".scss": "text/x-scss",
|
|
7475
|
+
".html": "text/html",
|
|
7476
|
+
".htm": "text/html",
|
|
7477
|
+
".xml": "application/xml",
|
|
7478
|
+
".yaml": "application/yaml",
|
|
7479
|
+
".yml": "application/yaml",
|
|
7480
|
+
".toml": "application/toml",
|
|
7481
|
+
".ini": "text/plain",
|
|
7482
|
+
".env": "text/plain",
|
|
7483
|
+
".sh": "text/x-shellscript",
|
|
7484
|
+
".bash": "text/x-shellscript",
|
|
7485
|
+
".py": "text/x-python",
|
|
7486
|
+
".go": "text/x-go",
|
|
7487
|
+
".rs": "text/x-rust",
|
|
7488
|
+
".java": "text/x-java-source",
|
|
7489
|
+
".c": "text/x-c",
|
|
7490
|
+
".h": "text/x-c",
|
|
7491
|
+
".cpp": "text/x-c++src",
|
|
7492
|
+
".hpp": "text/x-c++hdr",
|
|
7493
|
+
".sql": "application/sql",
|
|
7494
|
+
".svg": "image/svg+xml",
|
|
7495
|
+
".png": "image/png",
|
|
7496
|
+
".jpg": "image/jpeg",
|
|
7497
|
+
".jpeg": "image/jpeg",
|
|
7498
|
+
".gif": "image/gif",
|
|
7499
|
+
".webp": "image/webp",
|
|
7500
|
+
".avif": "image/avif",
|
|
7501
|
+
".bmp": "image/bmp",
|
|
7502
|
+
".ico": "image/x-icon",
|
|
7503
|
+
".mp4": "video/mp4",
|
|
7504
|
+
".webm": "video/webm",
|
|
7505
|
+
".mov": "video/quicktime",
|
|
7506
|
+
".m4v": "video/x-m4v",
|
|
7507
|
+
".ogv": "video/ogg",
|
|
7508
|
+
".avi": "video/x-msvideo",
|
|
7509
|
+
".mp3": "audio/mpeg",
|
|
7510
|
+
".wav": "audio/wav",
|
|
7511
|
+
".ogg": "audio/ogg",
|
|
7512
|
+
".m4a": "audio/mp4",
|
|
7513
|
+
".aac": "audio/aac",
|
|
7514
|
+
".flac": "audio/flac",
|
|
7515
|
+
".opus": "audio/ogg",
|
|
7516
|
+
".glb": "model/gltf-binary",
|
|
7517
|
+
".gltf": "model/gltf+json",
|
|
7518
|
+
".stl": "model/stl",
|
|
7519
|
+
".obj": "model/obj",
|
|
7520
|
+
".3mf": "model/3mf",
|
|
7521
|
+
".usdz": "model/vnd.usdz+zip",
|
|
7522
|
+
".mtl": "text/plain",
|
|
7523
|
+
".pdf": "application/pdf",
|
|
7524
|
+
".wasm": "application/wasm",
|
|
7525
|
+
".woff": "font/woff",
|
|
7526
|
+
".woff2": "font/woff2",
|
|
7527
|
+
".zip": "application/zip",
|
|
7528
|
+
".gz": "application/gzip",
|
|
7529
|
+
".tar": "application/x-tar",
|
|
7530
|
+
".rar": "application/vnd.rar",
|
|
7531
|
+
".7z": "application/x-7z-compressed",
|
|
7532
|
+
".exe": "application/x-msdownload",
|
|
7533
|
+
".dmg": "application/x-apple-diskimage",
|
|
7534
|
+
".deb": "application/vnd.debian.binary-package",
|
|
7535
|
+
".rpm": "application/x-rpm"
|
|
7536
|
+
};
|
|
7537
|
+
const MIME_BY_FILENAME = {
|
|
7538
|
+
dockerfile: "text/x-dockerfile",
|
|
7539
|
+
makefile: "text/x-makefile"
|
|
7540
|
+
};
|
|
7541
|
+
function mimeTypeForPath(path) {
|
|
7542
|
+
const name = (path.split(/[\\/]/).pop() ?? "").toLowerCase();
|
|
7543
|
+
const byName = Object.hasOwn(MIME_BY_FILENAME, name) ? MIME_BY_FILENAME[name] : void 0;
|
|
7544
|
+
if (byName) return byName;
|
|
7545
|
+
const dot = name.lastIndexOf(".");
|
|
7546
|
+
const byExtension = dot > 0 ? MIME_BY_EXTENSION[name.slice(dot)] : void 0;
|
|
7547
|
+
if (byExtension) return byExtension;
|
|
7548
|
+
return name.startsWith(".") ? "text/plain" : null;
|
|
7549
|
+
}
|
|
7550
|
+
function normalizeMime$1(mimeType) {
|
|
7551
|
+
if (!mimeType) return null;
|
|
7552
|
+
return mimeType.split(";")[0]?.trim().toLowerCase() || null;
|
|
7553
|
+
}
|
|
7554
|
+
const MODEL_FORMAT_BY_MIME = {
|
|
7555
|
+
"model/gltf-binary": "glb",
|
|
7556
|
+
"model/gltf+json": "gltf",
|
|
7557
|
+
"model/stl": "stl",
|
|
7558
|
+
"model/obj": "obj"
|
|
7559
|
+
};
|
|
7560
|
+
function modelFormatForPath(path, mimeType) {
|
|
7561
|
+
const format = (mime) => {
|
|
7562
|
+
const key = normalizeMime$1(mime);
|
|
7563
|
+
return key && Object.hasOwn(MODEL_FORMAT_BY_MIME, key) ? MODEL_FORMAT_BY_MIME[key] : void 0;
|
|
7564
|
+
};
|
|
7565
|
+
return format(mimeTypeForPath(path)) ?? format(mimeType) ?? null;
|
|
7566
|
+
}
|
|
7567
|
+
//#endregion
|
|
7377
7568
|
//#region ../sdk/src/board/model/script-index.ts
|
|
7378
7569
|
const scriptsByItems = /* @__PURE__ */ new WeakMap();
|
|
7379
7570
|
function boardScriptItems(document) {
|
|
@@ -8470,7 +8661,6 @@ function boardSequence(document, chapters) {
|
|
|
8470
8661
|
const chapterIndex = String(index).padStart(String(chapters.length).length, "0");
|
|
8471
8662
|
for (const [id, track] of Object.entries(animation.tracks)) {
|
|
8472
8663
|
if (document.animations[track.target]) throw new Error(`Chapter ${chapter.animation} contains nested clocks; compose its leaf animations instead.`);
|
|
8473
|
-
if (chapter.frame && track.target === "camera" && track.property === "focus") continue;
|
|
8474
8664
|
tracks[`chapter-${chapterIndex}-${ranks.get(id)}`] = {
|
|
8475
8665
|
...track,
|
|
8476
8666
|
keyframes: track.keyframes.map((keyframe) => ({
|
|
@@ -8501,7 +8691,7 @@ function boardSequence(document, chapters) {
|
|
|
8501
8691
|
}] : []
|
|
8502
8692
|
]
|
|
8503
8693
|
};
|
|
8504
|
-
tracks[`
|
|
8694
|
+
tracks[`chapter-${chapterIndex}--camera`] = {
|
|
8505
8695
|
target: "camera",
|
|
8506
8696
|
property: "focus",
|
|
8507
8697
|
composite: "replace",
|
|
@@ -9192,6 +9382,14 @@ function getMediaResourceTitle(value) {
|
|
|
9192
9382
|
return value.split("/").filter(Boolean).pop() || value;
|
|
9193
9383
|
}
|
|
9194
9384
|
}
|
|
9385
|
+
function boardModelFormat(src, mimeType) {
|
|
9386
|
+
const source = parseBoardMediaSource$1(src);
|
|
9387
|
+
if (!source) return null;
|
|
9388
|
+
return modelFormatForPath(source.kind === "url" ? source.value.split(/[?#]/, 1)[0] ?? "" : source.value, mimeType);
|
|
9389
|
+
}
|
|
9390
|
+
function isBoardModelItem(item) {
|
|
9391
|
+
return item?.type === "file" && boardModelFormat(item.props.src, item.props.snapshot?.mimeType) !== null;
|
|
9392
|
+
}
|
|
9195
9393
|
//#endregion
|
|
9196
9394
|
//#region ../sdk/src/board/model/file-snapshot.ts
|
|
9197
9395
|
/**
|
|
@@ -27372,6 +27570,14 @@ const PIXEL_GLYPHS = {
|
|
|
27372
27570
|
".###..",
|
|
27373
27571
|
".###.."
|
|
27374
27572
|
],
|
|
27573
|
+
model: [
|
|
27574
|
+
"..#...",
|
|
27575
|
+
".###..",
|
|
27576
|
+
"#####.",
|
|
27577
|
+
"#####.",
|
|
27578
|
+
".###..",
|
|
27579
|
+
"..#..."
|
|
27580
|
+
],
|
|
27375
27581
|
file: [
|
|
27376
27582
|
"####..",
|
|
27377
27583
|
"#..##.",
|
|
@@ -27422,6 +27628,9 @@ function drawLineGlyph(graphics, glyph, color) {
|
|
|
27422
27628
|
]) graphics.moveTo(x, 6 - height / 2).lineTo(x, 6 + height / 2);
|
|
27423
27629
|
graphics.stroke(line);
|
|
27424
27630
|
return;
|
|
27631
|
+
case "model":
|
|
27632
|
+
traceCube(graphics, 6, 6, 4.5).stroke(line);
|
|
27633
|
+
return;
|
|
27425
27634
|
case "file":
|
|
27426
27635
|
graphics.poly([
|
|
27427
27636
|
2.5,
|
|
@@ -27459,6 +27668,25 @@ function drawLineGlyph(graphics, glyph, color) {
|
|
|
27459
27668
|
return;
|
|
27460
27669
|
}
|
|
27461
27670
|
}
|
|
27671
|
+
function traceCube(graphics, cx, cy, radius) {
|
|
27672
|
+
const dx = radius * .866;
|
|
27673
|
+
const dy = radius / 2;
|
|
27674
|
+
graphics.poly([
|
|
27675
|
+
cx,
|
|
27676
|
+
cy - radius,
|
|
27677
|
+
cx + dx,
|
|
27678
|
+
cy - dy,
|
|
27679
|
+
cx + dx,
|
|
27680
|
+
cy + dy,
|
|
27681
|
+
cx,
|
|
27682
|
+
cy + radius,
|
|
27683
|
+
cx - dx,
|
|
27684
|
+
cy + dy,
|
|
27685
|
+
cx - dx,
|
|
27686
|
+
cy - dy
|
|
27687
|
+
]).moveTo(cx - dx, cy - dy).lineTo(cx, cy).lineTo(cx + dx, cy - dy).moveTo(cx, cy).lineTo(cx, cy + radius);
|
|
27688
|
+
return graphics;
|
|
27689
|
+
}
|
|
27462
27690
|
function drawCardGlyph(graphics, glyph, color, pixel) {
|
|
27463
27691
|
if (!pixel) {
|
|
27464
27692
|
drawLineGlyph(graphics, glyph, color);
|
|
@@ -27957,9 +28185,28 @@ function drawMediaPlayKey(graphics, cx, cy, radius, context, solid = false) {
|
|
|
27957
28185
|
alpha: .96
|
|
27958
28186
|
});
|
|
27959
28187
|
}
|
|
28188
|
+
function drawModelKey(graphics, cx, cy, radius, context) {
|
|
28189
|
+
if (context.style.corner === "pixel") {
|
|
28190
|
+
const size = Math.round(radius * 1.6);
|
|
28191
|
+
tracePixelRect(graphics, Math.round(cx - size / 2), Math.round(cy - size / 2), size, size, 2).fill({
|
|
28192
|
+
color: MEDIA_SCRIM,
|
|
28193
|
+
alpha: .62
|
|
28194
|
+
});
|
|
28195
|
+
} else graphics.circle(cx, cy, radius).fill({
|
|
28196
|
+
color: MEDIA_SCRIM,
|
|
28197
|
+
alpha: .45
|
|
28198
|
+
});
|
|
28199
|
+
traceCube(graphics, cx, cy, radius * .5).stroke({
|
|
28200
|
+
color: MEDIA_INK,
|
|
28201
|
+
width: Math.max(1, radius / 10),
|
|
28202
|
+
alpha: .96,
|
|
28203
|
+
join: "round",
|
|
28204
|
+
cap: "round"
|
|
28205
|
+
});
|
|
28206
|
+
}
|
|
27960
28207
|
const GAP$1 = 12;
|
|
27961
28208
|
const WAVE_HEIGHT = 16;
|
|
27962
|
-
const partsByContainer$
|
|
28209
|
+
const partsByContainer$13 = /* @__PURE__ */ new WeakMap();
|
|
27963
28210
|
function audioKeyCenter(width, height) {
|
|
27964
28211
|
const radius = Math.min(16, Math.max(8, height / 2 - 8), width / 4);
|
|
27965
28212
|
return {
|
|
@@ -27968,8 +28215,8 @@ function audioKeyCenter(width, height) {
|
|
|
27968
28215
|
radius
|
|
27969
28216
|
};
|
|
27970
28217
|
}
|
|
27971
|
-
function sync$
|
|
27972
|
-
const parts = partsByContainer$
|
|
28218
|
+
function sync$13(container, item, context) {
|
|
28219
|
+
const parts = partsByContainer$13.get(container);
|
|
27973
28220
|
if (!parts) return;
|
|
27974
28221
|
positionShell(parts.root, item);
|
|
27975
28222
|
const { width, height } = item.frame;
|
|
@@ -28040,7 +28287,7 @@ const audioCardRenderer = {
|
|
|
28040
28287
|
roundPixels: true
|
|
28041
28288
|
});
|
|
28042
28289
|
root.addChild(plate, wave, title);
|
|
28043
|
-
partsByContainer$
|
|
28290
|
+
partsByContainer$13.set(root, {
|
|
28044
28291
|
root,
|
|
28045
28292
|
plate,
|
|
28046
28293
|
wave,
|
|
@@ -28048,11 +28295,11 @@ const audioCardRenderer = {
|
|
|
28048
28295
|
sig: "",
|
|
28049
28296
|
resolution
|
|
28050
28297
|
});
|
|
28051
|
-
if (item.type === "audio") sync$
|
|
28298
|
+
if (item.type === "audio") sync$13(root, item, context);
|
|
28052
28299
|
return root;
|
|
28053
28300
|
},
|
|
28054
28301
|
update: (container, item, context) => {
|
|
28055
|
-
if (item.type === "audio") sync$
|
|
28302
|
+
if (item.type === "audio") sync$13(container, item, context);
|
|
28056
28303
|
},
|
|
28057
28304
|
renderFar: (graphics, item, context) => {
|
|
28058
28305
|
drawFarPlate(graphics, item.frame, {
|
|
@@ -28062,6 +28309,127 @@ const audioCardRenderer = {
|
|
|
28062
28309
|
accentAlpha: .72
|
|
28063
28310
|
});
|
|
28064
28311
|
},
|
|
28312
|
+
destroy: (container) => {
|
|
28313
|
+
partsByContainer$13.get(container)?.root.destroy({ children: true });
|
|
28314
|
+
partsByContainer$13.delete(container);
|
|
28315
|
+
}
|
|
28316
|
+
};
|
|
28317
|
+
//#endregion
|
|
28318
|
+
//#region ../sdk/src/board/render/renderers/model-card-renderer.ts
|
|
28319
|
+
const partsByContainer$12 = /* @__PURE__ */ new WeakMap();
|
|
28320
|
+
const INSET_RATIO = .06;
|
|
28321
|
+
const KEY_RADIUS = 14;
|
|
28322
|
+
const KEY_MARGIN = 10;
|
|
28323
|
+
function modelKeyCenter(width, height) {
|
|
28324
|
+
const radius = Math.max(8, Math.min(KEY_RADIUS, Math.min(width, height) * .12));
|
|
28325
|
+
const margin = Math.min(KEY_MARGIN, radius * .7);
|
|
28326
|
+
return {
|
|
28327
|
+
x: width - margin - radius,
|
|
28328
|
+
y: height - margin - radius,
|
|
28329
|
+
radius
|
|
28330
|
+
};
|
|
28331
|
+
}
|
|
28332
|
+
function sync$12(container, item, context) {
|
|
28333
|
+
const parts = partsByContainer$12.get(container);
|
|
28334
|
+
if (!parts) return;
|
|
28335
|
+
positionShell(parts.root, item);
|
|
28336
|
+
const { width, height } = item.frame;
|
|
28337
|
+
const { src, snapshot } = item.props;
|
|
28338
|
+
const meta = fileMetaLine(src, snapshot?.size);
|
|
28339
|
+
const title = snapshot?.title || fileStem(src);
|
|
28340
|
+
syncCardTag(parts.tag, {
|
|
28341
|
+
glyph: "model",
|
|
28342
|
+
text: `${title} · ${meta}`,
|
|
28343
|
+
width
|
|
28344
|
+
}, context);
|
|
28345
|
+
const key = context.assetKey(item);
|
|
28346
|
+
const texture = key ? context.getTexture(key) : null;
|
|
28347
|
+
const failed = Boolean(key && !texture && context.hasError(key));
|
|
28348
|
+
const detailed = boardCardDetailed(context.zoom);
|
|
28349
|
+
const elevation = cardElevation(context, item.id);
|
|
28350
|
+
const sig = [
|
|
28351
|
+
key ?? "",
|
|
28352
|
+
texture ? `${texture.width}x${texture.height}` : "none",
|
|
28353
|
+
failed,
|
|
28354
|
+
width,
|
|
28355
|
+
height,
|
|
28356
|
+
elevation,
|
|
28357
|
+
detailed,
|
|
28358
|
+
context.themeKey
|
|
28359
|
+
].join("|");
|
|
28360
|
+
if (sig === parts.sig) return;
|
|
28361
|
+
parts.sig = sig;
|
|
28362
|
+
drawCardSurface(parts.plate.clear(), {
|
|
28363
|
+
x: 0,
|
|
28364
|
+
y: 0,
|
|
28365
|
+
width,
|
|
28366
|
+
height
|
|
28367
|
+
}, context.style, {
|
|
28368
|
+
fill: context.palette.surface,
|
|
28369
|
+
border: context.palette.border,
|
|
28370
|
+
borderAlpha: .85,
|
|
28371
|
+
elevation
|
|
28372
|
+
});
|
|
28373
|
+
if (texture && parts.sprite.texture !== texture) parts.sprite.texture = texture;
|
|
28374
|
+
parts.sprite.visible = Boolean(texture);
|
|
28375
|
+
if (texture) {
|
|
28376
|
+
const inset = Math.min(width, height) * INSET_RATIO;
|
|
28377
|
+
const fitted = containRect(width - inset * 2, height - inset * 2, texture.width, texture.height);
|
|
28378
|
+
parts.sprite.position.set(inset + fitted.x, inset + fitted.y);
|
|
28379
|
+
parts.sprite.width = fitted.width;
|
|
28380
|
+
parts.sprite.height = fitted.height;
|
|
28381
|
+
} else {
|
|
28382
|
+
const radius = Math.max(6, Math.min(28, Math.min(width, height) * .14));
|
|
28383
|
+
traceCube(parts.plate, width / 2, height / 2, radius).stroke({
|
|
28384
|
+
color: context.palette.muted,
|
|
28385
|
+
width: 1.5,
|
|
28386
|
+
alpha: failed ? .35 : .6,
|
|
28387
|
+
join: "round",
|
|
28388
|
+
cap: "round"
|
|
28389
|
+
});
|
|
28390
|
+
}
|
|
28391
|
+
parts.chrome.clear();
|
|
28392
|
+
if (detailed) {
|
|
28393
|
+
const center = modelKeyCenter(width, height);
|
|
28394
|
+
drawModelKey(parts.chrome, center.x, center.y, center.radius, context);
|
|
28395
|
+
}
|
|
28396
|
+
}
|
|
28397
|
+
const modelCardRenderer = {
|
|
28398
|
+
id: "model-card",
|
|
28399
|
+
canRender: (item) => isBoardModelItem(item),
|
|
28400
|
+
create: (item, context) => {
|
|
28401
|
+
const root = new Container();
|
|
28402
|
+
const plate = new Graphics();
|
|
28403
|
+
const sprite = new Sprite(Texture.EMPTY);
|
|
28404
|
+
const chrome = new Graphics();
|
|
28405
|
+
const tag = createCardTag();
|
|
28406
|
+
root.addChild(plate, sprite, chrome, tag.root);
|
|
28407
|
+
partsByContainer$12.set(root, {
|
|
28408
|
+
root,
|
|
28409
|
+
plate,
|
|
28410
|
+
sprite,
|
|
28411
|
+
chrome,
|
|
28412
|
+
tag,
|
|
28413
|
+
sig: ""
|
|
28414
|
+
});
|
|
28415
|
+
if (item.type === "file") sync$12(root, item, context);
|
|
28416
|
+
return root;
|
|
28417
|
+
},
|
|
28418
|
+
update: (container, item, context) => {
|
|
28419
|
+
if (item.type === "file") sync$12(container, item, context);
|
|
28420
|
+
},
|
|
28421
|
+
zoom: (container, zoom) => {
|
|
28422
|
+
const tag = partsByContainer$12.get(container)?.tag;
|
|
28423
|
+
if (tag) zoomCardTag(tag, zoom);
|
|
28424
|
+
},
|
|
28425
|
+
renderFar: (graphics, item, context) => {
|
|
28426
|
+
drawFarPlate(graphics, item.frame, {
|
|
28427
|
+
fill: context.palette.surface,
|
|
28428
|
+
fillAlpha: .96,
|
|
28429
|
+
accent: context.palette.legendary,
|
|
28430
|
+
accentAlpha: .45
|
|
28431
|
+
});
|
|
28432
|
+
},
|
|
28065
28433
|
destroy: (container) => {
|
|
28066
28434
|
partsByContainer$12.get(container)?.root.destroy({ children: true });
|
|
28067
28435
|
partsByContainer$12.delete(container);
|
|
@@ -30212,6 +30580,7 @@ const builtinCardRenderers = [
|
|
|
30212
30580
|
imageCardRenderer,
|
|
30213
30581
|
videoCardRenderer,
|
|
30214
30582
|
audioCardRenderer,
|
|
30583
|
+
modelCardRenderer,
|
|
30215
30584
|
fileCardRenderer,
|
|
30216
30585
|
taskCardRenderer,
|
|
30217
30586
|
shapeCardRenderer,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { openAsBlob } from "node:fs";
|
|
2
2
|
import { mkdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
3
3
|
import { basename, dirname, extname, join } from "node:path";
|
|
4
|
-
import { GenerationPolicyError, assertGenerationRequestAllowedByPolicy, parseGenerationPolicyFromEnv, } from "@neta-art/cohub";
|
|
4
|
+
import { GenerationPolicyError, assertGenerationRequestAllowedByPolicy, mimeTypeForPath, parseGenerationPolicyFromEnv, } from "@neta-art/cohub";
|
|
5
5
|
import { probeMediaInfo } from "@neta-art/cohub/media";
|
|
6
6
|
import { createClient } from "../client.js";
|
|
7
7
|
import { resolveSpace } from "../space.js";
|
|
@@ -14,19 +14,6 @@ const rolesByMediaType = {
|
|
|
14
14
|
audio: new Set(["reference_audio"]),
|
|
15
15
|
};
|
|
16
16
|
const mediaRoles = new Set([...frameMediaRoles, ...referenceMediaRoles]);
|
|
17
|
-
const mimeByExt = {
|
|
18
|
-
".png": "image/png",
|
|
19
|
-
".jpg": "image/jpeg",
|
|
20
|
-
".jpeg": "image/jpeg",
|
|
21
|
-
".webp": "image/webp",
|
|
22
|
-
".gif": "image/gif",
|
|
23
|
-
".mp4": "video/mp4",
|
|
24
|
-
".webm": "video/webm",
|
|
25
|
-
".mov": "video/quicktime",
|
|
26
|
-
".mp3": "audio/mpeg",
|
|
27
|
-
".wav": "audio/wav",
|
|
28
|
-
".ogg": "audio/ogg",
|
|
29
|
-
};
|
|
30
17
|
function parseValue(value) {
|
|
31
18
|
const trimmed = value.trim();
|
|
32
19
|
if (trimmed === "true")
|
|
@@ -84,8 +71,8 @@ async function mediaContent({ type, value, role }, upload) {
|
|
|
84
71
|
const block = (source) => ({ type, source, ...(role ? { meta: { role } } : {}) });
|
|
85
72
|
if (/^https?:\/\//.test(value))
|
|
86
73
|
return block({ type: "url", url: value });
|
|
87
|
-
const mediaType =
|
|
88
|
-
if (mediaType && upload) {
|
|
74
|
+
const mediaType = mimeTypeForPath(value);
|
|
75
|
+
if (mediaType && /^(image|video|audio)\//.test(mediaType) && upload) {
|
|
89
76
|
try {
|
|
90
77
|
return block({ type: "url", url: await upload(value, mediaType) });
|
|
91
78
|
}
|
|
@@ -189,11 +176,13 @@ function slugOutputLabel(block) {
|
|
|
189
176
|
return slugify(metaRole(block) ?? block.type);
|
|
190
177
|
}
|
|
191
178
|
const PROBE_TIMEOUT_MS = 3_000;
|
|
192
|
-
/** Size, duration, and frames of URL outputs, probed in parallel; best effort. */
|
|
179
|
+
/** Size, duration, and frames of image, video, and audio URL outputs, probed in parallel; best effort. */
|
|
193
180
|
async function probeOutputs(output) {
|
|
194
181
|
const signal = AbortSignal.timeout(PROBE_TIMEOUT_MS);
|
|
195
182
|
const probed = await Promise.all(output.map(async (block, index) => {
|
|
196
|
-
if (block.type
|
|
183
|
+
if (block.type !== "image" && block.type !== "video" && block.type !== "audio")
|
|
184
|
+
return null;
|
|
185
|
+
if (block.source.type !== "url")
|
|
197
186
|
return null;
|
|
198
187
|
const info = await probeMediaInfo(block.source.url, { type: block.type, signal });
|
|
199
188
|
return Object.keys(info).length > 0 ? { index, ...info } : null;
|
package/dist/commands/public.js
CHANGED
|
@@ -1,45 +1,12 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import { lstat, readdir } from "node:fs/promises";
|
|
3
|
-
import { basename,
|
|
3
|
+
import { basename, relative, resolve } from "node:path";
|
|
4
|
+
import { isTextMime, mimeTypeForPath, } from "@neta-art/cohub";
|
|
4
5
|
import { createClient } from "../client.js";
|
|
5
6
|
import { HttpPutError, putLocalFile } from "../http-put.js";
|
|
6
7
|
import { error, handleHttp, json as outJson, jsonRequested } from "../output.js";
|
|
7
8
|
import { resolveSpace } from "../space.js";
|
|
8
9
|
const UPLOAD_CONCURRENCY = 4;
|
|
9
|
-
const MIME_TYPES = {
|
|
10
|
-
".aac": "audio/aac",
|
|
11
|
-
".avi": "video/x-msvideo",
|
|
12
|
-
".avif": "image/avif",
|
|
13
|
-
".css": "text/css; charset=utf-8",
|
|
14
|
-
".csv": "text/csv; charset=utf-8",
|
|
15
|
-
".gif": "image/gif",
|
|
16
|
-
".htm": "text/html; charset=utf-8",
|
|
17
|
-
".html": "text/html; charset=utf-8",
|
|
18
|
-
".ico": "image/x-icon",
|
|
19
|
-
".jpeg": "image/jpeg",
|
|
20
|
-
".jpg": "image/jpeg",
|
|
21
|
-
".js": "text/javascript; charset=utf-8",
|
|
22
|
-
".json": "application/json; charset=utf-8",
|
|
23
|
-
".m4a": "audio/mp4",
|
|
24
|
-
".md": "text/markdown; charset=utf-8",
|
|
25
|
-
".mov": "video/quicktime",
|
|
26
|
-
".mp3": "audio/mpeg",
|
|
27
|
-
".mp4": "video/mp4",
|
|
28
|
-
".ogg": "audio/ogg",
|
|
29
|
-
".ogv": "video/ogg",
|
|
30
|
-
".pdf": "application/pdf",
|
|
31
|
-
".png": "image/png",
|
|
32
|
-
".svg": "image/svg+xml",
|
|
33
|
-
".txt": "text/plain; charset=utf-8",
|
|
34
|
-
".wasm": "application/wasm",
|
|
35
|
-
".wav": "audio/wav",
|
|
36
|
-
".webm": "video/webm",
|
|
37
|
-
".webp": "image/webp",
|
|
38
|
-
".woff": "font/woff",
|
|
39
|
-
".woff2": "font/woff2",
|
|
40
|
-
".xml": "application/xml; charset=utf-8",
|
|
41
|
-
".zip": "application/zip",
|
|
42
|
-
};
|
|
43
10
|
function hasControlCharacters(value) {
|
|
44
11
|
return [...value].some((char) => {
|
|
45
12
|
const code = char.charCodeAt(0);
|
|
@@ -65,8 +32,11 @@ function normalizePublicPath(input) {
|
|
|
65
32
|
}
|
|
66
33
|
return parts.join("/");
|
|
67
34
|
}
|
|
68
|
-
function
|
|
69
|
-
|
|
35
|
+
function contentTypeForPath(path) {
|
|
36
|
+
const mimeType = mimeTypeForPath(path);
|
|
37
|
+
if (!mimeType)
|
|
38
|
+
return "application/octet-stream";
|
|
39
|
+
return isTextMime(mimeType) ? `${mimeType}; charset=utf-8` : mimeType;
|
|
70
40
|
}
|
|
71
41
|
async function walkDirectory(root, directory, destination) {
|
|
72
42
|
const names = await readdir(directory);
|
|
@@ -90,7 +60,7 @@ async function walkDirectory(root, directory, destination) {
|
|
|
90
60
|
localPath,
|
|
91
61
|
publicPath,
|
|
92
62
|
size: info.size,
|
|
93
|
-
mimeType:
|
|
63
|
+
mimeType: contentTypeForPath(localPath),
|
|
94
64
|
});
|
|
95
65
|
}
|
|
96
66
|
return files;
|
|
@@ -114,7 +84,7 @@ export async function collectPublicUpload(source, destination) {
|
|
|
114
84
|
localPath,
|
|
115
85
|
publicPath,
|
|
116
86
|
size: info.size,
|
|
117
|
-
mimeType:
|
|
87
|
+
mimeType: contentTypeForPath(localPath),
|
|
118
88
|
}],
|
|
119
89
|
};
|
|
120
90
|
}
|
|
@@ -7,7 +7,7 @@ import { Readable, Transform } from "node:stream";
|
|
|
7
7
|
import { pipeline } from "node:stream/promises";
|
|
8
8
|
import { createGunzip } from "node:zlib";
|
|
9
9
|
// Pin a global release tag after its helper artifacts are published.
|
|
10
|
-
export const RTC_HELPER_VERSION = "v2.
|
|
10
|
+
export const RTC_HELPER_VERSION = "v2.68.0";
|
|
11
11
|
const MAX_BINARY_BYTES = 128 * 1024 * 1024;
|
|
12
12
|
async function digest(path) {
|
|
13
13
|
const hash = createHash("sha256");
|
|
@@ -1,30 +1,13 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
|
-
import {
|
|
2
|
+
import { batchUploadEntries } from "@neta-art/cohub";
|
|
3
3
|
import { putLocalFile } from "../http-put.js";
|
|
4
4
|
import { createLimiter } from "./limit.js";
|
|
5
5
|
const PUT_CONCURRENCY = 4;
|
|
6
|
-
function batches(entries) {
|
|
7
|
-
const result = [];
|
|
8
|
-
let batch = [];
|
|
9
|
-
let bytes = 0;
|
|
10
|
-
for (const entry of entries) {
|
|
11
|
-
if (batch.length > 0 && (batch.length >= UPLOAD_MAX_BATCH_FILES || bytes + entry.size > UPLOAD_MAX_BATCH_BYTES)) {
|
|
12
|
-
result.push(batch);
|
|
13
|
-
batch = [];
|
|
14
|
-
bytes = 0;
|
|
15
|
-
}
|
|
16
|
-
batch.push(entry);
|
|
17
|
-
bytes += entry.size;
|
|
18
|
-
}
|
|
19
|
-
if (batch.length > 0)
|
|
20
|
-
result.push(batch);
|
|
21
|
-
return result;
|
|
22
|
-
}
|
|
23
6
|
export async function uploadLocalFiles(files, entries, options = {}) {
|
|
24
7
|
const uploaded = [];
|
|
25
8
|
const uploadIds = [];
|
|
26
9
|
const limit = createLimiter(PUT_CONCURRENCY);
|
|
27
|
-
for (const batch of
|
|
10
|
+
for (const batch of batchUploadEntries(entries, (entry) => entry.size)) {
|
|
28
11
|
const byId = new Map(batch.map((entry) => [randomUUID(), entry]));
|
|
29
12
|
const plan = await files.createUpload({
|
|
30
13
|
destination: { kind: "workspace", targetDir: options.targetDir },
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neta-art/cohub-cli",
|
|
3
|
-
"version": "10.4.
|
|
3
|
+
"version": "10.4.3",
|
|
4
4
|
"description": "CLI for Cohub — spaces, sessions, and agent collaboration.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
"NOTICE"
|
|
19
19
|
],
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@neta-art/cohub": "11.3.
|
|
22
|
-
"@neta-art/generation": "^0.1.
|
|
21
|
+
"@neta-art/cohub": "11.3.3",
|
|
22
|
+
"@neta-art/generation": "^0.1.39",
|
|
23
23
|
"commander": "^15.0.0",
|
|
24
24
|
"sharp": "^0.35.4",
|
|
25
25
|
"ws": "^8.21.3"
|