pmx-canvas 0.6.5 → 0.7.1
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/.github/extensions/pmx-canvas/extension.mjs +139 -14
- package/CHANGELOG.md +70 -0
- package/Readme.md +32 -6
- package/dist/canvas/global.css +510 -31
- package/dist/canvas/index.js +92 -77
- package/dist/types/cli/agent.d.ts +3 -0
- package/dist/types/cli/commands/backup.d.ts +1 -0
- package/dist/types/cli/commands/boards.d.ts +1 -0
- package/dist/types/cli/commands/export.d.ts +1 -0
- package/dist/types/cli/daemon.d.ts +5 -5
- package/dist/types/cli/shared.d.ts +3 -1
- package/dist/types/client/canvas/BoardCopyDialog.d.ts +5 -0
- package/dist/types/client/canvas/BoardFolderDialog.d.ts +7 -0
- package/dist/types/client/canvas/BoardLinkDialog.d.ts +3 -0
- package/dist/types/client/canvas/BoardSwitcher.d.ts +8 -0
- package/dist/types/client/canvas/ExportDialog.d.ts +7 -0
- package/dist/types/client/canvas/HomeView.d.ts +9 -0
- package/dist/types/client/nodes/AttachmentNode.d.ts +6 -0
- package/dist/types/client/nodes/BoardNode.d.ts +5 -0
- package/dist/types/client/state/boards-store.d.ts +79 -0
- package/dist/types/client/state/canvas-store.d.ts +2 -0
- package/dist/types/client/state/intent-bridge.d.ts +1 -0
- package/dist/types/client/state/session-store.d.ts +7 -0
- package/dist/types/client/types.d.ts +2 -2
- package/dist/types/json-render/catalog.d.ts +1 -1
- package/dist/types/json-render/charts/definitions.d.ts +1 -1
- package/dist/types/json-render/server.d.ts +6 -0
- package/dist/types/mcp/canvas-access.d.ts +10 -3
- package/dist/types/mcp/context-uri-template.d.ts +6 -0
- package/dist/types/server/agent-presence.d.ts +1 -1
- package/dist/types/server/attribution.d.ts +11 -0
- package/dist/types/server/ax-context.d.ts +3 -1
- package/dist/types/server/ax-interaction.d.ts +2 -2
- package/dist/types/server/ax-state.d.ts +13 -3
- package/dist/types/server/backup.d.ts +36 -0
- package/dist/types/server/board-export.d.ts +45 -0
- package/dist/types/server/canvas-db.d.ts +63 -9
- package/dist/types/server/canvas-operations.d.ts +23 -0
- package/dist/types/server/canvas-provenance.d.ts +1 -1
- package/dist/types/server/canvas-state.d.ts +140 -3
- package/dist/types/server/context-brief.d.ts +111 -0
- package/dist/types/server/context-reads.d.ts +55 -0
- package/dist/types/server/document-import.d.ts +66 -0
- package/dist/types/server/index.d.ts +103 -4
- package/dist/types/server/mutation-history.d.ts +1 -0
- package/dist/types/server/operations/invoker.d.ts +2 -0
- package/dist/types/server/operations/mcp.d.ts +7 -1
- package/dist/types/server/operations/ops/ax-shared.d.ts +2 -2
- package/dist/types/server/operations/ops/backup.d.ts +2 -0
- package/dist/types/server/operations/ops/boards.d.ts +10 -0
- package/dist/types/server/operations/ops/export.d.ts +2 -0
- package/dist/types/server/operations/ops/imports.d.ts +2 -0
- package/dist/types/server/operations/ops/nodes.d.ts +1 -1
- package/dist/types/server/operations/ops/query.d.ts +2 -0
- package/dist/types/server/operations/registry.d.ts +9 -1
- package/dist/types/server/operations/types.d.ts +1 -1
- package/dist/types/server/server.d.ts +1 -0
- package/dist/types/server/trace-manager.d.ts +7 -0
- package/dist/types/server/webpage-node.d.ts +22 -1
- package/dist/types/server/workbench-auth.d.ts +3 -0
- package/dist/types/shared/boards.d.ts +6 -0
- package/docs/RELEASE.md +5 -0
- package/docs/cli.md +73 -0
- package/docs/http-api.md +198 -2
- package/docs/mcp.md +71 -6
- package/docs/node-types.md +26 -0
- package/docs/plans/plan-010-attributed-ask-answers.md +39 -0
- package/docs/plans/plan-011-context-read-instrumentation.md +54 -0
- package/docs/plans/plan-012-many-boards-stage-1.md +98 -0
- package/docs/plans/plan-013-static-board-export.md +47 -0
- package/docs/plans/plan-014-connected-board-memory.md +140 -0
- package/docs/product-vision-2026-09.md +118 -18
- package/docs/sdk.md +50 -0
- package/package.json +1 -1
- package/skills/pmx-canvas/SKILL.md +68 -11
- package/skills/pmx-canvas/evals/evals.json +130 -0
- package/skills/pmx-canvas/references/full-reference.md +43 -7
- package/skills/pmx-canvas/references/github-copilot-app-adapter.md +3 -0
- package/skills/pmx-canvas/references/installing-pmx-canvas.md +4 -4
- package/skills/pmx-canvas/references/tours-and-recording.md +69 -0
- package/skills/pmx-canvas-orchestration/SKILL.md +5 -0
- package/skills/pmx-canvas-testing/SKILL.md +11 -2
- package/src/cli/agent.ts +4 -0
- package/src/cli/commands/apps.ts +1 -1
- package/src/cli/commands/ax.ts +13 -0
- package/src/cli/commands/backup.ts +66 -0
- package/src/cli/commands/boards.ts +71 -0
- package/src/cli/commands/export.ts +37 -0
- package/src/cli/commands/nodes.ts +4 -1
- package/src/cli/commands/pins.ts +6 -2
- package/src/cli/commands/pump.ts +3 -0
- package/src/cli/commands/query.ts +33 -7
- package/src/cli/commands/view.ts +7 -5
- package/src/cli/daemon.ts +37 -7
- package/src/cli/index.ts +19 -9
- package/src/cli/shared.ts +11 -2
- package/src/client/App.tsx +21 -4
- package/src/client/canvas/AttentionToast.tsx +5 -3
- package/src/client/canvas/BoardCopyDialog.tsx +153 -0
- package/src/client/canvas/BoardFolderDialog.tsx +120 -0
- package/src/client/canvas/BoardLinkDialog.tsx +93 -0
- package/src/client/canvas/BoardSwitcher.tsx +149 -0
- package/src/client/canvas/CanvasNode.tsx +0 -1
- package/src/client/canvas/CanvasViewport.tsx +3 -0
- package/src/client/canvas/CommandPalette.tsx +107 -4
- package/src/client/canvas/ContextMenu.tsx +4 -1
- package/src/client/canvas/ExpandedNodeOverlay.tsx +3 -0
- package/src/client/canvas/ExportDialog.tsx +199 -0
- package/src/client/canvas/HomeView.tsx +277 -0
- package/src/client/canvas/Presentation.tsx +39 -9
- package/src/client/canvas/SelectionBar.tsx +0 -2
- package/src/client/canvas/SessionPanel.tsx +28 -1
- package/src/client/canvas/ToolRail.tsx +38 -3
- package/src/client/canvas/TopBar.tsx +34 -18
- package/src/client/canvas/import-files.ts +19 -1
- package/src/client/canvas/kind-colors.ts +1 -0
- package/src/client/icons.tsx +2 -0
- package/src/client/nodes/AttachmentNode.tsx +145 -0
- package/src/client/nodes/BoardNode.tsx +35 -0
- package/src/client/nodes/FileNode.tsx +6 -0
- package/src/client/nodes/MarkdownNode.tsx +47 -19
- package/src/client/nodes/ax-node-actions.ts +2 -5
- package/src/client/nodes/use-ax-surface-bridge.ts +1 -1
- package/src/client/state/attention-bridge.ts +3 -1
- package/src/client/state/boards-store.ts +167 -0
- package/src/client/state/canvas-store.ts +22 -0
- package/src/client/state/intent-bridge.ts +30 -2
- package/src/client/state/node-factory.ts +1 -0
- package/src/client/state/session-store.ts +5 -0
- package/src/client/state/sse-bridge.ts +52 -6
- package/src/client/theme/global.css +510 -31
- package/src/client/types.ts +2 -0
- package/src/json-render/server.ts +16 -9
- package/src/mcp/canvas-access.ts +59 -22
- package/src/mcp/context-uri-template.ts +28 -0
- package/src/mcp/server.ts +122 -15
- package/src/server/agent-context.ts +116 -29
- package/src/server/attribution.ts +29 -0
- package/src/server/ax-context.ts +4 -2
- package/src/server/ax-interaction.ts +1 -0
- package/src/server/ax-state-manager.ts +72 -3
- package/src/server/ax-state.ts +41 -0
- package/src/server/backup.ts +178 -0
- package/src/server/board-export.ts +686 -0
- package/src/server/canvas-db.ts +599 -107
- package/src/server/canvas-operations.ts +68 -9
- package/src/server/canvas-provenance.ts +1 -0
- package/src/server/canvas-schema.ts +12 -0
- package/src/server/canvas-state.ts +774 -45
- package/src/server/context-brief.ts +372 -0
- package/src/server/context-reads.ts +238 -0
- package/src/server/demo-state.json +659 -2
- package/src/server/document-import.ts +223 -0
- package/src/server/index.ts +231 -5
- package/src/server/mutation-history.ts +10 -13
- package/src/server/operations/composites.ts +26 -4
- package/src/server/operations/http.ts +9 -3
- package/src/server/operations/index.ts +8 -0
- package/src/server/operations/invoker.ts +14 -3
- package/src/server/operations/mcp.ts +50 -11
- package/src/server/operations/ops/app.ts +5 -0
- package/src/server/operations/ops/ax-read.ts +10 -6
- package/src/server/operations/ops/ax-timeline.ts +75 -0
- package/src/server/operations/ops/backup.ts +134 -0
- package/src/server/operations/ops/batch.ts +8 -1
- package/src/server/operations/ops/boards.ts +351 -0
- package/src/server/operations/ops/export.ts +74 -0
- package/src/server/operations/ops/ext-app.ts +4 -0
- package/src/server/operations/ops/imports.ts +236 -0
- package/src/server/operations/ops/nodes.ts +57 -5
- package/src/server/operations/ops/query.ts +206 -9
- package/src/server/operations/registry.ts +123 -31
- package/src/server/operations/types.ts +1 -1
- package/src/server/server.ts +146 -2
- package/src/server/spatial-analysis.ts +9 -17
- package/src/server/trace-manager.ts +19 -0
- package/src/server/web-artifacts.ts +2 -1
- package/src/server/webpage-node.ts +173 -13
- package/src/server/workbench-auth.ts +11 -0
- package/src/shared/boards.ts +18 -0
- package/src/shared/node-sizes.ts +1 -0
|
@@ -16,14 +16,14 @@ export declare const AX_SOURCES: readonly ["agent", "amp", "api", "browser", "cl
|
|
|
16
16
|
export declare const AX_SOURCE_SHAPE: z.ZodOptional<z.ZodEnum<{
|
|
17
17
|
amp: "amp";
|
|
18
18
|
agent: "agent";
|
|
19
|
+
system: "system";
|
|
20
|
+
sdk: "sdk";
|
|
19
21
|
api: "api";
|
|
20
22
|
browser: "browser";
|
|
21
23
|
cli: "cli";
|
|
22
24
|
codex: "codex";
|
|
23
25
|
copilot: "copilot";
|
|
24
26
|
mcp: "mcp";
|
|
25
|
-
sdk: "sdk";
|
|
26
|
-
system: "system";
|
|
27
27
|
}>>;
|
|
28
28
|
/** Zod schema for the optional `agentId` field shared by AX MCP tool shapes. */
|
|
29
29
|
export declare const AX_AGENT_ID_SHAPE: z.ZodOptional<z.ZodString>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type CanvasLayout } from '../../canvas-state.js';
|
|
2
|
+
import { type Operation } from '../types.js';
|
|
3
|
+
export declare function boardsPayload(): Record<string, unknown>;
|
|
4
|
+
/** Read a board without opening it. Omitted board preserves the active-board contract. */
|
|
5
|
+
export declare function readTargetBoard(boardId?: unknown, includeBlobs?: boolean): {
|
|
6
|
+
boardId: string | null;
|
|
7
|
+
layout: CanvasLayout;
|
|
8
|
+
pinnedNodeIds: Set<string>;
|
|
9
|
+
};
|
|
10
|
+
export declare const boardOperations: Operation[];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type CanvasLayout, type CanvasNodeState } from '../../canvas-state.js';
|
|
2
2
|
import { type CanvasSizeAdjustment } from '../../canvas-operations.js';
|
|
3
3
|
import { type Operation } from '../types.js';
|
|
4
|
-
export declare const NODE_TYPES: readonly ["markdown", "status", "context", "ledger", "trace", "file", "diff", "mermaid", "image", "mcp-app", "webpage", "html", "group"];
|
|
4
|
+
export declare const NODE_TYPES: readonly ["markdown", "board", "status", "context", "ledger", "trace", "file", "diff", "mermaid", "image", "mcp-app", "webpage", "html", "group"];
|
|
5
5
|
/** Per-type default node frame size (formerly copy-pasted ladders). */
|
|
6
6
|
export declare function defaultNodeSize(type: string): {
|
|
7
7
|
width: number;
|
|
@@ -9,7 +9,7 @@ export declare function setOperationEventEmitter(emitter: OperationEventEmitter
|
|
|
9
9
|
* mcpapp.open, whose canvas node is created as a side-effect of `ext-app-open` —
|
|
10
10
|
* use this to reject loudly instead of silently no-op'ing in a suppressed run. */
|
|
11
11
|
export declare function isEmitSuppressed(): boolean;
|
|
12
|
-
/**
|
|
12
|
+
/** Suppress this call chain's per-entry frames; the batch emits its final frame afterward. */
|
|
13
13
|
export declare function runWithSuppressedEmits<T>(fn: () => Promise<T>): Promise<T>;
|
|
14
14
|
export interface ExecuteOperationMeta {
|
|
15
15
|
/**
|
|
@@ -29,6 +29,14 @@ export interface ExecuteOperationMeta {
|
|
|
29
29
|
* to agents only, and batch inner writes are always agent-originated.
|
|
30
30
|
*/
|
|
31
31
|
fromWorkbench?: boolean;
|
|
32
|
+
/** Authorship only: true when the per-boot workbench token matched. */
|
|
33
|
+
humanAuthor?: boolean;
|
|
34
|
+
/**
|
|
35
|
+
* An MCP server attached to this daemon, or a host adapter, fetching on an
|
|
36
|
+
* agent's behalf. It records the read the agent actually made itself
|
|
37
|
+
* (POST /api/canvas/ax/context-reads), so this fetch is not recorded.
|
|
38
|
+
*/
|
|
39
|
+
proxiedRead?: boolean;
|
|
32
40
|
}
|
|
33
41
|
export declare function executeOperation(name: string, rawInput: unknown, meta?: ExecuteOperationMeta): Promise<unknown>;
|
|
34
42
|
export {};
|
|
@@ -45,7 +45,7 @@ export interface OperationHttpRoute {
|
|
|
45
45
|
}
|
|
46
46
|
/** Host capabilities available to MCP result formatters. */
|
|
47
47
|
export interface OperationMcpToolHost {
|
|
48
|
-
getPinnedNodeIds(): Promise<string[]>;
|
|
48
|
+
getPinnedNodeIds(board?: string): Promise<string[]>;
|
|
49
49
|
/**
|
|
50
50
|
* Invoke another registered operation over the host's transport (local or
|
|
51
51
|
* HTTP) — structural subset of OperationInvoker to avoid an import cycle.
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
* - POST /api/canvas/graph -> create a native graph node
|
|
24
24
|
* - GET /api/canvas/json-render/view?nodeId=... -> local json-render viewer
|
|
25
25
|
* - GET /api/canvas/file-bytes?nodeId=... -> raw bytes for a file node
|
|
26
|
+
* - GET /api/canvas/exports/<file> -> a written static board export (sandboxed)
|
|
26
27
|
* - POST /api/canvas/web-artifact -> build bundled HTML artifact + optional canvas node
|
|
27
28
|
* - GET /api/workbench/events -> SSE event stream
|
|
28
29
|
* - GET /api/workbench/poll -> proxy-safe polling transport (same events, JSON)
|
|
@@ -37,6 +37,13 @@ declare class TraceManager {
|
|
|
37
37
|
durationMs?: number;
|
|
38
38
|
failed?: boolean;
|
|
39
39
|
}): void;
|
|
40
|
+
/**
|
|
41
|
+
* The chain's last node is gone (another board was opened, or it was
|
|
42
|
+
* deleted): start a new chain instead of wiring edges to a missing node.
|
|
43
|
+
*/
|
|
44
|
+
private dropStaleChain;
|
|
45
|
+
/** Forget the trace chain without touching nodes. */
|
|
46
|
+
resetChain(): void;
|
|
40
47
|
clearTrace(): void;
|
|
41
48
|
getTraceNodeCount(): number;
|
|
42
49
|
private getOrigin;
|
|
@@ -17,9 +17,30 @@ export interface WebpageSnapshot {
|
|
|
17
17
|
}
|
|
18
18
|
export declare function normalizeWebpageUrl(rawUrl: string): string;
|
|
19
19
|
export declare function summarizeWebpageContent(data: Record<string, unknown>, maxLength?: number): string;
|
|
20
|
-
export
|
|
20
|
+
export type AddressScope = 'public' | 'private' | 'link-local';
|
|
21
|
+
/**
|
|
22
|
+
* Where an IP literal points. `private` covers loopback, RFC 1918, CGNAT and
|
|
23
|
+
* IPv6 ULA; `link-local` is kept apart because it holds cloud metadata
|
|
24
|
+
* (169.254.169.254) and is refused on every hop.
|
|
25
|
+
*/
|
|
26
|
+
export declare function classifyAddress(address: string): AddressScope;
|
|
27
|
+
type ResolveHost = (hostname: string) => Promise<Array<{
|
|
28
|
+
address: string;
|
|
29
|
+
family: number;
|
|
30
|
+
}>>;
|
|
31
|
+
/**
|
|
32
|
+
* Refuses link-local on every hop, and a redirect that moves a public fetch
|
|
33
|
+
* onto a loopback or private address. A URL the caller points at a local dev
|
|
34
|
+
* server on purpose still loads, and may redirect within the local network.
|
|
35
|
+
*/
|
|
36
|
+
export declare function checkWebpageHop(originScope: AddressScope, hopScope: AddressScope, hopUrl: string): void;
|
|
37
|
+
export declare function fetchWebpageSnapshot(inputUrl: string, options?: {
|
|
38
|
+
resolveHost?: ResolveHost;
|
|
39
|
+
timeoutMs?: number;
|
|
40
|
+
}): Promise<WebpageSnapshot>;
|
|
21
41
|
export declare function getWebpageFetchErrorDetails(error: unknown): {
|
|
22
42
|
message: string;
|
|
23
43
|
statusCode: number | null;
|
|
24
44
|
contentType: string | null;
|
|
25
45
|
};
|
|
46
|
+
export {};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** The Home category migrated 0.6 snapshots land on, so they do not bury the boards in use. */
|
|
2
|
+
export declare const MIGRATED_SNAPSHOT_CATEGORY = "From old snapshots";
|
|
3
|
+
/** Slash-separated folder paths shared by the UI, HTTP/MCP and SDK. */
|
|
4
|
+
export declare function normalizeBoardCategory(value: string | null): string | null;
|
|
5
|
+
/** Includes implicit parents, so a board in A/B can also be moved into A. */
|
|
6
|
+
export declare function categoryAncestors(path: string): string[];
|
package/docs/RELEASE.md
CHANGED
|
@@ -40,6 +40,11 @@ bun run pack:dry-run # confirms the tarball shape
|
|
|
40
40
|
do not call `bun x playwright test` directly; it fails before test
|
|
41
41
|
discovery with a `.esm.preflight` loader error (ERR-20260508-001).
|
|
42
42
|
|
|
43
|
+
The Playwright run includes the `pane-600` project
|
|
44
|
+
(`tests/e2e/reference-pane.pw.ts`): the reference surface, Chromium at
|
|
45
|
+
600 px. Every node type must paint there or the release does not ship.
|
|
46
|
+
Embedded WebKit panes (the Copilot app) stay best-effort.
|
|
47
|
+
|
|
43
48
|
`bun run test:e2e-cli` starts a local server in a fresh temp workspace
|
|
44
49
|
and exercises the CLI flows from
|
|
45
50
|
[`docs/evals/e2e-cli-coverage.md`](evals/e2e-cli-coverage.md).
|
package/docs/cli.md
CHANGED
|
@@ -8,6 +8,19 @@ wins over `--port`, and both win over the environment variables). An invalid
|
|
|
8
8
|
value for either flag is a hard error — the CLI never falls back silently to
|
|
9
9
|
the default port.
|
|
10
10
|
|
|
11
|
+
Read commands accept `--board <board-id>` without switching the active board:
|
|
12
|
+
`layout` (including `--summary`), `status`, `spatial`, `pin --list`, and
|
|
13
|
+
`node get`. Writes and presence still target the board open in the workbench;
|
|
14
|
+
unknown board IDs fail rather than falling back to it.
|
|
15
|
+
|
|
16
|
+
An in-flight asynchronous write stops if the board changes; subsequent calls use
|
|
17
|
+
the newly open board. Batches stop rather than continuing on another board, and
|
|
18
|
+
already-completed entries remain applied.
|
|
19
|
+
|
|
20
|
+
On SIGINT or SIGTERM, the server saves before exiting. If saving fails, it reports
|
|
21
|
+
the error and stays running so the in-memory edits can be recovered. Fix the
|
|
22
|
+
storage failure and retry shutdown; a forced process kill can still lose edits.
|
|
23
|
+
|
|
11
24
|
```bash
|
|
12
25
|
pmx-canvas node list --port 4750 # target a non-default daemon
|
|
13
26
|
pmx-canvas --server-url http://127.0.0.1:4750 status # same, by URL
|
|
@@ -262,6 +275,53 @@ pmx-canvas fit <id-a> <id-b> # Fit to just these nodes
|
|
|
262
275
|
`--width` / `--height`. After creating output a human should see, focus a single
|
|
263
276
|
node or fit the new ids — auto-placement is board-relative, not camera-relative.
|
|
264
277
|
|
|
278
|
+
## Boards
|
|
279
|
+
|
|
280
|
+
```bash
|
|
281
|
+
pmx-canvas board list # most recently opened first; activeBoardId null = Home
|
|
282
|
+
pmx-canvas board create "Q4 planning" # created, not opened
|
|
283
|
+
pmx-canvas board rename <board-id> "New name"
|
|
284
|
+
pmx-canvas board create "Q4 planning" --category Planning
|
|
285
|
+
pmx-canvas board category <board-id> "Planning/Quarterly" # nested folders; --clear unfiles it
|
|
286
|
+
pmx-canvas board from <source-id> "Follow-up" --preview
|
|
287
|
+
pmx-canvas board from <source-id> "Follow-up" --nodes id1,id2 --readme --structure
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
Commands write to the board open in the workbench. Opening, switching and
|
|
291
|
+
deleting boards happens in the workbench (the human's call). `board from`
|
|
292
|
+
excludes `prompt`, `response`, `trace`, and `mcp-app` cards; selected reusable
|
|
293
|
+
cards get fresh IDs. `--structure` includes group frames; edges between copied
|
|
294
|
+
cards are retained automatically. `--readme` carries the designated README. The new board remains inactive and
|
|
295
|
+
does not inherit pins, AX state, or mutation history.
|
|
296
|
+
|
|
297
|
+
## Backup and restore
|
|
298
|
+
|
|
299
|
+
Boards save automatically. Backups are separate recovery copies of the whole library,
|
|
300
|
+
configured through the CLI or HTTP API rather than the Home screen. Scheduled backups
|
|
301
|
+
run while the server is running; scheduling is off until configured.
|
|
302
|
+
|
|
303
|
+
```bash
|
|
304
|
+
pmx-canvas backup # every board, now; into .pmx-canvas/backups
|
|
305
|
+
pmx-canvas backup --to ~/Backups/pmx --keep 14
|
|
306
|
+
pmx-canvas backup schedule --every 24h --keep 14 --to ~/Backups/pmx # run by the server
|
|
307
|
+
pmx-canvas backup schedule --off
|
|
308
|
+
pmx-canvas backup status
|
|
309
|
+
pmx-canvas restore ~/Backups/pmx/canvas-20260927T090000000Z.db # keeps canvas.db.before-restore
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
## Export
|
|
313
|
+
|
|
314
|
+
```bash
|
|
315
|
+
pmx-canvas export # the open board → .pmx-canvas/exports/<board>-<time>.html
|
|
316
|
+
pmx-canvas export --board <board-id> --out ~/Desktop/okrs.html
|
|
317
|
+
pmx-canvas export --include-files # include local file contents (left out by default)
|
|
318
|
+
pmx-canvas export --include-derived-text # include imported document text (left out by default)
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
The two private-content flags are independent opt-ins. `--include-files` does not include
|
|
322
|
+
source-derived document text, and `--include-derived-text` does not include local file contents.
|
|
323
|
+
Unknown export flags are rejected instead of being ignored.
|
|
324
|
+
|
|
265
325
|
## Snapshots
|
|
266
326
|
|
|
267
327
|
```bash
|
|
@@ -275,6 +335,18 @@ pmx-canvas diff <snapshot-id> # Compare the canvas against a snapshot
|
|
|
275
335
|
|
|
276
336
|
## AX context
|
|
277
337
|
|
|
338
|
+
The cross-board brief has its own compact command. Its budget is measured in
|
|
339
|
+
UTF-16 code units (default 16000, maximum 100000), not model tokens. `--consumer`
|
|
340
|
+
selects a durable cursor scoped to the open board; `--since` performs an
|
|
341
|
+
explicit pull without changing that cursor. With neither flag, every call starts
|
|
342
|
+
from the beginning. Use a stable, unique consumer ID per agent/adapter; changing
|
|
343
|
+
or sharing it loses or conflates delivery progress.
|
|
344
|
+
|
|
345
|
+
```bash
|
|
346
|
+
pmx-canvas context --consumer codex --budget 16000
|
|
347
|
+
pmx-canvas context --since 42 --budget 8000
|
|
348
|
+
```
|
|
349
|
+
|
|
278
350
|
AX commands expose the host-agnostic context contract used by adapters. Pins
|
|
279
351
|
remain the explicit human-curated context set; AX focus is the current
|
|
280
352
|
attention target and persists with canvas state and snapshots.
|
|
@@ -298,6 +370,7 @@ pmx-canvas ax event add --kind tool-start --summary "ran tests"
|
|
|
298
370
|
pmx-canvas ax steer "focus on the failing test first"
|
|
299
371
|
pmx-canvas ax evidence add --kind test-output --title "unit pass"
|
|
300
372
|
pmx-canvas ax timeline --limit 50
|
|
373
|
+
pmx-canvas ax reads --limit 50 # context read log: which context each agent read, pinned delivery
|
|
301
374
|
|
|
302
375
|
# Work items (canvas-bound)
|
|
303
376
|
pmx-canvas ax work add --title "Wire up auth" --status in-progress node-1
|
package/docs/http-api.md
CHANGED
|
@@ -43,14 +43,173 @@ targets, duration, easing, padding, and pullback. Open `/workbench?present=1` to
|
|
|
43
43
|
chrome; camera movement is local to that viewer. Recording writes local files via
|
|
44
44
|
the CLI, not an HTTP job endpoint.
|
|
45
45
|
|
|
46
|
+
## Boards
|
|
47
|
+
|
|
48
|
+
A workspace holds many named boards; one is open at a time. Agent writes go to
|
|
49
|
+
the open board. While no board is open (Home), the first write opens the most
|
|
50
|
+
recently opened board, or creates one when the workspace has none;
|
|
51
|
+
`canvas.clear` on Home opens nothing. Only the trusted workbench opens or
|
|
52
|
+
deletes a board — HTTP calls require both `x-pmx-workbench: 1` and the
|
|
53
|
+
per-boot `x-pmx-workbench-token` embedded in the served `/workbench` HTML;
|
|
54
|
+
the marker alone is not authority. Public HTTP integrations must not open or
|
|
55
|
+
delete boards. In-process SDK embedding hosts retain authority to do so.
|
|
56
|
+
Every change emits a
|
|
57
|
+
`boards-changed` SSE frame with `{ activeBoardId, boards }`.
|
|
58
|
+
|
|
59
|
+
`category` is a folder path, for example `Engineering/Canvas/Decisions`.
|
|
60
|
+
Home renders nested, collapsible folders and searches board names and paths.
|
|
61
|
+
Paths support up to eight levels, each with 1–60 characters; surrounding spaces
|
|
62
|
+
are trimmed. Empty segments and `.`/`..` are rejected. `null` or `""` unfiles a
|
|
63
|
+
board. Folders are derived from boards, so empty folders do not persist. Moving
|
|
64
|
+
a board changes its path, not its ID or content.
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
# List boards (most recently opened first) and which is open (null = Home)
|
|
68
|
+
curl http://localhost:4313/api/canvas/boards
|
|
69
|
+
|
|
70
|
+
# Read one board
|
|
71
|
+
curl http://localhost:4313/api/canvas/boards/<board-id>
|
|
72
|
+
|
|
73
|
+
# Create a board (optionally in a category) — it is NOT opened
|
|
74
|
+
curl -X POST http://localhost:4313/api/canvas/boards \
|
|
75
|
+
-H "Content-Type: application/json" -d '{"name":"Q4 planning","category":"Planning"}'
|
|
76
|
+
|
|
77
|
+
# Preview/create an inactive copy from reusable cards (preview false creates)
|
|
78
|
+
curl -X POST http://localhost:4313/api/canvas/boards/from \
|
|
79
|
+
-H "Content-Type: application/json" \
|
|
80
|
+
-d '{"sourceBoardId":"board-source","name":"Follow-up","nodeIds":["node-1"],"includeReadme":true,"includeStructure":true,"preview":true}'
|
|
81
|
+
|
|
82
|
+
# Rename and/or file under a category on Home ("category": "" removes it)
|
|
83
|
+
curl -X PATCH http://localhost:4313/api/canvas/boards/<board-id> \
|
|
84
|
+
-H "Content-Type: application/json" -d '{"name":"Q4 planning (final)","category":"Planning"}'
|
|
85
|
+
|
|
86
|
+
# Designate a Markdown card on this board as its README (null clears it)
|
|
87
|
+
curl -X PATCH http://localhost:4313/api/canvas/boards/<board-id> \
|
|
88
|
+
-H "Content-Type: application/json" -d '{"readmeNodeId":"<markdown-node-id>"}'
|
|
89
|
+
|
|
90
|
+
# Open a board, or Home with {"id":null} — workbench only
|
|
91
|
+
curl -X POST http://localhost:4313/api/canvas/boards/open \
|
|
92
|
+
-H "Content-Type: application/json" -H "x-pmx-workbench: 1" \
|
|
93
|
+
-H "x-pmx-workbench-token: <token-from-served-workbench>" -d '{"id":"<board-id>"}'
|
|
94
|
+
|
|
95
|
+
# Delete a board and its snapshots — workbench only; deleting the open board returns to Home
|
|
96
|
+
curl -X DELETE http://localhost:4313/api/canvas/boards/<board-id> \
|
|
97
|
+
-H "x-pmx-workbench: 1" -H "x-pmx-workbench-token: <token-from-served-workbench>"
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Backup and restore
|
|
101
|
+
|
|
102
|
+
A backup is one SQLite file holding every board, its snapshots and blobs,
|
|
103
|
+
written with `VACUUM INTO` (safe while the server runs) to
|
|
104
|
+
`canvas-<timestamp>.db` in the backup folder — by default `backups/` beside the
|
|
105
|
+
database (`.pmx-canvas/backups`). Keeping the newest `keep` (default 14)
|
|
106
|
+
removes older backups in that folder. The schedule is stored in the database
|
|
107
|
+
and runs inside the server. Not exposed over MCP.
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
# Folder, schedule, last backup and the backups on disk
|
|
111
|
+
curl http://localhost:4313/api/canvas/backup
|
|
112
|
+
|
|
113
|
+
# Back up now (optional folder and keep)
|
|
114
|
+
curl -X POST http://localhost:4313/api/canvas/backup \
|
|
115
|
+
-H "Content-Type: application/json" -d '{"to":"/Users/me/Backups/pmx","keep":14}'
|
|
116
|
+
|
|
117
|
+
# Back up every 24h ("30m", "7d"; at least once a minute; "off" stops it)
|
|
118
|
+
curl -X POST http://localhost:4313/api/canvas/backup/schedule \
|
|
119
|
+
-H "Content-Type: application/json" -d '{"every":"24h","keep":14,"to":"/Users/me/Backups/pmx"}'
|
|
120
|
+
|
|
121
|
+
# Replace every board with a backup; the current file is kept as canvas.db.before-restore.
|
|
122
|
+
# Refuses files that are not PMX Canvas databases, and the live database itself.
|
|
123
|
+
curl -X POST http://localhost:4313/api/canvas/backup/restore \
|
|
124
|
+
-H "Content-Type: application/json" -d '{"file":"/Users/me/Backups/pmx/canvas-20260927T090000000Z.db"}'
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Static board export
|
|
128
|
+
|
|
129
|
+
One self-contained, read-only HTML file of one board (pan, zoom, expand) that
|
|
130
|
+
opens with no server or install. Cards render as escaped text; html cards,
|
|
131
|
+
charts, diagrams and built apps run in sandboxed iframes, with viewer bundles
|
|
132
|
+
stored once per file. Live MCP apps become placeholders; local file contents
|
|
133
|
+
are left out unless `includeFiles` is true. Files are written to `exports/`
|
|
134
|
+
beside the database. Built-app files are only embedded when they are regular,
|
|
135
|
+
bounded-size files inside the board's owned `.pmx-canvas/artifacts/` directory.
|
|
136
|
+
The preview manifest lists card links, remote images, and statically visible
|
|
137
|
+
network destinations in embedded HTML. Imported source-linked Markdown is also
|
|
138
|
+
excluded unless `includeDerivedText=true`, independently of `includeFiles`;
|
|
139
|
+
editing it does not remove that classification. Original attachment bytes are
|
|
140
|
+
never embedded in v1. Embedded scripts can make additional
|
|
141
|
+
network requests that cannot be inventoried in advance. Not exposed over MCP —
|
|
142
|
+
sharing is the human's act.
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
# What the file would contain (defaults to the open board; ?board=<id> for another)
|
|
146
|
+
curl "http://localhost:4313/api/canvas/export/preview?includeFiles=false&includeDerivedText=false"
|
|
147
|
+
|
|
148
|
+
# Write it → { path, url, bytes, manifest }
|
|
149
|
+
curl -X POST http://localhost:4313/api/canvas/export \
|
|
150
|
+
-H "Content-Type: application/json" \
|
|
151
|
+
-d '{"board":"<board-id>","includeFiles":false,"includeDerivedText":false}'
|
|
152
|
+
|
|
153
|
+
# Serve a written export (opaque-origin sandbox; ?download=1 as an attachment)
|
|
154
|
+
curl "http://localhost:4313/api/canvas/exports/<file>.html?download=1" -o board.html
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Agent-assisted document imports
|
|
158
|
+
|
|
159
|
+
PDF and Office uploads are raw bytes, not JSON. Upload requires the trusted
|
|
160
|
+
workbench token, an active captured board, a non-empty body of at most 20 MiB,
|
|
161
|
+
and creates both an original file card and an `attached` import. The original
|
|
162
|
+
remains board-owned until board deletion; snapshot restore does not remove it,
|
|
163
|
+
and whole-database backups include it.
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
curl -X POST \
|
|
167
|
+
"http://localhost:4313/api/canvas/attachments?boardId=<board-id>&name=report.pdf&mime=application/pdf&x=40&y=40" \
|
|
168
|
+
-H "x-pmx-workbench-token: <token>" --data-binary @report.pdf
|
|
169
|
+
|
|
170
|
+
# Human-only: explicit consent asks the connected agent; captured board must be open
|
|
171
|
+
curl -X POST http://localhost:4313/api/canvas/imports/<import-id>/request \
|
|
172
|
+
-H "Content-Type: application/json" -H "x-pmx-workbench: 1" \
|
|
173
|
+
-H "x-pmx-workbench-token: <token>" \
|
|
174
|
+
-d '{"consent":true}'
|
|
175
|
+
|
|
176
|
+
# Agent reads metadata and a controlled byte path; inline=true adds base64 only <=2 MiB
|
|
177
|
+
curl "http://localhost:4313/api/canvas/imports/<import-id>?inline=true"
|
|
178
|
+
curl http://localhost:4313/api/canvas/attachments/<attachment-id>/bytes -o source.bin
|
|
179
|
+
|
|
180
|
+
# Agent submits a reviewable draft (allowed even if another board is active)
|
|
181
|
+
curl -X POST http://localhost:4313/api/canvas/imports/<import-id>/submit \
|
|
182
|
+
-H "Content-Type: application/json" \
|
|
183
|
+
-d '{"sections":[{"title":"Summary","markdown":"...","reference":"page 1"}],"warnings":[],"agentDescription":"Extracted with the connected host PDF reader"}'
|
|
184
|
+
|
|
185
|
+
# Human-only review/commit; the original captured board must be open
|
|
186
|
+
curl -X POST http://localhost:4313/api/canvas/imports/<import-id>/commit \
|
|
187
|
+
-H "x-pmx-workbench: 1" -H "x-pmx-workbench-token: <token>"
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
`GET /api/canvas/imports?boardId=...` lists jobs. An agent that cannot access or
|
|
191
|
+
interpret the source posts `{ "reason": "..." }` to
|
|
192
|
+
`/api/canvas/imports/:id/unavailable`; a human may later request a new attempt.
|
|
193
|
+
Humans can cancel requested or drafted jobs at `/cancel`. There is no bundled
|
|
194
|
+
converter, OCR, automatic agent launch, or guarantee for charts, scans, and
|
|
195
|
+
host-specific formats. A remote agent may need the human/host to transfer the
|
|
196
|
+
bytes before it can submit a draft.
|
|
197
|
+
|
|
46
198
|
## Canvas state
|
|
47
199
|
|
|
200
|
+
Read endpoints accept an optional `board=<board-id>` query parameter without
|
|
201
|
+
opening that board or changing where writes go. This is supported by
|
|
202
|
+
`/api/canvas/state`, `/api/canvas/node/:id`, `/api/canvas/summary`,
|
|
203
|
+
`/api/canvas/spatial-context`, and `/api/canvas/pinned-context`. Unknown boards
|
|
204
|
+
return 404. Omit `board` to read the active board. Live AX session/delivery reads
|
|
205
|
+
and fixed MCP resources continue to describe the open board.
|
|
206
|
+
|
|
48
207
|
```bash
|
|
49
208
|
# Get canvas state
|
|
50
209
|
curl http://localhost:4313/api/canvas/state
|
|
51
210
|
|
|
52
|
-
# Search
|
|
53
|
-
curl "http://localhost:4313/api/canvas/search?q=auth&limit=10"
|
|
211
|
+
# Search the library (omit scope for the active board)
|
|
212
|
+
curl "http://localhost:4313/api/canvas/search?q=auth&limit=10&scope=library"
|
|
54
213
|
|
|
55
214
|
# Validate the current layout
|
|
56
215
|
curl http://localhost:4313/api/canvas/validate
|
|
@@ -108,6 +267,11 @@ A node creation request must resolve a `type` — pass it in the body (`{ "type"
|
|
|
108
267
|
... }`) or as a `?type=` query param. An empty / type-less body returns `400`
|
|
109
268
|
rather than silently creating a markdown node.
|
|
110
269
|
|
|
270
|
+
An optional `boardId` on node creation is a captured-board precondition, not a
|
|
271
|
+
switch command: if it no longer matches the active board, the request returns
|
|
272
|
+
`409` without creating a node or opening a board from Home. The file-drop UI
|
|
273
|
+
uses this to prevent delayed uploads from landing on a different board.
|
|
274
|
+
|
|
111
275
|
Mermaid nodes accept `data: { "fit": "contain" | "none" }` on both
|
|
112
276
|
`POST /api/canvas/node` and `PATCH /api/canvas/node/:id`. The default, `contain`,
|
|
113
277
|
shrinks overflowing diagrams without changing aspect ratio; `none` keeps 100%
|
|
@@ -223,14 +387,30 @@ curl -X POST http://localhost:4313/api/canvas/context-pins \
|
|
|
223
387
|
|
|
224
388
|
# Get pinned context
|
|
225
389
|
curl http://localhost:4313/api/canvas/pinned-context
|
|
390
|
+
|
|
391
|
+
# Cross-board brief. budget is a UTF-16 character ceiling (default 16000, max 100000).
|
|
392
|
+
# Without since, the board/consumer cursor advances through only fully delivered revisions.
|
|
393
|
+
curl 'http://localhost:4313/api/canvas/context?consumer=codex&budget=16000'
|
|
226
394
|
```
|
|
227
395
|
|
|
396
|
+
`consumer` is optional. Supply a stable unique value only for a durable,
|
|
397
|
+
board-scoped cursor; without `consumer` or `since`, each request starts from the
|
|
398
|
+
beginning. An explicit `since` never advances a cursor. The brief prioritizes
|
|
399
|
+
pins, then relevant current-board changes and asks, then compact linked or
|
|
400
|
+
same-folder board context. Every item carries source board/card IDs. If card text
|
|
401
|
+
is clipped, use those IDs with the board/node read route rather than guessing
|
|
402
|
+
from the excerpt. Reading inactive boards does not open them.
|
|
403
|
+
|
|
228
404
|
## AX context and focus
|
|
229
405
|
|
|
230
406
|
AX context is the host-agnostic agent-experience layer. It combines existing
|
|
231
407
|
context pins with a persisted focus node set that adapters can inject into
|
|
232
408
|
their native prompt/context hooks.
|
|
233
409
|
|
|
410
|
+
The context response includes `boardId` (`null` on Home), captured with its content
|
|
411
|
+
and pins. Adapters should send that ID when recording a proxied context read, rather
|
|
412
|
+
than looking up whichever board is active after delivery.
|
|
413
|
+
|
|
234
414
|
```bash
|
|
235
415
|
# Get persisted AX state
|
|
236
416
|
curl http://localhost:4313/api/canvas/ax
|
|
@@ -276,6 +456,22 @@ curl -X POST http://localhost:4313/api/canvas/ax/evidence \
|
|
|
276
456
|
# Timeline — read the bounded timeline (default limit 50, max 200)
|
|
277
457
|
curl "http://localhost:4313/api/canvas/ax/timeline?limit=50"
|
|
278
458
|
|
|
459
|
+
# Context reads — which canvas context each agent read, and whether its pinned
|
|
460
|
+
# nodes were in what came back (newest first, default 50, max 500; the per-consumer
|
|
461
|
+
# summary covers the whole retained log of 5,000 reads). Agent reads of pinned
|
|
462
|
+
# context, AX context, AX state, summary, spatial context and layout are recorded
|
|
463
|
+
# automatically; the workbench's own reads are not.
|
|
464
|
+
curl "http://localhost:4313/api/canvas/ax/context-reads?limit=50"
|
|
465
|
+
|
|
466
|
+
# Context reads — a proxy (an MCP server attached to this daemon, a host adapter)
|
|
467
|
+
# records the read its agent actually made. Its own fetches send
|
|
468
|
+
# `x-pmx-proxied-read: 1` so they are not recorded twice.
|
|
469
|
+
# Pass boardId captured at read time (null for Home); omitting it uses the
|
|
470
|
+
# currently open board. MCP bytes measure the final formatted text response.
|
|
471
|
+
curl -X POST http://localhost:4313/api/canvas/ax/context-reads \
|
|
472
|
+
-H "Content-Type: application/json" \
|
|
473
|
+
-d '{"channel":"adapter","resource":"copilot:prompt-context","consumer":"copilot","pinnedNodeIds":["node-1"],"deliveredNodeIds":["node-1"],"bytes":2048}'
|
|
474
|
+
|
|
279
475
|
# Canvas-bound — add / update a work item
|
|
280
476
|
curl -X POST http://localhost:4313/api/canvas/ax/work \
|
|
281
477
|
-H "Content-Type: application/json" \
|