pmx-canvas 0.6.4 → 0.7.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 (204) hide show
  1. package/.github/extensions/pmx-canvas/extension.mjs +67 -3
  2. package/CHANGELOG.md +73 -0
  3. package/Readme.md +35 -5
  4. package/dist/canvas/global.css +498 -28
  5. package/dist/canvas/index.js +110 -95
  6. package/dist/canvas/mermaid-entry.js +258 -258
  7. package/dist/types/cli/agent.d.ts +4 -0
  8. package/dist/types/cli/commands/backup.d.ts +1 -0
  9. package/dist/types/cli/commands/boards.d.ts +1 -0
  10. package/dist/types/cli/commands/export.d.ts +1 -0
  11. package/dist/types/cli/commands/record.d.ts +12 -0
  12. package/dist/types/client/canvas/BoardCopyDialog.d.ts +5 -0
  13. package/dist/types/client/canvas/BoardFolderDialog.d.ts +7 -0
  14. package/dist/types/client/canvas/BoardLinkDialog.d.ts +3 -0
  15. package/dist/types/client/canvas/BoardSwitcher.d.ts +8 -0
  16. package/dist/types/client/canvas/ExportDialog.d.ts +7 -0
  17. package/dist/types/client/canvas/HomeView.d.ts +9 -0
  18. package/dist/types/client/canvas/Presentation.d.ts +13 -0
  19. package/dist/types/client/canvas/use-node-drag.d.ts +2 -1
  20. package/dist/types/client/nodes/AttachmentNode.d.ts +6 -0
  21. package/dist/types/client/nodes/BoardNode.d.ts +5 -0
  22. package/dist/types/client/nodes/McpAppNode.d.ts +24 -1
  23. package/dist/types/client/state/boards-store.d.ts +79 -0
  24. package/dist/types/client/state/canvas-store.d.ts +2 -0
  25. package/dist/types/client/state/intent-bridge.d.ts +1 -0
  26. package/dist/types/client/state/presentation.d.ts +3 -0
  27. package/dist/types/client/state/session-store.d.ts +7 -0
  28. package/dist/types/client/types.d.ts +2 -2
  29. package/dist/types/json-render/catalog.d.ts +3 -3
  30. package/dist/types/json-render/charts/definitions.d.ts +1 -1
  31. package/dist/types/json-render/server.d.ts +8 -0
  32. package/dist/types/mcp/canvas-access.d.ts +10 -3
  33. package/dist/types/mcp/context-uri-template.d.ts +6 -0
  34. package/dist/types/server/agent-presence.d.ts +1 -1
  35. package/dist/types/server/attribution.d.ts +11 -0
  36. package/dist/types/server/ax-context.d.ts +3 -1
  37. package/dist/types/server/ax-interaction.d.ts +2 -2
  38. package/dist/types/server/ax-state.d.ts +13 -3
  39. package/dist/types/server/backup.d.ts +36 -0
  40. package/dist/types/server/board-export.d.ts +45 -0
  41. package/dist/types/server/canvas-db.d.ts +65 -9
  42. package/dist/types/server/canvas-operations.d.ts +45 -0
  43. package/dist/types/server/canvas-provenance.d.ts +1 -1
  44. package/dist/types/server/canvas-schema.d.ts +1 -0
  45. package/dist/types/server/canvas-state.d.ts +146 -3
  46. package/dist/types/server/canvas-validation.d.ts +3 -0
  47. package/dist/types/server/context-brief.d.ts +111 -0
  48. package/dist/types/server/context-reads.d.ts +55 -0
  49. package/dist/types/server/document-import.d.ts +66 -0
  50. package/dist/types/server/html-surface.d.ts +1 -1
  51. package/dist/types/server/index.d.ts +107 -4
  52. package/dist/types/server/mutation-history.d.ts +1 -0
  53. package/dist/types/server/operations/invoker.d.ts +2 -0
  54. package/dist/types/server/operations/mcp.d.ts +7 -1
  55. package/dist/types/server/operations/ops/app.d.ts +2 -0
  56. package/dist/types/server/operations/ops/ax-shared.d.ts +2 -2
  57. package/dist/types/server/operations/ops/backup.d.ts +2 -0
  58. package/dist/types/server/operations/ops/boards.d.ts +10 -0
  59. package/dist/types/server/operations/ops/export.d.ts +2 -0
  60. package/dist/types/server/operations/ops/imports.d.ts +2 -0
  61. package/dist/types/server/operations/ops/json-render.d.ts +2 -0
  62. package/dist/types/server/operations/ops/nodes.d.ts +4 -2
  63. package/dist/types/server/operations/ops/query.d.ts +2 -0
  64. package/dist/types/server/operations/registry.d.ts +9 -1
  65. package/dist/types/server/operations/types.d.ts +1 -1
  66. package/dist/types/server/server.d.ts +1 -0
  67. package/dist/types/server/trace-manager.d.ts +7 -0
  68. package/dist/types/server/web-artifacts.d.ts +3 -0
  69. package/dist/types/server/webpage-node.d.ts +22 -1
  70. package/dist/types/server/workbench-auth.d.ts +3 -0
  71. package/dist/types/shared/boards.d.ts +6 -0
  72. package/dist/types/shared/tour.d.ts +72 -0
  73. package/docs/RELEASE.md +5 -0
  74. package/docs/cli.md +157 -0
  75. package/docs/http-api.md +277 -6
  76. package/docs/mcp.md +96 -7
  77. package/docs/node-types.md +106 -0
  78. package/docs/plans/plan-010-attributed-ask-answers.md +39 -0
  79. package/docs/plans/plan-011-context-read-instrumentation.md +54 -0
  80. package/docs/plans/plan-012-many-boards-stage-1.md +98 -0
  81. package/docs/plans/plan-013-static-board-export.md +47 -0
  82. package/docs/plans/plan-014-connected-board-memory.md +140 -0
  83. package/docs/product-vision-2026-09.md +118 -18
  84. package/docs/sdk.md +50 -0
  85. package/package.json +1 -1
  86. package/skills/pmx-canvas/SKILL.md +62 -5
  87. package/skills/pmx-canvas/references/full-reference.md +44 -8
  88. package/skills/pmx-canvas/references/github-copilot-app-adapter.md +3 -0
  89. package/skills/pmx-canvas/references/installing-pmx-canvas.md +4 -4
  90. package/skills/pmx-canvas-orchestration/SKILL.md +5 -0
  91. package/skills/pmx-canvas-testing/SKILL.md +4 -0
  92. package/src/cli/agent.ts +9 -0
  93. package/src/cli/commands/ax.ts +13 -0
  94. package/src/cli/commands/backup.ts +66 -0
  95. package/src/cli/commands/boards.ts +71 -0
  96. package/src/cli/commands/export.ts +30 -0
  97. package/src/cli/commands/nodes.ts +14 -1
  98. package/src/cli/commands/pins.ts +6 -2
  99. package/src/cli/commands/pump.ts +3 -0
  100. package/src/cli/commands/query.ts +33 -7
  101. package/src/cli/commands/record.ts +218 -0
  102. package/src/cli/commands/view.ts +7 -5
  103. package/src/cli/index.ts +21 -9
  104. package/src/client/App.tsx +28 -4
  105. package/src/client/canvas/AgentPresenceLayer.tsx +1 -1
  106. package/src/client/canvas/BoardCopyDialog.tsx +153 -0
  107. package/src/client/canvas/BoardFolderDialog.tsx +120 -0
  108. package/src/client/canvas/BoardLinkDialog.tsx +93 -0
  109. package/src/client/canvas/BoardSwitcher.tsx +149 -0
  110. package/src/client/canvas/CanvasNode.tsx +8 -0
  111. package/src/client/canvas/CanvasViewport.tsx +3 -0
  112. package/src/client/canvas/CommandPalette.tsx +107 -4
  113. package/src/client/canvas/ContextMenu.tsx +4 -0
  114. package/src/client/canvas/ExpandedNodeOverlay.tsx +3 -0
  115. package/src/client/canvas/ExportDialog.tsx +197 -0
  116. package/src/client/canvas/HomeView.tsx +277 -0
  117. package/src/client/canvas/IntentLayer.tsx +9 -2
  118. package/src/client/canvas/Presentation.tsx +108 -0
  119. package/src/client/canvas/SessionPanel.tsx +28 -1
  120. package/src/client/canvas/ToolRail.tsx +38 -3
  121. package/src/client/canvas/TopBar.tsx +49 -7
  122. package/src/client/canvas/import-files.ts +19 -1
  123. package/src/client/canvas/kind-colors.ts +1 -0
  124. package/src/client/canvas/use-node-drag.ts +8 -3
  125. package/src/client/icons.tsx +2 -0
  126. package/src/client/mermaid-entry.ts +39 -0
  127. package/src/client/nodes/AttachmentNode.tsx +148 -0
  128. package/src/client/nodes/BoardNode.tsx +35 -0
  129. package/src/client/nodes/FileNode.tsx +6 -0
  130. package/src/client/nodes/HtmlNode.tsx +12 -13
  131. package/src/client/nodes/MarkdownNode.tsx +47 -19
  132. package/src/client/nodes/McpAppNode.tsx +105 -13
  133. package/src/client/nodes/MermaidNode.tsx +3 -2
  134. package/src/client/nodes/ax-node-actions.ts +2 -5
  135. package/src/client/nodes/use-ax-surface-bridge.ts +1 -1
  136. package/src/client/state/boards-store.ts +167 -0
  137. package/src/client/state/canvas-store.ts +22 -0
  138. package/src/client/state/intent-bridge.ts +30 -2
  139. package/src/client/state/intent-store.ts +5 -1
  140. package/src/client/state/node-factory.ts +1 -0
  141. package/src/client/state/presentation.ts +7 -0
  142. package/src/client/state/session-store.ts +8 -0
  143. package/src/client/state/sse-bridge.ts +52 -5
  144. package/src/client/theme/global.css +498 -28
  145. package/src/client/types.ts +2 -0
  146. package/src/json-render/server.ts +45 -9
  147. package/src/mcp/canvas-access.ts +59 -22
  148. package/src/mcp/context-uri-template.ts +28 -0
  149. package/src/mcp/server.ts +122 -15
  150. package/src/server/agent-context.ts +116 -29
  151. package/src/server/agent-presence.ts +15 -9
  152. package/src/server/attribution.ts +29 -0
  153. package/src/server/ax-context.ts +4 -2
  154. package/src/server/ax-interaction.ts +1 -0
  155. package/src/server/ax-state-manager.ts +72 -3
  156. package/src/server/ax-state.ts +41 -0
  157. package/src/server/backup.ts +178 -0
  158. package/src/server/board-export.ts +686 -0
  159. package/src/server/canvas-db.ts +612 -105
  160. package/src/server/canvas-operations.ts +183 -31
  161. package/src/server/canvas-provenance.ts +1 -0
  162. package/src/server/canvas-schema.ts +22 -0
  163. package/src/server/canvas-state.ts +812 -48
  164. package/src/server/canvas-validation.ts +9 -1
  165. package/src/server/context-brief.ts +372 -0
  166. package/src/server/context-reads.ts +238 -0
  167. package/src/server/demo-state.json +670 -9
  168. package/src/server/document-import.ts +223 -0
  169. package/src/server/html-primitives.ts +199 -91
  170. package/src/server/html-surface.ts +8 -3
  171. package/src/server/index.ts +243 -5
  172. package/src/server/mutation-history.ts +10 -13
  173. package/src/server/operations/composites.ts +29 -5
  174. package/src/server/operations/http.ts +9 -3
  175. package/src/server/operations/index.ts +8 -0
  176. package/src/server/operations/invoker.ts +14 -3
  177. package/src/server/operations/mcp.ts +50 -11
  178. package/src/server/operations/ops/app.ts +15 -0
  179. package/src/server/operations/ops/ax-read.ts +10 -6
  180. package/src/server/operations/ops/ax-timeline.ts +75 -0
  181. package/src/server/operations/ops/backup.ts +134 -0
  182. package/src/server/operations/ops/batch.ts +20 -4
  183. package/src/server/operations/ops/boards.ts +351 -0
  184. package/src/server/operations/ops/export.ts +74 -0
  185. package/src/server/operations/ops/ext-app.ts +4 -0
  186. package/src/server/operations/ops/groups.ts +14 -7
  187. package/src/server/operations/ops/imports.ts +220 -0
  188. package/src/server/operations/ops/json-render.ts +37 -5
  189. package/src/server/operations/ops/nodes.ts +99 -21
  190. package/src/server/operations/ops/query.ts +206 -9
  191. package/src/server/operations/ops/viewport.ts +32 -0
  192. package/src/server/operations/registry.ts +129 -31
  193. package/src/server/operations/types.ts +1 -1
  194. package/src/server/scope-fence.ts +1 -1
  195. package/src/server/server.ts +155 -8
  196. package/src/server/spatial-analysis.ts +9 -17
  197. package/src/server/trace-manager.ts +19 -0
  198. package/src/server/web-artifacts.ts +11 -3
  199. package/src/server/webpage-node.ts +173 -13
  200. package/src/server/workbench-auth.ts +11 -0
  201. package/src/server/workboard.ts +3 -3
  202. package/src/shared/boards.ts +18 -0
  203. package/src/shared/node-sizes.ts +1 -0
  204. package/src/shared/tour.ts +87 -0
@@ -0,0 +1,223 @@
1
+ import type { Database } from 'bun:sqlite';
2
+ import { randomUUID } from 'node:crypto';
3
+
4
+ export const MAX_ATTACHMENT_BYTES = 20 * 1024 * 1024;
5
+ export const MAX_INLINE_ATTACHMENT_BYTES = 2 * 1024 * 1024;
6
+ export const MAX_ATTACHMENT_NAME_LENGTH = 255;
7
+ export const MAX_IMPORT_SECTIONS = 32;
8
+ export const MAX_IMPORT_WARNINGS = 20;
9
+ export const MAX_IMPORT_TEXT = 200_000;
10
+ export const MAX_IMPORT_TITLE_LENGTH = 500;
11
+ export const MAX_IMPORT_REFERENCE_LENGTH = 2_000;
12
+ export const MAX_IMPORT_WARNING_LENGTH = 2_000;
13
+ export const MAX_IMPORT_AGENT_DESCRIPTION_LENGTH = 4_000;
14
+ export const MAX_IMPORT_REASON_LENGTH = 4_000;
15
+
16
+ export interface Attachment {
17
+ id: string;
18
+ boardId: string;
19
+ sha256: string;
20
+ name: string;
21
+ mime: string;
22
+ size: number;
23
+ createdAt: string;
24
+ }
25
+
26
+ export interface ImportSection {
27
+ title: string;
28
+ markdown: string;
29
+ reference?: string;
30
+ }
31
+ export type DocumentImportStatus = 'attached' | 'requested' | 'drafted' | 'unavailable' | 'cancelled' | 'committed';
32
+ export interface DocumentImport {
33
+ id: string;
34
+ boardId: string;
35
+ attachmentId: string;
36
+ status: DocumentImportStatus;
37
+ position: { x: number; y: number };
38
+ sections: ImportSection[];
39
+ warnings: string[];
40
+ agentDescription: string | null;
41
+ reason: string | null;
42
+ committedNodeIds: string[];
43
+ createdAt: string;
44
+ updatedAt: string;
45
+ }
46
+
47
+ interface AttachmentRow {
48
+ id: string;
49
+ board_id: string;
50
+ sha256: string;
51
+ name: string;
52
+ mime: string;
53
+ size: number;
54
+ created_at: string;
55
+ }
56
+ interface ImportRow {
57
+ id: string;
58
+ board_id: string;
59
+ attachment_id: string;
60
+ status: DocumentImportStatus;
61
+ position_x: number;
62
+ position_y: number;
63
+ sections: string | null;
64
+ warnings: string | null;
65
+ agent_description: string | null;
66
+ reason: string | null;
67
+ committed_node_ids: string | null;
68
+ created_at: string;
69
+ updated_at: string;
70
+ }
71
+ const attachment = (r: AttachmentRow): Attachment => ({
72
+ id: r.id,
73
+ boardId: r.board_id,
74
+ sha256: r.sha256,
75
+ name: r.name,
76
+ mime: r.mime,
77
+ size: r.size,
78
+ createdAt: r.created_at,
79
+ });
80
+ const imported = (r: ImportRow): DocumentImport => ({
81
+ id: r.id,
82
+ boardId: r.board_id,
83
+ attachmentId: r.attachment_id,
84
+ status: r.status,
85
+ position: { x: r.position_x, y: r.position_y },
86
+ sections: r.sections ? (JSON.parse(r.sections) as ImportSection[]) : [],
87
+ warnings: r.warnings ? (JSON.parse(r.warnings) as string[]) : [],
88
+ agentDescription: r.agent_description,
89
+ reason: r.reason,
90
+ committedNodeIds: r.committed_node_ids ? (JSON.parse(r.committed_node_ids) as string[]) : [],
91
+ createdAt: r.created_at,
92
+ updatedAt: r.updated_at,
93
+ });
94
+
95
+ export function storeAttachment(
96
+ db: Database,
97
+ input: { boardId: string; name: string; mime: string; bytes: Uint8Array },
98
+ ): Attachment {
99
+ if (!input.name.trim() || input.name.length > MAX_ATTACHMENT_NAME_LENGTH)
100
+ throw new Error(`Attachment name must be 1-${MAX_ATTACHMENT_NAME_LENGTH} characters.`);
101
+ if (input.bytes.byteLength === 0 || input.bytes.byteLength > MAX_ATTACHMENT_BYTES)
102
+ throw new Error(`Attachment must contain 1-${MAX_ATTACHMENT_BYTES} bytes.`);
103
+ const sha256 = new Bun.CryptoHasher('sha256').update(input.bytes).digest('hex');
104
+ const value: Attachment = {
105
+ id: randomUUID(),
106
+ boardId: input.boardId,
107
+ sha256,
108
+ name: input.name,
109
+ mime: input.mime,
110
+ size: input.bytes.byteLength,
111
+ createdAt: new Date().toISOString(),
112
+ };
113
+ db.transaction(() => {
114
+ db.run('INSERT OR IGNORE INTO attachment_bytes (sha256,data,size) VALUES (?,?,?)', [
115
+ sha256,
116
+ input.bytes,
117
+ value.size,
118
+ ]);
119
+ db.run('INSERT INTO attachments (id,board_id,sha256,name,mime,size,created_at) VALUES (?,?,?,?,?,?,?)', [
120
+ value.id,
121
+ value.boardId,
122
+ value.sha256,
123
+ value.name,
124
+ value.mime,
125
+ value.size,
126
+ value.createdAt,
127
+ ]);
128
+ })();
129
+ return value;
130
+ }
131
+
132
+ export function getAttachment(db: Database, id: string): Attachment | null {
133
+ const row = db
134
+ .query<AttachmentRow, [string]>('SELECT id,board_id,sha256,name,mime,size,created_at FROM attachments WHERE id=?')
135
+ .get(id);
136
+ return row ? attachment(row) : null;
137
+ }
138
+ export function readAttachmentBytes(db: Database, id: string): Uint8Array | null {
139
+ return (
140
+ db
141
+ .query<{ data: Uint8Array }, [string]>(
142
+ 'SELECT b.data FROM attachment_bytes b JOIN attachments a ON a.sha256=b.sha256 WHERE a.id=?',
143
+ )
144
+ .get(id)?.data ?? null
145
+ );
146
+ }
147
+ export function copyBoardAttachments(
148
+ db: Database,
149
+ sourceBoardId: string,
150
+ targetBoardId: string,
151
+ referencedIds: Set<string>,
152
+ ): Map<string, string> {
153
+ const map = new Map<string, string>();
154
+ const rows = db
155
+ .query<AttachmentRow, string[]>(
156
+ `SELECT id,board_id,sha256,name,mime,size,created_at FROM attachments WHERE board_id=? AND id IN (${[...referencedIds].map(() => '?').join(',') || "''"})`,
157
+ )
158
+ .all(sourceBoardId, ...referencedIds);
159
+ for (const row of rows) {
160
+ const id = randomUUID();
161
+ map.set(row.id, id);
162
+ db.run('INSERT INTO attachments (id,board_id,sha256,name,mime,size,created_at) VALUES (?,?,?,?,?,?,?)', [
163
+ id,
164
+ targetBoardId,
165
+ row.sha256,
166
+ row.name,
167
+ row.mime,
168
+ row.size,
169
+ new Date().toISOString(),
170
+ ]);
171
+ }
172
+ return map;
173
+ }
174
+ export function createImport(db: Database, attachmentId: string, position: { x: number; y: number }): DocumentImport {
175
+ const a = getAttachment(db, attachmentId);
176
+ if (!a) throw new Error('Attachment not found.');
177
+ const now = new Date().toISOString(),
178
+ id = randomUUID();
179
+ db.run(
180
+ "INSERT INTO document_imports (id,board_id,attachment_id,status,position_x,position_y,created_at,updated_at) VALUES (?,?,?,'attached',?,?,?,?)",
181
+ [id, a.boardId, attachmentId, position.x, position.y, now, now],
182
+ );
183
+ return getImport(db, id)!;
184
+ }
185
+ export function getImport(db: Database, id: string): DocumentImport | null {
186
+ const r = db.query<ImportRow, [string]>('SELECT * FROM document_imports WHERE id=?').get(id);
187
+ return r ? imported(r) : null;
188
+ }
189
+ export function listImports(db: Database, boardId?: string): DocumentImport[] {
190
+ const rows = boardId
191
+ ? db
192
+ .query<ImportRow, [string]>('SELECT * FROM document_imports WHERE board_id=? ORDER BY created_at DESC')
193
+ .all(boardId)
194
+ : db.query<ImportRow, []>('SELECT * FROM document_imports ORDER BY created_at DESC').all();
195
+ return rows.map(imported);
196
+ }
197
+ export function updateImport(
198
+ db: Database,
199
+ id: string,
200
+ status: DocumentImportStatus,
201
+ fields: {
202
+ sections?: ImportSection[];
203
+ warnings?: string[];
204
+ agentDescription?: string;
205
+ reason?: string;
206
+ committedNodeIds?: string[];
207
+ } = {},
208
+ ): DocumentImport {
209
+ db.run(
210
+ 'UPDATE document_imports SET status=?,sections=COALESCE(?,sections),warnings=COALESCE(?,warnings),agent_description=COALESCE(?,agent_description),reason=COALESCE(?,reason),committed_node_ids=COALESCE(?,committed_node_ids),updated_at=? WHERE id=?',
211
+ [
212
+ status,
213
+ fields.sections ? JSON.stringify(fields.sections) : null,
214
+ fields.warnings ? JSON.stringify(fields.warnings) : null,
215
+ fields.agentDescription ?? null,
216
+ fields.reason ?? null,
217
+ fields.committedNodeIds ? JSON.stringify(fields.committedNodeIds) : null,
218
+ new Date().toISOString(),
219
+ id,
220
+ ],
221
+ );
222
+ return getImport(db, id)!;
223
+ }