@neta-art/cohub 3.2.0 → 4.0.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.
- package/dist/board/codec.js +0 -9
- package/dist/board/core/draw-geometry.d.ts +3 -4
- package/dist/board/core/draw-geometry.js +21 -29
- package/dist/board/core/file-preview.d.ts +4 -2
- package/dist/board/core/file-preview.js +20 -9
- package/dist/board/core/palette.d.ts +2 -2
- package/dist/board/core/palette.js +28 -0
- package/dist/board/core/shape-types.d.ts +2 -6
- package/dist/board/core/text-metrics.d.ts +2 -2
- package/dist/board/core/text-metrics.js +2 -2
- package/dist/board/core/tool-styles.d.ts +52 -0
- package/dist/board/core/tool-styles.js +51 -0
- package/dist/board/geometry.d.ts +9 -1
- package/dist/board/geometry.js +25 -1
- package/dist/board/index.d.ts +6 -5
- package/dist/board/index.js +5 -4
- package/dist/board/render/renderers/board-renderer-registry.js +0 -2
- package/dist/board/render/renderers/file-card-renderer.d.ts +8 -1
- package/dist/board/render/renderers/file-card-renderer.js +37 -58
- package/dist/board/render/themes/board-theme-registry.d.ts +2 -0
- package/dist/board/render/themes/clean-theme.js +6 -3
- package/dist/chunks/http.d.ts +2 -2
- package/dist/chunks/http.js +4 -0
- package/dist/chunks/websocket.d.ts +54 -2
- package/dist/http.d.ts +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/protocol/dist/board-constants.js +2 -1
- package/dist/protocol/dist/board-document.d.ts +3 -80
- package/dist/protocol/dist/board-document.js +4 -14
- package/dist/protocol/dist/realtime/board-awareness.js +3 -1
- package/docs/work-runtime-guide.md +68 -2
- package/package.json +3 -2
- package/dist/board/render/renderers/note-card-renderer.d.ts +0 -5
- package/dist/board/render/renderers/note-card-renderer.js +0 -112
|
@@ -110,38 +110,6 @@ declare const BoardTextItemSchema: z.ZodObject<{
|
|
|
110
110
|
color: z.ZodDefault<z.ZodString>;
|
|
111
111
|
fontSize: z.ZodDefault<z.ZodNumber>;
|
|
112
112
|
}, z.core.$strip>;
|
|
113
|
-
declare const BoardNoteItemSchema: z.ZodObject<{
|
|
114
|
-
id: z.ZodString;
|
|
115
|
-
frame: z.ZodObject<{
|
|
116
|
-
x: z.ZodNumber;
|
|
117
|
-
y: z.ZodNumber;
|
|
118
|
-
width: z.ZodNumber;
|
|
119
|
-
height: z.ZodNumber;
|
|
120
|
-
rotation: z.ZodDefault<z.ZodNumber>;
|
|
121
|
-
}, z.core.$strip>;
|
|
122
|
-
locked: z.ZodOptional<z.ZodBoolean>;
|
|
123
|
-
style: z.ZodOptional<z.ZodObject<{
|
|
124
|
-
variant: z.ZodDefault<z.ZodString>;
|
|
125
|
-
theme: z.ZodOptional<z.ZodString>;
|
|
126
|
-
accentColor: z.ZodOptional<z.ZodString>;
|
|
127
|
-
size: z.ZodDefault<z.ZodEnum<{
|
|
128
|
-
lg: "lg";
|
|
129
|
-
md: "md";
|
|
130
|
-
sm: "sm";
|
|
131
|
-
}>>;
|
|
132
|
-
emphasis: z.ZodDefault<z.ZodEnum<{
|
|
133
|
-
epic: "epic";
|
|
134
|
-
legendary: "legendary";
|
|
135
|
-
normal: "normal";
|
|
136
|
-
rare: "rare";
|
|
137
|
-
}>>;
|
|
138
|
-
effects: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
139
|
-
}, z.core.$strip>>;
|
|
140
|
-
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
141
|
-
type: z.ZodLiteral<"note">;
|
|
142
|
-
text: z.ZodDefault<z.ZodString>;
|
|
143
|
-
color: z.ZodDefault<z.ZodString>;
|
|
144
|
-
}, z.core.$strip>;
|
|
145
113
|
declare const BoardGeoItemSchema: z.ZodObject<{
|
|
146
114
|
id: z.ZodString;
|
|
147
115
|
frame: z.ZodObject<{
|
|
@@ -490,7 +458,7 @@ declare const BoardFileItemSchema: z.ZodObject<{
|
|
|
490
458
|
* authored by newer clients round-trip losslessly — data is never dropped or
|
|
491
459
|
* silently downgraded just because this client predates a shape type.
|
|
492
460
|
*/
|
|
493
|
-
declare const KNOWN_BOARD_ITEM_TYPES: readonly ["image", "video", "file", "text", "
|
|
461
|
+
declare const KNOWN_BOARD_ITEM_TYPES: readonly ["image", "video", "file", "text", "geo", "draw", "arrow", "frame"];
|
|
494
462
|
type KnownBoardItemType = (typeof KNOWN_BOARD_ITEM_TYPES)[number];
|
|
495
463
|
/**
|
|
496
464
|
* A forward-compatible carrier for shape types this client does not recognise.
|
|
@@ -637,28 +605,6 @@ declare const BoardItemSchema: z.ZodPipe<z.ZodAny, z.ZodTransform<BoardUnknownIt
|
|
|
637
605
|
text: string;
|
|
638
606
|
color: string;
|
|
639
607
|
fontSize: number;
|
|
640
|
-
} | {
|
|
641
|
-
id: string;
|
|
642
|
-
frame: {
|
|
643
|
-
x: number;
|
|
644
|
-
y: number;
|
|
645
|
-
width: number;
|
|
646
|
-
height: number;
|
|
647
|
-
rotation: number;
|
|
648
|
-
};
|
|
649
|
-
locked?: boolean | undefined;
|
|
650
|
-
style?: {
|
|
651
|
-
variant: string;
|
|
652
|
-
theme?: string | undefined;
|
|
653
|
-
accentColor?: string | undefined;
|
|
654
|
-
size: "lg" | "md" | "sm";
|
|
655
|
-
emphasis: "epic" | "legendary" | "normal" | "rare";
|
|
656
|
-
effects: string[];
|
|
657
|
-
} | undefined;
|
|
658
|
-
metadata?: Record<string, unknown> | undefined;
|
|
659
|
-
type: "note";
|
|
660
|
-
text: string;
|
|
661
|
-
color: string;
|
|
662
608
|
} | {
|
|
663
609
|
id: string;
|
|
664
610
|
frame: {
|
|
@@ -948,28 +894,6 @@ declare const BoardDocumentSchema: z.ZodObject<{
|
|
|
948
894
|
text: string;
|
|
949
895
|
color: string;
|
|
950
896
|
fontSize: number;
|
|
951
|
-
} | {
|
|
952
|
-
id: string;
|
|
953
|
-
frame: {
|
|
954
|
-
x: number;
|
|
955
|
-
y: number;
|
|
956
|
-
width: number;
|
|
957
|
-
height: number;
|
|
958
|
-
rotation: number;
|
|
959
|
-
};
|
|
960
|
-
locked?: boolean | undefined;
|
|
961
|
-
style?: {
|
|
962
|
-
variant: string;
|
|
963
|
-
theme?: string | undefined;
|
|
964
|
-
accentColor?: string | undefined;
|
|
965
|
-
size: "lg" | "md" | "sm";
|
|
966
|
-
emphasis: "epic" | "legendary" | "normal" | "rare";
|
|
967
|
-
effects: string[];
|
|
968
|
-
} | undefined;
|
|
969
|
-
metadata?: Record<string, unknown> | undefined;
|
|
970
|
-
type: "note";
|
|
971
|
-
text: string;
|
|
972
|
-
color: string;
|
|
973
897
|
} | {
|
|
974
898
|
id: string;
|
|
975
899
|
frame: {
|
|
@@ -1100,7 +1024,6 @@ type BoardItemStyle = z.infer<typeof BoardItemStyleSchema>;
|
|
|
1100
1024
|
type SpaceFileRef = z.infer<typeof SpaceFileRefSchema>;
|
|
1101
1025
|
type BoardMediaSnapshot = z.infer<typeof BoardMediaSnapshotSchema>;
|
|
1102
1026
|
type BoardTextItem = z.infer<typeof BoardTextItemSchema>;
|
|
1103
|
-
type BoardNoteItem = z.infer<typeof BoardNoteItemSchema>;
|
|
1104
1027
|
type BoardGeoItem = z.infer<typeof BoardGeoItemSchema>;
|
|
1105
1028
|
type DrawPoint = z.infer<typeof DrawPointSchema>;
|
|
1106
1029
|
type BoardDrawItem = z.infer<typeof BoardDrawItemSchema>;
|
|
@@ -1112,7 +1035,7 @@ type BoardVideoItem = z.infer<typeof BoardVideoItemSchema>;
|
|
|
1112
1035
|
type BoardFileSnapshot = z.infer<typeof BoardFileSnapshotSchema>;
|
|
1113
1036
|
type BoardFileItem = z.infer<typeof BoardFileItemSchema>;
|
|
1114
1037
|
/** Known (natively handled) item variants. */
|
|
1115
|
-
type BoardKnownItem = BoardImageItem | BoardVideoItem | BoardFileItem | BoardTextItem |
|
|
1038
|
+
type BoardKnownItem = BoardImageItem | BoardVideoItem | BoardFileItem | BoardTextItem | BoardGeoItem | BoardDrawItem | BoardArrowItem | BoardFrameItem;
|
|
1116
1039
|
/** Any item, including forward-compatible unknown types. */
|
|
1117
1040
|
type BoardItem = BoardKnownItem | BoardUnknownItem;
|
|
1118
1041
|
type BoardDocument = z.infer<typeof BoardDocumentSchema>;
|
|
@@ -1121,4 +1044,4 @@ declare function isMediaItem(item: BoardItem): item is BoardImageItem | BoardVid
|
|
|
1121
1044
|
/** Whether an item references a workspace file (image, video or file card). */
|
|
1122
1045
|
declare function isFileBackedItem(item: BoardItem): item is BoardImageItem | BoardVideoItem | BoardFileItem;
|
|
1123
1046
|
//#endregion
|
|
1124
|
-
export { ArrowEndpoint, ArrowEndpointSchema, BOARD_DOCUMENT_KIND, BOARD_EXTENSION, BoardAppearance, BoardAppearanceSchema, BoardArrowItem, BoardArrowItemSchema, BoardDocument, BoardDocumentSchema, BoardDrawItem, BoardDrawItemSchema, BoardFileItem, BoardFileItemSchema, BoardFileSnapshot, BoardFileSnapshotSchema, BoardFrame, BoardFrameItem, BoardFrameItemSchema, BoardFrameSchema, BoardGeoItem, BoardGeoItemSchema, BoardImageItem, BoardImageItemSchema, BoardItem, BoardItemSchema, BoardItemStyle, BoardItemStyleSchema, BoardKnownItem, BoardMediaSnapshot, BoardMediaSnapshotSchema,
|
|
1047
|
+
export { ArrowEndpoint, ArrowEndpointSchema, BOARD_DOCUMENT_KIND, BOARD_EXTENSION, BoardAppearance, BoardAppearanceSchema, BoardArrowItem, BoardArrowItemSchema, BoardDocument, BoardDocumentSchema, BoardDrawItem, BoardDrawItemSchema, BoardFileItem, BoardFileItemSchema, BoardFileSnapshot, BoardFileSnapshotSchema, BoardFrame, BoardFrameItem, BoardFrameItemSchema, BoardFrameSchema, BoardGeoItem, BoardGeoItemSchema, BoardImageItem, BoardImageItemSchema, BoardItem, BoardItemSchema, BoardItemStyle, BoardItemStyleSchema, BoardKnownItem, BoardMediaSnapshot, BoardMediaSnapshotSchema, BoardTextItem, BoardTextItemSchema, BoardUnknownItem, BoardVideoItem, BoardVideoItemSchema, BoardViewport, BoardViewportSchema, DrawPoint, DrawPointSchema, KNOWN_BOARD_ITEM_TYPES, KnownBoardItemType, SpaceFileRef, SpaceFileRefSchema, UNKNOWN_BOARD_ITEM_TYPE, isFileBackedItem, isMediaItem, isUnknownItem, parseBoardItemLoose, unknownRealType };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import "./board-constants.js";
|
|
1
|
+
import { BOARD_ARROW_STROKE_SIZE } from "./board-constants.js";
|
|
2
2
|
import { BOARD_DOCUMENT_KIND, BOARD_EXTENSION } from "./board.js";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
//#region ../protocol/dist/board-document.js
|
|
@@ -95,12 +95,7 @@ const BoardTextItemSchema = BoardItemBaseSchema.extend({
|
|
|
95
95
|
type: z.literal("text"),
|
|
96
96
|
text: z.string().default(""),
|
|
97
97
|
color: z.string().min(1).default("neutral"),
|
|
98
|
-
fontSize: z.number().finite().min(2).max(512).default(
|
|
99
|
-
});
|
|
100
|
-
const BoardNoteItemSchema = BoardItemBaseSchema.extend({
|
|
101
|
-
type: z.literal("note"),
|
|
102
|
-
text: z.string().default(""),
|
|
103
|
-
color: z.string().min(1).default("amber")
|
|
98
|
+
fontSize: z.number().finite().min(2).max(512).default(24)
|
|
104
99
|
});
|
|
105
100
|
const BoardGeoItemSchema = BoardItemBaseSchema.extend({
|
|
106
101
|
type: z.literal("geo"),
|
|
@@ -139,7 +134,7 @@ const BoardArrowItemSchema = BoardItemBaseSchema.extend({
|
|
|
139
134
|
end: ArrowEndpointSchema,
|
|
140
135
|
bend: z.number().finite().default(0),
|
|
141
136
|
color: z.string().min(1).default("brand"),
|
|
142
|
-
size: z.number().finite().positive().default(
|
|
137
|
+
size: z.number().finite().positive().default(BOARD_ARROW_STROKE_SIZE),
|
|
143
138
|
arrowStart: z.boolean().default(false),
|
|
144
139
|
arrowEnd: z.boolean().default(true),
|
|
145
140
|
label: z.string().default("")
|
|
@@ -215,7 +210,6 @@ const KNOWN_BOARD_ITEM_TYPES = [
|
|
|
215
210
|
"video",
|
|
216
211
|
"file",
|
|
217
212
|
"text",
|
|
218
|
-
"note",
|
|
219
213
|
"geo",
|
|
220
214
|
"draw",
|
|
221
215
|
"arrow",
|
|
@@ -258,10 +252,6 @@ function parseBoardItemLoose(raw) {
|
|
|
258
252
|
const parsed = BoardTextItemSchema.safeParse(raw);
|
|
259
253
|
return parsed.success ? parsed.data : makeUnknownItem(raw);
|
|
260
254
|
}
|
|
261
|
-
case "note": {
|
|
262
|
-
const parsed = BoardNoteItemSchema.safeParse(raw);
|
|
263
|
-
return parsed.success ? parsed.data : makeUnknownItem(raw);
|
|
264
|
-
}
|
|
265
255
|
case "geo": {
|
|
266
256
|
const parsed = BoardGeoItemSchema.safeParse(raw);
|
|
267
257
|
return parsed.success ? parsed.data : makeUnknownItem(raw);
|
|
@@ -328,4 +318,4 @@ function isFileBackedItem(item) {
|
|
|
328
318
|
return item.type === "image" || item.type === "video" || item.type === "file";
|
|
329
319
|
}
|
|
330
320
|
//#endregion
|
|
331
|
-
export { ArrowEndpointSchema, BOARD_DOCUMENT_KIND, BOARD_EXTENSION, BoardAppearanceSchema, BoardArrowItemSchema, BoardDocumentSchema, BoardDrawItemSchema, BoardFileItemSchema, BoardFileSnapshotSchema, BoardFrameItemSchema, BoardFrameSchema, BoardGeoItemSchema, BoardImageItemSchema, BoardItemSchema, BoardItemStyleSchema, BoardMediaSnapshotSchema,
|
|
321
|
+
export { ArrowEndpointSchema, BOARD_DOCUMENT_KIND, BOARD_EXTENSION, BoardAppearanceSchema, BoardArrowItemSchema, BoardDocumentSchema, BoardDrawItemSchema, BoardFileItemSchema, BoardFileSnapshotSchema, BoardFrameItemSchema, BoardFrameSchema, BoardGeoItemSchema, BoardImageItemSchema, BoardItemSchema, BoardItemStyleSchema, BoardMediaSnapshotSchema, BoardTextItemSchema, BoardVideoItemSchema, BoardViewportSchema, DrawPointSchema, KNOWN_BOARD_ITEM_TYPES, SpaceFileRefSchema, UNKNOWN_BOARD_ITEM_TYPE, isFileBackedItem, isMediaItem, isUnknownItem, parseBoardItemLoose, unknownRealType };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { BOARD_ARROW_STROKE_SIZE } from "../board-constants.js";
|
|
1
2
|
import { z } from "zod";
|
|
2
3
|
//#region ../protocol/dist/realtime/board-awareness.js
|
|
3
4
|
const idSchema = z.string().min(1).max(160);
|
|
@@ -66,7 +67,8 @@ const BoardAwarenessGestureSchema = z.discriminatedUnion("kind", [
|
|
|
66
67
|
nodeId: idSchema,
|
|
67
68
|
start: BoardAwarenessPointSchema,
|
|
68
69
|
current: BoardAwarenessPointSchema,
|
|
69
|
-
color: z.string().min(1).max(64)
|
|
70
|
+
color: z.string().min(1).max(64),
|
|
71
|
+
size: finiteSchema.positive().max(256).default(BOARD_ARROW_STROKE_SIZE)
|
|
70
72
|
}),
|
|
71
73
|
z.object({
|
|
72
74
|
kind: z.literal("box"),
|
|
@@ -205,7 +205,8 @@ result needs `taskrun.view` (a work scope).
|
|
|
205
205
|
|---|---|---|---|
|
|
206
206
|
| Read space config | `space.get()` / `space.getConfig()` | `space.view` | work |
|
|
207
207
|
| List models | `client.models.list()` / `listMultimodal()` | *(none — just authenticated)* | — |
|
|
208
|
-
| Send a prompt | `space.prompt({ content, ... })` | `session.prompt.fullaccess`
|
|
208
|
+
| Send a prompt (full) | `space.prompt({ accessMode: "full_access", content, ... })` | `session.prompt.fullaccess` | viewer |
|
|
209
|
+
| Send a prompt (read-only) | `space.prompt({ accessMode: "read_only", content, ... })` | `session.prompt.readonly` | viewer |
|
|
209
210
|
| Read turn result | `session.turns.get(turnId)` | `session.view` | work |
|
|
210
211
|
| Stream generation | `session.subscribeGeneration({ state, finalized })` | `session.view` | work |
|
|
211
212
|
| Read file tree | `space.files.tree()` | `file.view` | work |
|
|
@@ -385,14 +386,23 @@ Assume `client` and `space` are already initialized per [§4](#4-initialization-
|
|
|
385
386
|
### LLM chat (`space.prompt` + `subscribeGeneration`)
|
|
386
387
|
|
|
387
388
|
**Scopes:** viewer `session.prompt.fullaccess` (to send) + work `session.view` (to read/stream).
|
|
389
|
+
For a read-only prompt (no side effects), use viewer `session.prompt.readonly`
|
|
390
|
+
instead — but you **must** pass `accessMode: "read_only"` in the call (see the
|
|
391
|
+
read-only recipe below).
|
|
392
|
+
|
|
393
|
+
> **`accessMode` defaults to `full_access`.** If you omit it, the backend
|
|
394
|
+
treats the call as full-access and requires `session.prompt.fullaccess`. This
|
|
395
|
+
is the #1 cause of "I requested `session.prompt.readonly` but still got 403".
|
|
396
|
+
Always set `accessMode` explicitly to match the scope you requested.
|
|
388
397
|
|
|
389
398
|
`space.prompt()` is **asynchronous** — it returns immediately with a turn
|
|
390
399
|
whose `assistantText` is `null`. You must either stream the reply via
|
|
391
400
|
`subscribeGeneration` or poll `turns.get()`.
|
|
392
401
|
|
|
393
402
|
```js
|
|
394
|
-
// Send a prompt (creates or continues a session)
|
|
403
|
+
// Send a prompt (creates or continues a session) — full access
|
|
395
404
|
const result = await space.prompt({
|
|
405
|
+
accessMode: "full_access", // default; needs session.prompt.fullaccess
|
|
396
406
|
content: [{ type: "text", text: "Describe a shiba inu on Mars." }],
|
|
397
407
|
sessionId: null, // null → creates a new session; pass an id to continue
|
|
398
408
|
model: "gpt-5.5", // optional; omit for default
|
|
@@ -449,6 +459,58 @@ const reply = turn.assistantText;
|
|
|
449
459
|
ignore it, your code silently degrades to polling — which will also 403.
|
|
450
460
|
Surface the error so you can diagnose the missing scope.
|
|
451
461
|
|
|
462
|
+
#### Read-only prompt (`accessMode: "read_only"`)
|
|
463
|
+
|
|
464
|
+
Use this when your Work only needs to **generate** a reply without persisting
|
|
465
|
+
any side effects (no new session is written, no turn stored on the space's
|
|
466
|
+
history). It requires the lighter viewer scope `session.prompt.readonly`
|
|
467
|
+
instead of `session.prompt.fullaccess`.
|
|
468
|
+
|
|
469
|
+
The critical detail: you **must** pass `accessMode: "read_only"` explicitly
|
|
470
|
+
in the `space.prompt()` call. The scope you request via `auth.request` and
|
|
471
|
+
the `accessMode` you send must match — the backend picks the permission check
|
|
472
|
+
based on `accessMode`, defaulting to `full_access` when omitted.
|
|
473
|
+
|
|
474
|
+
```js
|
|
475
|
+
// 1. Request ONLY the read-only scope from a user gesture
|
|
476
|
+
await client.auth.request({
|
|
477
|
+
scopes: ["session.prompt.readonly"],
|
|
478
|
+
reason: "Generate a one-off character reply (read-only).",
|
|
479
|
+
});
|
|
480
|
+
|
|
481
|
+
// 2. Send the prompt with accessMode matching the granted scope
|
|
482
|
+
const result = await space.prompt({
|
|
483
|
+
accessMode: "read_only", // ← required; omitting it → full_access → 403
|
|
484
|
+
sessionId: null, // read-only prompts use a throwaway session
|
|
485
|
+
content: [{ type: "text", text: prompt }],
|
|
486
|
+
});
|
|
487
|
+
const sessionId = result.session.id;
|
|
488
|
+
const turnId = result.turn.id;
|
|
489
|
+
|
|
490
|
+
// 3. Read the reply — still needs the work scope: session.view
|
|
491
|
+
const stop = space.session(sessionId).subscribeGeneration({
|
|
492
|
+
finalized: (event) => {
|
|
493
|
+
const reply = event.turn.assistantText
|
|
494
|
+
?? (event.turn.assistantContent ?? [])
|
|
495
|
+
.filter(b => b.type === "text").map(b => b.text).join("");
|
|
496
|
+
console.log("reply:", reply);
|
|
497
|
+
stop();
|
|
498
|
+
},
|
|
499
|
+
error: (event) => console.error("stream error:", event),
|
|
500
|
+
});
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
Publish the Work with:
|
|
504
|
+
- workScopes: `["space.view", "session.view"]` (still needed to read the reply)
|
|
505
|
+
- allowedViewerScopes: `["session.prompt.readonly"]`
|
|
506
|
+
|
|
507
|
+
> **Scope/accessMode mismatch → 403.** Requesting `session.prompt.readonly`
|
|
508
|
+
but calling `space.prompt({ content })` (no `accessMode`) fails because the
|
|
509
|
+
backend defaults to `full_access` and checks `session.prompt.fullaccess`.
|
|
510
|
+
Symmetrically, requesting `session.prompt.fullaccess` while passing
|
|
511
|
+
`accessMode: "read_only"` also works only if `session.prompt.readonly` is
|
|
512
|
+
additionally granted — otherwise 403. Always keep them in sync.
|
|
513
|
+
|
|
452
514
|
### Image / media generation (`generations.createAndWait`)
|
|
453
515
|
|
|
454
516
|
**Scopes:** viewer `generation.create` (to create) + work `taskrun.view` (to poll).
|
|
@@ -895,6 +957,10 @@ Before publishing your Work, verify each item:
|
|
|
895
957
|
(for file reads). Missing any of these → 403 on reads.
|
|
896
958
|
- [ ] **Viewer scopes include all action operations**: `session.prompt.fullaccess`
|
|
897
959
|
(or `.readonly`) for prompts, `generation.create` for generation.
|
|
960
|
+
- [ ] **`session.prompt.*` scope matches `space.prompt({ accessMode })`.**
|
|
961
|
+
Omitting `accessMode` defaults to `full_access`, so requesting only
|
|
962
|
+
`session.prompt.readonly` and then calling `space.prompt({ content })` → 403.
|
|
963
|
+
Set `accessMode: "read_only"` explicitly when using the readonly scope.
|
|
898
964
|
- [ ] **`session.prompt.fullaccess` does NOT include `session.view`** — they
|
|
899
965
|
are separate. Sending a prompt succeeds but reading the reply 403s without
|
|
900
966
|
`session.view`.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neta-art/cohub",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.1",
|
|
4
4
|
"description": "Cohub SDK for spaces, sessions, boards, and realtime agent collaboration.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"private": false,
|
|
@@ -71,6 +71,7 @@
|
|
|
71
71
|
"NOTICE"
|
|
72
72
|
],
|
|
73
73
|
"dependencies": {
|
|
74
|
+
"perfect-freehand": "1.2.3",
|
|
74
75
|
"zod": "^4.4.3"
|
|
75
76
|
},
|
|
76
77
|
"devDependencies": {
|
|
@@ -99,7 +100,7 @@
|
|
|
99
100
|
"build": "tsdown",
|
|
100
101
|
"lint": "biome lint .",
|
|
101
102
|
"lint:fix": "biome lint --write .",
|
|
102
|
-
"test": "
|
|
103
|
+
"test": "node ../../scripts/test/run.mjs 'src/**/*.test.ts' 'tests/**/*.test.ts'",
|
|
103
104
|
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
104
105
|
}
|
|
105
106
|
}
|
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
import { BOARD_FONT_STACK } from "../../../protocol/dist/board-constants.js";
|
|
2
|
-
import { pickBoardColor } from "../../core/palette.js";
|
|
3
|
-
import { syncTextResolution, syncTextWrapWidth, textResolutionForZoom } from "../text-resolution.js";
|
|
4
|
-
import { drawFarPlate } from "./far-plate.js";
|
|
5
|
-
import { positionShell } from "./base-card-renderer.js";
|
|
6
|
-
import { Container, Graphics, Text } from "pixi.js";
|
|
7
|
-
//#region src/board/render/renderers/note-card-renderer.ts
|
|
8
|
-
const RADIUS = 8;
|
|
9
|
-
const PADDING = 12;
|
|
10
|
-
const partsByContainer = /* @__PURE__ */ new WeakMap();
|
|
11
|
-
function sync(container, item, context) {
|
|
12
|
-
const parts = partsByContainer.get(container);
|
|
13
|
-
if (!parts) return;
|
|
14
|
-
positionShell(parts.root, item);
|
|
15
|
-
const { width, height } = item.frame;
|
|
16
|
-
const selected = context.selectedIds.has(item.id);
|
|
17
|
-
const hovered = context.hoveredId === item.id;
|
|
18
|
-
const color = pickBoardColor(context.colors, item.color, context.colorScheme);
|
|
19
|
-
syncTextResolution(parts.body, parts, context.zoom);
|
|
20
|
-
const resizing = context.resizingIds.has(item.id);
|
|
21
|
-
const visualSig = [
|
|
22
|
-
width,
|
|
23
|
-
height,
|
|
24
|
-
selected,
|
|
25
|
-
hovered,
|
|
26
|
-
color.fill,
|
|
27
|
-
color.stroke,
|
|
28
|
-
context.palette.surface,
|
|
29
|
-
context.palette.muted,
|
|
30
|
-
context.palette.border
|
|
31
|
-
].join("|");
|
|
32
|
-
if (visualSig !== parts.visualSig) {
|
|
33
|
-
parts.visualSig = visualSig;
|
|
34
|
-
parts.background.clear();
|
|
35
|
-
parts.background.roundRect(0, 0, width, height, RADIUS).fill({
|
|
36
|
-
color: color.fill,
|
|
37
|
-
alpha: .16
|
|
38
|
-
}).roundRect(0, 0, width, height, RADIUS).fill({
|
|
39
|
-
color: context.palette.surface,
|
|
40
|
-
alpha: .6
|
|
41
|
-
}).rect(1, 1, width - 2, 4).fill({
|
|
42
|
-
color: color.stroke,
|
|
43
|
-
alpha: .95
|
|
44
|
-
});
|
|
45
|
-
parts.background.roundRect(0, 0, width, height, RADIUS).stroke({
|
|
46
|
-
color: selected ? color.stroke : hovered ? context.palette.muted : context.palette.border,
|
|
47
|
-
width: selected ? 2 : 1,
|
|
48
|
-
alpha: selected ? .95 : .8
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
const textSig = [item.text, color.label].join("|");
|
|
52
|
-
if (textSig !== parts.textSig) {
|
|
53
|
-
parts.textSig = textSig;
|
|
54
|
-
parts.body.text = item.text;
|
|
55
|
-
parts.body.style.fill = color.label;
|
|
56
|
-
}
|
|
57
|
-
syncTextWrapWidth(parts.body, parts, Math.max(1, width - PADDING * 2), resizing);
|
|
58
|
-
parts.body.position.set(PADDING, 16);
|
|
59
|
-
}
|
|
60
|
-
const noteCardRenderer = {
|
|
61
|
-
id: "note-card",
|
|
62
|
-
canRender: (item) => item.type === "note",
|
|
63
|
-
create: (item, context) => {
|
|
64
|
-
const root = new Container();
|
|
65
|
-
const background = new Graphics();
|
|
66
|
-
const resolution = textResolutionForZoom(context.zoom);
|
|
67
|
-
const body = new Text({
|
|
68
|
-
text: "",
|
|
69
|
-
style: {
|
|
70
|
-
fill: 16777215,
|
|
71
|
-
fontFamily: BOARD_FONT_STACK,
|
|
72
|
-
fontSize: 14,
|
|
73
|
-
fontWeight: "500",
|
|
74
|
-
wordWrap: true,
|
|
75
|
-
lineHeight: 20
|
|
76
|
-
},
|
|
77
|
-
resolution,
|
|
78
|
-
roundPixels: true
|
|
79
|
-
});
|
|
80
|
-
root.addChild(background, body);
|
|
81
|
-
partsByContainer.set(root, {
|
|
82
|
-
root,
|
|
83
|
-
background,
|
|
84
|
-
body,
|
|
85
|
-
visualSig: "",
|
|
86
|
-
textSig: "",
|
|
87
|
-
wrapWidth: 0,
|
|
88
|
-
resolution
|
|
89
|
-
});
|
|
90
|
-
if (item.type === "note") sync(root, item, context);
|
|
91
|
-
return root;
|
|
92
|
-
},
|
|
93
|
-
update: (container, item, context) => {
|
|
94
|
-
if (item.type === "note") sync(container, item, context);
|
|
95
|
-
},
|
|
96
|
-
renderFar: (graphics, item, context) => {
|
|
97
|
-
if (item.type !== "note") return;
|
|
98
|
-
const color = pickBoardColor(context.colors, item.color, context.colorScheme);
|
|
99
|
-
drawFarPlate(graphics, item.frame, {
|
|
100
|
-
fill: color.fill,
|
|
101
|
-
fillAlpha: .28,
|
|
102
|
-
accent: color.stroke,
|
|
103
|
-
accentAlpha: .95
|
|
104
|
-
});
|
|
105
|
-
},
|
|
106
|
-
destroy: (container) => {
|
|
107
|
-
partsByContainer.get(container)?.root.destroy({ children: true });
|
|
108
|
-
partsByContainer.delete(container);
|
|
109
|
-
}
|
|
110
|
-
};
|
|
111
|
-
//#endregion
|
|
112
|
-
export { noteCardRenderer };
|