@neta-art/cohub-cli 10.10.0 → 10.11.1
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.
|
@@ -3,5 +3,4 @@ export declare const BOARD_CREATE_INPUT_MAX_BYTES: number;
|
|
|
3
3
|
export declare const BOARD_DOMAIN_INPUT_MAX_BYTES: number;
|
|
4
4
|
export declare function parseBoardJsonObject(text: string, source?: string): Record<string, unknown>;
|
|
5
5
|
export declare function readBoardJsonObject(source: string, maxBytes?: number): Promise<Record<string, unknown>>;
|
|
6
|
-
export declare function resolveBoardId(spaceId: string, target: string): Promise<string>;
|
|
7
6
|
export declare function writeBoardOutput(path: string, bytes: Uint8Array, force?: boolean): Promise<void>;
|
|
@@ -2,8 +2,6 @@ import { randomUUID } from "node:crypto";
|
|
|
2
2
|
import { constants } from "node:fs";
|
|
3
3
|
import { access, link, open, rename, unlink } from "node:fs/promises";
|
|
4
4
|
import { basename, dirname, join } from "node:path";
|
|
5
|
-
import { isBoardPath, parseBoardManifest, } from "@neta-art/cohub/board";
|
|
6
|
-
import { createClient } from "./client.js";
|
|
7
5
|
export const BOARD_TRANSACTION_INPUT_MAX_BYTES = 16 * 1024 * 1024;
|
|
8
6
|
export const BOARD_CREATE_INPUT_MAX_BYTES = 32 * 1024 * 1024;
|
|
9
7
|
export const BOARD_DOMAIN_INPUT_MAX_BYTES = 1024 * 1024;
|
|
@@ -62,15 +60,6 @@ export async function readBoardJsonObject(source, maxBytes = BOARD_DOMAIN_INPUT_
|
|
|
62
60
|
await handle.close();
|
|
63
61
|
}
|
|
64
62
|
}
|
|
65
|
-
export async function resolveBoardId(spaceId, target) {
|
|
66
|
-
if (!isBoardPath(target))
|
|
67
|
-
return target;
|
|
68
|
-
const file = await createClient().space(spaceId).files.read(target);
|
|
69
|
-
if (!("content" in file) || typeof file.content !== "string") {
|
|
70
|
-
throw new Error(`${target} is not a readable Board manifest`);
|
|
71
|
-
}
|
|
72
|
-
return parseBoardManifest(file.content).boardId;
|
|
73
|
-
}
|
|
74
63
|
export async function writeBoardOutput(path, bytes, force = false) {
|
|
75
64
|
if (!force) {
|
|
76
65
|
await access(path).then(() => { throw new Error(`Output already exists: ${path}; use --force to replace it`); }, () => undefined);
|
package/dist/board-export.js
CHANGED
|
@@ -12,7 +12,6 @@ const execFile = promisify(execFileCallback);
|
|
|
12
12
|
import { parseBoardMediaSource } from "@neta-art/cohub/board";
|
|
13
13
|
import { imageVariantUrl, MEDIA_VARIANT_MAX, mediaVariantSize, videoFrameUrl } from "@neta-art/cohub/media";
|
|
14
14
|
import { hasBoardScripts, boardAssetKey, boardAssetKeySource, boardDocumentAt, boardRenderTheme, boardTextureEdge, boardTexturePixels, createBoardRenderSampler, buildBoardScene, createNodeBoardRenderer, createNodeBoardScriptHost, exportBoardImageBytes, parseBoardDocument, planBoardExport, prepareBoardExport, selectBoardExportAssets, } from "./board-kernel.js";
|
|
15
|
-
import { resolveBoardId } from "./board-command-support.js";
|
|
16
15
|
import { settleBoardDocument } from "./board-media.js";
|
|
17
16
|
import { BOARD_EXPORT_FONTS } from "./board-fonts.js";
|
|
18
17
|
import { createClient } from "./client.js";
|
|
@@ -40,7 +39,7 @@ export function resolveBundledFonts() {
|
|
|
40
39
|
});
|
|
41
40
|
}
|
|
42
41
|
export async function loadBoardDocument(spaceId, target) {
|
|
43
|
-
const board = createClient().space(spaceId).
|
|
42
|
+
const board = await createClient().space(spaceId).boards.open(target);
|
|
44
43
|
let result = await board.get();
|
|
45
44
|
const snapshot = result;
|
|
46
45
|
const items = { ...result.items };
|
package/dist/board-kernel.js
CHANGED
|
@@ -6127,10 +6127,17 @@ const BoardCustomItemSchema$1 = object({
|
|
|
6127
6127
|
props: object({}).strict().default({})
|
|
6128
6128
|
}).strict();
|
|
6129
6129
|
const BOARD_EXTENSION_TYPE_PATTERN$1 = /^[a-z][a-z0-9]*(?:\.[a-z0-9-]+)+$/;
|
|
6130
|
+
const BoardItemPreviewSchema$1 = object({
|
|
6131
|
+
title: string().max(500).optional(),
|
|
6132
|
+
excerpt: string().max(2e3).optional(),
|
|
6133
|
+
cover: BoardMediaSourceSchema$1.optional().describe("An image for the card."),
|
|
6134
|
+
src: BoardMediaSourceSchema$1.optional().describe("The file or page the card stands for.")
|
|
6135
|
+
}).strict().describe("How a client without this type's renderer shows the card, and what it refers to. The type's own client keeps it current.");
|
|
6130
6136
|
const BoardExtensionItemSchema$1 = object({
|
|
6131
6137
|
...boxed$1(BOARD_DEFAULT_ITEM_SIZE$1),
|
|
6132
6138
|
type: string().regex(BOARD_EXTENSION_TYPE_PATTERN$1),
|
|
6133
|
-
props: record(string(), unknown()).default({})
|
|
6139
|
+
props: record(string(), unknown()).default({}),
|
|
6140
|
+
preview: BoardItemPreviewSchema$1.optional()
|
|
6134
6141
|
}).strict();
|
|
6135
6142
|
const BOARD_ITEM_SCHEMAS$1 = {
|
|
6136
6143
|
frame: BoardFrameItemSchema$1,
|
|
@@ -6150,6 +6157,12 @@ const BOARD_ITEM_TYPES$1 = Object.keys(BOARD_ITEM_SCHEMAS$1);
|
|
|
6150
6157
|
function isBuiltinItemType(type) {
|
|
6151
6158
|
return Object.hasOwn(BOARD_ITEM_SCHEMAS$1, type);
|
|
6152
6159
|
}
|
|
6160
|
+
function isBuiltinItem(item) {
|
|
6161
|
+
return isBuiltinItemType(item.type);
|
|
6162
|
+
}
|
|
6163
|
+
function boardItemPreview(item) {
|
|
6164
|
+
return isBuiltinItem(item) ? null : item.preview ?? null;
|
|
6165
|
+
}
|
|
6153
6166
|
function boardItemSchema(type) {
|
|
6154
6167
|
if (isBuiltinItemType(type)) return BOARD_ITEM_SCHEMAS$1[type];
|
|
6155
6168
|
return BOARD_EXTENSION_TYPE_PATTERN$1.test(type) ? BoardExtensionItemSchema$1 : null;
|
|
@@ -7687,6 +7700,16 @@ function unionRects(rects) {
|
|
|
7687
7700
|
height: maxY - minY
|
|
7688
7701
|
};
|
|
7689
7702
|
}
|
|
7703
|
+
function rotatePointAround(point, center, angleRad) {
|
|
7704
|
+
const cos = Math.cos(angleRad);
|
|
7705
|
+
const sin = Math.sin(angleRad);
|
|
7706
|
+
const dx = point.x - center.x;
|
|
7707
|
+
const dy = point.y - center.y;
|
|
7708
|
+
return {
|
|
7709
|
+
x: center.x + dx * cos - dy * sin,
|
|
7710
|
+
y: center.y + dx * sin + dy * cos
|
|
7711
|
+
};
|
|
7712
|
+
}
|
|
7690
7713
|
function itemBounds(frame) {
|
|
7691
7714
|
const rotation = frame.rotation || 0;
|
|
7692
7715
|
if (rotation === 0) return frameRect(frame);
|
|
@@ -9287,8 +9310,12 @@ const MEDIA_HOSTS = /* @__PURE__ */ new Map([
|
|
|
9287
9310
|
transform: "oss",
|
|
9288
9311
|
metaHeaders: true
|
|
9289
9312
|
}],
|
|
9313
|
+
["oss.talesofai.com", { transform: "oss" }],
|
|
9290
9314
|
["public.cohub.live", { transform: "oss" }],
|
|
9315
|
+
["public.cohub.run", { transform: "oss" }],
|
|
9291
9316
|
["sessions.cohub.live", { transform: "oss" }],
|
|
9317
|
+
["works.cohub.live", { transform: "oss" }],
|
|
9318
|
+
["works.cohub.run", { transform: "oss" }],
|
|
9292
9319
|
["cca.neta.art", { transform: "cloudflare" }]
|
|
9293
9320
|
]);
|
|
9294
9321
|
const parseHttpsUrl = (url) => {
|
|
@@ -9374,6 +9401,7 @@ function isBoardModelItem(item) {
|
|
|
9374
9401
|
}
|
|
9375
9402
|
//#endregion
|
|
9376
9403
|
//#region ../sdk/src/board/model/asset-key.ts
|
|
9404
|
+
const COVER = "cover:";
|
|
9377
9405
|
function imageAssetKey(item) {
|
|
9378
9406
|
if (item.type === "image") {
|
|
9379
9407
|
const source = parseBoardMediaSource$1(item.props.src);
|
|
@@ -9389,11 +9417,12 @@ function imageAssetKey(item) {
|
|
|
9389
9417
|
const url = taskArtifactPreviewUrl(featuredTaskArtifact(item.props.snapshot.artifacts));
|
|
9390
9418
|
return url ? `url:${url}` : null;
|
|
9391
9419
|
}
|
|
9392
|
-
|
|
9420
|
+
const cover = boardItemPreview(item)?.cover;
|
|
9421
|
+
const source = cover ? parseBoardMediaSource$1(cover) : null;
|
|
9422
|
+
return source ? `${source.kind}:${source.value}` : null;
|
|
9393
9423
|
}
|
|
9394
9424
|
const STILL_MEDIA = ["video", "model"];
|
|
9395
|
-
function stillKey(media,
|
|
9396
|
-
const source = parseBoardMediaSource$1(src);
|
|
9425
|
+
function stillKey(media, source, mtimeMs) {
|
|
9397
9426
|
if (!source) return null;
|
|
9398
9427
|
return source.kind === "url" ? `${media}-url:${encodeURIComponent(source.value)}` : `${media}:${encodeURIComponent(source.value)}:${mtimeMs ?? "unknown"}`;
|
|
9399
9428
|
}
|
|
@@ -9407,8 +9436,8 @@ function taskPreviewKey(item) {
|
|
|
9407
9436
|
}
|
|
9408
9437
|
function boardAssetKey(item) {
|
|
9409
9438
|
if (item.type === "task") return taskPreviewKey(item);
|
|
9410
|
-
if (item.type === "video") return stillKey("video", item.props.src, item.props.snapshot?.mtimeMs);
|
|
9411
|
-
if (item.type === "file" && isBoardModelItem(item)) return stillKey("model", item.props.src, item.props.snapshot?.mtimeMs);
|
|
9439
|
+
if (item.type === "video") return stillKey("video", parseBoardMediaSource$1(item.props.src), item.props.snapshot?.mtimeMs);
|
|
9440
|
+
if (item.type === "file" && isBoardModelItem(item)) return stillKey("model", parseBoardMediaSource$1(item.props.src), item.props.snapshot?.mtimeMs);
|
|
9412
9441
|
return imageAssetKey(item);
|
|
9413
9442
|
}
|
|
9414
9443
|
function boardAssetKeySource(key) {
|
|
@@ -9418,6 +9447,14 @@ function boardAssetKeySource(key) {
|
|
|
9418
9447
|
if (separator < 0) return null;
|
|
9419
9448
|
base = key.slice(separator + 1);
|
|
9420
9449
|
}
|
|
9450
|
+
if (!base.startsWith(COVER)) return sourceOf(base);
|
|
9451
|
+
const source = sourceOf(base.slice(6));
|
|
9452
|
+
return source?.media === "image" ? {
|
|
9453
|
+
...source,
|
|
9454
|
+
fit: "cover"
|
|
9455
|
+
} : null;
|
|
9456
|
+
}
|
|
9457
|
+
function sourceOf(base) {
|
|
9421
9458
|
try {
|
|
9422
9459
|
for (const media of STILL_MEDIA) {
|
|
9423
9460
|
if (base.startsWith(`${media}-url:`)) return {
|
|
@@ -10071,12 +10108,12 @@ const BOARD_THEME_DATA = {
|
|
|
10071
10108
|
colorScheme: "dark",
|
|
10072
10109
|
palette: {
|
|
10073
10110
|
bg: 329221,
|
|
10074
|
-
surface:
|
|
10075
|
-
hover:
|
|
10111
|
+
surface: 1249814,
|
|
10112
|
+
hover: 1973788,
|
|
10076
10113
|
border: 1842202,
|
|
10077
|
-
brand:
|
|
10078
|
-
text:
|
|
10079
|
-
muted:
|
|
10114
|
+
brand: 3900150,
|
|
10115
|
+
text: 16314853,
|
|
10116
|
+
muted: 7630695,
|
|
10080
10117
|
rare: 9235170,
|
|
10081
10118
|
epic: 7266776,
|
|
10082
10119
|
legendary: 15449187
|
|
@@ -10085,58 +10122,61 @@ const BOARD_THEME_DATA = {
|
|
|
10085
10122
|
brand: {
|
|
10086
10123
|
stroke: 15524306,
|
|
10087
10124
|
fill: 15524306,
|
|
10088
|
-
label:
|
|
10125
|
+
label: 16314853
|
|
10089
10126
|
},
|
|
10090
10127
|
neutral: {
|
|
10091
|
-
stroke:
|
|
10092
|
-
fill:
|
|
10093
|
-
label:
|
|
10128
|
+
stroke: 15524306,
|
|
10129
|
+
fill: 15524306,
|
|
10130
|
+
label: 16314853
|
|
10094
10131
|
},
|
|
10095
10132
|
black: {
|
|
10096
10133
|
stroke: 0,
|
|
10097
10134
|
fill: 0,
|
|
10098
|
-
label:
|
|
10135
|
+
label: 16314853
|
|
10099
10136
|
},
|
|
10100
10137
|
white: {
|
|
10101
10138
|
stroke: 16777215,
|
|
10102
10139
|
fill: 16777215,
|
|
10103
|
-
label:
|
|
10140
|
+
label: 16314853
|
|
10104
10141
|
},
|
|
10105
10142
|
blue: {
|
|
10106
10143
|
stroke: 9235170,
|
|
10107
10144
|
fill: 9235170,
|
|
10108
|
-
label:
|
|
10145
|
+
label: 16314853
|
|
10109
10146
|
},
|
|
10110
10147
|
green: {
|
|
10111
10148
|
stroke: 8177036,
|
|
10112
10149
|
fill: 8177036,
|
|
10113
|
-
label:
|
|
10150
|
+
label: 16314853
|
|
10114
10151
|
},
|
|
10115
10152
|
amber: {
|
|
10116
10153
|
stroke: 15449187,
|
|
10117
10154
|
fill: 15449187,
|
|
10118
|
-
label:
|
|
10155
|
+
label: 16314853
|
|
10119
10156
|
},
|
|
10120
10157
|
violet: {
|
|
10121
10158
|
stroke: 11971327,
|
|
10122
10159
|
fill: 11971327,
|
|
10123
|
-
label:
|
|
10160
|
+
label: 16314853
|
|
10124
10161
|
},
|
|
10125
10162
|
rose: {
|
|
10126
10163
|
stroke: 15562341,
|
|
10127
10164
|
fill: 15562341,
|
|
10128
|
-
label:
|
|
10165
|
+
label: 16314853
|
|
10129
10166
|
}
|
|
10130
10167
|
},
|
|
10131
|
-
style: {
|
|
10168
|
+
style: {
|
|
10169
|
+
selection: { outset: 0 },
|
|
10170
|
+
frameLabelSize: 16
|
|
10171
|
+
}
|
|
10132
10172
|
},
|
|
10133
10173
|
"neta-pixel": {
|
|
10134
10174
|
colorScheme: "light",
|
|
10135
10175
|
palette: {
|
|
10136
10176
|
bg: 16185078,
|
|
10137
10177
|
surface: 16777215,
|
|
10138
|
-
hover:
|
|
10139
|
-
border:
|
|
10178
|
+
hover: 16185078,
|
|
10179
|
+
border: 15527149,
|
|
10140
10180
|
brand: 1824230,
|
|
10141
10181
|
text: 1447704,
|
|
10142
10182
|
muted: 7566452,
|
|
@@ -10200,9 +10240,9 @@ const BOARD_THEME_DATA = {
|
|
|
10200
10240
|
y: 0
|
|
10201
10241
|
},
|
|
10202
10242
|
selection: {
|
|
10203
|
-
width:
|
|
10204
|
-
outset:
|
|
10205
|
-
dash:
|
|
10243
|
+
width: 1.5,
|
|
10244
|
+
outset: 0,
|
|
10245
|
+
dash: 0,
|
|
10206
10246
|
handle: "square",
|
|
10207
10247
|
handleSize: 8
|
|
10208
10248
|
},
|
|
@@ -10210,19 +10250,20 @@ const BOARD_THEME_DATA = {
|
|
|
10210
10250
|
progress: "mosaic",
|
|
10211
10251
|
icons: "pixel",
|
|
10212
10252
|
motion: "stepped",
|
|
10213
|
-
font: "\"Figtree Variable\", \"PingFang SC\", \"Noto Sans CJK SC\", \"Microsoft YaHei\", system-ui, sans-serif"
|
|
10253
|
+
font: "\"Figtree Variable\", \"PingFang SC\", \"Noto Sans CJK SC\", \"Microsoft YaHei\", system-ui, sans-serif",
|
|
10254
|
+
frameLabelSize: 16
|
|
10214
10255
|
}
|
|
10215
10256
|
},
|
|
10216
10257
|
"neta-pixel-dark": {
|
|
10217
10258
|
colorScheme: "dark",
|
|
10218
10259
|
palette: {
|
|
10219
|
-
bg:
|
|
10220
|
-
surface:
|
|
10221
|
-
hover:
|
|
10222
|
-
border:
|
|
10260
|
+
bg: 1118739,
|
|
10261
|
+
surface: 1842463,
|
|
10262
|
+
hover: 2237220,
|
|
10263
|
+
border: 2763565,
|
|
10223
10264
|
brand: 1824230,
|
|
10224
|
-
text:
|
|
10225
|
-
muted:
|
|
10265
|
+
text: 16185078,
|
|
10266
|
+
muted: 9079436,
|
|
10226
10267
|
rare: 1824230,
|
|
10227
10268
|
epic: 1824230,
|
|
10228
10269
|
legendary: 16766287
|
|
@@ -10231,47 +10272,47 @@ const BOARD_THEME_DATA = {
|
|
|
10231
10272
|
brand: {
|
|
10232
10273
|
stroke: 16185078,
|
|
10233
10274
|
fill: 16185078,
|
|
10234
|
-
label:
|
|
10275
|
+
label: 16185078
|
|
10235
10276
|
},
|
|
10236
10277
|
neutral: {
|
|
10237
|
-
stroke:
|
|
10238
|
-
fill:
|
|
10239
|
-
label:
|
|
10278
|
+
stroke: 9079436,
|
|
10279
|
+
fill: 9079436,
|
|
10280
|
+
label: 16185078
|
|
10240
10281
|
},
|
|
10241
10282
|
black: {
|
|
10242
10283
|
stroke: 0,
|
|
10243
10284
|
fill: 0,
|
|
10244
|
-
label:
|
|
10285
|
+
label: 16185078
|
|
10245
10286
|
},
|
|
10246
10287
|
white: {
|
|
10247
10288
|
stroke: 16777215,
|
|
10248
10289
|
fill: 16777215,
|
|
10249
|
-
label:
|
|
10290
|
+
label: 16185078
|
|
10250
10291
|
},
|
|
10251
10292
|
blue: {
|
|
10252
10293
|
stroke: 6010853,
|
|
10253
10294
|
fill: 6010853,
|
|
10254
|
-
label:
|
|
10295
|
+
label: 16185078
|
|
10255
10296
|
},
|
|
10256
10297
|
green: {
|
|
10257
10298
|
stroke: 9683613,
|
|
10258
10299
|
fill: 9683613,
|
|
10259
|
-
label:
|
|
10300
|
+
label: 16185078
|
|
10260
10301
|
},
|
|
10261
10302
|
amber: {
|
|
10262
10303
|
stroke: 14264410,
|
|
10263
10304
|
fill: 14264410,
|
|
10264
|
-
label:
|
|
10305
|
+
label: 16185078
|
|
10265
10306
|
},
|
|
10266
10307
|
violet: {
|
|
10267
10308
|
stroke: 11441117,
|
|
10268
10309
|
fill: 11441117,
|
|
10269
|
-
label:
|
|
10310
|
+
label: 16185078
|
|
10270
10311
|
},
|
|
10271
10312
|
rose: {
|
|
10272
10313
|
stroke: 15043210,
|
|
10273
10314
|
fill: 15043210,
|
|
10274
|
-
label:
|
|
10315
|
+
label: 16185078
|
|
10275
10316
|
}
|
|
10276
10317
|
},
|
|
10277
10318
|
style: {
|
|
@@ -10283,9 +10324,9 @@ const BOARD_THEME_DATA = {
|
|
|
10283
10324
|
y: 0
|
|
10284
10325
|
},
|
|
10285
10326
|
selection: {
|
|
10286
|
-
width:
|
|
10287
|
-
outset:
|
|
10288
|
-
dash:
|
|
10327
|
+
width: 1.5,
|
|
10328
|
+
outset: 0,
|
|
10329
|
+
dash: 0,
|
|
10289
10330
|
handle: "square",
|
|
10290
10331
|
handleSize: 8
|
|
10291
10332
|
},
|
|
@@ -10293,7 +10334,8 @@ const BOARD_THEME_DATA = {
|
|
|
10293
10334
|
progress: "mosaic",
|
|
10294
10335
|
icons: "pixel",
|
|
10295
10336
|
motion: "stepped",
|
|
10296
|
-
font: "\"Figtree Variable\", \"PingFang SC\", \"Noto Sans CJK SC\", \"Microsoft YaHei\", system-ui, sans-serif"
|
|
10337
|
+
font: "\"Figtree Variable\", \"PingFang SC\", \"Noto Sans CJK SC\", \"Microsoft YaHei\", system-ui, sans-serif",
|
|
10338
|
+
frameLabelSize: 16
|
|
10297
10339
|
}
|
|
10298
10340
|
}
|
|
10299
10341
|
};
|
|
@@ -10358,6 +10400,13 @@ function layoutShapeLabel(props, width) {
|
|
|
10358
10400
|
width: Math.max(1, width - 16)
|
|
10359
10401
|
});
|
|
10360
10402
|
}
|
|
10403
|
+
const BOARD_FRAME_LABEL_LINE_HEIGHT = 1.25;
|
|
10404
|
+
function frameLabelOffset(size) {
|
|
10405
|
+
return {
|
|
10406
|
+
x: 4,
|
|
10407
|
+
y: -(size + 6)
|
|
10408
|
+
};
|
|
10409
|
+
}
|
|
10361
10410
|
//#endregion
|
|
10362
10411
|
//#region ../../node_modules/.pnpm/pixi.js@8.20.1/node_modules/pixi.js/lib/environment-browser/browserExt.mjs
|
|
10363
10412
|
const browserExt = {
|
|
@@ -32769,8 +32818,8 @@ const measuredFonts = /* @__PURE__ */ new Set();
|
|
|
32769
32818
|
const measuredFamilies = /* @__PURE__ */ new Set();
|
|
32770
32819
|
const TRAILING_SPACE = /[ \t]+$/u;
|
|
32771
32820
|
const unquote = (name) => name.trim().replace(/^["']|["']$/gu, "");
|
|
32772
|
-
function prepareText(text, font) {
|
|
32773
|
-
const key = `${font}\n${text}`;
|
|
32821
|
+
function prepareText(text, font, whiteSpace) {
|
|
32822
|
+
const key = `${whiteSpace}\n${font}\n${text}`;
|
|
32774
32823
|
let value = prepared.get(key);
|
|
32775
32824
|
if (value) {
|
|
32776
32825
|
prepared.delete(key);
|
|
@@ -32781,30 +32830,75 @@ function prepareText(text, font) {
|
|
|
32781
32830
|
measuredFonts.add(font);
|
|
32782
32831
|
for (const name of /px\s+(.+)$/u.exec(font)?.[1]?.split(",") ?? []) measuredFamilies.add(unquote(name));
|
|
32783
32832
|
}
|
|
32784
|
-
value = prepareWithSegments(text, font, { whiteSpace
|
|
32833
|
+
value = prepareWithSegments(text, font, { whiteSpace });
|
|
32785
32834
|
if (prepared.size >= PREPARED_LIMIT) prepared.delete(prepared.keys().next().value);
|
|
32786
32835
|
prepared.set(key, value);
|
|
32787
32836
|
return value;
|
|
32788
32837
|
}
|
|
32789
|
-
|
|
32838
|
+
let measureContext;
|
|
32839
|
+
function measureTextWidth(text, font) {
|
|
32840
|
+
measureContext ??= DOMAdapter.get().createCanvas(1, 1).getContext("2d");
|
|
32841
|
+
if (!measureContext) return 0;
|
|
32842
|
+
measureContext.font = font;
|
|
32843
|
+
return measureContext.measureText(text).width;
|
|
32844
|
+
}
|
|
32845
|
+
function layoutTextLines(text, font, maxWidth = Number.POSITIVE_INFINITY, { whiteSpace = "pre-wrap", maxLines = Number.POSITIVE_INFINITY } = {}) {
|
|
32790
32846
|
const lines = [];
|
|
32791
|
-
|
|
32792
|
-
|
|
32847
|
+
const widths = [];
|
|
32848
|
+
if (maxLines <= 0) return {
|
|
32849
|
+
lines,
|
|
32850
|
+
width: 0,
|
|
32851
|
+
truncated: text.length > 0
|
|
32852
|
+
};
|
|
32853
|
+
let source = whiteSpace === "normal" ? text.replace(/\s+/gu, " ").trim() : text.replace(/\r\n?/gu, "\n").replaceAll(" ", " ");
|
|
32854
|
+
const cap = Number.isFinite(maxLines) && Number.isFinite(maxWidth) ? maxLines * (Math.ceil(maxWidth) + 1) : Number.POSITIVE_INFINITY;
|
|
32855
|
+
let truncated = source.length > cap;
|
|
32856
|
+
if (truncated) source = source.slice(0, cap);
|
|
32857
|
+
const paragraphs = whiteSpace === "normal" ? source ? [source] : [] : source.split("\n");
|
|
32858
|
+
for (const paragraph of paragraphs) {
|
|
32859
|
+
if (lines.length > maxLines) break;
|
|
32793
32860
|
if (!paragraph) {
|
|
32794
32861
|
lines.push("");
|
|
32862
|
+
widths.push(0);
|
|
32795
32863
|
continue;
|
|
32796
32864
|
}
|
|
32797
|
-
const wrapped = layoutWithLines(prepareText(paragraph, font), maxWidth, 1).lines;
|
|
32865
|
+
const wrapped = layoutWithLines(prepareText(paragraph, font, whiteSpace), maxWidth, 1).lines;
|
|
32798
32866
|
for (const [index, line] of wrapped.entries()) {
|
|
32799
32867
|
lines.push(index === wrapped.length - 1 ? line.text : line.text.replace(TRAILING_SPACE, ""));
|
|
32800
|
-
|
|
32868
|
+
widths.push(line.width);
|
|
32801
32869
|
}
|
|
32802
32870
|
}
|
|
32871
|
+
if (lines.length > maxLines) {
|
|
32872
|
+
truncated = true;
|
|
32873
|
+
lines.length = maxLines;
|
|
32874
|
+
widths.length = maxLines;
|
|
32875
|
+
}
|
|
32876
|
+
if (truncated && lines.length > 0) {
|
|
32877
|
+
const last = lines.length - 1;
|
|
32878
|
+
lines[last] = fitLineWithEllipsis(lines[last], maxWidth, (value) => measureTextWidth(value, font));
|
|
32879
|
+
widths[last] = measureTextWidth(lines[last], font);
|
|
32880
|
+
}
|
|
32803
32881
|
return {
|
|
32804
32882
|
lines,
|
|
32805
|
-
width
|
|
32883
|
+
width: widths.reduce((max, width) => Math.max(max, width), 0),
|
|
32884
|
+
truncated
|
|
32806
32885
|
};
|
|
32807
32886
|
}
|
|
32887
|
+
const graphemes = typeof Intl.Segmenter === "function" ? new Intl.Segmenter(void 0, { granularity: "grapheme" }) : null;
|
|
32888
|
+
function fitLineWithEllipsis(line, width, measureWidth) {
|
|
32889
|
+
const trimmed = line.replace(/\s+$/u, "");
|
|
32890
|
+
if (!trimmed) return "…";
|
|
32891
|
+
if (measureWidth(`${trimmed}…`) <= width) return `${trimmed}…`;
|
|
32892
|
+
const parts = graphemes ? Array.from(graphemes.segment(trimmed), ({ segment }) => segment) : Array.from(trimmed);
|
|
32893
|
+
let lo = 0;
|
|
32894
|
+
let hi = parts.length - 1;
|
|
32895
|
+
while (lo < hi) {
|
|
32896
|
+
const mid = lo + hi + 1 >> 1;
|
|
32897
|
+
if (measureWidth(`${parts.slice(0, mid).join("")}…`) <= width) lo = mid;
|
|
32898
|
+
else hi = mid - 1;
|
|
32899
|
+
}
|
|
32900
|
+
return `${parts.slice(0, lo).join("")}…`;
|
|
32901
|
+
}
|
|
32808
32902
|
const baselineShifts = /* @__PURE__ */ new Map();
|
|
32809
32903
|
function cssBaselineShift(style) {
|
|
32810
32904
|
const font = fontStringFromTextStyle(style);
|
|
@@ -32996,40 +33090,10 @@ function boardTextSize(item) {
|
|
|
32996
33090
|
}
|
|
32997
33091
|
//#endregion
|
|
32998
33092
|
//#region ../sdk/src/board/render/text-fit.ts
|
|
32999
|
-
function fitLineWithEllipsis(line, wrapWidth, measureWidth) {
|
|
33000
|
-
const trimmed = line.replace(/\s+$/u, "");
|
|
33001
|
-
if (!trimmed) return "…";
|
|
33002
|
-
const full = `${trimmed}…`;
|
|
33003
|
-
if (measureWidth(full) <= wrapWidth) return full;
|
|
33004
|
-
let lo = 0;
|
|
33005
|
-
let hi = trimmed.length;
|
|
33006
|
-
let best = "…";
|
|
33007
|
-
while (lo <= hi) {
|
|
33008
|
-
const mid = lo + hi >> 1;
|
|
33009
|
-
const candidate = mid > 0 ? `${trimmed.slice(0, mid)}…` : "…";
|
|
33010
|
-
if (measureWidth(candidate) <= wrapWidth) {
|
|
33011
|
-
best = candidate;
|
|
33012
|
-
lo = mid + 1;
|
|
33013
|
-
} else hi = mid - 1;
|
|
33014
|
-
}
|
|
33015
|
-
return best;
|
|
33016
|
-
}
|
|
33017
33093
|
function fitTextToLines(text, value, maxLines, wrapWidth) {
|
|
33018
|
-
const width = Math.max(1, wrapWidth);
|
|
33019
33094
|
text.style.wordWrap = false;
|
|
33020
|
-
|
|
33021
|
-
|
|
33022
|
-
return;
|
|
33023
|
-
}
|
|
33024
|
-
const charCap = Math.max(maxLines * Math.ceil(width), maxLines * 4);
|
|
33025
|
-
const sample = value.length > charCap ? value.slice(0, charCap) : value;
|
|
33026
|
-
const { lines } = layoutTextLines(sample, fontStringFromTextStyle(text.style), width);
|
|
33027
|
-
const kept = lines.slice(0, maxLines);
|
|
33028
|
-
if (lines.length > maxLines || sample !== value) {
|
|
33029
|
-
const lastIndex = kept.length - 1;
|
|
33030
|
-
kept[lastIndex] = fitLineWithEllipsis(kept[lastIndex] ?? "", width, (candidate) => CanvasTextMetrics.measureText(candidate, text.style).width);
|
|
33031
|
-
}
|
|
33032
|
-
const fitted = kept.join("\n");
|
|
33095
|
+
const { lines } = layoutTextLines(value, fontStringFromTextStyle(text.style), Math.max(1, wrapWidth), { maxLines });
|
|
33096
|
+
const fitted = lines.join("\n");
|
|
33033
33097
|
if (text.text !== fitted) text.text = fitted;
|
|
33034
33098
|
}
|
|
33035
33099
|
function fitTextToWidth(text, value, width) {
|
|
@@ -33644,6 +33708,10 @@ function traceLocal(graphics, frame, rect) {
|
|
|
33644
33708
|
const d = corner(x, y + height);
|
|
33645
33709
|
graphics.moveTo(a.x, a.y).lineTo(b.x, b.y).lineTo(c.x, c.y).lineTo(d.x, d.y).closePath();
|
|
33646
33710
|
}
|
|
33711
|
+
function farPictureTone(item, context) {
|
|
33712
|
+
const key = context.assetKey(item);
|
|
33713
|
+
return (key ? context.assetTone?.(key) : null) ?? void 0;
|
|
33714
|
+
}
|
|
33647
33715
|
function drawFarPlate(graphics, frame, style) {
|
|
33648
33716
|
if (frame.width <= 0 || frame.height <= 0) return;
|
|
33649
33717
|
traceLocal(graphics, frame, {
|
|
@@ -33983,7 +34051,7 @@ const modelCardRenderer = {
|
|
|
33983
34051
|
},
|
|
33984
34052
|
renderFar: (graphics, item, context) => {
|
|
33985
34053
|
drawFarPlate(graphics, item.frame, {
|
|
33986
|
-
fill: context.palette.surface,
|
|
34054
|
+
fill: farPictureTone(item, context) ?? context.palette.surface,
|
|
33987
34055
|
fillAlpha: .96,
|
|
33988
34056
|
accent: context.palette.legendary,
|
|
33989
34057
|
accentAlpha: .45
|
|
@@ -33995,6 +34063,64 @@ const modelCardRenderer = {
|
|
|
33995
34063
|
}
|
|
33996
34064
|
};
|
|
33997
34065
|
//#endregion
|
|
34066
|
+
//#region ../sdk/src/board/render/media-interaction.ts
|
|
34067
|
+
const BOARD_PLAY_MEDIA = "play-media";
|
|
34068
|
+
function mediaPlayBadgeVisible(item, zoom, options) {
|
|
34069
|
+
if (!options.materialized) return false;
|
|
34070
|
+
if (item.type === "video" || item.type === "audio") return true;
|
|
34071
|
+
if (isBoardModelItem(item)) return boardCardDetailed(zoom);
|
|
34072
|
+
if (item.type !== "task" || !boardCardDetailed(zoom)) return false;
|
|
34073
|
+
const artifact = featuredTaskArtifact(item.props.snapshot.artifacts);
|
|
34074
|
+
if (artifact?.type === "audio") return true;
|
|
34075
|
+
return artifact?.type === "video" && (Boolean(artifact.previewUrl) || options.hasVideoPreview);
|
|
34076
|
+
}
|
|
34077
|
+
function cornerKey(item) {
|
|
34078
|
+
const { width, height } = item.frame;
|
|
34079
|
+
if (item.type === "audio") return audioKeyCenter(width, height);
|
|
34080
|
+
return isBoardModelItem(item) ? modelKeyCenter(width, height) : null;
|
|
34081
|
+
}
|
|
34082
|
+
function mediaPlayKeyCenter(item) {
|
|
34083
|
+
const { x, y, width, height, rotation } = item.frame;
|
|
34084
|
+
const center = worldPoint(x + width / 2, y + height / 2);
|
|
34085
|
+
const key = cornerKey(item);
|
|
34086
|
+
if (!key) return center;
|
|
34087
|
+
return rotatePointAround(worldPoint(x + key.x, y + key.y), center, degToRad(rotation || 0));
|
|
34088
|
+
}
|
|
34089
|
+
function mediaPlayBadgeHit(item, point, zoom) {
|
|
34090
|
+
const scale = Math.max(zoom, .05);
|
|
34091
|
+
const radius = isBoardModelItem(item) ? Math.max(cornerKey(item)?.radius ?? 0, 16 / scale) : 28 / scale;
|
|
34092
|
+
const center = mediaPlayKeyCenter(item);
|
|
34093
|
+
return Math.hypot(point.x - center.x, point.y - center.y) <= radius;
|
|
34094
|
+
}
|
|
34095
|
+
function boardMediaActionAt(item, point, zoom, options) {
|
|
34096
|
+
return mediaPlayBadgeVisible(item, zoom, options) && mediaPlayBadgeHit(item, point, zoom) ? {
|
|
34097
|
+
action: BOARD_PLAY_MEDIA,
|
|
34098
|
+
itemId: item.id
|
|
34099
|
+
} : null;
|
|
34100
|
+
}
|
|
34101
|
+
const PLAY_HIT = {
|
|
34102
|
+
action: BOARD_PLAY_MEDIA,
|
|
34103
|
+
cursor: "pointer"
|
|
34104
|
+
};
|
|
34105
|
+
function mediaPlayHit(item, point, context) {
|
|
34106
|
+
const key = context.assetKey(item);
|
|
34107
|
+
return boardMediaActionAt(item, point, context.zoom, {
|
|
34108
|
+
materialized: true,
|
|
34109
|
+
hasVideoPreview: Boolean(key && context.getTexture(key))
|
|
34110
|
+
}) ? PLAY_HIT : null;
|
|
34111
|
+
}
|
|
34112
|
+
//#endregion
|
|
34113
|
+
//#region ../sdk/src/board/render/labels.ts
|
|
34114
|
+
const ARROW_LABEL = {
|
|
34115
|
+
fontWeight: "500",
|
|
34116
|
+
lineHeight: 1.25,
|
|
34117
|
+
padX: .5,
|
|
34118
|
+
padY: .25
|
|
34119
|
+
};
|
|
34120
|
+
function arrowLabelAnchor(arrow, style) {
|
|
34121
|
+
return style.trim === void 0 ? arrow.mid : pathPointAt(arrow.path, .5);
|
|
34122
|
+
}
|
|
34123
|
+
//#endregion
|
|
33998
34124
|
//#region ../sdk/src/board/render/renderers/arrow-card-renderer.ts
|
|
33999
34125
|
const partsByContainer$11 = /* @__PURE__ */ new WeakMap();
|
|
34000
34126
|
function sync$11(container, item, context) {
|
|
@@ -34056,8 +34182,9 @@ function sync$11(container, item, context) {
|
|
|
34056
34182
|
parts.label.text = props.label;
|
|
34057
34183
|
parts.label.style.fill = context.palette.text;
|
|
34058
34184
|
parts.label.style.fontSize = props.fontSize;
|
|
34059
|
-
|
|
34060
|
-
const
|
|
34185
|
+
parts.label.style.lineHeight = props.fontSize * ARROW_LABEL.lineHeight;
|
|
34186
|
+
const padX = props.fontSize * ARROW_LABEL.padX;
|
|
34187
|
+
const padY = props.fontSize * ARROW_LABEL.padY;
|
|
34061
34188
|
const { width, height } = parts.label;
|
|
34062
34189
|
const plate = {
|
|
34063
34190
|
x: -width / 2 - padX,
|
|
@@ -34077,7 +34204,7 @@ function sync$11(container, item, context) {
|
|
|
34077
34204
|
const visible = props.label.length > 0 && (style.trim === void 0 || style.trim >= .5);
|
|
34078
34205
|
parts.label.visible = visible;
|
|
34079
34206
|
parts.backdrop.visible = visible;
|
|
34080
|
-
const mid =
|
|
34207
|
+
const mid = arrowLabelAnchor(resolved, style);
|
|
34081
34208
|
parts.label.position.set(mid.x, mid.y);
|
|
34082
34209
|
parts.backdrop.position.set(mid.x, mid.y);
|
|
34083
34210
|
}
|
|
@@ -34093,7 +34220,7 @@ const arrowCardRenderer = {
|
|
|
34093
34220
|
fill: 16777215,
|
|
34094
34221
|
fontFamily: BOARD_FONT_STACK,
|
|
34095
34222
|
fontSize: 14,
|
|
34096
|
-
fontWeight:
|
|
34223
|
+
fontWeight: ARROW_LABEL.fontWeight
|
|
34097
34224
|
},
|
|
34098
34225
|
resolution: context.textResolution,
|
|
34099
34226
|
roundPixels: true
|
|
@@ -34481,8 +34608,34 @@ const partsByContainer$8 = /* @__PURE__ */ new WeakMap();
|
|
|
34481
34608
|
function detailFor(zoom) {
|
|
34482
34609
|
return boardCardDetailed(zoom) ? "full" : "title";
|
|
34483
34610
|
}
|
|
34484
|
-
function
|
|
34485
|
-
if (
|
|
34611
|
+
function viewOf(item) {
|
|
34612
|
+
if (item.type === "file") {
|
|
34613
|
+
const { src, snapshot } = item.props;
|
|
34614
|
+
return {
|
|
34615
|
+
src,
|
|
34616
|
+
title: snapshot?.title || fileStem(src),
|
|
34617
|
+
excerpt: snapshot?.excerpt ?? "",
|
|
34618
|
+
kind: filePreviewKind(snapshot),
|
|
34619
|
+
meta: fileMetaLine(src, snapshot?.size),
|
|
34620
|
+
mark: fileTypeLabel(src),
|
|
34621
|
+
category: fileCategory(src, snapshot?.mimeType)
|
|
34622
|
+
};
|
|
34623
|
+
}
|
|
34624
|
+
const preview = boardItemPreview(item);
|
|
34625
|
+
if (!preview) return null;
|
|
34626
|
+
const label = (item.type.split(".").pop() ?? item.type).toUpperCase();
|
|
34627
|
+
return {
|
|
34628
|
+
src: preview.src ?? null,
|
|
34629
|
+
title: preview.title || item.type,
|
|
34630
|
+
excerpt: preview.excerpt ?? "",
|
|
34631
|
+
kind: preview.cover ? "cover" : preview.excerpt ? "text" : "blank",
|
|
34632
|
+
meta: label,
|
|
34633
|
+
mark: label,
|
|
34634
|
+
category: preview.src ? fileCategory(preview.src) : "other"
|
|
34635
|
+
};
|
|
34636
|
+
}
|
|
34637
|
+
function coverHeight(view, height) {
|
|
34638
|
+
if (view.kind !== "cover") return 0;
|
|
34486
34639
|
const ideal = Math.round(height * COVER_RATIO);
|
|
34487
34640
|
return Math.max(0, Math.min(ideal, height - MIN_BODY_FOR_COVER));
|
|
34488
34641
|
}
|
|
@@ -34501,31 +34654,31 @@ function syncClip(parts, rect, style) {
|
|
|
34501
34654
|
}
|
|
34502
34655
|
function sync$8(container, item, context) {
|
|
34503
34656
|
const parts = partsByContainer$8.get(container);
|
|
34504
|
-
|
|
34505
|
-
|
|
34657
|
+
const view = viewOf(item);
|
|
34658
|
+
if (!parts || !view) return;
|
|
34659
|
+
syncContent(parts, item, view, context);
|
|
34506
34660
|
for (const text of [
|
|
34507
34661
|
parts.title,
|
|
34508
34662
|
parts.excerpt,
|
|
34509
34663
|
parts.typeMark
|
|
34510
34664
|
]) syncTextResolution(text, context.textResolution);
|
|
34511
34665
|
}
|
|
34512
|
-
function syncContent(parts, item, context) {
|
|
34666
|
+
function syncContent(parts, item, view, context) {
|
|
34513
34667
|
positionShell(parts.root, item);
|
|
34514
34668
|
const { width, height } = item.frame;
|
|
34515
34669
|
const detail = detailFor(context.zoom);
|
|
34516
34670
|
const elevation = cardElevation(context, item.id);
|
|
34517
34671
|
syncCardTag(parts.tag, {
|
|
34518
34672
|
glyph: "file",
|
|
34519
|
-
text:
|
|
34673
|
+
text: view.meta,
|
|
34520
34674
|
width
|
|
34521
34675
|
}, context);
|
|
34522
34676
|
const key = context.assetKey(item);
|
|
34523
34677
|
const texture = key ? context.getTexture(key) : null;
|
|
34524
34678
|
const coverFailed = Boolean(key && !texture && context.hasError(key));
|
|
34525
|
-
const fileState = context.fileState(
|
|
34526
|
-
const band = coverHeight(
|
|
34527
|
-
const kind =
|
|
34528
|
-
const category = fileCategory(item.props.src, item.props.snapshot?.mimeType);
|
|
34679
|
+
const fileState = view.src ? context.fileState(view.src) : "ok";
|
|
34680
|
+
const band = coverHeight(view, height);
|
|
34681
|
+
const { kind, category, title, excerpt, mark } = view;
|
|
34529
34682
|
const accent = fileCategoryAccent(category, context.palette);
|
|
34530
34683
|
const visualSig = [
|
|
34531
34684
|
key ?? "",
|
|
@@ -34584,9 +34737,6 @@ function syncContent(parts, item, context) {
|
|
|
34584
34737
|
parts.excerpt.visible = detail === "full";
|
|
34585
34738
|
parts.typeMark.visible = kind === "blank";
|
|
34586
34739
|
}
|
|
34587
|
-
const title = item.props.snapshot?.title || fileStem(item.props.src);
|
|
34588
|
-
const excerpt = item.props.snapshot?.excerpt ?? "";
|
|
34589
|
-
const mark = fileTypeLabel(item.props.src);
|
|
34590
34740
|
const innerWidth = Math.max(1, width - 20);
|
|
34591
34741
|
const showTypeMark = kind === "blank";
|
|
34592
34742
|
const textSig = [
|
|
@@ -34642,7 +34792,7 @@ function syncContent(parts, item, context) {
|
|
|
34642
34792
|
}
|
|
34643
34793
|
const fileCardRenderer = {
|
|
34644
34794
|
id: "file-card",
|
|
34645
|
-
canRender: (item) => item.type === "file",
|
|
34795
|
+
canRender: (item) => item.type === "file" || boardItemPreview(item) !== null,
|
|
34646
34796
|
create: (item, context) => {
|
|
34647
34797
|
const root = new Container();
|
|
34648
34798
|
const plate = new Graphics();
|
|
@@ -34706,23 +34856,19 @@ const fileCardRenderer = {
|
|
|
34706
34856
|
visualSig: "",
|
|
34707
34857
|
textSig: ""
|
|
34708
34858
|
});
|
|
34709
|
-
|
|
34859
|
+
sync$8(root, item, context);
|
|
34710
34860
|
return root;
|
|
34711
34861
|
},
|
|
34712
|
-
update:
|
|
34713
|
-
|
|
34714
|
-
},
|
|
34715
|
-
resolution: (container, item, context) => {
|
|
34716
|
-
if (item.type === "file") sync$8(container, item, context);
|
|
34717
|
-
},
|
|
34862
|
+
update: sync$8,
|
|
34863
|
+
resolution: sync$8,
|
|
34718
34864
|
zoom: (container, zoom) => {
|
|
34719
34865
|
const tag = partsByContainer$8.get(container)?.tag;
|
|
34720
34866
|
if (tag) zoomCardTag(tag, zoom);
|
|
34721
34867
|
},
|
|
34722
34868
|
renderFar: (graphics, item, context) => {
|
|
34723
|
-
const category =
|
|
34869
|
+
const category = viewOf(item)?.category ?? "other";
|
|
34724
34870
|
drawFarPlate(graphics, item.frame, {
|
|
34725
|
-
fill: context.palette.surface,
|
|
34871
|
+
fill: farPictureTone(item, context) ?? context.palette.surface,
|
|
34726
34872
|
fillAlpha: .96,
|
|
34727
34873
|
accent: fileCategoryAccent(category, context.palette),
|
|
34728
34874
|
accentAlpha: .45
|
|
@@ -34786,19 +34932,24 @@ function sync$7(container, item, context) {
|
|
|
34786
34932
|
parts.label.visible = decorated;
|
|
34787
34933
|
const title = locked ? `🔒 ${props.label}`.trim() : props.label;
|
|
34788
34934
|
const labelColor = style.stroke ? baseStroke : context.palette.muted;
|
|
34935
|
+
const size = context.style.frameLabelSize;
|
|
34789
34936
|
const textSig = [
|
|
34790
34937
|
title,
|
|
34791
34938
|
labelColor,
|
|
34792
|
-
context.style.font
|
|
34939
|
+
context.style.font,
|
|
34940
|
+
size
|
|
34793
34941
|
].join("|");
|
|
34794
34942
|
if (textSig !== parts.textSig) {
|
|
34795
34943
|
parts.textSig = textSig;
|
|
34796
34944
|
parts.label.text = title;
|
|
34797
34945
|
parts.label.style.fill = labelColor;
|
|
34798
34946
|
parts.label.style.fontFamily = context.style.font;
|
|
34947
|
+
parts.label.style.fontSize = size;
|
|
34948
|
+
parts.label.style.lineHeight = size * BOARD_FRAME_LABEL_LINE_HEIGHT;
|
|
34949
|
+
const offset = frameLabelOffset(size);
|
|
34950
|
+
parts.label.position.set(offset.x, offset.y);
|
|
34799
34951
|
}
|
|
34800
34952
|
syncTextResolution(parts.label, context.textResolution);
|
|
34801
|
-
parts.label.position.set(4, -18);
|
|
34802
34953
|
}
|
|
34803
34954
|
const frameCardRenderer = {
|
|
34804
34955
|
id: "frame-card",
|
|
@@ -34809,7 +34960,6 @@ const frameCardRenderer = {
|
|
|
34809
34960
|
const label = createLabel("", {
|
|
34810
34961
|
fill: context.palette.muted,
|
|
34811
34962
|
fontFamily: BOARD_FONT_STACK,
|
|
34812
|
-
fontSize: 12,
|
|
34813
34963
|
fontWeight: "600"
|
|
34814
34964
|
}, context.textResolution);
|
|
34815
34965
|
root.addChild(box, label);
|
|
@@ -35284,7 +35434,7 @@ const imageCardRenderer = {
|
|
|
35284
35434
|
lod: { kind: "media" },
|
|
35285
35435
|
renderFar: (graphics, item, context) => {
|
|
35286
35436
|
drawFarPlate(graphics, item.frame, {
|
|
35287
|
-
fill: context.palette.hover,
|
|
35437
|
+
fill: farPictureTone(item, context) ?? context.palette.hover,
|
|
35288
35438
|
fillAlpha: FAR_ALPHA
|
|
35289
35439
|
});
|
|
35290
35440
|
},
|
|
@@ -35797,7 +35947,7 @@ const taskCardRenderer = {
|
|
|
35797
35947
|
const { status } = liveStatus(item, context);
|
|
35798
35948
|
const active = status === "failed" || status === "running" || status === "pending";
|
|
35799
35949
|
drawFarPlate(graphics, item.frame, {
|
|
35800
|
-
fill: context.palette.surface,
|
|
35950
|
+
fill: farPictureTone(item, context) ?? context.palette.surface,
|
|
35801
35951
|
fillAlpha: .82,
|
|
35802
35952
|
...active ? {
|
|
35803
35953
|
accent: statusColor(status, context),
|
|
@@ -36170,7 +36320,7 @@ const videoCardRenderer = {
|
|
|
36170
36320
|
lod: { kind: "media" },
|
|
36171
36321
|
renderFar: (graphics, item, context) => {
|
|
36172
36322
|
drawFarPlate(graphics, item.frame, {
|
|
36173
|
-
fill: context.palette.surface,
|
|
36323
|
+
fill: farPictureTone(item, context) ?? context.palette.surface,
|
|
36174
36324
|
fillAlpha: .96,
|
|
36175
36325
|
accent: context.palette.brand,
|
|
36176
36326
|
accentAlpha: .75
|
|
@@ -36190,14 +36340,18 @@ const DEFAULT_BOARD_RENDER_LABELS = {
|
|
|
36190
36340
|
previewUnavailable: "Preview unavailable",
|
|
36191
36341
|
noPreview: "No preview"
|
|
36192
36342
|
};
|
|
36343
|
+
const playable = (renderer) => ({
|
|
36344
|
+
...renderer,
|
|
36345
|
+
hitAt: mediaPlayHit
|
|
36346
|
+
});
|
|
36193
36347
|
const builtinCardRenderers = [
|
|
36194
36348
|
textCardRenderer,
|
|
36195
36349
|
imageCardRenderer,
|
|
36196
|
-
videoCardRenderer,
|
|
36197
|
-
audioCardRenderer,
|
|
36198
|
-
modelCardRenderer,
|
|
36350
|
+
playable(videoCardRenderer),
|
|
36351
|
+
playable(audioCardRenderer),
|
|
36352
|
+
playable(modelCardRenderer),
|
|
36199
36353
|
fileCardRenderer,
|
|
36200
|
-
taskCardRenderer,
|
|
36354
|
+
playable(taskCardRenderer),
|
|
36201
36355
|
shapeCardRenderer,
|
|
36202
36356
|
drawCardRenderer,
|
|
36203
36357
|
arrowCardRenderer,
|
|
@@ -36690,10 +36844,17 @@ object({
|
|
|
36690
36844
|
props: object({}).strict().default({})
|
|
36691
36845
|
}).strict();
|
|
36692
36846
|
const BOARD_EXTENSION_TYPE_PATTERN = /^[a-z][a-z0-9]*(?:\.[a-z0-9-]+)+$/;
|
|
36847
|
+
const BoardItemPreviewSchema = object({
|
|
36848
|
+
title: string().max(500).optional(),
|
|
36849
|
+
excerpt: string().max(2e3).optional(),
|
|
36850
|
+
cover: BoardMediaSourceSchema.optional().describe("An image for the card."),
|
|
36851
|
+
src: BoardMediaSourceSchema.optional().describe("The file or page the card stands for.")
|
|
36852
|
+
}).strict().describe("How a client without this type's renderer shows the card, and what it refers to. The type's own client keeps it current.");
|
|
36693
36853
|
object({
|
|
36694
36854
|
...boxed(BOARD_DEFAULT_ITEM_SIZE),
|
|
36695
36855
|
type: string().regex(BOARD_EXTENSION_TYPE_PATTERN),
|
|
36696
|
-
props: record(string(), unknown()).default({})
|
|
36856
|
+
props: record(string(), unknown()).default({}),
|
|
36857
|
+
preview: BoardItemPreviewSchema.optional()
|
|
36697
36858
|
}).strict();
|
|
36698
36859
|
const CSS_EASE_KEYWORDS = /* @__PURE__ */ new Set([
|
|
36699
36860
|
"linear",
|
|
@@ -37143,7 +37304,8 @@ const BASE = {
|
|
|
37143
37304
|
progress: "shimmer",
|
|
37144
37305
|
icons: "line",
|
|
37145
37306
|
motion: "smooth",
|
|
37146
|
-
font: BOARD_FONT_STACK
|
|
37307
|
+
font: BOARD_FONT_STACK,
|
|
37308
|
+
frameLabelSize: 12
|
|
37147
37309
|
};
|
|
37148
37310
|
const SHADOW = {
|
|
37149
37311
|
light: {
|
package/dist/commands/boards.js
CHANGED
|
@@ -3,7 +3,7 @@ import { existsSync } from "node:fs";
|
|
|
3
3
|
import { mkdir } from "node:fs/promises";
|
|
4
4
|
import { dirname } from "node:path";
|
|
5
5
|
import { BOARD_PRESET_NAMES, BOARD_SCHEMA_TARGETS, BOARD_SCRIPT_API, BOARD_THEME_IDS, boardJsonSchema, boardPresetTracks, boardSchemaOverview, isBoardPresetName, listBoardPresets, } from "@neta-art/cohub/board";
|
|
6
|
-
import { BOARD_CREATE_INPUT_MAX_BYTES, BOARD_TRANSACTION_INPUT_MAX_BYTES, parseBoardJsonObject, readBoardJsonObject,
|
|
6
|
+
import { BOARD_CREATE_INPUT_MAX_BYTES, BOARD_TRANSACTION_INPUT_MAX_BYTES, parseBoardJsonObject, readBoardJsonObject, writeBoardOutput, } from "../board-command-support.js";
|
|
7
7
|
import { BOARD_EXPORT_IMAGE_MEMORY_MIB } from "../board-export-resources.js";
|
|
8
8
|
import { settleBoardPatch } from "../board-media.js";
|
|
9
9
|
import { formatBoardTime, parseBoardTime, parseBoardTimes } from "../board-time.js";
|
|
@@ -55,7 +55,7 @@ function list(value) {
|
|
|
55
55
|
}
|
|
56
56
|
async function boardClient(boards, target, spaceId) {
|
|
57
57
|
spaceId ??= await resolveSpace(boards);
|
|
58
|
-
return createClient().space(spaceId).
|
|
58
|
+
return createClient().space(spaceId).boards.open(target);
|
|
59
59
|
}
|
|
60
60
|
/** A patch from an inline argument, a file, or stdin (`-`). */
|
|
61
61
|
async function readPatch(inline, input, maxBytes) {
|
|
@@ -538,9 +538,9 @@ Presets: ${BOARD_PRESET_NAMES.join(", ")}
|
|
|
538
538
|
.action(async (target, options) => {
|
|
539
539
|
try {
|
|
540
540
|
const spaceId = await resolveSpace(boards);
|
|
541
|
-
const boardId = await resolveBoardId(spaceId, target);
|
|
542
541
|
const client = createRealtimeClient();
|
|
543
|
-
const board = client.space(spaceId).
|
|
542
|
+
const board = await client.space(spaceId).boards.open(target);
|
|
543
|
+
const boardId = board.id;
|
|
544
544
|
if (!jsonRequested(options))
|
|
545
545
|
process.stderr.write(`Watching Board ${boardId}…\n`);
|
|
546
546
|
const offConnection = client.onConnection((state) => {
|
|
@@ -90,6 +90,7 @@ export async function runRuntime(config, onState, externalSignal, onDiagnostic)
|
|
|
90
90
|
};
|
|
91
91
|
let closeInstance;
|
|
92
92
|
let bridgeTask;
|
|
93
|
+
let retryDisconnectedBridge;
|
|
93
94
|
let nativeStarted = false;
|
|
94
95
|
let tokenInFlight = null;
|
|
95
96
|
const token = (forceRefresh = false) => {
|
|
@@ -139,6 +140,9 @@ export async function runRuntime(config, onState, externalSignal, onDiagnostic)
|
|
|
139
140
|
let probeTimer;
|
|
140
141
|
let managed = false;
|
|
141
142
|
let childStopped = false;
|
|
143
|
+
let bridgeDisconnected = false;
|
|
144
|
+
let terminating = false;
|
|
145
|
+
let recoveryTimer;
|
|
142
146
|
let controlPipe = null;
|
|
143
147
|
try {
|
|
144
148
|
const initialToken = await token();
|
|
@@ -156,6 +160,8 @@ export async function runRuntime(config, onState, externalSignal, onDiagnostic)
|
|
|
156
160
|
bridge.once("error", (error) => diagnostics.log("error", "sandboxd.process_error", { error: serializeDiagnosticError(error) }));
|
|
157
161
|
bridge.once("exit", (code, exitSignal) => {
|
|
158
162
|
childStopped = true;
|
|
163
|
+
clearTimeout(recoveryTimer);
|
|
164
|
+
recoveryTimer = undefined;
|
|
159
165
|
if (!signal.aborted)
|
|
160
166
|
diagnostics.log("warn", "sandboxd.process_exit", { code, signal: exitSignal });
|
|
161
167
|
// Descendants may still hold inherited pipes. After draining buffered
|
|
@@ -198,8 +204,10 @@ export async function runRuntime(config, onState, externalSignal, onDiagnostic)
|
|
|
198
204
|
managed = true;
|
|
199
205
|
if (event.type === "connected" || event.type === "disconnected") {
|
|
200
206
|
const connected = event.type === "connected";
|
|
207
|
+
bridgeDisconnected = !connected;
|
|
201
208
|
update({ workspaceConnected: connected });
|
|
202
209
|
diagnostics.log(connected ? "info" : "warn", `sandboxd.${event.type}`);
|
|
210
|
+
retryDisconnectedBridge?.();
|
|
203
211
|
}
|
|
204
212
|
}
|
|
205
213
|
catch {
|
|
@@ -238,6 +246,11 @@ export async function runRuntime(config, onState, externalSignal, onDiagnostic)
|
|
|
238
246
|
};
|
|
239
247
|
probeTimer = setTimeout(() => void probe(), 1000);
|
|
240
248
|
const terminate = () => {
|
|
249
|
+
if (terminating || childStopped)
|
|
250
|
+
return;
|
|
251
|
+
terminating = true;
|
|
252
|
+
clearTimeout(recoveryTimer);
|
|
253
|
+
recoveryTimer = undefined;
|
|
241
254
|
// Windows has no SIGTERM; closing the managed stdin lets sandboxd stop gracefully.
|
|
242
255
|
if (process.platform === "win32")
|
|
243
256
|
bridge.stdin?.end();
|
|
@@ -246,6 +259,26 @@ export async function runRuntime(config, onState, externalSignal, onDiagnostic)
|
|
|
246
259
|
const timeout = setTimeout(() => bridge.kill("SIGKILL"), 3000);
|
|
247
260
|
void closed.finally(() => clearTimeout(timeout));
|
|
248
261
|
};
|
|
262
|
+
// A managed bridge may be sleeping for five minutes after a lease
|
|
263
|
+
// rejection. Retry only after it reports a lost connection and the
|
|
264
|
+
// Harness has regained its lease; a connected bridge stays untouched.
|
|
265
|
+
retryDisconnectedBridge = () => {
|
|
266
|
+
if (signal.aborted || !status.harnessConnected || !bridgeDisconnected || terminating || childStopped) {
|
|
267
|
+
clearTimeout(recoveryTimer);
|
|
268
|
+
recoveryTimer = undefined;
|
|
269
|
+
}
|
|
270
|
+
else if (!recoveryTimer) {
|
|
271
|
+
// Give the bridge its normal retry and channel reattachment
|
|
272
|
+
// window before replacing a process stuck in config backoff.
|
|
273
|
+
recoveryTimer = setTimeout(() => {
|
|
274
|
+
recoveryTimer = undefined;
|
|
275
|
+
if (!signal.aborted && status.harnessConnected && bridgeDisconnected && !terminating && !childStopped) {
|
|
276
|
+
diagnostics.log("info", "sandboxd.lease_recovery");
|
|
277
|
+
terminate();
|
|
278
|
+
}
|
|
279
|
+
}, 30_000);
|
|
280
|
+
}
|
|
281
|
+
};
|
|
249
282
|
signal.addEventListener("abort", terminate, { once: true });
|
|
250
283
|
if (signal.aborted)
|
|
251
284
|
terminate();
|
|
@@ -257,10 +290,12 @@ export async function runRuntime(config, onState, externalSignal, onDiagnostic)
|
|
|
257
290
|
diagnostics.log("warn", "sandboxd.restart_failed", { error: serializeDiagnosticError(error) });
|
|
258
291
|
}
|
|
259
292
|
finally {
|
|
293
|
+
retryDisconnectedBridge = undefined;
|
|
260
294
|
childStopped = true;
|
|
261
295
|
controlPipe?.close();
|
|
262
296
|
clearTimeout(refreshTimer);
|
|
263
297
|
clearTimeout(probeTimer);
|
|
298
|
+
clearTimeout(recoveryTimer);
|
|
264
299
|
update({ workspaceConnected: false });
|
|
265
300
|
}
|
|
266
301
|
if (Date.now() - startedAt > 60_000)
|
|
@@ -276,8 +311,8 @@ export async function runRuntime(config, onState, externalSignal, onDiagnostic)
|
|
|
276
311
|
await serveRuntime({
|
|
277
312
|
spaceId: config.spaceId, cwd: config.root, url: url.toString(), capabilities,
|
|
278
313
|
runtimeId: status.runtimeId, diagnostics, token, signal, executor: native.executor,
|
|
279
|
-
onReady: () => update({ harnessConnected: true }),
|
|
280
|
-
onDisconnected: () => { native.connect(null); update({ harnessConnected: false }); },
|
|
314
|
+
onReady: () => { update({ harnessConnected: true }); retryDisconnectedBridge?.(); },
|
|
315
|
+
onDisconnected: () => { native.connect(null); update({ harnessConnected: false }); retryDisconnectedBridge?.(); },
|
|
281
316
|
onNativeStop: (stop) => { native.stop(stop.sessionId, stop.turnId); },
|
|
282
317
|
onNativeChannel: (send) => {
|
|
283
318
|
native.connect(send);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neta-art/cohub-cli",
|
|
3
|
-
"version": "10.
|
|
3
|
+
"version": "10.11.1",
|
|
4
4
|
"description": "CLI for Cohub — spaces, sessions, and agent collaboration.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"NOTICE"
|
|
19
19
|
],
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@neta-art/cohub": "12.
|
|
21
|
+
"@neta-art/cohub": "12.4.0",
|
|
22
22
|
"@neta-art/generation": "^0.1.40",
|
|
23
23
|
"commander": "^15.0.0",
|
|
24
24
|
"sharp": "^0.35.4",
|