pmx-canvas 0.1.18 → 0.1.19

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/docs/sdk.md ADDED
@@ -0,0 +1,92 @@
1
+ # JavaScript/TypeScript SDK (Bun runtime)
2
+
3
+ The published SDK entrypoint is Bun-first. Node.js consumers should use the
4
+ [CLI](cli.md), [MCP server](mcp.md), or [HTTP API](http-api.md) instead.
5
+
6
+ ```bash
7
+ bun add pmx-canvas
8
+ ```
9
+
10
+ ## Quick example
11
+
12
+ ```ts
13
+ import { createCanvas } from 'pmx-canvas';
14
+
15
+ const canvas = createCanvas({ port: 4313 });
16
+ await canvas.start({ open: true });
17
+
18
+ // Add nodes
19
+ const n1 = canvas.addNode({ type: 'markdown', title: 'Plan', content: '# Step 1\nDo the thing.' });
20
+ const n2 = canvas.addNode({ type: 'status', title: 'Build', content: 'passing' });
21
+ const n3 = canvas.addNode({ type: 'file', content: 'src/index.ts' });
22
+
23
+ // Connect them
24
+ canvas.addEdge({ from: n1, to: n2, type: 'flow' });
25
+
26
+ // Group related nodes
27
+ canvas.createGroup({ title: 'Build Pipeline', childIds: [n1, n2] });
28
+
29
+ // Self-contained HTML in a sandboxed iframe
30
+ canvas.addHtmlNode({
31
+ title: 'Cost projection',
32
+ html: '<canvas id="c"></canvas><script src="https://cdn.jsdelivr.net/npm/chart.js"></script><script>/* ... */</script>',
33
+ });
34
+
35
+ // Hand-drawn diagram via the Excalidraw MCP-app preset
36
+ await canvas.addDiagram({
37
+ elements: [
38
+ { type: 'rectangle', id: 'r1', x: 80, y: 80, width: 160, height: 60,
39
+ roundness: { type: 3 }, backgroundColor: '#a5d8ff', fillStyle: 'solid',
40
+ label: { text: 'Agent' } },
41
+ ],
42
+ title: 'Quick sketch',
43
+ });
44
+
45
+ // Batch-build a graph and group around it
46
+ await canvas.runBatch([
47
+ {
48
+ op: 'graph.add',
49
+ assign: 'graph',
50
+ args: {
51
+ title: 'Major wins',
52
+ graphType: 'bar',
53
+ data: [
54
+ { label: 'Docs', value: 5 },
55
+ { label: 'Tests', value: 8 },
56
+ ],
57
+ xKey: 'label',
58
+ yKey: 'value',
59
+ },
60
+ },
61
+ {
62
+ op: 'group.create',
63
+ args: {
64
+ title: 'Quarterly graphs',
65
+ childIds: ['$graph.id'],
66
+ },
67
+ },
68
+ ]);
69
+
70
+ // Arrange and inspect
71
+ canvas.arrange('grid');
72
+ console.log(canvas.validate());
73
+ console.log(canvas.getLayout());
74
+ ```
75
+
76
+ ## WebView automation
77
+
78
+ ```ts
79
+ const webview = await canvas.startAutomationWebView({ backend: 'chrome', width: 1280, height: 800 });
80
+ console.log(webview.active);
81
+ console.log(await canvas.evaluateAutomationWebView('document.title'));
82
+ await canvas.resizeAutomationWebView(1440, 900);
83
+ const screenshot = await canvas.screenshotAutomationWebView({ format: 'png' });
84
+ console.log(screenshot.byteLength);
85
+ await canvas.stopAutomationWebView();
86
+ ```
87
+
88
+ ## See also
89
+
90
+ - [Node types](node-types.md) — what each node type is for
91
+ - [HTTP API](http-api.md) — the same operations from any language
92
+ - [MCP reference](mcp.md) — the agent-facing surface
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pmx-canvas",
3
- "version": "0.1.18",
3
+ "version": "0.1.19",
4
4
  "description": "Spatial canvas workbench for coding agents — infinite 2D canvas with agent-native CLI, MCP integration, nodes, edges, file watching, and snapshots",
5
5
  "type": "module",
6
6
  "main": "./src/server/index.ts",
@@ -18,6 +18,7 @@
18
18
  "files": [
19
19
  "src/",
20
20
  "skills/",
21
+ "docs/",
21
22
  "dist/canvas/",
22
23
  "dist/json-render/",
23
24
  "dist/types/",
package/src/cli/agent.ts CHANGED
@@ -1698,6 +1698,7 @@ cmd('snapshot save', 'Save a named snapshot of the current canvas', [
1698
1698
  cmd('snapshot list', 'List saved snapshots', [
1699
1699
  'pmx-canvas snapshot list',
1700
1700
  'pmx-canvas snapshot list --limit 50 --query baseline',
1701
+ 'pmx-canvas snapshot list --after 2026-05-01T00:00:00Z --before 2026-05-05T00:00:00Z',
1701
1702
  'pmx-canvas snapshot list --all',
1702
1703
  ], async (args) => {
1703
1704
  const { flags } = parseFlags(args);
@@ -1706,8 +1707,12 @@ cmd('snapshot list', 'List saved snapshots', [
1706
1707
  const params = new URLSearchParams();
1707
1708
  const limit = optionalNumberFlag(flags, 'limit', 'Use a positive integer, e.g. --limit 50');
1708
1709
  const query = getStringFlag(flags, 'query', 'q');
1710
+ const before = getStringFlag(flags, 'before');
1711
+ const after = getStringFlag(flags, 'after');
1709
1712
  if (limit !== undefined) params.set('limit', String(limit));
1710
1713
  if (query) params.set('q', query);
1714
+ if (before) params.set('before', before);
1715
+ if (after) params.set('after', after);
1711
1716
  if (flags.all) params.set('all', 'true');
1712
1717
  const result = await api('GET', `/api/canvas/snapshots${params.size > 0 ? `?${params.toString()}` : ''}`);
1713
1718
  output(result);
@@ -2328,8 +2333,20 @@ function showCommandHelp(name: string): void {
2328
2333
  console.log('\nOptions:');
2329
2334
  console.log(' --limit <number> Maximum snapshots to return (default 20)');
2330
2335
  console.log(' --query <text> Case-insensitive ID/name filter');
2336
+ console.log(' --before <timestamp> Only return snapshots created at or before this ISO timestamp');
2337
+ console.log(' --after <timestamp> Only return snapshots created at or after this ISO timestamp');
2331
2338
  console.log(' --all Return all snapshots');
2332
2339
  }
2340
+ if (name === 'node update') {
2341
+ console.log('\nTrace fields:');
2342
+ console.log(' --tool-name, --toolName Trace tool or operation label');
2343
+ console.log(' --category <name> Trace category, e.g. mcp, file, subagent, other');
2344
+ console.log(' --status <status> Trace status, e.g. running, success, failed');
2345
+ console.log(' --duration <text> Trace duration badge text');
2346
+ console.log(' --result-summary, --resultSummary <text>');
2347
+ console.log(' Trace result summary');
2348
+ console.log(' --error <text> Trace error message');
2349
+ }
2333
2350
  if (name === 'snapshot gc') {
2334
2351
  console.log('\nOptions:');
2335
2352
  console.log(' --keep <number> Number of newest snapshots to keep (default 20)');
@@ -559,6 +559,8 @@ class RemoteCanvasAccess implements CanvasAccess {
559
559
  const params = new URLSearchParams();
560
560
  if (typeof options?.limit === 'number') params.set('limit', String(options.limit));
561
561
  if (options?.query) params.set('q', options.query);
562
+ if (options?.before) params.set('before', options.before);
563
+ if (options?.after) params.set('after', options.after);
562
564
  if (options?.all) params.set('all', 'true');
563
565
  const query = params.size > 0 ? `?${params.toString()}` : '';
564
566
  return await this.requestJson<SnapshotList>('GET', `/api/canvas/snapshots${query}`);
package/src/mcp/server.ts CHANGED
@@ -1759,6 +1759,8 @@ export async function startMcpServer(): Promise<void> {
1759
1759
  {
1760
1760
  limit: z.number().optional().describe('Maximum snapshots to return (default: 20)'),
1761
1761
  query: z.string().optional().describe('Optional case-insensitive ID/name filter'),
1762
+ before: z.string().optional().describe('Only return snapshots created at or before this ISO timestamp'),
1763
+ after: z.string().optional().describe('Only return snapshots created at or after this ISO timestamp'),
1762
1764
  all: z.boolean().optional().describe('Return all snapshots instead of the default limit'),
1763
1765
  },
1764
1766
  async (input) => {
@@ -32,6 +32,12 @@ function normalizePositiveInteger(value: number | undefined): number | undefined
32
32
  return Math.floor(value);
33
33
  }
34
34
 
35
+ function normalizeSnapshotTimestamp(value: string | undefined): string | undefined {
36
+ if (!value) return undefined;
37
+ const parsed = Date.parse(value);
38
+ return Number.isFinite(parsed) ? new Date(parsed).toISOString() : undefined;
39
+ }
40
+
35
41
  export const PMX_CANVAS_DIR = '.pmx-canvas';
36
42
  const STATE_FILENAME = 'state.json';
37
43
  const SNAPSHOTS_SUBDIR = 'snapshots';
@@ -89,6 +95,8 @@ export interface CanvasSnapshot {
89
95
  export interface CanvasSnapshotListOptions {
90
96
  limit?: number;
91
97
  query?: string;
98
+ before?: string;
99
+ after?: string;
92
100
  all?: boolean;
93
101
  }
94
102
 
@@ -856,11 +864,16 @@ class CanvasStateManager {
856
864
  }
857
865
  }
858
866
  const query = options.query?.trim().toLowerCase();
859
- const filtered = query
860
- ? snapshots.filter((snapshot) =>
861
- snapshot.id.toLowerCase().includes(query) || snapshot.name.toLowerCase().includes(query),
862
- )
863
- : snapshots;
867
+ const before = normalizeSnapshotTimestamp(options.before);
868
+ const after = normalizeSnapshotTimestamp(options.after);
869
+ const filtered = snapshots.filter((snapshot) => {
870
+ if (query && !snapshot.id.toLowerCase().includes(query) && !snapshot.name.toLowerCase().includes(query)) {
871
+ return false;
872
+ }
873
+ if (before && snapshot.createdAt > before) return false;
874
+ if (after && snapshot.createdAt < after) return false;
875
+ return true;
876
+ });
864
877
  const sorted = filtered.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
865
878
  const limit = options.all ? undefined : (normalizePositiveInteger(options.limit) ?? 20);
866
879
  return limit === undefined ? sorted : sorted.slice(0, limit);
@@ -4145,6 +4145,8 @@ export function startCanvasServer(options: CanvasServerOptions = {}): string | n
4145
4145
  return responseJson(listCanvasSnapshots({
4146
4146
  limit: parsePositiveIntegerParam(url.searchParams.get('limit')),
4147
4147
  query: url.searchParams.get('q') ?? url.searchParams.get('query') ?? undefined,
4148
+ before: url.searchParams.get('before') ?? undefined,
4149
+ after: url.searchParams.get('after') ?? undefined,
4148
4150
  all: url.searchParams.get('all') === 'true',
4149
4151
  }));
4150
4152
  }