pmx-canvas 0.1.18 → 0.1.20
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 +128 -0
- package/Readme.md +19 -6
- package/dist/canvas/global.css +35 -2
- package/dist/canvas/index.js +70 -69
- package/dist/json-render/index.js +109 -109
- package/dist/types/client/canvas/CanvasViewport.d.ts +1 -1
- package/dist/types/client/icons.d.ts +2 -0
- package/dist/types/client/state/canvas-store.d.ts +2 -0
- package/dist/types/client/types.d.ts +2 -1
- package/dist/types/json-render/charts/components.d.ts +5 -1
- package/dist/types/json-render/renderer/index.d.ts +1 -0
- package/dist/types/json-render/server.d.ts +1 -0
- package/dist/types/mcp/canvas-access.d.ts +3 -0
- package/dist/types/server/canvas-operations.d.ts +4 -0
- package/dist/types/server/canvas-schema.d.ts +19 -3
- package/dist/types/server/canvas-serialization.d.ts +1 -0
- package/dist/types/server/canvas-state.d.ts +8 -2
- package/dist/types/server/html-primitives.d.ts +34 -0
- package/dist/types/server/index.d.ts +19 -0
- package/docs/RELEASE.md +153 -0
- package/docs/bun-webview-integration.md +296 -0
- package/docs/cli.md +143 -0
- package/docs/evals/e2e-cli-coverage.md +61 -0
- package/docs/http-api.md +201 -0
- package/docs/mcp.md +137 -0
- package/docs/node-types.md +272 -0
- package/docs/plans/.gitkeep +0 -0
- package/docs/plans/plan-001-semantic-watch-mvp.md +335 -0
- package/docs/plans/plan-002-human-attention-layer-design-spec.md +679 -0
- package/docs/plans/plan-003-human-attention-layer-implementation-plan.md +572 -0
- package/docs/reactive-canvas-proposal.md +578 -0
- package/docs/release-review-0.1.0.md +38 -0
- package/docs/screenshot.png +0 -0
- package/docs/screenshots/demo-workbench-dark.png +0 -0
- package/docs/screenshots/demo-workbench-light.png +0 -0
- package/docs/screenshots/welcome-dark.png +0 -0
- package/docs/screenshots/welcome-light.png +0 -0
- package/docs/sdk.md +103 -0
- package/package.json +2 -1
- package/skills/pmx-canvas/SKILL.md +8 -0
- package/src/cli/agent.ts +167 -5
- package/src/client/App.tsx +20 -1
- package/src/client/canvas/AnnotationLayer.tsx +33 -12
- package/src/client/canvas/CanvasViewport.tsx +88 -7
- package/src/client/canvas/CommandPalette.tsx +1 -1
- package/src/client/canvas/ContextMenu.tsx +2 -2
- package/src/client/canvas/ExpandedNodeOverlay.tsx +7 -1
- package/src/client/icons.tsx +13 -0
- package/src/client/nodes/McpAppNode.tsx +12 -4
- package/src/client/state/canvas-store.ts +15 -5
- package/src/client/state/sse-bridge.ts +4 -3
- package/src/client/theme/global.css +35 -2
- package/src/client/types.ts +2 -1
- package/src/json-render/charts/components.tsx +41 -7
- package/src/json-render/charts/extra-components.tsx +13 -12
- package/src/json-render/renderer/index.tsx +1 -0
- package/src/json-render/server.ts +3 -1
- package/src/mcp/canvas-access.ts +25 -0
- package/src/mcp/server.ts +85 -27
- package/src/server/agent-context.ts +17 -0
- package/src/server/canvas-operations.ts +91 -38
- package/src/server/canvas-schema.ts +83 -3
- package/src/server/canvas-serialization.ts +9 -2
- package/src/server/canvas-state.ts +27 -9
- package/src/server/demo-state.json +1143 -0
- package/src/server/demo.ts +25 -777
- package/src/server/html-primitives.ts +990 -0
- package/src/server/index.ts +43 -2
- package/src/server/server.ts +140 -14
- package/src/server/spatial-analysis.ts +3 -3
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { CanvasNodeState } from '../types';
|
|
2
|
-
type AnnotationTool = 'pen' | 'eraser' | null;
|
|
2
|
+
type AnnotationTool = 'pen' | 'eraser' | 'text' | null;
|
|
3
3
|
interface CanvasViewportProps {
|
|
4
4
|
onNodeContextMenu?: (e: MouseEvent, nodeId: string) => void;
|
|
5
5
|
onCanvasContextMenu?: (e: MouseEvent, canvasX: number, canvasY: number) => void;
|
|
@@ -23,6 +23,8 @@ export declare function IconMoon(p: IconProps): JSX.Element;
|
|
|
23
23
|
export declare function IconPen(p: IconProps): JSX.Element;
|
|
24
24
|
/** Eraser — remove canvas annotations */
|
|
25
25
|
export declare function IconEraser(p: IconProps): JSX.Element;
|
|
26
|
+
/** Text cursor — canvas text annotation mode */
|
|
27
|
+
export declare function IconTextAnnotation(p: IconProps): JSX.Element;
|
|
26
28
|
/** Camera — snapshots */
|
|
27
29
|
export declare function IconSnapshot(p: IconProps): JSX.Element;
|
|
28
30
|
/** Bullseye — trace toggle */
|
|
@@ -45,9 +45,11 @@ export declare function removeEdgesForNode(nodeId: string): void;
|
|
|
45
45
|
export declare function addAnnotation(annotation: CanvasAnnotation): void;
|
|
46
46
|
export declare function removeAnnotation(id: string): void;
|
|
47
47
|
export declare function createAnnotationFromClient(input: {
|
|
48
|
+
type?: CanvasAnnotation['type'];
|
|
48
49
|
points: CanvasAnnotation['points'];
|
|
49
50
|
color: string;
|
|
50
51
|
width: number;
|
|
52
|
+
text?: string;
|
|
51
53
|
label?: string;
|
|
52
54
|
}): Promise<{
|
|
53
55
|
ok: boolean;
|
|
@@ -35,7 +35,7 @@ export interface CanvasAnnotationPoint {
|
|
|
35
35
|
}
|
|
36
36
|
export interface CanvasAnnotation {
|
|
37
37
|
id: string;
|
|
38
|
-
type: 'freehand';
|
|
38
|
+
type: 'freehand' | 'text';
|
|
39
39
|
points: CanvasAnnotationPoint[];
|
|
40
40
|
bounds: {
|
|
41
41
|
x: number;
|
|
@@ -45,6 +45,7 @@ export interface CanvasAnnotation {
|
|
|
45
45
|
};
|
|
46
46
|
color: string;
|
|
47
47
|
width: number;
|
|
48
|
+
text?: string;
|
|
48
49
|
label?: string;
|
|
49
50
|
createdAt: string;
|
|
50
51
|
}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* chat example. Each component receives BaseComponentProps<T> and renders
|
|
7
7
|
* a responsive chart inside a styled container.
|
|
8
8
|
*/
|
|
9
|
-
import type
|
|
9
|
+
import { type ReactNode } from 'react';
|
|
10
10
|
import type { BaseComponentProps } from '@json-render/react';
|
|
11
11
|
export declare const CHART_COLORS: string[];
|
|
12
12
|
export type AggregateMode = 'sum' | 'count' | 'avg';
|
|
@@ -56,6 +56,10 @@ export declare const axisTickMargin = 8;
|
|
|
56
56
|
export declare const legendMargin: {
|
|
57
57
|
top: number;
|
|
58
58
|
};
|
|
59
|
+
export declare function useChartFrameHeight(explicitHeight: number | null | undefined, fallbackHeight?: number): {
|
|
60
|
+
frameRef: import("react").RefObject<HTMLDivElement | null>;
|
|
61
|
+
height: number;
|
|
62
|
+
};
|
|
59
63
|
/** Shared wrapper for cartesian charts (Line + Bar). */
|
|
60
64
|
export declare function CartesianChart({ props, children, className, }: {
|
|
61
65
|
props: CartesianChartProps;
|
|
@@ -8,6 +8,8 @@ type AddDiagramInput = Parameters<PmxCanvas['addDiagram']>[0];
|
|
|
8
8
|
type AddJsonRenderNodeInput = Parameters<PmxCanvas['addJsonRenderNode']>[0];
|
|
9
9
|
type AddJsonRenderNodeResult = ReturnType<PmxCanvas['addJsonRenderNode']>;
|
|
10
10
|
type AddHtmlNodeInput = Parameters<PmxCanvas['addHtmlNode']>[0];
|
|
11
|
+
type AddHtmlPrimitiveInput = Parameters<PmxCanvas['addHtmlPrimitive']>[0];
|
|
12
|
+
type AddHtmlPrimitiveResult = ReturnType<PmxCanvas['addHtmlPrimitive']>;
|
|
11
13
|
type AddGraphNodeInput = Parameters<PmxCanvas['addGraphNode']>[0];
|
|
12
14
|
type AddGraphNodeResult = ReturnType<PmxCanvas['addGraphNode']>;
|
|
13
15
|
type UpdateNodePatch = Parameters<PmxCanvas['updateNode']>[1];
|
|
@@ -50,6 +52,7 @@ export interface CanvasAccess {
|
|
|
50
52
|
addDiagram(input: AddDiagramInput): Promise<OpenMcpAppResult>;
|
|
51
53
|
addJsonRenderNode(input: AddJsonRenderNodeInput): Promise<AddJsonRenderNodeResult>;
|
|
52
54
|
addHtmlNode(input: AddHtmlNodeInput): Promise<string>;
|
|
55
|
+
addHtmlPrimitive(input: AddHtmlPrimitiveInput): Promise<AddHtmlPrimitiveResult>;
|
|
53
56
|
addGraphNode(input: AddGraphNodeInput): Promise<AddGraphNodeResult>;
|
|
54
57
|
buildWebArtifact(input: WebArtifactInput): Promise<WebArtifactResult>;
|
|
55
58
|
updateNode(id: string, patch: UpdateNodePatch): Promise<void>;
|
|
@@ -56,6 +56,10 @@ interface CanvasAddNodeInput {
|
|
|
56
56
|
fileMode?: 'path' | 'inline' | 'auto';
|
|
57
57
|
strictSize?: boolean;
|
|
58
58
|
}
|
|
59
|
+
export declare const MARKDOWN_NODE_DEFAULT_SIZE: {
|
|
60
|
+
width: number;
|
|
61
|
+
height: number;
|
|
62
|
+
};
|
|
59
63
|
interface CanvasCreateGroupInput {
|
|
60
64
|
title?: string;
|
|
61
65
|
childIds?: string[];
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type JsonRenderComponentDescriptor } from '../json-render/catalog.js';
|
|
2
2
|
import { type GraphNodeInput, type JsonRenderSpec } from '../json-render/server.js';
|
|
3
|
+
import { type HtmlPrimitiveDescriptor } from './html-primitives.js';
|
|
3
4
|
export interface CanvasCreateField {
|
|
4
5
|
name: string;
|
|
5
6
|
type: string;
|
|
@@ -19,8 +20,17 @@ export interface CanvasCreateTypeSchema {
|
|
|
19
20
|
}
|
|
20
21
|
export interface StructuredValidationResult {
|
|
21
22
|
ok: true;
|
|
22
|
-
type: 'json-render' | 'graph';
|
|
23
|
-
normalizedSpec
|
|
23
|
+
type: 'json-render' | 'graph' | 'html-primitive';
|
|
24
|
+
normalizedSpec?: JsonRenderSpec;
|
|
25
|
+
normalizedPrimitive?: {
|
|
26
|
+
kind: string;
|
|
27
|
+
title: string;
|
|
28
|
+
htmlBytes: number;
|
|
29
|
+
defaultSize: {
|
|
30
|
+
width: number;
|
|
31
|
+
height: number;
|
|
32
|
+
};
|
|
33
|
+
};
|
|
24
34
|
summary: Record<string, unknown>;
|
|
25
35
|
}
|
|
26
36
|
declare const CANONICAL_GRAPH_TYPES: readonly ["line", "bar", "pie", "area", "scatter", "radar", "stacked-bar", "composed"];
|
|
@@ -37,6 +47,7 @@ export declare function describeCanvasSchema(): {
|
|
|
37
47
|
graph: {
|
|
38
48
|
graphTypes: CanvasGraphType[];
|
|
39
49
|
};
|
|
50
|
+
htmlPrimitives: HtmlPrimitiveDescriptor[];
|
|
40
51
|
mcp: {
|
|
41
52
|
tools: string[];
|
|
42
53
|
resources: string[];
|
|
@@ -44,8 +55,13 @@ export declare function describeCanvasSchema(): {
|
|
|
44
55
|
};
|
|
45
56
|
};
|
|
46
57
|
export declare function validateStructuredCanvasPayload(input: {
|
|
47
|
-
type: 'json-render' | 'graph';
|
|
58
|
+
type: 'json-render' | 'graph' | 'html-primitive';
|
|
48
59
|
spec?: unknown;
|
|
49
60
|
graph?: GraphNodeInput;
|
|
61
|
+
primitive?: {
|
|
62
|
+
kind: string;
|
|
63
|
+
title?: string;
|
|
64
|
+
data?: Record<string, unknown>;
|
|
65
|
+
};
|
|
50
66
|
}): StructuredValidationResult;
|
|
51
67
|
export {};
|
|
@@ -39,6 +39,8 @@ export interface CanvasSnapshot {
|
|
|
39
39
|
export interface CanvasSnapshotListOptions {
|
|
40
40
|
limit?: number;
|
|
41
41
|
query?: string;
|
|
42
|
+
before?: string;
|
|
43
|
+
after?: string;
|
|
42
44
|
all?: boolean;
|
|
43
45
|
}
|
|
44
46
|
export interface CanvasSnapshotGcOptions {
|
|
@@ -88,7 +90,7 @@ export interface CanvasAnnotationPoint {
|
|
|
88
90
|
}
|
|
89
91
|
export interface CanvasAnnotation {
|
|
90
92
|
id: string;
|
|
91
|
-
type: 'freehand';
|
|
93
|
+
type: 'freehand' | 'text';
|
|
92
94
|
points: CanvasAnnotationPoint[];
|
|
93
95
|
bounds: {
|
|
94
96
|
x: number;
|
|
@@ -98,6 +100,7 @@ export interface CanvasAnnotation {
|
|
|
98
100
|
};
|
|
99
101
|
color: string;
|
|
100
102
|
width: number;
|
|
103
|
+
text?: string;
|
|
101
104
|
label?: string;
|
|
102
105
|
createdAt: string;
|
|
103
106
|
}
|
|
@@ -132,6 +135,9 @@ interface GroupNodesOptions {
|
|
|
132
135
|
layout?: 'grid' | 'column' | 'flow';
|
|
133
136
|
keepGroupFrame?: boolean;
|
|
134
137
|
}
|
|
138
|
+
interface ApplyUpdatesOptions {
|
|
139
|
+
skipGroupChildTranslation?: boolean;
|
|
140
|
+
}
|
|
135
141
|
declare class CanvasStateManager {
|
|
136
142
|
private nodes;
|
|
137
143
|
private edges;
|
|
@@ -229,7 +235,7 @@ declare class CanvasStateManager {
|
|
|
229
235
|
private removeEdgesForNode;
|
|
230
236
|
getLayout(): CanvasLayout;
|
|
231
237
|
getLayoutForPersistence(): CanvasLayout;
|
|
232
|
-
applyUpdates(updates: CanvasNodeUpdate[]): {
|
|
238
|
+
applyUpdates(updates: CanvasNodeUpdate[], options?: ApplyUpdatesOptions): {
|
|
233
239
|
applied: number;
|
|
234
240
|
skipped: number;
|
|
235
241
|
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export declare const HTML_PRIMITIVE_KINDS: readonly ["choice-grid", "plan-timeline", "review-sheet", "pr-writeup", "system-map", "code-walkthrough", "design-sheet", "component-gallery", "interaction-prototype", "flowchart", "deck", "illustration-set", "explainer", "status-report", "incident-report", "triage-board", "config-editor", "prompt-tuner"];
|
|
2
|
+
export type HtmlPrimitiveKind = typeof HTML_PRIMITIVE_KINDS[number];
|
|
3
|
+
export interface HtmlPrimitiveDescriptor {
|
|
4
|
+
kind: HtmlPrimitiveKind;
|
|
5
|
+
title: string;
|
|
6
|
+
description: string;
|
|
7
|
+
useWhen: string;
|
|
8
|
+
defaultSize: {
|
|
9
|
+
width: number;
|
|
10
|
+
height: number;
|
|
11
|
+
};
|
|
12
|
+
dataShape: string;
|
|
13
|
+
example: Record<string, unknown>;
|
|
14
|
+
}
|
|
15
|
+
export interface HtmlPrimitiveInput {
|
|
16
|
+
kind: HtmlPrimitiveKind;
|
|
17
|
+
title?: string;
|
|
18
|
+
data?: Record<string, unknown>;
|
|
19
|
+
}
|
|
20
|
+
export interface HtmlPrimitiveBuildResult {
|
|
21
|
+
kind: HtmlPrimitiveKind;
|
|
22
|
+
title: string;
|
|
23
|
+
html: string;
|
|
24
|
+
summary: string;
|
|
25
|
+
defaultSize: {
|
|
26
|
+
width: number;
|
|
27
|
+
height: number;
|
|
28
|
+
};
|
|
29
|
+
data: Record<string, unknown>;
|
|
30
|
+
}
|
|
31
|
+
export declare function isHtmlPrimitiveKind(value: string): value is HtmlPrimitiveKind;
|
|
32
|
+
export declare function getHtmlPrimitiveDescriptor(kind: HtmlPrimitiveKind): HtmlPrimitiveDescriptor;
|
|
33
|
+
export declare function listHtmlPrimitiveDescriptors(): HtmlPrimitiveDescriptor[];
|
|
34
|
+
export declare function buildHtmlPrimitive(input: HtmlPrimitiveInput): HtmlPrimitiveBuildResult;
|
|
@@ -3,6 +3,7 @@ import type { CanvasAnnotation, CanvasNodeState, CanvasEdge, CanvasLayout } from
|
|
|
3
3
|
import { searchNodes } from './spatial-analysis.js';
|
|
4
4
|
import { diffLayouts } from './mutation-history.js';
|
|
5
5
|
import { fitCanvasView, gcCanvasSnapshots, listCanvasSnapshots } from './canvas-operations.js';
|
|
6
|
+
import type { HtmlPrimitiveKind } from './html-primitives.js';
|
|
6
7
|
import { type WebArtifactBuildInput, type WebArtifactCanvasBuildResult } from './web-artifacts.js';
|
|
7
8
|
import { type ExternalMcpTransportConfig } from './mcp-app-runtime.js';
|
|
8
9
|
import { type DiagramPresetOpenInput } from './diagram-presets.js';
|
|
@@ -181,6 +182,7 @@ export declare class PmxCanvas extends EventEmitter {
|
|
|
181
182
|
graph: {
|
|
182
183
|
graphTypes: ("line" | "bar" | "pie" | "area" | "scatter" | "radar" | "composed" | "stacked-bar")[];
|
|
183
184
|
};
|
|
185
|
+
htmlPrimitives: import("./html-primitives.js").HtmlPrimitiveDescriptor[];
|
|
184
186
|
mcp: {
|
|
185
187
|
tools: string[];
|
|
186
188
|
resources: string[];
|
|
@@ -248,6 +250,21 @@ export declare class PmxCanvas extends EventEmitter {
|
|
|
248
250
|
height?: number;
|
|
249
251
|
strictSize?: boolean;
|
|
250
252
|
}): string;
|
|
253
|
+
addHtmlPrimitive(input: {
|
|
254
|
+
kind: HtmlPrimitiveKind;
|
|
255
|
+
title?: string;
|
|
256
|
+
data?: Record<string, unknown>;
|
|
257
|
+
x?: number;
|
|
258
|
+
y?: number;
|
|
259
|
+
width?: number;
|
|
260
|
+
height?: number;
|
|
261
|
+
strictSize?: boolean;
|
|
262
|
+
}): {
|
|
263
|
+
id: string;
|
|
264
|
+
kind: HtmlPrimitiveKind;
|
|
265
|
+
title: string;
|
|
266
|
+
htmlBytes: number;
|
|
267
|
+
};
|
|
251
268
|
addGraphNode(input: GraphNodeInput): {
|
|
252
269
|
id: string;
|
|
253
270
|
url: string;
|
|
@@ -275,10 +292,12 @@ export type { SpatialCluster, SpatialContext, SpatialNeighbor, NodeSpatialInfo }
|
|
|
275
292
|
export { mutationHistory, diffLayouts, formatDiff } from './mutation-history.js';
|
|
276
293
|
export { recomputeCodeGraph, buildCodeGraphSummary, formatCodeGraph } from './code-graph.js';
|
|
277
294
|
export { describeCanvasSchema, validateStructuredCanvasPayload } from './canvas-schema.js';
|
|
295
|
+
export { buildHtmlPrimitive, isHtmlPrimitiveKind, listHtmlPrimitiveDescriptors } from './html-primitives.js';
|
|
278
296
|
export { buildWebArtifactOnCanvas, executeWebArtifactBuild, openWebArtifactInCanvas, resolveWebArtifactScriptPath, resolveWorkspacePath, } from './web-artifacts.js';
|
|
279
297
|
export { buildGraphSpec, buildJsonRenderViewerHtml, createJsonRenderNodeData, GRAPH_NODE_SIZE, JSON_RENDER_NODE_SIZE, normalizeAndValidateJsonRenderSpec, } from '../json-render/server.js';
|
|
280
298
|
export type { CodeGraphSummary, CodeGraphEdge } from './code-graph.js';
|
|
281
299
|
export type { MutationEntry, MutationSummary, SnapshotDiffResult } from './mutation-history.js';
|
|
282
300
|
export type { WebArtifactBuildInput, WebArtifactBuildOutput, WebArtifactCanvasBuildResult, WebArtifactCanvasOpenResult, } from './web-artifacts.js';
|
|
283
301
|
export type { GraphNodeInput, JsonRenderNodeInput, JsonRenderSpec } from '../json-render/server.js';
|
|
302
|
+
export type { HtmlPrimitiveKind, HtmlPrimitiveDescriptor, HtmlPrimitiveInput, HtmlPrimitiveBuildResult } from './html-primitives.js';
|
|
284
303
|
export { traceManager } from './trace-manager.js';
|
package/docs/RELEASE.md
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# Release process
|
|
2
|
+
|
|
3
|
+
Internal recipe for cutting a new `pmx-canvas` release. Lives in `docs/`
|
|
4
|
+
rather than the README so end-user agents and humans driving the canvas
|
|
5
|
+
aren't distracted by maintainer-only flow. Agents working **on** this
|
|
6
|
+
repo (improving the canvas itself) should treat this file as the
|
|
7
|
+
single source of truth for the release dance — see also
|
|
8
|
+
[`AGENTS.md`](../AGENTS.md) and [`CLAUDE.md`](../CLAUDE.md).
|
|
9
|
+
|
|
10
|
+
## TL;DR
|
|
11
|
+
|
|
12
|
+
1. Land all the changes you want in the release on `main` with green CI.
|
|
13
|
+
2. Bump `package.json` `version`.
|
|
14
|
+
3. Add a `## [X.Y.Z]` block to `CHANGELOG.md`.
|
|
15
|
+
4. Commit, push, wait for `test.yml` green.
|
|
16
|
+
5. `git tag -a vX.Y.Z -m "..." && git push origin vX.Y.Z` →
|
|
17
|
+
`publish.yml` runs `npm publish --access public --provenance`.
|
|
18
|
+
6. `gh release create vX.Y.Z --notes-file <notes.md>`.
|
|
19
|
+
7. Smoke-test the published tarball: `bunx pmx-canvas@X.Y.Z --no-open`.
|
|
20
|
+
|
|
21
|
+
## Pre-flight gates
|
|
22
|
+
|
|
23
|
+
Run these locally before tagging. They mirror what `publish.yml`
|
|
24
|
+
re-runs in CI; a failure here means the publish workflow will also fail.
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
bun install --frozen-lockfile
|
|
28
|
+
bun run typecheck
|
|
29
|
+
bun run build
|
|
30
|
+
bun test tests/unit # 200+ tests, all green
|
|
31
|
+
bun run test:web-canvas # Playwright E2E, all green
|
|
32
|
+
bun run test:e2e-cli # fresh-workspace CLI eval
|
|
33
|
+
bun run release:check # bundles + lints
|
|
34
|
+
bun run release:smoke # packs + boots from a clean dir
|
|
35
|
+
bun run pack:dry-run # confirms the tarball shape
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
`bun run test:e2e-cli` starts a local server in a fresh temp workspace
|
|
39
|
+
and exercises the CLI flows from
|
|
40
|
+
[`docs/evals/e2e-cli-coverage.md`](evals/e2e-cli-coverage.md).
|
|
41
|
+
|
|
42
|
+
## Versioning
|
|
43
|
+
|
|
44
|
+
Semantic versioning. While we are still in `0.1.x`:
|
|
45
|
+
|
|
46
|
+
- Patch (`0.1.x → 0.1.x+1`): bug fixes, hardening, internal cleanups,
|
|
47
|
+
additive CLI flags / MCP fields with backwards-compat fallbacks.
|
|
48
|
+
- Minor (`0.1.x → 0.2.0`): documented breaking changes (e.g. dropping
|
|
49
|
+
the `hostMode + path` fallback in `getCanvasNodeKind`, removing legacy
|
|
50
|
+
`ext-app-ext-app-…` ID handling, JSON-shape changes that aren't
|
|
51
|
+
additive).
|
|
52
|
+
- Major (`0.x → 1.0`): production-stability commitment.
|
|
53
|
+
|
|
54
|
+
CLAUDE.md rule #5 (CanvasStateManager / PmxCanvas SDK / HTTP / MCP
|
|
55
|
+
four-layer parity) is the strongest hard rule for what counts as
|
|
56
|
+
non-breaking — a CLI/HTTP-only addition without MCP parity has
|
|
57
|
+
historically required a follow-up patch release to restore parity.
|
|
58
|
+
|
|
59
|
+
## CHANGELOG
|
|
60
|
+
|
|
61
|
+
`CHANGELOG.md` follows [Keep a Changelog](https://keepachangelog.com/).
|
|
62
|
+
Each release section uses these subheadings:
|
|
63
|
+
|
|
64
|
+
- **Added** — new public surface (HTTP endpoint, MCP tool/resource, CLI
|
|
65
|
+
command/flag, SDK export, JSON shape).
|
|
66
|
+
- **Changed** — behavior changes that aren't strictly bug fixes
|
|
67
|
+
(response shape additions, schema cleanups, stricter validation).
|
|
68
|
+
- **Fixed** — bug fixes.
|
|
69
|
+
- **Internal** — refactors, test additions, docs that don't affect
|
|
70
|
+
the public surface.
|
|
71
|
+
|
|
72
|
+
Don't ship a release without a CHANGELOG entry. The GitHub release
|
|
73
|
+
notes file (`/tmp/pmx-canvas-vX.Y.Z-release-notes.md` by convention)
|
|
74
|
+
expands on the CHANGELOG with examples and migration notes.
|
|
75
|
+
|
|
76
|
+
## Tag → publish
|
|
77
|
+
|
|
78
|
+
The publish workflow ([`/.github/workflows/publish.yml`](../.github/workflows/publish.yml))
|
|
79
|
+
triggers on tags matching `v*`:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
git tag -a v0.1.6 -m "v0.1.6 — short summary"
|
|
83
|
+
git push origin v0.1.6
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
It will:
|
|
87
|
+
|
|
88
|
+
1. Verify the tag matches `package.json` version.
|
|
89
|
+
2. Re-run typecheck / build / unit / E2E / pack.
|
|
90
|
+
3. `npm publish --access public --provenance` using the `NPM_TOKEN`
|
|
91
|
+
secret. Provenance attestations are signed via sigstore and visible
|
|
92
|
+
on the npm package page.
|
|
93
|
+
|
|
94
|
+
Watch it complete:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
gh run watch
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
If publish fails after npm has accepted the tarball, you cannot reuse
|
|
101
|
+
the same version number. Bump the patch and re-tag.
|
|
102
|
+
|
|
103
|
+
If this is the first release from your machine, run `bunx npm login`
|
|
104
|
+
once so Bun can reuse your npm credentials. CI does not need this —
|
|
105
|
+
it uses `NPM_TOKEN` directly.
|
|
106
|
+
|
|
107
|
+
## GitHub release
|
|
108
|
+
|
|
109
|
+
After `npm publish` succeeds:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
gh release create v0.1.6 \
|
|
113
|
+
--title "pmx-canvas 0.1.6 — short theme" \
|
|
114
|
+
--notes-file /tmp/pmx-canvas-v0.1.6-release-notes.md \
|
|
115
|
+
--verify-tag
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
`--verify-tag` makes the command fail if the local tag drifted from
|
|
119
|
+
the remote — a small but useful guard.
|
|
120
|
+
|
|
121
|
+
## Smoke test from npm
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
cd /tmp && rm -rf smoke && mkdir smoke && cd smoke
|
|
125
|
+
bunx --bun pmx-canvas@<version> --no-open --port=4926 > smoke.log &
|
|
126
|
+
SP=$!
|
|
127
|
+
for i in 1 2 3 4 5 6 7 8 9 10; do
|
|
128
|
+
curl -sf http://localhost:4926/health >/dev/null 2>&1 && break
|
|
129
|
+
sleep 1
|
|
130
|
+
done
|
|
131
|
+
curl -s http://localhost:4926/health # → {"ok":true,"workspace":"…"}
|
|
132
|
+
bunx pmx-canvas@<version> --version # → <version>
|
|
133
|
+
kill $SP
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
If `bunx pmx-canvas@<version>` resolves and the health endpoint replies
|
|
137
|
+
with `ok: true`, the published tarball is intact end-to-end.
|
|
138
|
+
|
|
139
|
+
## Common gotchas
|
|
140
|
+
|
|
141
|
+
- **`/.pmx-canvas/artifacts/.web-artifacts/sdlc-control-room/.parcel-cache/`**
|
|
142
|
+
files always show as modified after running an artifact build. They
|
|
143
|
+
are workspace-local cache and must not be committed; they're gitignored
|
|
144
|
+
but still appear in `git status`. Use `git restore --staged` if they
|
|
145
|
+
sneak into a `git add -A`.
|
|
146
|
+
- **`docs/screenshot.png`** updates whenever the showcase E2E runs.
|
|
147
|
+
Don't bake those updates into a release commit unless the screenshot
|
|
148
|
+
in `Readme.md` actually needs the refresh.
|
|
149
|
+
- **CHANGELOG dates**: use the actual publish date in the
|
|
150
|
+
`## [version] - YYYY-MM-DD` header, not the day you wrote the entry.
|
|
151
|
+
- **Node 24 deprecation timeline**: GitHub Actions is migrating
|
|
152
|
+
`actions/checkout`, `setup-node`, `upload-artifact` to Node 24 by
|
|
153
|
+
June 2, 2026. The publish workflow already pins `@v5` of all three.
|