@neta-art/cohub 11.5.0 → 12.0.0

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.
Files changed (88) hide show
  1. package/dist/board/editor/animation.js +2 -1
  2. package/dist/board/editor/clipboard.js +1 -1
  3. package/dist/board/editor/creation.js +2 -2
  4. package/dist/board/editor/document-edits.d.ts +1 -1
  5. package/dist/board/editor/document-edits.js +1 -19
  6. package/dist/board/editor/document.js +2 -1
  7. package/dist/board/editor/editor.js +2 -2
  8. package/dist/board/editor/index.d.ts +2 -1
  9. package/dist/board/editor/index.js +2 -1
  10. package/dist/board/editor/selection.js +1 -1
  11. package/dist/board/editor/snapshots.js +11 -13
  12. package/dist/board/export/index.js +2 -2
  13. package/dist/board/export/node/scripts.js +1 -1
  14. package/dist/board/export/scene.js +2 -2
  15. package/dist/board/model/client-geometry.d.ts +22 -0
  16. package/dist/board/model/client-geometry.js +94 -0
  17. package/dist/board/model/document-share.d.ts +5 -0
  18. package/dist/board/model/document-share.js +27 -0
  19. package/dist/board/model/index.d.ts +5 -4
  20. package/dist/board/model/index.js +19 -18
  21. package/dist/board/model/items/create.d.ts +5 -1
  22. package/dist/board/model/items/create.js +30 -59
  23. package/dist/board/model/items/index.d.ts +2 -2
  24. package/dist/board/model/items/index.js +2 -2
  25. package/dist/board/model/items/registry.js +2 -5
  26. package/dist/board/model/json.d.ts +4 -0
  27. package/dist/board/model/json.js +22 -0
  28. package/dist/board/model/media-playback.d.ts +6 -3
  29. package/dist/board/model/sampling.js +1 -1
  30. package/dist/board/player/index.d.ts +6 -2
  31. package/dist/board/player/index.js +33 -15
  32. package/dist/board/render/index.d.ts +2 -2
  33. package/dist/board/render/index.js +6 -6
  34. package/dist/board/render/media-interaction.js +1 -1
  35. package/dist/board/render/renderers/arrow-card-renderer.js +5 -1
  36. package/dist/board/render/renderers/audio-card-renderer.js +5 -2
  37. package/dist/board/render/renderers/base-card-renderer.js +2 -5
  38. package/dist/board/render/renderers/board-renderer-registry.d.ts +4 -2
  39. package/dist/board/render/renderers/custom-card-renderer.js +7 -3
  40. package/dist/board/render/renderers/draw-card-renderer.js +1 -1
  41. package/dist/board/render/renderers/file-card-renderer.js +6 -3
  42. package/dist/board/render/renderers/frame-card-renderer.js +5 -1
  43. package/dist/board/render/renderers/image-card-renderer.js +13 -49
  44. package/dist/board/render/renderers/model-card-renderer.js +7 -4
  45. package/dist/board/render/renderers/shape-card-renderer.js +5 -1
  46. package/dist/board/render/renderers/task-card-renderer.js +6 -3
  47. package/dist/board/render/renderers/text-card-renderer.js +6 -2
  48. package/dist/board/render/renderers/unknown-card-renderer.js +4 -0
  49. package/dist/board/render/renderers/video-card-renderer.js +20 -19
  50. package/dist/board/render/script-export.js +1 -1
  51. package/dist/board/render/script-host.d.ts +2 -0
  52. package/dist/board/render/script-host.js +45 -10
  53. package/dist/board/render/script-resolution.d.ts +4 -0
  54. package/dist/board/render/script-resolution.js +18 -0
  55. package/dist/board/render/surface.d.ts +9 -2
  56. package/dist/board/render/surface.js +15 -1
  57. package/dist/board/render/text-resolution.d.ts +4 -1
  58. package/dist/board/render/text-resolution.js +10 -5
  59. package/dist/board/replica/index.js +4 -1
  60. package/dist/board/stage/assets.d.ts +12 -8
  61. package/dist/board/stage/assets.js +174 -89
  62. package/dist/board/stage/display-density.d.ts +4 -0
  63. package/dist/board/stage/display-density.js +25 -0
  64. package/dist/board/stage/index.d.ts +3 -3
  65. package/dist/board/stage/index.js +3 -3
  66. package/dist/board/stage/lru.d.ts +3 -2
  67. package/dist/board/stage/lru.js +8 -4
  68. package/dist/board/stage/pointer.d.ts +1 -1
  69. package/dist/board/stage/pointer.js +4 -5
  70. package/dist/board/stage/scene.d.ts +3 -0
  71. package/dist/board/stage/scene.js +44 -8
  72. package/dist/board/stage/stage.d.ts +1 -0
  73. package/dist/board/stage/stage.js +152 -69
  74. package/dist/board/stage/views.d.ts +7 -2
  75. package/dist/board/stage/views.js +50 -21
  76. package/dist/chunks/environment.d.ts +16 -2
  77. package/dist/chunks/http.d.ts +6 -2
  78. package/dist/index.js +65 -22
  79. package/dist/protocol/dist/board-constants.js +56 -1
  80. package/dist/protocol/dist/board-layout.d.ts +8 -1
  81. package/dist/protocol/dist/board-layout.js +16 -4
  82. package/dist/protocol/dist/board-model.js +13 -19
  83. package/dist/protocol/dist/board-patch.js +1 -1
  84. package/dist/protocol/dist/board-schema.d.ts +52 -0
  85. package/dist/protocol/dist/board-schema.js +8 -0
  86. package/dist/protocol/dist/core/media.js +1 -0
  87. package/dist/protocol/dist/index.d.ts +2 -2
  88. package/package.json +1 -1
@@ -1,55 +1,80 @@
1
+ import { itemBounds } from "../model/geometry.js";
1
2
  import { toBoardPointerEvent } from "./pointer.js";
2
3
  //#region src/board/stage/views.ts
3
4
  const VISIBLE_MARGIN = 240;
4
- function screenStyle(frame, camera, order) {
5
- const { zoom } = camera;
5
+ function worldStyle(frame, order) {
6
6
  return [
7
7
  `z-index:${order}`,
8
- `left:${frame.x * zoom + camera.x}px`,
9
- `top:${frame.y * zoom + camera.y}px`,
10
- `width:${frame.width * zoom}px`,
11
- `height:${frame.height * zoom}px`,
12
- `--board-zoom:${zoom}`,
8
+ `left:${frame.x}px`,
9
+ `top:${frame.y}px`,
10
+ `width:${frame.width}px`,
11
+ `height:${frame.height}px`,
13
12
  `transform:rotate(${frame.rotation}deg)`
14
13
  ].join(";");
15
14
  }
16
15
  function onScreen(frame, camera, surface) {
17
- const left = frame.x * camera.zoom + camera.x;
18
- const top = frame.y * camera.zoom + camera.y;
19
- return left + frame.width * camera.zoom >= -240 && top + frame.height * camera.zoom >= -240 && left <= surface.width + VISIBLE_MARGIN && top <= surface.height + VISIBLE_MARGIN;
16
+ const bounds = itemBounds(frame);
17
+ const left = bounds.x * camera.zoom + camera.x;
18
+ const top = bounds.y * camera.zoom + camera.y;
19
+ return left + bounds.width * camera.zoom >= -240 && top + bounds.height * camera.zoom >= -240 && left <= surface.width + VISIBLE_MARGIN && top <= surface.height + VISIBLE_MARGIN;
20
20
  }
21
- function createBoardItemViewLayer(host, editor, views, camera) {
21
+ function createBoardItemViewLayer(host, editor, views, camera, onInvalidate = () => {}) {
22
22
  const element = host.ownerDocument.createElement("div");
23
23
  element.dataset.boardViews = "";
24
24
  element.style.cssText = "position:absolute;inset:0;z-index:2;overflow:hidden;pointer-events:none";
25
25
  host.appendChild(element);
26
+ const world = host.ownerDocument.createElement("div");
27
+ world.style.cssText = "position:absolute;inset:0;transform-origin:0 0;pointer-events:none";
28
+ element.appendChild(world);
29
+ let cameraStyle = "";
26
30
  const mounted = /* @__PURE__ */ new Map();
27
- const toPointerEvent = (event) => toBoardPointerEvent(event, host.getBoundingClientRect(), camera());
31
+ const pointers = /* @__PURE__ */ new Map();
32
+ const retained = (id, entry) => entry.element.contains(host.ownerDocument.activeElement) || [...pointers.values()].includes(id);
33
+ const pointerDown = (event) => {
34
+ const id = event.target?.closest("[data-board-item]")?.dataset.boardItem;
35
+ if (id && mounted.has(id)) pointers.set(event.pointerId, id);
36
+ };
37
+ const pointerEnd = (event) => {
38
+ if (pointers.delete(event.pointerId)) onInvalidate();
39
+ };
40
+ element.addEventListener("pointerdown", pointerDown, true);
41
+ element.addEventListener("focusout", onInvalidate);
42
+ host.ownerDocument.addEventListener("pointerup", pointerEnd, true);
43
+ host.ownerDocument.addEventListener("pointercancel", pointerEnd, true);
44
+ const toPointerEvent = (event) => toBoardPointerEvent(event, host, camera());
28
45
  const viewFor = (item) => views.find((view) => typeof view.type === "string" ? view.type === item.type : view.type(item));
29
46
  function unmount(id, entry) {
30
47
  entry.instance.destroy?.();
31
48
  entry.element.remove();
32
49
  mounted.delete(id);
50
+ for (const [pointer, owner] of pointers) if (owner === id) pointers.delete(pointer);
33
51
  }
34
52
  return {
35
53
  element,
36
54
  sync({ ids, scene, camera: view, surface, selection }) {
37
55
  if (views.length === 0) return;
56
+ const transform = `translate(${view.x}px,${view.y}px) scale(${view.zoom})`;
57
+ if (transform !== cameraStyle) world.style.transform = cameraStyle = transform;
38
58
  const live = /* @__PURE__ */ new Set();
39
- for (const id of ids ?? scene.items.map((item) => item.id)) {
59
+ const candidates = new Set(ids ?? scene.items.map((item) => item.id));
60
+ for (const [id, entry] of mounted) if (retained(id, entry)) candidates.add(id);
61
+ for (const id of candidates) {
40
62
  const item = scene.get(id);
41
63
  if (!item) continue;
42
64
  const itemView = viewFor(item);
43
- if (!itemView || !onScreen(item.frame, view, surface)) continue;
65
+ let entry = mounted.get(item.id);
66
+ const held = entry ? retained(id, entry) : false;
67
+ if (!itemView || !held && !onScreen(item.frame, view, surface)) continue;
44
68
  live.add(item.id);
69
+ const style = worldStyle(item.frame, scene.indexOf(item.id));
70
+ const minimum = itemView.contentSize;
71
+ const threshold = entry?.detailed ? .85 : 1;
45
72
  const context = {
46
73
  editor,
47
- zoom: view.zoom,
74
+ detailed: held || !minimum || item.frame.width * view.zoom >= minimum.width * threshold && item.frame.height * view.zoom >= minimum.height * threshold,
48
75
  selected: selection.has(item.id),
49
76
  toPointerEvent
50
77
  };
51
- const style = screenStyle(item.frame, view, scene.indexOf(item.id));
52
- let entry = mounted.get(item.id);
53
78
  if (entry && entry.view !== itemView) {
54
79
  unmount(item.id, entry);
55
80
  entry = void 0;
@@ -58,13 +83,13 @@ function createBoardItemViewLayer(host, editor, views, camera) {
58
83
  const node = host.ownerDocument.createElement("div");
59
84
  node.dataset.boardItem = item.id;
60
85
  node.style.cssText = `position:absolute;pointer-events:none;transform-origin:center;${style}`;
61
- element.appendChild(node);
86
+ world.appendChild(node);
62
87
  mounted.set(item.id, {
63
88
  view: itemView,
64
89
  element: node,
65
90
  instance: itemView.mount(node, item, context),
66
91
  item,
67
- zoom: context.zoom,
92
+ detailed: context.detailed,
68
93
  selected: context.selected,
69
94
  style
70
95
  });
@@ -74,9 +99,9 @@ function createBoardItemViewLayer(host, editor, views, camera) {
74
99
  entry.element.style.cssText = `position:absolute;pointer-events:none;transform-origin:center;${style}`;
75
100
  entry.style = style;
76
101
  }
77
- if (entry.item !== item || entry.zoom !== context.zoom || entry.selected !== context.selected) {
102
+ if (entry.item !== item || entry.detailed !== context.detailed || entry.selected !== context.selected) {
78
103
  entry.item = item;
79
- entry.zoom = context.zoom;
104
+ entry.detailed = context.detailed;
80
105
  entry.selected = context.selected;
81
106
  entry.instance.update?.(item, context);
82
107
  }
@@ -84,6 +109,10 @@ function createBoardItemViewLayer(host, editor, views, camera) {
84
109
  for (const [id, entry] of mounted) if (!live.has(id)) unmount(id, entry);
85
110
  },
86
111
  destroy() {
112
+ element.removeEventListener("pointerdown", pointerDown, true);
113
+ element.removeEventListener("focusout", onInvalidate);
114
+ host.ownerDocument.removeEventListener("pointerup", pointerEnd, true);
115
+ host.ownerDocument.removeEventListener("pointercancel", pointerEnd, true);
87
116
  for (const [id, entry] of mounted) unmount(id, entry);
88
117
  element.remove();
89
118
  }
@@ -2767,6 +2767,7 @@ declare const harnessArchiveSchema: z.ZodObject<{
2767
2767
  harness: z.ZodEnum<{
2768
2768
  claude: "claude";
2769
2769
  codex: "codex";
2770
+ cursor: "cursor";
2770
2771
  pi: "pi";
2771
2772
  workbuddy: "workbuddy";
2772
2773
  }>;
@@ -2777,6 +2778,7 @@ declare const harnessArchiveIndexSchema: z.ZodObject<{
2777
2778
  harness: z.ZodEnum<{
2778
2779
  claude: "claude";
2779
2780
  codex: "codex";
2781
+ cursor: "cursor";
2780
2782
  pi: "pi";
2781
2783
  workbuddy: "workbuddy";
2782
2784
  }>;
@@ -2814,7 +2816,7 @@ declare function validateArchiveBoundary(index: HarnessArchiveIndex, parent: Har
2814
2816
  //#endregion
2815
2817
  //#region ../protocol/dist/runtime/harnesses.d.ts
2816
2818
  /** Single source of truth for local Harness identities. Adding a Harness starts here. */
2817
- declare const LOCAL_HARNESSES: readonly ["pi", "codex", "claude", "workbuddy"];
2819
+ declare const LOCAL_HARNESSES: readonly ["pi", "codex", "claude", "workbuddy", "cursor"];
2818
2820
  type LocalHarness = typeof LOCAL_HARNESSES[number];
2819
2821
  type LocalHarnessSpec = {
2820
2822
  label: string;
@@ -2827,6 +2829,7 @@ declare const LOCAL_HARNESS_SPECS: Readonly<Record<LocalHarness, LocalHarnessSpe
2827
2829
  declare const localHarnessSchema: z.ZodEnum<{
2828
2830
  claude: "claude";
2829
2831
  codex: "codex";
2832
+ cursor: "cursor";
2830
2833
  pi: "pi";
2831
2834
  workbuddy: "workbuddy";
2832
2835
  }>;
@@ -2834,6 +2837,7 @@ declare const harnessSchema: z.ZodEnum<{
2834
2837
  claude: "claude";
2835
2838
  codex: "codex";
2836
2839
  cohub: "cohub";
2840
+ cursor: "cursor";
2837
2841
  pi: "pi";
2838
2842
  workbuddy: "workbuddy";
2839
2843
  }>;
@@ -2973,6 +2977,7 @@ declare const nativeIngestSchema: z.ZodObject<{
2973
2977
  harness: z.ZodEnum<{
2974
2978
  claude: "claude";
2975
2979
  codex: "codex";
2980
+ cursor: "cursor";
2976
2981
  pi: "pi";
2977
2982
  workbuddy: "workbuddy";
2978
2983
  }>;
@@ -3023,6 +3028,7 @@ declare const nativeRuntimeEventSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
3023
3028
  harness: z.ZodEnum<{
3024
3029
  claude: "claude";
3025
3030
  codex: "codex";
3031
+ cursor: "cursor";
3026
3032
  pi: "pi";
3027
3033
  workbuddy: "workbuddy";
3028
3034
  }>;
@@ -3271,6 +3277,7 @@ declare const runtimeCapabilitiesSchema: z.ZodObject<{
3271
3277
  harnesses: z.ZodArray<z.ZodEnum<{
3272
3278
  claude: "claude";
3273
3279
  codex: "codex";
3280
+ cursor: "cursor";
3274
3281
  pi: "pi";
3275
3282
  workbuddy: "workbuddy";
3276
3283
  }>>;
@@ -3278,6 +3285,7 @@ declare const runtimeCapabilitiesSchema: z.ZodObject<{
3278
3285
  harness: z.ZodEnum<{
3279
3286
  claude: "claude";
3280
3287
  codex: "codex";
3288
+ cursor: "cursor";
3281
3289
  pi: "pi";
3282
3290
  workbuddy: "workbuddy";
3283
3291
  }>;
@@ -3313,6 +3321,7 @@ declare const runtimePendingExecutionSchema: z.ZodObject<{
3313
3321
  harness: z.ZodEnum<{
3314
3322
  claude: "claude";
3315
3323
  codex: "codex";
3324
+ cursor: "cursor";
3316
3325
  pi: "pi";
3317
3326
  workbuddy: "workbuddy";
3318
3327
  }>;
@@ -3503,6 +3512,7 @@ declare const runtimeEventSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
3503
3512
  harness: z.ZodEnum<{
3504
3513
  claude: "claude";
3505
3514
  codex: "codex";
3515
+ cursor: "cursor";
3506
3516
  pi: "pi";
3507
3517
  workbuddy: "workbuddy";
3508
3518
  }>;
@@ -3533,6 +3543,7 @@ declare const runtimeCommandSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
3533
3543
  harness: z.ZodEnum<{
3534
3544
  claude: "claude";
3535
3545
  codex: "codex";
3546
+ cursor: "cursor";
3536
3547
  pi: "pi";
3537
3548
  workbuddy: "workbuddy";
3538
3549
  }>;
@@ -3555,6 +3566,7 @@ declare const runtimeCommandSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
3555
3566
  harness: z.ZodEnum<{
3556
3567
  claude: "claude";
3557
3568
  codex: "codex";
3569
+ cursor: "cursor";
3558
3570
  pi: "pi";
3559
3571
  workbuddy: "workbuddy";
3560
3572
  }>;
@@ -3603,6 +3615,7 @@ declare const runtimeCommandSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
3603
3615
  harness: z.ZodEnum<{
3604
3616
  claude: "claude";
3605
3617
  codex: "codex";
3618
+ cursor: "cursor";
3606
3619
  pi: "pi";
3607
3620
  workbuddy: "workbuddy";
3608
3621
  }>;
@@ -3667,6 +3680,7 @@ declare const runtimeCommandSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
3667
3680
  harness: z.ZodEnum<{
3668
3681
  claude: "claude";
3669
3682
  codex: "codex";
3683
+ cursor: "cursor";
3670
3684
  pi: "pi";
3671
3685
  workbuddy: "workbuddy";
3672
3686
  }>;
@@ -6536,7 +6550,7 @@ interface SystemOneRequest<Q extends Questions = Questions> {
6536
6550
  model?: string;
6537
6551
  }
6538
6552
  //#endregion
6539
- //#region ../../node_modules/.pnpm/@neta-art+generation@0.1.39/node_modules/@neta-art/generation/dist/builtins-BYR-8YTe.d.ts
6553
+ //#region ../../node_modules/.pnpm/@neta-art+generation@0.1.40/node_modules/@neta-art/generation/dist/builtins-BYR-8YTe.d.ts
6540
6554
  //#region src/types.d.ts
6541
6555
  declare const MODEL_SCHEMA: "neta.generation.model.v1";
6542
6556
  declare const GENERATION_MODEL_CATEGORIES: readonly ["image", "video", "audio", "3d", "decision"];
@@ -73,9 +73,13 @@ type ModelAvailabilityStatus = "operational" | "degraded" | "outage";
73
73
  */
74
74
  type ModelStatusEntry = {
75
75
  status: ModelAvailabilityStatus;
76
- /** 5-minute success rate — drives the selector dot color. Real observed
77
- * traffic (`online`) when available, else the probe self-test window. */
76
+ /** Exact 5-minute success rate. Real observed traffic (`online`) when
77
+ * available, else the probe self-test window. */
78
78
  successRate5m: number | null;
79
+ /** Most recent non-empty success rate used by the selector dot. */
80
+ successRateRecent: number | null;
81
+ /** Window in minutes that produced `successRateRecent`. */
82
+ successRateRecentWindowMinutes: number | null;
79
83
  successRate2h: number | null;
80
84
  successRate24h: number | null;
81
85
  /** 1-hour average / P90 response duration in milliseconds. */
package/dist/index.js CHANGED
@@ -118,6 +118,51 @@ function batchUploadEntries(entries, sizeOf, options = {}) {
118
118
  if (batch.length > 0) batches.push(batch);
119
119
  return batches;
120
120
  }
121
+ const BOARD_DEFAULT_ITEM_SIZE = {
122
+ width: 240,
123
+ height: 160
124
+ };
125
+ const BOARD_DEFAULT_SIZES = {
126
+ frame: {
127
+ width: 480,
128
+ height: 320
129
+ },
130
+ shape: {
131
+ width: 200,
132
+ height: 140
133
+ },
134
+ image: {
135
+ width: 480,
136
+ height: 270
137
+ },
138
+ video: {
139
+ width: 480,
140
+ height: 270
141
+ },
142
+ audio: {
143
+ width: 320,
144
+ height: 112
145
+ },
146
+ file: {
147
+ width: 260,
148
+ height: 132
149
+ },
150
+ task: {
151
+ width: 480,
152
+ height: 270
153
+ },
154
+ effect: {
155
+ width: 240,
156
+ height: 240
157
+ },
158
+ custom: {
159
+ width: 480,
160
+ height: 320
161
+ }
162
+ };
163
+ function boardDefaultSize(type) {
164
+ return { ...Object.hasOwn(BOARD_DEFAULT_SIZES, type) ? BOARD_DEFAULT_SIZES[type] : BOARD_DEFAULT_ITEM_SIZE };
165
+ }
121
166
  //#endregion
122
167
  //#region ../protocol/dist/board-url.js
123
168
  const BOARD_REMOTE_URL_MAX_LENGTH = 4096;
@@ -293,12 +338,9 @@ const itemEnvelope = {
293
338
  locked: z.boolean().optional(),
294
339
  metadata: z.record(z.string(), z.unknown()).optional()
295
340
  };
296
- const boxed = (width, height) => ({
341
+ const boxed = (size) => ({
297
342
  ...itemEnvelope,
298
- size: BoardSizeSchema.default({
299
- width,
300
- height
301
- })
343
+ size: BoardSizeSchema.default({ ...size })
302
344
  });
303
345
  const unsized = { ...itemEnvelope };
304
346
  const fontSize = finite$1.min(2).max(512);
@@ -316,7 +358,7 @@ const BOARD_SHAPE_GEOMETRIES = [
316
358
  "path"
317
359
  ];
318
360
  const BoardFrameItemSchema = z.object({
319
- ...boxed(480, 320),
361
+ ...boxed(BOARD_DEFAULT_SIZES.frame),
320
362
  type: z.literal("frame"),
321
363
  props: z.object({
322
364
  label: z.string().max(280).default(""),
@@ -340,7 +382,7 @@ const BoardTextItemSchema = z.object({
340
382
  }).strict().prefault({})
341
383
  }).strict();
342
384
  const BoardShapeItemSchema = z.object({
343
- ...boxed(240, 160),
385
+ ...boxed(BOARD_DEFAULT_SIZES.shape),
344
386
  type: z.literal("shape"),
345
387
  props: z.object({
346
388
  geometry: z.enum(BOARD_SHAPE_GEOMETRIES).default("rectangle"),
@@ -440,7 +482,7 @@ const BoardCropSchema = z.object({
440
482
  h: ratio
441
483
  }).strict().describe("Region shown, as fractions of the image. Without it the whole image fits inside size.");
442
484
  const BoardImageItemSchema = z.object({
443
- ...boxed(640, 360),
485
+ ...boxed(BOARD_DEFAULT_SIZES.image),
444
486
  type: z.literal("image"),
445
487
  props: z.object({
446
488
  ...mediaProps,
@@ -448,17 +490,17 @@ const BoardImageItemSchema = z.object({
448
490
  }).strict()
449
491
  }).strict();
450
492
  const BoardVideoItemSchema = z.object({
451
- ...boxed(640, 360),
493
+ ...boxed(BOARD_DEFAULT_SIZES.video),
452
494
  type: z.literal("video"),
453
495
  props: z.object(timedFileProps).strict()
454
496
  }).strict();
455
497
  const BoardAudioItemSchema = z.object({
456
- ...boxed(480, 96),
498
+ ...boxed(BOARD_DEFAULT_SIZES.audio),
457
499
  type: z.literal("audio"),
458
500
  props: z.object(timedFileProps).strict()
459
501
  }).strict();
460
502
  const BoardFileItemSchema = z.object({
461
- ...boxed(360, 220),
503
+ ...boxed(BOARD_DEFAULT_SIZES.file),
462
504
  type: z.literal("file"),
463
505
  props: z.object(fileProps).strict()
464
506
  }).strict();
@@ -515,7 +557,7 @@ const BoardTaskSnapshotSchema = z.object({
515
557
  updatedAt: z.string().optional()
516
558
  }).strict();
517
559
  const BoardTaskItemSchema = z.object({
518
- ...boxed(420, 240),
560
+ ...boxed(BOARD_DEFAULT_SIZES.task),
519
561
  type: z.literal("task"),
520
562
  props: z.object({
521
563
  taskRunId: z.string().min(1).max(160).describe("The generation run shown; the server keeps the card's status and results up to date."),
@@ -530,7 +572,7 @@ const BOARD_EFFECT_KINDS = [
530
572
  "glow"
531
573
  ];
532
574
  const BoardEffectItemSchema = z.object({
533
- ...boxed(240, 240),
575
+ ...boxed(BOARD_DEFAULT_SIZES.effect),
534
576
  type: z.literal("effect"),
535
577
  props: z.object({
536
578
  kind: z.enum(BOARD_EFFECT_KINDS),
@@ -547,18 +589,14 @@ const BoardEffectItemSchema = z.object({
547
589
  }).strict()
548
590
  }).strict();
549
591
  const BoardCustomItemSchema = z.object({
550
- ...boxed(480, 320),
592
+ ...boxed(BOARD_DEFAULT_SIZES.custom),
551
593
  type: z.literal("custom"),
552
594
  script: BoardScriptSchema,
553
595
  props: z.object({}).strict().default({})
554
596
  }).strict();
555
597
  const BOARD_EXTENSION_TYPE_PATTERN = /^[a-z][a-z0-9]*(?:\.[a-z0-9-]+)+$/;
556
598
  const BoardExtensionItemSchema = z.object({
557
- ...itemEnvelope,
558
- size: BoardSizeSchema.default({
559
- width: 240,
560
- height: 160
561
- }),
599
+ ...boxed(BOARD_DEFAULT_ITEM_SIZE),
562
600
  type: z.string().regex(BOARD_EXTENSION_TYPE_PATTERN),
563
601
  props: z.record(z.string(), z.unknown()).default({})
564
602
  }).strict();
@@ -1098,8 +1136,7 @@ function createBoardLayout(initialLookup, dependents) {
1098
1136
  } else box = {
1099
1137
  x: 0,
1100
1138
  y: 0,
1101
- width: 240,
1102
- height: 160
1139
+ ...boardDefaultSize(item.type)
1103
1140
  };
1104
1141
  boxes.set(id, box);
1105
1142
  return box;
@@ -2718,7 +2755,8 @@ const LOCAL_HARNESSES = [
2718
2755
  "pi",
2719
2756
  "codex",
2720
2757
  "claude",
2721
- "workbuddy"
2758
+ "workbuddy",
2759
+ "cursor"
2722
2760
  ];
2723
2761
  const LOCAL_HARNESS_SPECS = {
2724
2762
  pi: {
@@ -2740,6 +2778,11 @@ const LOCAL_HARNESS_SPECS = {
2740
2778
  label: "WorkBuddy",
2741
2779
  nativeFormat: "codebuddy.jsonl",
2742
2780
  readOnly: true
2781
+ },
2782
+ cursor: {
2783
+ label: "Cursor",
2784
+ nativeFormat: "cursor.jsonl",
2785
+ readOnly: false
2743
2786
  }
2744
2787
  };
2745
2788
  const localHarnessSchema = z.enum(LOCAL_HARNESSES);
@@ -1,6 +1,61 @@
1
1
  //#region ../protocol/dist/board-constants.js
2
2
  const BOARD_TEXT_FONT_FAMILY = "Geist";
3
3
  const BOARD_ARROW_STROKE_SIZE = 2.5;
4
+ const BOARD_PAGE_SIZE = {
5
+ width: 960,
6
+ height: 540
7
+ };
8
+ const BOARD_TEXT_SCALE = {
9
+ title: 56,
10
+ heading: 40,
11
+ body: 24,
12
+ caption: 16
13
+ };
14
+ const BOARD_DEFAULT_ITEM_SIZE = {
15
+ width: 240,
16
+ height: 160
17
+ };
18
+ const BOARD_DEFAULT_SIZES = {
19
+ frame: {
20
+ width: 480,
21
+ height: 320
22
+ },
23
+ shape: {
24
+ width: 200,
25
+ height: 140
26
+ },
27
+ image: {
28
+ width: 480,
29
+ height: 270
30
+ },
31
+ video: {
32
+ width: 480,
33
+ height: 270
34
+ },
35
+ audio: {
36
+ width: 320,
37
+ height: 112
38
+ },
39
+ file: {
40
+ width: 260,
41
+ height: 132
42
+ },
43
+ task: {
44
+ width: 480,
45
+ height: 270
46
+ },
47
+ effect: {
48
+ width: 240,
49
+ height: 240
50
+ },
51
+ custom: {
52
+ width: 480,
53
+ height: 320
54
+ }
55
+ };
56
+ function boardDefaultSize(type) {
57
+ return { ...Object.hasOwn(BOARD_DEFAULT_SIZES, type) ? BOARD_DEFAULT_SIZES[type] : BOARD_DEFAULT_ITEM_SIZE };
58
+ }
4
59
  const BOARD_STROKE_MIN_SIZE = 1;
5
60
  const BOARD_STROKE_MAX_SIZE = 64;
6
61
  function clampBoardStrokeSize(size) {
@@ -10,4 +65,4 @@ function clampBoardStrokeSize(size) {
10
65
  const BOARD_FONT_STACK = "\"Geist\", system-ui, -apple-system, \"Noto Sans CJK SC\", \"Noto Sans SC\", \"PingFang SC\", \"Microsoft YaHei\", \"Noto Sans Math\", \"Noto Sans Symbols 2\", \"DejaVu Sans\", \"FreeSans\", \"FreeSerif\", sans-serif";
11
66
  const BOARD_MONO_FONT_STACK = "\"Geist Mono\", \"Fira Code\", ui-monospace, \"Noto Sans Mono CJK SC\", \"Noto Sans Math\", \"DejaVu Sans\", \"FreeSans\", \"FreeSerif\", monospace";
12
67
  //#endregion
13
- export { BOARD_ARROW_STROKE_SIZE, BOARD_FONT_STACK, BOARD_MONO_FONT_STACK, BOARD_STROKE_MAX_SIZE, BOARD_STROKE_MIN_SIZE, BOARD_TEXT_FONT_FAMILY, clampBoardStrokeSize };
68
+ export { BOARD_ARROW_STROKE_SIZE, BOARD_DEFAULT_ITEM_SIZE, BOARD_DEFAULT_SIZES, BOARD_FONT_STACK, BOARD_MONO_FONT_STACK, BOARD_PAGE_SIZE, BOARD_STROKE_MAX_SIZE, BOARD_STROKE_MIN_SIZE, BOARD_TEXT_FONT_FAMILY, BOARD_TEXT_SCALE, boardDefaultSize, clampBoardStrokeSize };
@@ -26,6 +26,13 @@ type BoardTextLayout = {
26
26
  };
27
27
  declare function clampBoardFontSize(fontSize: number): number;
28
28
  declare function layoutBoardText(props: Pick<BoardTextItem["props"], "text" | "fontSize" | "fontWeight" | "font" | "lineHeight" | "width">): BoardTextLayout;
29
+ declare function fitBoardMediaSize(natural: {
30
+ width: number;
31
+ height: number;
32
+ }, edge: number): {
33
+ width: number;
34
+ height: number;
35
+ } | null;
29
36
  declare function drawSampleRadius(strokeWidth: number, pressure: number): number;
30
37
  declare function drawPointsBounds(points: readonly BoardDrawPoint[], strokeWidth: number): BoardRect;
31
38
  declare function pointsRect(points: readonly BoardVec2[]): BoardRect;
@@ -56,4 +63,4 @@ declare function sideAnchor(side: "top" | "right" | "bottom" | "left", offset: n
56
63
  declare function anchorPoint(frame: BoardFrame, anchor: BoardArrowAnchor, toward: BoardVec2): BoardVec2;
57
64
  declare function createDocumentLayout(items: Readonly<Record<string, BoardItem>>): BoardLayout;
58
65
  //#endregion
59
- export { BoardFrame, BoardItemLookup, BoardLayout, BoardMatrix, BoardRect, BoardTextLayout, BoardTextMeasurer, IDENTITY_MATRIX, anchorPoint, applyMatrix, arrowBindings, autoAnchorSide, bendControl, clampBoardFontSize, createBoardLayout, createDocumentLayout, drawPointsBounds, drawSampleRadius, estimateTextWidth, framePoint, invertMatrix, isArrowBinding, layoutBoardText, multiplyMatrix, pointsRect, rotateAround, scaleVector, setBoardTextMeasurer, sideAnchor };
66
+ export { BoardFrame, BoardItemLookup, BoardLayout, BoardMatrix, BoardRect, BoardTextLayout, BoardTextMeasurer, IDENTITY_MATRIX, anchorPoint, applyMatrix, arrowBindings, autoAnchorSide, bendControl, clampBoardFontSize, createBoardLayout, createDocumentLayout, drawPointsBounds, drawSampleRadius, estimateTextWidth, fitBoardMediaSize, framePoint, invertMatrix, isArrowBinding, layoutBoardText, multiplyMatrix, pointsRect, rotateAround, scaleVector, setBoardTextMeasurer, sideAnchor };
@@ -1,4 +1,4 @@
1
- import "./board-constants.js";
1
+ import { boardDefaultSize } from "./board-constants.js";
2
2
  //#region ../protocol/dist/board-layout.js
3
3
  const IDENTITY_MATRIX = [
4
4
  1,
@@ -111,6 +111,19 @@ function layoutBoardText(props) {
111
111
  textSizeCache.set(key, layout);
112
112
  return layout;
113
113
  }
114
+ function fitBoardMediaSize(natural, edge) {
115
+ const { width, height } = natural;
116
+ if (![
117
+ width,
118
+ height,
119
+ edge
120
+ ].every((value) => Number.isFinite(value) && value > 0)) return null;
121
+ const scale = edge / Math.max(width, height);
122
+ return {
123
+ width: Math.max(1, Math.round(width * scale)),
124
+ height: Math.max(1, Math.round(height * scale))
125
+ };
126
+ }
114
127
  function drawSampleRadius(strokeWidth, pressure) {
115
128
  const clamped = Math.min(1, Math.max(0, pressure));
116
129
  return Math.max(.5, strokeWidth / 2 * (.5 + clamped));
@@ -275,8 +288,7 @@ function createBoardLayout(initialLookup, dependents) {
275
288
  } else box = {
276
289
  x: 0,
277
290
  y: 0,
278
- width: 240,
279
- height: 160
291
+ ...boardDefaultSize(item.type)
280
292
  };
281
293
  boxes.set(id, box);
282
294
  return box;
@@ -479,4 +491,4 @@ function createDocumentLayout(items) {
479
491
  return createBoardLayout((id) => items[id], dependents);
480
492
  }
481
493
  //#endregion
482
- export { IDENTITY_MATRIX, anchorPoint, applyMatrix, arrowBindings, autoAnchorSide, bendControl, clampBoardFontSize, createBoardLayout, createDocumentLayout, drawPointsBounds, drawSampleRadius, estimateTextWidth, framePoint, invertMatrix, isArrowBinding, layoutBoardText, multiplyMatrix, pointsRect, rotateAround, scaleVector, setBoardTextMeasurer, sideAnchor };
494
+ export { IDENTITY_MATRIX, anchorPoint, applyMatrix, arrowBindings, autoAnchorSide, bendControl, clampBoardFontSize, createBoardLayout, createDocumentLayout, drawPointsBounds, drawSampleRadius, estimateTextWidth, fitBoardMediaSize, framePoint, invertMatrix, isArrowBinding, layoutBoardText, multiplyMatrix, pointsRect, rotateAround, scaleVector, setBoardTextMeasurer, sideAnchor };