pmx-canvas 0.3.2 → 0.3.4

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 (70) hide show
  1. package/CHANGELOG.md +69 -0
  2. package/Readme.md +2 -1
  3. package/dist/canvas/index.js +85 -83
  4. package/dist/json-render/index.js +47 -47
  5. package/dist/types/cli/agent.d.ts +13 -8
  6. package/dist/types/cli/commands/apps.d.ts +1 -0
  7. package/dist/types/cli/commands/ax.d.ts +1 -0
  8. package/dist/types/cli/commands/copilot.d.ts +1 -0
  9. package/dist/types/cli/commands/edges.d.ts +1 -0
  10. package/dist/types/cli/commands/groups.d.ts +1 -0
  11. package/dist/types/cli/commands/history.d.ts +1 -0
  12. package/dist/types/cli/commands/nodes.d.ts +1 -0
  13. package/dist/types/cli/commands/pins.d.ts +1 -0
  14. package/dist/types/cli/commands/query.d.ts +1 -0
  15. package/dist/types/cli/commands/view.d.ts +1 -0
  16. package/dist/types/cli/commands/webview.d.ts +1 -0
  17. package/dist/types/cli/daemon.d.ts +17 -0
  18. package/dist/types/cli/shared.d.ts +73 -0
  19. package/dist/types/client/canvas/ExpandedNodeOverlay.d.ts +1 -1
  20. package/dist/types/client/nodes/ExtAppFrame.d.ts +13 -0
  21. package/dist/types/client/nodes/HtmlNode.d.ts +1 -1
  22. package/dist/types/client/nodes/McpAppNode.d.ts +1 -1
  23. package/dist/types/client/nodes/use-ax-surface-bridge.d.ts +20 -0
  24. package/dist/types/server/canvas-operations.d.ts +2 -0
  25. package/dist/types/server/diagram-presets.d.ts +8 -0
  26. package/dist/types/server/operations/composites.d.ts +0 -9
  27. package/dist/types/shared/ax-surface-protocol.d.ts +18 -0
  28. package/docs/RELEASE.md +11 -0
  29. package/docs/bun-webview-integration.md +5 -0
  30. package/docs/environment.md +48 -0
  31. package/docs/node-types.md +5 -0
  32. package/docs/plans/plan-009-tech-debt-backlog.md +27 -9
  33. package/docs/screenshot.png +0 -0
  34. package/package.json +8 -5
  35. package/skills/pmx-canvas/SKILL.md +11 -8
  36. package/skills/pmx-canvas/evals/evals.json +5 -5
  37. package/skills/pmx-canvas/references/full-reference.md +8 -1
  38. package/src/cli/agent.ts +22 -3512
  39. package/src/cli/commands/apps.ts +165 -0
  40. package/src/cli/commands/ax.ts +604 -0
  41. package/src/cli/commands/copilot.ts +43 -0
  42. package/src/cli/commands/edges.ts +73 -0
  43. package/src/cli/commands/groups.ts +81 -0
  44. package/src/cli/commands/history.ts +220 -0
  45. package/src/cli/commands/nodes.ts +954 -0
  46. package/src/cli/commands/pins.ts +42 -0
  47. package/src/cli/commands/query.ts +223 -0
  48. package/src/cli/commands/view.ts +186 -0
  49. package/src/cli/commands/webview.ts +227 -0
  50. package/src/cli/daemon.ts +39 -7
  51. package/src/cli/shared.ts +860 -0
  52. package/src/client/canvas/ExpandedNodeOverlay.tsx +3 -2
  53. package/src/client/nodes/ExtAppFrame.tsx +166 -52
  54. package/src/client/nodes/HtmlNode.tsx +8 -51
  55. package/src/client/nodes/McpAppNode.tsx +12 -47
  56. package/src/client/nodes/use-ax-surface-bridge.ts +71 -0
  57. package/src/json-render/renderer/index.tsx +3 -2
  58. package/src/mcp/server.ts +0 -47
  59. package/src/server/bundled-skills.ts +5 -1
  60. package/src/server/canvas-operations.ts +8 -0
  61. package/src/server/diagram-presets.ts +15 -1
  62. package/src/server/html-surface.ts +11 -6
  63. package/src/server/operations/composites.ts +1 -13
  64. package/src/server/operations/invoker.ts +10 -3
  65. package/src/server/operations/mcp.ts +51 -1
  66. package/src/server/operations/ops/app.ts +5 -0
  67. package/src/server/server.ts +61 -3
  68. package/src/shared/ax-surface-protocol.ts +22 -0
  69. package/dist/types/client/canvas/ContextPinHud.d.ts +0 -1
  70. package/src/client/canvas/ContextPinHud.tsx +0 -17
@@ -0,0 +1,165 @@
1
+ // App/composite commands: external-app add, diagram add, batch, and
2
+ // web-artifact build.
3
+
4
+ import { readFileSync } from 'node:fs';
5
+ import { DEFAULT_EXCALIDRAW_ELEMENTS } from '../../server/diagram-presets.js';
6
+ import {
7
+ applyCommonGeometryFlags,
8
+ cmd,
9
+ COMMANDS,
10
+ die,
11
+ getStringFlag,
12
+ invokeOperation,
13
+ optionalPositiveFiniteFlag,
14
+ output,
15
+ parseFlags,
16
+ parseJsonValue,
17
+ readStdin,
18
+ runWebArtifactBuildCommand,
19
+ showCommandHelp,
20
+ } from '../shared.js';
21
+
22
+ // ── external-app add ─────────────────────────────────────────
23
+ cmd(
24
+ 'external-app add',
25
+ 'Create a hosted external app node',
26
+ ['pmx-canvas external-app add --kind excalidraw --title "Diagram"'],
27
+ async (args) => {
28
+ const { flags } = parseFlags(args);
29
+ if (flags.help || flags.h) return showCommandHelp('external-app add');
30
+
31
+ const kind = typeof flags.kind === 'string' ? flags.kind.trim() : '';
32
+ if (kind !== 'excalidraw') {
33
+ die('Unsupported external app kind.', 'Use: pmx-canvas external-app add --kind excalidraw --title "Diagram"');
34
+ }
35
+
36
+ const body: Record<string, unknown> = {
37
+ title: typeof flags.title === 'string' ? flags.title : 'Excalidraw Diagram',
38
+ elements: DEFAULT_EXCALIDRAW_ELEMENTS,
39
+ };
40
+ const nodeId = getStringFlag(flags, 'node-id', 'nodeId', 'id');
41
+ if (nodeId) body.nodeId = nodeId;
42
+ const elementsJson = getStringFlag(flags, 'elements-json', 'elements');
43
+ if (elementsJson !== undefined)
44
+ body.elements = parseJsonValue(
45
+ elementsJson,
46
+ 'Excalidraw elements',
47
+ 'Use --elements-json \'[{"type":"rectangle","id":"r1","x":0,"y":0,"width":120,"height":80}]\'',
48
+ );
49
+ const elementsFile = getStringFlag(flags, 'elements-file', 'initial-file');
50
+ if (elementsFile)
51
+ body.elements = parseJsonValue(
52
+ readFileSync(elementsFile, 'utf-8'),
53
+ 'Excalidraw elements file',
54
+ 'Use --elements-file ./scene.excalidraw',
55
+ );
56
+ applyCommonGeometryFlags(body, flags, {
57
+ x: 'Use a finite number, e.g. --x 500',
58
+ y: 'Use a finite number, e.g. --y 300',
59
+ width: 'Use a positive number, e.g. --width 960',
60
+ height: 'Use a positive number, e.g. --height 720',
61
+ });
62
+ const timeoutMs = optionalPositiveFiniteFlag(
63
+ flags,
64
+ 'timeout-ms',
65
+ 'Use a positive number, e.g. --timeout-ms 120000',
66
+ );
67
+ if (timeoutMs !== undefined) body.timeoutMs = timeoutMs;
68
+
69
+ const result = await invokeOperation('diagram.open', body);
70
+ output(
71
+ result && typeof result === 'object' && !Array.isArray(result) && 'nodeId' in result && !('id' in result)
72
+ ? { id: (result as { nodeId?: unknown }).nodeId, ...result }
73
+ : result,
74
+ );
75
+ },
76
+ );
77
+
78
+ cmd(
79
+ 'diagram add',
80
+ 'Create an Excalidraw diagram node',
81
+ [
82
+ 'pmx-canvas diagram add --title "Architecture"',
83
+ 'pmx-canvas diagram add --title "Architecture" --elements \'[{"type":"rectangle","id":"r1","x":0,"y":0,"width":120,"height":80}]\'',
84
+ ],
85
+ async (args) => {
86
+ const { flags } = parseFlags(args);
87
+ if (flags.help || flags.h) return showCommandHelp('diagram add');
88
+ const externalAppAdd = COMMANDS['external-app add'];
89
+ await externalAppAdd.run([...args, '--kind', 'excalidraw']);
90
+ },
91
+ );
92
+
93
+ // ── batch ────────────────────────────────────────────────────
94
+ cmd(
95
+ 'batch',
96
+ 'Run a batch of canvas operations from JSON',
97
+ [
98
+ 'pmx-canvas batch --file ./canvas-ops.json',
99
+ 'pmx-canvas batch --json \'[{"op":"node.add","assign":"a","args":{"type":"markdown","title":"A"}}]\'',
100
+ 'pmx-canvas batch --json \'[{"op":"graph.add","assign":"g","args":{"graphType":"bar","data":[{"label":"Docs","value":5}],"xKey":"label","yKey":"value"}}]\'',
101
+ 'cat ops.json | pmx-canvas batch --stdin',
102
+ ],
103
+ async (args) => {
104
+ const { flags } = parseFlags(args);
105
+ if (flags.help || flags.h) return showCommandHelp('batch');
106
+
107
+ let raw = '';
108
+ if (typeof flags.file === 'string') {
109
+ try {
110
+ raw = readFileSync(flags.file, 'utf-8');
111
+ } catch (error) {
112
+ die(
113
+ `Unable to read --file: ${error instanceof Error ? error.message : String(error)}`,
114
+ 'Use: pmx-canvas batch --file ./canvas-ops.json',
115
+ );
116
+ }
117
+ } else if (typeof flags.json === 'string') {
118
+ raw = flags.json;
119
+ } else if (flags.stdin) {
120
+ raw = await readStdin();
121
+ } else {
122
+ die('Batch operations require --file, --json, or --stdin.', 'Use: pmx-canvas batch --file ./canvas-ops.json');
123
+ }
124
+
125
+ let parsed: unknown;
126
+ try {
127
+ parsed = JSON.parse(raw);
128
+ } catch (error) {
129
+ die(
130
+ `Invalid batch JSON: ${error instanceof Error ? error.message : String(error)}`,
131
+ 'Use a JSON array of operations or an object with an "operations" array.',
132
+ );
133
+ }
134
+
135
+ // A parsed `null` (--json 'null') must become an empty batch — the invoker
136
+ // iterates Object.entries(input), which throws on null. The raw route
137
+ // coerced it to { ok:true, results: [] } server-side; keep that behavior.
138
+ const result = await invokeOperation(
139
+ 'canvas.batch',
140
+ Array.isArray(parsed) ? { operations: parsed } : ((parsed ?? { operations: [] }) as Record<string, unknown>),
141
+ );
142
+ output(result);
143
+ // canvas.batch declares errorBodyAsResult, so a failed batch is RETURNED as
144
+ // its full { ok:false, results, refs, failedIndex, error } envelope instead
145
+ // of throwing. Print it (above), then exit 1 — a deliberate change from the
146
+ // old bare stderr die: richer failure output, same non-zero exit.
147
+ if ((result as { ok?: boolean }).ok === false) process.exit(1);
148
+ },
149
+ );
150
+
151
+ // ── web-artifact build ───────────────────────────────────────
152
+ cmd(
153
+ 'web-artifact build',
154
+ 'Build a bundled HTML web artifact and optionally open it on the canvas',
155
+ [
156
+ 'pmx-canvas web-artifact build --title "Dashboard" --app-file ./App.tsx',
157
+ 'pmx-canvas web-artifact build --title "Dashboard" --app-file ./App.tsx --index-css-file ./index.css',
158
+ 'pmx-canvas web-artifact build --title "Dashboard" --app-file ./App.tsx --include-logs',
159
+ ],
160
+ async (args) => {
161
+ const { flags } = parseFlags(args);
162
+ if (flags.help || flags.h) return showCommandHelp('web-artifact build');
163
+ await runWebArtifactBuildCommand(flags);
164
+ },
165
+ );