pmx-canvas 0.1.19 → 0.1.21

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 (65) hide show
  1. package/CHANGELOG.md +159 -0
  2. package/Readme.md +19 -6
  3. package/dist/canvas/global.css +123 -2
  4. package/dist/canvas/index.js +103 -68
  5. package/dist/json-render/index.js +109 -109
  6. package/dist/types/client/canvas/CanvasViewport.d.ts +1 -1
  7. package/dist/types/client/icons.d.ts +2 -0
  8. package/dist/types/client/nodes/HtmlNode.d.ts +12 -1
  9. package/dist/types/client/state/canvas-store.d.ts +2 -0
  10. package/dist/types/client/types.d.ts +3 -2
  11. package/dist/types/json-render/charts/components.d.ts +5 -1
  12. package/dist/types/json-render/renderer/index.d.ts +1 -0
  13. package/dist/types/json-render/server.d.ts +1 -0
  14. package/dist/types/mcp/canvas-access.d.ts +3 -0
  15. package/dist/types/server/canvas-operations.d.ts +4 -0
  16. package/dist/types/server/canvas-schema.d.ts +19 -3
  17. package/dist/types/server/canvas-serialization.d.ts +1 -0
  18. package/dist/types/server/canvas-state.d.ts +6 -2
  19. package/dist/types/server/html-node-summary.d.ts +2 -0
  20. package/dist/types/server/html-primitives.d.ts +42 -0
  21. package/dist/types/server/index.d.ts +26 -0
  22. package/docs/cli.md +4 -1
  23. package/docs/http-api.md +11 -1
  24. package/docs/mcp.md +10 -4
  25. package/docs/node-types.md +54 -4
  26. package/docs/screenshot.png +0 -0
  27. package/docs/sdk.md +12 -0
  28. package/package.json +1 -1
  29. package/skills/pmx-canvas/SKILL.md +17 -3
  30. package/skills/pmx-canvas/references/html-primitives.md +132 -0
  31. package/src/cli/agent.ts +159 -5
  32. package/src/cli/index.ts +1 -1
  33. package/src/client/App.tsx +21 -2
  34. package/src/client/canvas/AnnotationLayer.tsx +33 -12
  35. package/src/client/canvas/CanvasViewport.tsx +88 -7
  36. package/src/client/canvas/CommandPalette.tsx +2 -2
  37. package/src/client/canvas/ContextMenu.tsx +2 -2
  38. package/src/client/canvas/ExpandedNodeOverlay.tsx +112 -3
  39. package/src/client/canvas/auto-fit.ts +5 -1
  40. package/src/client/icons.tsx +13 -0
  41. package/src/client/nodes/HtmlNode.tsx +125 -13
  42. package/src/client/nodes/McpAppNode.tsx +12 -4
  43. package/src/client/state/canvas-store.ts +15 -5
  44. package/src/client/state/sse-bridge.ts +5 -4
  45. package/src/client/theme/global.css +123 -2
  46. package/src/client/types.ts +2 -1
  47. package/src/json-render/charts/components.tsx +41 -7
  48. package/src/json-render/charts/extra-components.tsx +13 -12
  49. package/src/json-render/renderer/index.tsx +1 -0
  50. package/src/json-render/server.ts +3 -1
  51. package/src/mcp/canvas-access.ts +54 -1
  52. package/src/mcp/server.ts +98 -28
  53. package/src/server/agent-context.ts +39 -0
  54. package/src/server/canvas-operations.ts +99 -38
  55. package/src/server/canvas-provenance.ts +8 -6
  56. package/src/server/canvas-schema.ts +94 -3
  57. package/src/server/canvas-serialization.ts +16 -4
  58. package/src/server/canvas-state.ts +9 -4
  59. package/src/server/demo-state.json +1143 -0
  60. package/src/server/demo.ts +25 -777
  61. package/src/server/html-node-summary.ts +141 -0
  62. package/src/server/html-primitives.ts +1300 -0
  63. package/src/server/index.ts +63 -3
  64. package/src/server/server.ts +154 -17
  65. package/src/server/spatial-analysis.ts +5 -3
@@ -27,6 +27,7 @@ export interface CanvasAnnotationSummary {
27
27
  color: string;
28
28
  width: number;
29
29
  pointCount: number;
30
+ text: string | null;
30
31
  label: string | null;
31
32
  createdAt: string;
32
33
  }
@@ -75,6 +76,15 @@ export function getCanvasNodeTitle(node: CanvasNodeState): string | null {
75
76
  }
76
77
 
77
78
  export function getCanvasNodeContent(node: CanvasNodeState): string | null {
79
+ if (node.type === 'html') {
80
+ const primitive = typeof node.data.htmlPrimitive === 'string' ? node.data.htmlPrimitive : null;
81
+ const description = pickString(node.data.description);
82
+ return pickString(node.data.agentSummary)
83
+ ?? pickString(node.data.contentSummary)
84
+ ?? (primitive
85
+ ? (description ? `${primitive}: ${description}` : primitive)
86
+ : null);
87
+ }
78
88
  return pickString(node.data.content)
79
89
  ?? pickString(node.data.fileContent)
80
90
  ?? pickString(node.data.text)
@@ -86,12 +96,13 @@ export function getCanvasNodeContent(node: CanvasNodeState): string | null {
86
96
 
87
97
  export function serializeCanvasNode(node: CanvasNodeState): SerializedCanvasNode {
88
98
  const data = normalizeCanvasNodeData(node.type, node.data);
99
+ const normalizedNode = { ...node, data };
89
100
  return {
90
101
  ...node,
91
102
  data,
92
103
  kind: getCanvasNodeKind(node, data),
93
- title: getCanvasNodeTitle(node),
94
- content: getCanvasNodeContent(node),
104
+ title: getCanvasNodeTitle(normalizedNode),
105
+ content: getCanvasNodeContent(normalizedNode),
95
106
  path: pickString(data.path),
96
107
  url: pickString(data.url),
97
108
  provenance: pickProvenance(data.provenance),
@@ -180,7 +191,8 @@ export function summarizeCanvasAnnotation(annotation: CanvasAnnotation): CanvasA
180
191
  color: annotation.color,
181
192
  width: annotation.width,
182
193
  pointCount: annotation.points.length,
183
- label: annotation.label ?? null,
194
+ text: annotation.text ?? null,
195
+ label: annotation.label ?? annotation.text ?? null,
184
196
  createdAt: annotation.createdAt,
185
197
  };
186
198
  }
@@ -208,7 +220,7 @@ export function summarizeCanvasAnnotationForContext(
208
220
  const targetNodeTitles = targetNodes.map((node) => getCanvasNodeTitle(node) ?? node.id);
209
221
  return {
210
222
  id: annotation.id,
211
- label: annotation.label ?? null,
223
+ label: annotation.label ?? annotation.text ?? null,
212
224
  bounds: annotation.bounds,
213
225
  targetNodeIds: targetNodes.map((node) => node.id),
214
226
  targetNodeTitles,
@@ -162,11 +162,12 @@ export interface CanvasAnnotationPoint {
162
162
 
163
163
  export interface CanvasAnnotation {
164
164
  id: string;
165
- type: 'freehand';
165
+ type: 'freehand' | 'text';
166
166
  points: CanvasAnnotationPoint[];
167
167
  bounds: { x: number; y: number; width: number; height: number };
168
168
  color: string;
169
169
  width: number;
170
+ text?: string;
170
171
  label?: string;
171
172
  createdAt: string;
172
173
  }
@@ -201,6 +202,10 @@ interface GroupNodesOptions {
201
202
  keepGroupFrame?: boolean;
202
203
  }
203
204
 
205
+ interface ApplyUpdatesOptions {
206
+ skipGroupChildTranslation?: boolean;
207
+ }
208
+
204
209
  function formatBatchUpdateDescription(updates: CanvasNodeUpdate[]): string {
205
210
  let moved = 0;
206
211
  let resized = 0;
@@ -1216,7 +1221,7 @@ class CanvasStateManager {
1216
1221
  };
1217
1222
  }
1218
1223
 
1219
- applyUpdates(updates: CanvasNodeUpdate[]): { applied: number; skipped: number } {
1224
+ applyUpdates(updates: CanvasNodeUpdate[], options: ApplyUpdatesOptions = {}): { applied: number; skipped: number } {
1220
1225
  let applied = 0;
1221
1226
  let skipped = 0;
1222
1227
  const touchedParentGroups = new Map<string, { compact: boolean }>();
@@ -1259,7 +1264,7 @@ class CanvasStateManager {
1259
1264
  }
1260
1265
  oldSnapshots.set(update.id, structuredClone(existing));
1261
1266
  appliedUpdates.push({ id: update.id, ...structuredClone(nextPatch) });
1262
- if (existing.type === 'group' && nextPatch.position) {
1267
+ if (existing.type === 'group' && nextPatch.position && options.skipGroupChildTranslation !== true) {
1263
1268
  this.translateGroupChildren(
1264
1269
  update.id,
1265
1270
  nextPatch.position.x - existing.position.x,
@@ -1297,7 +1302,7 @@ class CanvasStateManager {
1297
1302
  operationType: 'batch',
1298
1303
  description: formatBatchUpdateDescription(appliedUpdates),
1299
1304
  forward: this.suppressed(() => {
1300
- this.applyUpdates(appliedUpdates.map((update) => structuredClone(update)));
1305
+ this.applyUpdates(appliedUpdates.map((update) => structuredClone(update)), options);
1301
1306
  }),
1302
1307
  inverse: this.suppressed(() => {
1303
1308
  for (const snapshot of inverseSnapshots) {