agentic-canvas 0.11.0 → 0.12.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.
- package/README.md +20 -2
- package/dist/{chunk-EE725BJ3.js → chunk-A4YK2SWM.js} +1 -1
- package/dist/cli.js +1 -1
- package/dist/embed.js +20 -16
- package/dist/index.js +1 -1
- package/dist/ui.css +17 -9
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
A shared whiteboard for diagrams, drawn by people and agents.
|
|
9
9
|
|
|
10
|
-
> Status: 0.
|
|
10
|
+
> Status: 0.12.0. The board model, the agent operations, the exports, the CLI, the
|
|
11
11
|
> MCP server, a small Worker API, and live co-editing work. The CLI, the MCP server,
|
|
12
12
|
> and the SDK can join a live room. A remote client calls the Worker API. A small web UI, served by the Worker, is new in 0.4.0.
|
|
13
13
|
> The package exports `agentic-canvas/ui`, a board view you can mount in your own app, new in 0.5.0.
|
|
@@ -111,6 +111,24 @@ There is one method per route: `me`, `listBoards`, `createBoard`, `readBoard`, `
|
|
|
111
111
|
and status 0. The client never retries. A 503 means "try again", and the caller decides, because a
|
|
112
112
|
repeated write can change a board twice. Pass `fetch` to use your own.
|
|
113
113
|
|
|
114
|
+
## Run locally
|
|
115
|
+
|
|
116
|
+
```sh
|
|
117
|
+
git clone https://github.com/pooriaarab/agentic-canvas
|
|
118
|
+
cd agentic-canvas
|
|
119
|
+
npm install && npm run dev
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
You can also use `bun install && bun run dev`. The `dev` script calls npm, so npm must be installed. The scripts need macOS, Linux, or WSL. The `dev` script builds the package, then starts `wrangler dev` on <http://localhost:8793>. Wrangler keeps a local D1 database. The `dev` script turns off Wrangler telemetry. Set `WRANGLER_SEND_METRICS=false` when you run other wrangler commands.
|
|
123
|
+
|
|
124
|
+
```sh
|
|
125
|
+
curl -i http://localhost:8793/health # 200
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
The `dev` script sets `CANVAS_REGION=unknown`, which local Wrangler needs. The API answers 401 until you sign in. For local work, see the dev fallback in "Auth".
|
|
129
|
+
|
|
130
|
+
`npm run dev:smoke` runs the same check by itself. It starts the dev server. It waits for `/health` to answer 200. It stops the server. CI runs it as the "dev smoke" step. To use another port, change `8793` in the `dev` and `dev:smoke` scripts.
|
|
131
|
+
|
|
114
132
|
## Live demo
|
|
115
133
|
|
|
116
134
|
A demo Worker runs on workers.dev: <https://agentic-canvas-demo.hello-fd1.workers.dev>. `GET /health` answers 200
|
|
@@ -240,7 +258,7 @@ What it does:
|
|
|
240
258
|
|
|
241
259
|
- Lists boards, makes a board, and opens one. Empty, loading, and error states have a retry.
|
|
242
260
|
- Draws shapes, connectors, text, and sticky notes. Select, move, resize, connect, and delete an
|
|
243
|
-
item. Pan by dragging the background, zoom with the wheel or the
|
|
261
|
+
item. Pan by dragging the background, zoom with the wheel or the zoom controls on the canvas.
|
|
244
262
|
- Marks an item an agent wrote with an "Agent" tag and in its accessible name. The side panel shows
|
|
245
263
|
who made the item and who last edited it.
|
|
246
264
|
- Shows who is in the board, from the live room (`agentic-realtime`). Edits go over the HTTP API.
|
package/dist/cli.js
CHANGED
package/dist/embed.js
CHANGED
|
@@ -477,25 +477,29 @@ function BoardView({ id, client: remote, host, room: roomOptions, me, backHref }
|
|
|
477
477
|
const empty = d.nodes.length === 0 && d.edges.length === 0;
|
|
478
478
|
return /* @__PURE__ */ jsxs3("section", { className: "board", "aria-labelledby": "board-h", children: [
|
|
479
479
|
/* @__PURE__ */ jsxs3("div", { className: "row", children: [
|
|
480
|
-
/* @__PURE__ */
|
|
480
|
+
/* @__PURE__ */ jsxs3("div", { className: "heading", children: [
|
|
481
|
+
/* @__PURE__ */ jsx3("h1", { id: "board-h", children: d.title || d.id }),
|
|
482
|
+
/* @__PURE__ */ jsx3("p", { className: "note", role: "status", children: editable ? status : "" })
|
|
483
|
+
] }),
|
|
481
484
|
/* @__PURE__ */ jsx3(PresenceStack, { entries: [{ id: "me", name: me.actor, kind: me.kind === "human" ? "person" : "agent" }, ...peers], label: live ? "In this board" : "In this board (not live)" })
|
|
482
485
|
] }),
|
|
483
|
-
/* @__PURE__ */ jsxs3(Toolbar, { label: "Board tools", children: [
|
|
484
|
-
TOOLS.map((t) => /* @__PURE__ */ jsx3(ToolbarButton, { label: t.text, icon: t.icon, disabled: !editable, onClick: () => add(t.type) }, t.type)),
|
|
485
|
-
/* @__PURE__ */ jsx3(ToolbarSeparator, {}),
|
|
486
|
-
/* @__PURE__ */ jsx3(ToolbarButton, { label: "Zoom out", icon: icon(/* @__PURE__ */ jsx3("path", { d: "M4 10h12" })), onClick: () => zoom(1 / 1.25) }),
|
|
487
|
-
/* @__PURE__ */ jsx3(ToolbarButton, { label: "Zoom in", icon: icon(/* @__PURE__ */ jsx3("path", { d: "M4 10h12M10 4v12" })), onClick: () => zoom(1.25) }),
|
|
488
|
-
/* @__PURE__ */ jsx3(ToolbarButton, { label: "Pan left", icon: icon(/* @__PURE__ */ jsx3("path", { d: "M12 4l-6 6 6 6" })), onClick: () => setView((v) => ({ ...v, x: v.x + PAN_STEP })) }),
|
|
489
|
-
/* @__PURE__ */ jsx3(ToolbarButton, { label: "Pan right", icon: icon(/* @__PURE__ */ jsx3("path", { d: "M8 4l6 6-6 6" })), onClick: () => setView((v) => ({ ...v, x: v.x - PAN_STEP })) }),
|
|
490
|
-
/* @__PURE__ */ jsx3(ToolbarButton, { label: "Pan up", icon: icon(/* @__PURE__ */ jsx3("path", { d: "M4 12l6-6 6 6" })), onClick: () => setView((v) => ({ ...v, y: v.y + PAN_STEP })) }),
|
|
491
|
-
/* @__PURE__ */ jsx3(ToolbarButton, { label: "Pan down", icon: icon(/* @__PURE__ */ jsx3("path", { d: "M4 8l6 6 6-6" })), onClick: () => setView((v) => ({ ...v, y: v.y - PAN_STEP })) }),
|
|
492
|
-
/* @__PURE__ */ jsx3(ToolbarButton, { label: "Reset view", icon: icon(/* @__PURE__ */ jsx3("path", { d: "M4 4h5M4 4v5M16 16h-5M16 16v-5" })), onClick: () => setView(HOME) })
|
|
493
|
-
] }),
|
|
494
|
-
/* @__PURE__ */ jsx3("p", { className: "note", role: "status", children: editable ? status : "" }),
|
|
495
486
|
!editable && /* @__PURE__ */ jsx3("p", { className: "note", children: host ? "This board is read only." : "This token can read the board but not change it." }),
|
|
496
|
-
/* @__PURE__ */ jsxs3("div", { className: "stage",
|
|
497
|
-
/* @__PURE__ */
|
|
498
|
-
|
|
487
|
+
/* @__PURE__ */ jsxs3("div", { className: "stage", children: [
|
|
488
|
+
/* @__PURE__ */ jsxs3("div", { className: "surface", ref: canvasBox, children: [
|
|
489
|
+
/* @__PURE__ */ jsx3("div", { className: "palette", children: /* @__PURE__ */ jsx3(Toolbar, { label: "Shape palette", children: TOOLS.map((t) => /* @__PURE__ */ jsx3(ToolbarButton, { label: t.text, icon: t.icon, disabled: !editable, onClick: () => add(t.type) }, t.type)) }) }),
|
|
490
|
+
/* @__PURE__ */ jsx3("div", { className: "zoom", children: /* @__PURE__ */ jsxs3(Toolbar, { label: "Zoom and pan", children: [
|
|
491
|
+
/* @__PURE__ */ jsx3(ToolbarButton, { label: "Zoom out", icon: icon(/* @__PURE__ */ jsx3("path", { d: "M4 10h12" })), onClick: () => zoom(1 / 1.25) }),
|
|
492
|
+
/* @__PURE__ */ jsx3(ToolbarButton, { label: "Zoom in", icon: icon(/* @__PURE__ */ jsx3("path", { d: "M4 10h12M10 4v12" })), onClick: () => zoom(1.25) }),
|
|
493
|
+
/* @__PURE__ */ jsx3(ToolbarSeparator, {}),
|
|
494
|
+
/* @__PURE__ */ jsx3(ToolbarButton, { label: "Pan left", icon: icon(/* @__PURE__ */ jsx3("path", { d: "M12 4l-6 6 6 6" })), onClick: () => setView((v) => ({ ...v, x: v.x + PAN_STEP })) }),
|
|
495
|
+
/* @__PURE__ */ jsx3(ToolbarButton, { label: "Pan right", icon: icon(/* @__PURE__ */ jsx3("path", { d: "M8 4l6 6-6 6" })), onClick: () => setView((v) => ({ ...v, x: v.x - PAN_STEP })) }),
|
|
496
|
+
/* @__PURE__ */ jsx3(ToolbarButton, { label: "Pan up", icon: icon(/* @__PURE__ */ jsx3("path", { d: "M4 12l6-6 6 6" })), onClick: () => setView((v) => ({ ...v, y: v.y + PAN_STEP })) }),
|
|
497
|
+
/* @__PURE__ */ jsx3(ToolbarButton, { label: "Pan down", icon: icon(/* @__PURE__ */ jsx3("path", { d: "M4 8l6 6 6-6" })), onClick: () => setView((v) => ({ ...v, y: v.y - PAN_STEP })) }),
|
|
498
|
+
/* @__PURE__ */ jsx3(ToolbarButton, { label: "Reset view", icon: icon(/* @__PURE__ */ jsx3("path", { d: "M4 4h5M4 4v5M16 16h-5M16 16v-5" })), onClick: () => setView(HOME) })
|
|
499
|
+
] }) }),
|
|
500
|
+
/* @__PURE__ */ jsx3(Canvas, { data: d, selected, editable, view, onView: setView, onSelect: setSelected, onMove: move, onResize: resize, onDelete: remove }),
|
|
501
|
+
empty && /* @__PURE__ */ jsx3("div", { className: "empty-overlay", children: /* @__PURE__ */ jsx3(EmptyState, { title: "This board is empty", description: editable ? "Pick a shape from the palette to start." : "Nothing has been drawn yet." }) })
|
|
502
|
+
] }),
|
|
499
503
|
/* @__PURE__ */ jsx3(Inspector, { item, nodes: d.nodes, editable, onText: (text) => item && write(() => client.update(id, item.id, { text }), "Could not save the text"), onPlace: place, onDelete: remove, onConnect: (to) => item && write(() => client.addConnector(id, { from: { id: item.id }, to: { id: to } }), "Could not connect") }, item?.id ?? "none")
|
|
500
504
|
] })
|
|
501
505
|
] });
|
package/dist/index.js
CHANGED
package/dist/ui.css
CHANGED
|
@@ -5,32 +5,40 @@
|
|
|
5
5
|
.note { color: var(--agd-color-text-muted); }
|
|
6
6
|
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
|
|
7
7
|
|
|
8
|
-
.board { display: grid; gap: var(--agd-space-
|
|
9
|
-
.
|
|
8
|
+
.board { display: grid; gap: var(--agd-space-4); }
|
|
9
|
+
.heading { display: grid; gap: var(--agd-space-1); }
|
|
10
|
+
.heading h1, .heading .note { margin: 0; }
|
|
11
|
+
.heading .note { font-size: var(--agd-font-size-sm); min-height: 1.25em; }
|
|
12
|
+
.stage { display: grid; grid-template-columns: minmax(0, 1fr) 15rem; gap: var(--agd-space-4); height: 68vh; min-height: 24rem; }
|
|
13
|
+
/* The palette and the zoom controls float on the canvas, so the page keeps one calm surface. They come before the canvas, so Tab reaches them first. */
|
|
14
|
+
.surface { position: relative; min-height: 18rem; }
|
|
15
|
+
.palette, .zoom { position: absolute; z-index: 1; left: var(--agd-space-3); max-width: calc(100% - 2 * var(--agd-space-3)); }
|
|
16
|
+
.palette { top: var(--agd-space-3); }
|
|
17
|
+
.zoom { bottom: var(--agd-space-3); }
|
|
18
|
+
.palette .agd-toolbar, .zoom .agd-toolbar { flex-wrap: wrap; box-shadow: var(--agd-shadow-raised); }
|
|
19
|
+
.canvas { height: 100%; box-sizing: border-box; background-color: var(--agd-color-surface); background-image: radial-gradient(var(--agd-color-border) 1px, transparent 1px); background-size: 24px 24px; border: 1px solid var(--agd-color-border); border-radius: var(--agd-radius-lg); overflow: hidden; touch-action: none; min-height: 18rem; }
|
|
10
20
|
@media (max-width: 48rem) { .stage { grid-template-columns: 1fr; height: auto; } .canvas { height: 55vh; } }
|
|
11
|
-
.canvas { background: var(--agd-color-surface-sunken); border: 1px solid var(--agd-color-border); border-radius: var(--agd-radius-md); overflow: hidden; touch-action: none; min-height: 18rem; }
|
|
12
21
|
.canvas:focus-visible { outline: 3px solid var(--agd-color-focus); outline-offset: 2px; }
|
|
13
22
|
.canvas svg { display: block; cursor: grab; font-family: var(--agd-font-family-sans); font-size: 14px; }
|
|
14
23
|
.item { outline: none; cursor: pointer; }
|
|
15
|
-
.shape { fill: var(--agd-color-surface-raised); stroke: var(--agd-color-border-strong); stroke-width: 1
|
|
24
|
+
.shape { fill: var(--agd-color-surface-raised); stroke: var(--agd-color-border-strong); stroke-width: 1; }
|
|
16
25
|
.shape.text { fill: transparent; stroke: none; }
|
|
17
26
|
.shape.frame, .shape.image { fill: none; stroke-dasharray: 6 4; pointer-events: visiblePainted; }
|
|
18
27
|
.shape.sticky { fill: var(--agd-color-warning-subtle); stroke: var(--agd-color-warning); }
|
|
19
28
|
.label { fill: var(--agd-color-text); pointer-events: none; }
|
|
20
29
|
.sticky-label { fill: var(--agd-color-warning-text); }
|
|
21
|
-
.edge { stroke: var(--agd-color-text-muted); stroke-width:
|
|
30
|
+
.edge { stroke: var(--agd-color-text-muted); stroke-width: 1.5; fill: none; pointer-events: none; }
|
|
22
31
|
.hit { stroke: transparent; stroke-width: 14; }
|
|
23
32
|
.arrowhead { fill: var(--agd-color-text-muted); }
|
|
24
|
-
.edge-text { fill: var(--agd-color-text); paint-order: stroke; stroke: var(--agd-color-surface
|
|
33
|
+
.edge-text { fill: var(--agd-color-text); paint-order: stroke; stroke: var(--agd-color-surface); stroke-width: 4px; pointer-events: none; }
|
|
25
34
|
.ring, .ring-line { fill: none; stroke: none; stroke-width: 3; pointer-events: none; }
|
|
26
35
|
.item.selected .ring, .item.selected .ring-line, .item:focus-visible .ring, .item:focus-visible .ring-line { stroke: var(--agd-color-focus); }
|
|
27
36
|
.item:focus-visible .ring, .item:focus-visible .ring-line { stroke-width: 4; }
|
|
28
37
|
.handle { fill: var(--agd-color-focus); stroke: var(--agd-color-bg); stroke-width: 2; cursor: nwse-resize; }
|
|
29
38
|
.agent-badge rect { fill: var(--agd-color-agent-subtle); stroke: var(--agd-color-agent); }
|
|
30
39
|
.agent-badge text { fill: var(--agd-color-agent-text); font-size: 11px; font-weight: 600; pointer-events: none; }
|
|
31
|
-
.empty-overlay { position: absolute; inset: 0
|
|
32
|
-
|
|
33
|
-
.inspector { border: 1px solid var(--agd-color-border); border-radius: var(--agd-radius-md); padding: var(--agd-space-3); background: var(--agd-color-surface); display: grid; gap: var(--agd-space-3); align-content: start; overflow: auto; }
|
|
40
|
+
.empty-overlay { position: absolute; inset: 0; display: grid; place-items: center; pointer-events: none; }
|
|
41
|
+
.inspector { border: 1px solid var(--agd-color-border); border-radius: var(--agd-radius-lg); padding: var(--agd-space-4); background: var(--agd-color-surface); display: grid; gap: var(--agd-space-3); align-content: start; overflow: auto; }
|
|
34
42
|
.inspector h2 { margin: 0; font-size: var(--agd-font-size-lg); }
|
|
35
43
|
.inspector form { display: grid; gap: var(--agd-space-3); }
|
|
36
44
|
.inspector .by { margin: 0; color: var(--agd-color-text-muted); font-size: var(--agd-font-size-sm); }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentic-canvas",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "A shared whiteboard for diagrams, drawn by people and agents.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"whiteboard",
|
|
@@ -74,6 +74,8 @@
|
|
|
74
74
|
"typecheck": "tsc --noEmit && tsc --noEmit -p ui",
|
|
75
75
|
"test": "vitest run",
|
|
76
76
|
"clean": "rm -rf dist",
|
|
77
|
+
"dev": "npm run build && WRANGLER_SEND_METRICS=false wrangler dev --port 8793 --var CANVAS_REGION:unknown",
|
|
78
|
+
"dev:smoke": "npm run build && node scripts/dev-smoke.mjs 8793 /health --var CANVAS_REGION:unknown",
|
|
77
79
|
"ci:local": "npm run build && npm run typecheck && npm test && npm run test:e2e",
|
|
78
80
|
"deploy:demo": "wrangler deploy -c wrangler.demo.jsonc",
|
|
79
81
|
"test:e2e": "playwright test -c e2e/playwright.config.ts"
|
|
@@ -81,7 +83,7 @@
|
|
|
81
83
|
"dependencies": {
|
|
82
84
|
"@dagrejs/dagre": "^3.1.3",
|
|
83
85
|
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
84
|
-
"agentic-design": "^0.
|
|
86
|
+
"agentic-design": "^0.5.0",
|
|
85
87
|
"agentic-identity": "^0.8.0",
|
|
86
88
|
"agentic-realtime": "^0.4.2",
|
|
87
89
|
"yjs": "^13.6.0",
|