pmx-canvas 0.4.6 → 0.4.7
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/CHANGELOG.md +62 -0
- package/Readme.md +56 -33
- package/dist/canvas/global.css +101 -3
- package/dist/canvas/index.js +87 -83
- package/dist/types/cli/shared.d.ts +13 -1
- package/dist/types/client/canvas/CanvasNode.d.ts +11 -0
- package/dist/types/client/canvas/EdgeLayer.d.ts +8 -0
- package/dist/types/client/nodes/AxStepControls.d.ts +4 -0
- package/dist/types/client/nodes/FileNode.d.ts +14 -0
- package/dist/types/client/state/canvas-store.d.ts +10 -0
- package/dist/types/client/state/intent-bridge.d.ts +9 -0
- package/dist/types/server/ax-flow-loop.d.ts +5 -0
- package/dist/types/server/ax-interaction.d.ts +21 -2
- package/dist/types/server/canvas-operations.d.ts +5 -0
- package/dist/types/server/canvas-state.d.ts +8 -0
- package/dist/types/server/canvas-validation.d.ts +15 -21
- package/dist/types/server/file-content.d.ts +46 -0
- package/dist/types/server/html-primitives.d.ts +13 -1
- package/dist/types/server/operations/ops/ax-work.d.ts +1 -0
- package/dist/types/server/server.d.ts +1 -0
- package/dist/types/server/web-artifacts.d.ts +14 -0
- package/dist/types/shared/ax-flow.d.ts +51 -0
- package/dist/types/shared/node-sizes.d.ts +33 -0
- package/docs/cli.md +19 -2
- package/docs/environment.md +1 -0
- package/docs/http-api.md +17 -0
- package/docs/mcp.md +12 -0
- package/docs/node-types.md +45 -1
- package/docs/screenshot.png +0 -0
- package/package.json +2 -2
- package/skills/pmx-canvas/SKILL.md +68 -7
- package/skills/pmx-canvas/evals/evals.json +54 -3
- package/skills/pmx-canvas/references/full-reference.md +11 -6
- package/src/cli/commands/history.ts +1 -1
- package/src/cli/commands/nodes.ts +2 -2
- package/src/cli/commands/query.ts +1 -1
- package/src/cli/commands/view.ts +1 -1
- package/src/cli/index.ts +6 -0
- package/src/cli/shared.ts +34 -5
- package/src/client/App.tsx +28 -15
- package/src/client/canvas/CanvasNode.tsx +54 -5
- package/src/client/canvas/EdgeLayer.tsx +44 -24
- package/src/client/canvas/ExpandedNodeOverlay.tsx +11 -0
- package/src/client/canvas/auto-fit.ts +10 -1
- package/src/client/canvas/use-pan-zoom.ts +16 -1
- package/src/client/nodes/AxStepControls.tsx +226 -0
- package/src/client/nodes/FileNode.tsx +249 -51
- package/src/client/state/canvas-store.ts +19 -0
- package/src/client/state/intent-bridge.ts +32 -0
- package/src/client/state/sse-bridge.ts +4 -1
- package/src/client/theme/global.css +101 -3
- package/src/server/ax-flow-loop.ts +114 -0
- package/src/server/ax-interaction.ts +299 -4
- package/src/server/canvas-operations.ts +44 -17
- package/src/server/canvas-state.ts +20 -10
- package/src/server/canvas-validation.ts +50 -41
- package/src/server/demo-state.json +4605 -523
- package/src/server/demo.ts +24 -0
- package/src/server/file-content.ts +152 -0
- package/src/server/file-watcher.ts +7 -10
- package/src/server/html-primitives.ts +636 -0
- package/src/server/operations/ops/ax-work.ts +5 -0
- package/src/server/operations/ops/nodes.ts +15 -1
- package/src/server/operations/ops/viewport.ts +7 -1
- package/src/server/server.ts +106 -5
- package/src/server/web-artifacts.ts +109 -0
- package/src/shared/ax-flow.ts +102 -0
- package/src/shared/node-sizes.ts +52 -0
- package/dist/types/server/chart-template.d.ts +0 -29
- package/src/server/chart-template.ts +0 -448
|
@@ -1,46 +1,11 @@
|
|
|
1
1
|
import type { CanvasLayout, CanvasNodeState } from './canvas-state.js';
|
|
2
2
|
import { getCanvasNodeTitle } from './canvas-serialization.js';
|
|
3
|
+
// The readability floor is SHARED with the client: the server clamps it at
|
|
4
|
+
// creation and `validate` reports violations, but the browser's auto-fit must
|
|
5
|
+
// honor the same floor or it silently undoes the clamp (0.4.6 Finding AA).
|
|
6
|
+
import { nodeMinSize } from '../shared/node-sizes.js';
|
|
3
7
|
|
|
4
|
-
|
|
5
|
-
* Per-type minimum node size (0.4.5 report follow-up): agents frequently
|
|
6
|
-
* create nodes with explicit frames far too small for their content — clipped
|
|
7
|
-
* markdown, charts squeezed behind inner scrollbars. Explicit sizes below the
|
|
8
|
-
* floor are clamped UP at creation (canvas-operations.ts creators);
|
|
9
|
-
* `strictSize: true` is the escape hatch for a genuinely small fixed frame.
|
|
10
|
-
* Floors sit below every type default and above the point of unreadability.
|
|
11
|
-
* Creation-only: later updates are untouched (the browser's drag-resize
|
|
12
|
-
* enforces its own 200×100 floor client-side), but `validate` reports any
|
|
13
|
-
* node below its floor as an advisory sizeWarning. Absent types (trace,
|
|
14
|
-
* group, prompt/response) are intentionally unclamped — trace is small by
|
|
15
|
-
* design, groups size to their children.
|
|
16
|
-
*/
|
|
17
|
-
export const NODE_MIN_CREATE_SIZES: Partial<Record<CanvasNodeState['type'], { width: number; height: number }>> = {
|
|
18
|
-
markdown: { width: 360, height: 180 },
|
|
19
|
-
context: { width: 360, height: 180 },
|
|
20
|
-
file: { width: 360, height: 200 },
|
|
21
|
-
diff: { width: 420, height: 240 },
|
|
22
|
-
mermaid: { width: 360, height: 240 },
|
|
23
|
-
status: { width: 280, height: 120 },
|
|
24
|
-
ledger: { width: 320, height: 200 },
|
|
25
|
-
image: { width: 240, height: 180 },
|
|
26
|
-
html: { width: 420, height: 280 },
|
|
27
|
-
webpage: { width: 420, height: 280 },
|
|
28
|
-
'json-render': { width: 420, height: 280 },
|
|
29
|
-
graph: { width: 420, height: 280 },
|
|
30
|
-
'mcp-app': { width: 480, height: 320 },
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
export function clampCreateNodeSize(
|
|
34
|
-
type: CanvasNodeState['type'],
|
|
35
|
-
width: number,
|
|
36
|
-
height: number,
|
|
37
|
-
strictSize?: boolean,
|
|
38
|
-
): { width: number; height: number } {
|
|
39
|
-
if (strictSize === true) return { width, height };
|
|
40
|
-
const min = NODE_MIN_CREATE_SIZES[type];
|
|
41
|
-
if (!min) return { width, height };
|
|
42
|
-
return { width: Math.max(width, min.width), height: Math.max(height, min.height) };
|
|
43
|
-
}
|
|
8
|
+
export { NODE_MIN_SIZES, clampCreateNodeSize, nodeMinSize } from '../shared/node-sizes.js';
|
|
44
9
|
|
|
45
10
|
export interface CanvasValidationPair {
|
|
46
11
|
aId: string;
|
|
@@ -66,12 +31,26 @@ export interface CanvasSizeWarning {
|
|
|
66
31
|
minHeight: number;
|
|
67
32
|
}
|
|
68
33
|
|
|
34
|
+
export interface CanvasHiddenEdgeEndpoint {
|
|
35
|
+
edgeId: string;
|
|
36
|
+
nodeId: string;
|
|
37
|
+
nodeTitle: string | null;
|
|
38
|
+
dockPosition: 'left' | 'right';
|
|
39
|
+
}
|
|
40
|
+
|
|
69
41
|
export interface CanvasValidationResult {
|
|
70
42
|
ok: boolean;
|
|
71
43
|
collisions: CanvasValidationPair[];
|
|
72
44
|
containments: CanvasContainmentIssue[];
|
|
73
45
|
containmentViolations: CanvasContainmentIssue[];
|
|
74
46
|
missingEdgeEndpoints: Array<{ edgeId: string; from: string; to: string }>;
|
|
47
|
+
/**
|
|
48
|
+
* Edges whose endpoint node is DOCKED — it renders in the HUD column, not on
|
|
49
|
+
* the canvas, so the edge visually terminates in empty space even though both
|
|
50
|
+
* endpoint IDs resolve (0.4.6 orb feedback #1). Advisory: reported for
|
|
51
|
+
* diagnosis, but does NOT fail `ok` (see the note at the return site).
|
|
52
|
+
*/
|
|
53
|
+
hiddenEdgeEndpoints: CanvasHiddenEdgeEndpoint[];
|
|
75
54
|
/** Nodes below their type's readable minimum (advisory — does not fail `ok`). */
|
|
76
55
|
sizeWarnings: CanvasSizeWarning[];
|
|
77
56
|
summary: {
|
|
@@ -81,6 +60,7 @@ export interface CanvasValidationResult {
|
|
|
81
60
|
containments: number;
|
|
82
61
|
containmentViolations: number;
|
|
83
62
|
missingEdgeEndpoints: number;
|
|
63
|
+
hiddenEdgeEndpoints: number;
|
|
84
64
|
sizeWarnings: number;
|
|
85
65
|
};
|
|
86
66
|
}
|
|
@@ -163,6 +143,28 @@ export function validateCanvasLayout(layout: CanvasLayout): CanvasValidationResu
|
|
|
163
143
|
.filter((edge) => !nodeIds.has(edge.from) || !nodeIds.has(edge.to))
|
|
164
144
|
.map((edge) => ({ edgeId: edge.id, from: edge.from, to: edge.to }));
|
|
165
145
|
|
|
146
|
+
// An edge to a DOCKED node cannot be drawn: docked nodes live in the HUD
|
|
147
|
+
// column, and the world-space edge layer skips them, so the edge trails off
|
|
148
|
+
// into empty canvas. Structural validation used to miss this entirely because
|
|
149
|
+
// both endpoint IDs resolve (0.4.6 orb feedback #1).
|
|
150
|
+
const dockedById = new Map(
|
|
151
|
+
layout.nodes.filter((node) => node.dockPosition != null).map((node) => [node.id, node] as const),
|
|
152
|
+
);
|
|
153
|
+
const hiddenEdgeEndpoints: CanvasHiddenEdgeEndpoint[] = layout.edges.flatMap((edge) =>
|
|
154
|
+
[edge.from, edge.to].flatMap((nodeId) => {
|
|
155
|
+
const docked = dockedById.get(nodeId);
|
|
156
|
+
if (!docked || docked.dockPosition == null) return [];
|
|
157
|
+
return [
|
|
158
|
+
{
|
|
159
|
+
edgeId: edge.id,
|
|
160
|
+
nodeId,
|
|
161
|
+
nodeTitle: getCanvasNodeTitle(docked),
|
|
162
|
+
dockPosition: docked.dockPosition,
|
|
163
|
+
},
|
|
164
|
+
];
|
|
165
|
+
}),
|
|
166
|
+
);
|
|
167
|
+
|
|
166
168
|
// Advisory: nodes below their type's readable floor (clipped/unreadable
|
|
167
169
|
// content — 0.4.5 report follow-up). Creation clamps these, but resized or
|
|
168
170
|
// strictSize-created nodes can still be undersized; surface them so an
|
|
@@ -171,7 +173,7 @@ export function validateCanvasLayout(layout: CanvasLayout): CanvasValidationResu
|
|
|
171
173
|
const sizeWarnings: CanvasSizeWarning[] = layout.nodes
|
|
172
174
|
.filter((node) => !node.collapsed && node.dockPosition == null && node.data?.strictSize !== true)
|
|
173
175
|
.flatMap((node) => {
|
|
174
|
-
const min =
|
|
176
|
+
const min = nodeMinSize(node.type);
|
|
175
177
|
if (!min || (node.size.width >= min.width && node.size.height >= min.height)) return [];
|
|
176
178
|
return [
|
|
177
179
|
{
|
|
@@ -187,11 +189,17 @@ export function validateCanvasLayout(layout: CanvasLayout): CanvasValidationResu
|
|
|
187
189
|
});
|
|
188
190
|
|
|
189
191
|
return {
|
|
192
|
+
// `hiddenEdgeEndpoints` is ADVISORY (like sizeWarnings): a docked endpoint
|
|
193
|
+
// is a rendering observation, not a structural defect, and folding it into
|
|
194
|
+
// `ok` would flip previously-healthy boards to ok:false with no user change
|
|
195
|
+
// — `ok` is a documented response field of a frozen surface, so that is a
|
|
196
|
+
// contract break, not a patch. It is still reported for diagnosis.
|
|
190
197
|
ok: collisions.length === 0 && containmentViolations.length === 0 && missingEdgeEndpoints.length === 0,
|
|
191
198
|
collisions,
|
|
192
199
|
containments,
|
|
193
200
|
containmentViolations,
|
|
194
201
|
missingEdgeEndpoints,
|
|
202
|
+
hiddenEdgeEndpoints,
|
|
195
203
|
sizeWarnings,
|
|
196
204
|
summary: {
|
|
197
205
|
nodes: layout.nodes.length,
|
|
@@ -200,6 +208,7 @@ export function validateCanvasLayout(layout: CanvasLayout): CanvasValidationResu
|
|
|
200
208
|
containments: containments.length,
|
|
201
209
|
containmentViolations: containmentViolations.length,
|
|
202
210
|
missingEdgeEndpoints: missingEdgeEndpoints.length,
|
|
211
|
+
hiddenEdgeEndpoints: hiddenEdgeEndpoints.length,
|
|
203
212
|
sizeWarnings: sizeWarnings.length,
|
|
204
213
|
},
|
|
205
214
|
};
|