pmx-canvas 0.1.26 → 0.1.28
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 +191 -0
- package/CHANGELOG.md +110 -0
- package/Readme.md +74 -27
- package/dist/canvas/index.js +82 -82
- package/dist/json-render/index.css +1 -1
- package/dist/json-render/index.js +944 -164
- package/dist/types/json-render/catalog.d.ts +195 -20
- package/dist/types/json-render/charts/components.d.ts +17 -0
- package/dist/types/json-render/charts/definitions.d.ts +13 -1
- package/dist/types/json-render/charts/tufte-components.d.ts +65 -0
- package/dist/types/json-render/charts/tufte-definitions.d.ts +164 -0
- package/dist/types/json-render/directives.d.ts +33 -0
- package/dist/types/json-render/renderer/index.d.ts +1 -0
- package/dist/types/json-render/server.d.ts +32 -1
- package/dist/types/mcp/canvas-access.d.ts +62 -0
- package/dist/types/server/ax-state.d.ts +170 -0
- package/dist/types/server/canvas-db.d.ts +17 -1
- package/dist/types/server/canvas-operations.d.ts +53 -0
- package/dist/types/server/canvas-schema.d.ts +5 -1
- package/dist/types/server/canvas-state.d.ts +95 -4
- package/dist/types/server/index.d.ts +120 -3
- package/dist/types/server/mutation-history.d.ts +1 -1
- package/docs/cli.md +42 -0
- package/docs/http-api.md +64 -0
- package/docs/mcp.md +23 -5
- package/docs/node-types.md +1 -1
- package/docs/screenshots/codex-app.png +0 -0
- package/docs/screenshots/github-copilot-app.png +0 -0
- package/docs/sdk.md +23 -5
- package/package.json +10 -7
- package/skills/control-session-orchestrator/SKILL.md +359 -0
- package/skills/control-session-orchestrator/evals/evals.json +75 -0
- package/skills/data-analysis/SKILL.md +6 -0
- package/skills/pmx-canvas/SKILL.md +50 -4
- package/skills/pmx-canvas/references/github-copilot-app-adapter.md +6 -0
- package/skills/tufte-viz/SKILL.md +157 -0
- package/skills/tufte-viz/references/analytical-design.md +217 -0
- package/skills/tufte-viz/references/tufte-principles.md +147 -0
- package/src/cli/agent.ts +302 -3
- package/src/cli/index.ts +2 -1
- package/src/client/nodes/ExtAppFrame.tsx +48 -1
- package/src/client/nodes/McpAppNode.tsx +6 -2
- package/src/json-render/catalog.ts +22 -1
- package/src/json-render/charts/components.tsx +127 -15
- package/src/json-render/charts/definitions.ts +19 -2
- package/src/json-render/charts/extra-components.tsx +5 -4
- package/src/json-render/charts/tufte-components.tsx +395 -0
- package/src/json-render/charts/tufte-definitions.ts +128 -0
- package/src/json-render/directives.ts +64 -0
- package/src/json-render/renderer/index.css +107 -1
- package/src/json-render/renderer/index.tsx +33 -0
- package/src/json-render/server.ts +275 -5
- package/src/mcp/canvas-access.ts +264 -1
- package/src/mcp/server.ts +498 -9
- package/src/server/ax-context.ts +8 -3
- package/src/server/ax-state.ts +447 -0
- package/src/server/canvas-db.ts +184 -1
- package/src/server/canvas-operations.ts +123 -2
- package/src/server/canvas-schema.ts +27 -3
- package/src/server/canvas-state.ts +349 -2
- package/src/server/index.ts +259 -7
- package/src/server/mutation-history.ts +6 -0
- package/src/server/server.ts +442 -5
- package/src/server/web-artifacts.ts +31 -5
|
@@ -388,6 +388,16 @@ async function startPanelServer(instanceId, ctx, pmx) {
|
|
|
388
388
|
return;
|
|
389
389
|
}
|
|
390
390
|
await copilotSession?.send({ prompt: body.prompt });
|
|
391
|
+
// Explicit user instruction from the panel → mirror onto the AX
|
|
392
|
+
// timeline as a steering message (fire-and-forget).
|
|
393
|
+
if (entry.pmx?.baseUrl) {
|
|
394
|
+
void fetchJson(entry.pmx.baseUrl, "/api/canvas/ax/steer", {
|
|
395
|
+
method: "POST",
|
|
396
|
+
headers: { "Content-Type": "application/json" },
|
|
397
|
+
body: JSON.stringify({ message: body.prompt, source: "copilot" }),
|
|
398
|
+
timeoutMs: 2_000,
|
|
399
|
+
}).catch(() => {});
|
|
400
|
+
}
|
|
391
401
|
jsonResponse(res, 200, { ok: true });
|
|
392
402
|
return;
|
|
393
403
|
}
|
|
@@ -434,6 +444,39 @@ async function setAxFocus(baseUrl, workspaceRoot, input = {}, nodeIds = []) {
|
|
|
434
444
|
});
|
|
435
445
|
}
|
|
436
446
|
|
|
447
|
+
// POST a host-agnostic AX record to the canvas with the copilot source label.
|
|
448
|
+
// Resolves the server first so the action returns an actionable error when the
|
|
449
|
+
// canvas is unavailable, then maps the neutral primitive over plain HTTP.
|
|
450
|
+
async function postAxRecord(ctx, path, payload) {
|
|
451
|
+
const resolved = await resolvePmxServer(ctx, { autoStart: false });
|
|
452
|
+
if (!resolved.ok || !resolved.baseUrl) {
|
|
453
|
+
return { ok: false, error: resolved.error ?? "PMX Canvas server is unavailable." };
|
|
454
|
+
}
|
|
455
|
+
try {
|
|
456
|
+
return await fetchJson(resolved.baseUrl, path, {
|
|
457
|
+
method: "POST",
|
|
458
|
+
headers: { "Content-Type": "application/json" },
|
|
459
|
+
body: JSON.stringify({ ...payload, source: "copilot" }),
|
|
460
|
+
timeoutMs: 2_000,
|
|
461
|
+
});
|
|
462
|
+
} catch (error) {
|
|
463
|
+
return { ok: false, error: error instanceof Error ? error.message : String(error) };
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
// Fire-and-forget mirror of a copilot-originated action onto the AX timeline.
|
|
468
|
+
// Never throws — adapter UX must not depend on the canvas being reachable.
|
|
469
|
+
function recordCopilotSteering(ctx, message) {
|
|
470
|
+
void postAxRecord(ctx, "/api/canvas/ax/steer", { message }).catch(() => {});
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
async function getAxTimeline(ctx, limit) {
|
|
474
|
+
const resolved = await resolvePmxServer(ctx, { autoStart: false });
|
|
475
|
+
if (!resolved.ok || !resolved.baseUrl) return { ok: false, error: resolved.error };
|
|
476
|
+
const query = typeof limit === "number" && limit > 0 ? `?limit=${limit}` : "";
|
|
477
|
+
return await fetchJson(resolved.baseUrl, `/api/canvas/ax/timeline${query}`, { timeoutMs: 2_000 });
|
|
478
|
+
}
|
|
479
|
+
|
|
437
480
|
function hasUsefulAxContext(context) {
|
|
438
481
|
return Boolean(context?.pinned?.count > 0 || context?.focus?.nodeIds?.length > 0);
|
|
439
482
|
}
|
|
@@ -513,9 +556,157 @@ const pmxCanvas = createCanvas({
|
|
|
513
556
|
const prompt = typeof ctx.input?.prompt === "string" ? ctx.input.prompt.trim() : "";
|
|
514
557
|
if (!prompt) throw new CanvasError("prompt_required", "prompt is required");
|
|
515
558
|
await copilotSession?.send({ prompt });
|
|
559
|
+
// Mirror the explicit user instruction onto the AX timeline as a
|
|
560
|
+
// steering message (fire-and-forget). This is an explicit action
|
|
561
|
+
// flow, never a sync from the prompt hook.
|
|
562
|
+
recordCopilotSteering(ctx, prompt);
|
|
516
563
|
return { ok: true };
|
|
517
564
|
},
|
|
518
565
|
},
|
|
566
|
+
{
|
|
567
|
+
name: "add_work_item",
|
|
568
|
+
description: "Add a canvas-bound PMX AX work item (visible task/plan/status) from Copilot.",
|
|
569
|
+
inputSchema: {
|
|
570
|
+
type: "object",
|
|
571
|
+
properties: {
|
|
572
|
+
title: { type: "string" },
|
|
573
|
+
status: { type: "string", enum: ["todo", "in-progress", "blocked", "done", "cancelled"] },
|
|
574
|
+
detail: { type: "string" },
|
|
575
|
+
nodeIds: { type: "array", items: { type: "string" } },
|
|
576
|
+
},
|
|
577
|
+
required: ["title"],
|
|
578
|
+
additionalProperties: false,
|
|
579
|
+
},
|
|
580
|
+
handler: async (ctx) => await postAxRecord(ctx, "/api/canvas/ax/work", {
|
|
581
|
+
title: ctx.input?.title,
|
|
582
|
+
...(ctx.input?.status ? { status: ctx.input.status } : {}),
|
|
583
|
+
...(ctx.input?.detail ? { detail: ctx.input.detail } : {}),
|
|
584
|
+
...(Array.isArray(ctx.input?.nodeIds) ? { nodeIds: ctx.input.nodeIds } : {}),
|
|
585
|
+
}),
|
|
586
|
+
},
|
|
587
|
+
{
|
|
588
|
+
name: "request_approval",
|
|
589
|
+
description: "Request human approval before a high-impact action via a PMX AX approval gate.",
|
|
590
|
+
inputSchema: {
|
|
591
|
+
type: "object",
|
|
592
|
+
properties: {
|
|
593
|
+
title: { type: "string" },
|
|
594
|
+
detail: { type: "string" },
|
|
595
|
+
action: { type: "string" },
|
|
596
|
+
nodeIds: { type: "array", items: { type: "string" } },
|
|
597
|
+
},
|
|
598
|
+
required: ["title"],
|
|
599
|
+
additionalProperties: false,
|
|
600
|
+
},
|
|
601
|
+
handler: async (ctx) => await postAxRecord(ctx, "/api/canvas/ax/approval", {
|
|
602
|
+
title: ctx.input?.title,
|
|
603
|
+
...(ctx.input?.detail ? { detail: ctx.input.detail } : {}),
|
|
604
|
+
...(ctx.input?.action ? { action: ctx.input.action } : {}),
|
|
605
|
+
...(Array.isArray(ctx.input?.nodeIds) ? { nodeIds: ctx.input.nodeIds } : {}),
|
|
606
|
+
}),
|
|
607
|
+
},
|
|
608
|
+
{
|
|
609
|
+
name: "resolve_approval",
|
|
610
|
+
description: "Resolve a pending PMX AX approval gate (approved or rejected).",
|
|
611
|
+
inputSchema: {
|
|
612
|
+
type: "object",
|
|
613
|
+
properties: {
|
|
614
|
+
id: { type: "string" },
|
|
615
|
+
decision: { type: "string", enum: ["approved", "rejected"] },
|
|
616
|
+
resolution: { type: "string" },
|
|
617
|
+
},
|
|
618
|
+
required: ["id", "decision"],
|
|
619
|
+
additionalProperties: false,
|
|
620
|
+
},
|
|
621
|
+
handler: async (ctx) => await postAxRecord(
|
|
622
|
+
ctx,
|
|
623
|
+
`/api/canvas/ax/approval/${encodeURIComponent(String(ctx.input?.id ?? ""))}/resolve`,
|
|
624
|
+
{
|
|
625
|
+
decision: ctx.input?.decision,
|
|
626
|
+
...(ctx.input?.resolution ? { resolution: ctx.input.resolution } : {}),
|
|
627
|
+
},
|
|
628
|
+
),
|
|
629
|
+
},
|
|
630
|
+
{
|
|
631
|
+
name: "add_review_annotation",
|
|
632
|
+
description: "Add a canvas-bound PMX AX review annotation (comment/finding) anchored to a node, file, or region.",
|
|
633
|
+
inputSchema: {
|
|
634
|
+
type: "object",
|
|
635
|
+
properties: {
|
|
636
|
+
body: { type: "string" },
|
|
637
|
+
kind: { type: "string", enum: ["comment", "finding"] },
|
|
638
|
+
severity: { type: "string", enum: ["info", "warning", "error"] },
|
|
639
|
+
anchorType: { type: "string", enum: ["node", "file", "region"] },
|
|
640
|
+
nodeId: { type: "string" },
|
|
641
|
+
file: { type: "string" },
|
|
642
|
+
},
|
|
643
|
+
required: ["body"],
|
|
644
|
+
additionalProperties: false,
|
|
645
|
+
},
|
|
646
|
+
handler: async (ctx) => await postAxRecord(ctx, "/api/canvas/ax/review", {
|
|
647
|
+
body: ctx.input?.body,
|
|
648
|
+
...(ctx.input?.kind ? { kind: ctx.input.kind } : {}),
|
|
649
|
+
...(ctx.input?.severity ? { severity: ctx.input.severity } : {}),
|
|
650
|
+
...(ctx.input?.anchorType ? { anchorType: ctx.input.anchorType } : {}),
|
|
651
|
+
...(ctx.input?.nodeId ? { nodeId: ctx.input.nodeId } : {}),
|
|
652
|
+
...(ctx.input?.file ? { file: ctx.input.file } : {}),
|
|
653
|
+
}),
|
|
654
|
+
},
|
|
655
|
+
{
|
|
656
|
+
name: "get_timeline",
|
|
657
|
+
description: "Read the bounded PMX AX timeline (events, evidence, steering) for diagnostics and continuity.",
|
|
658
|
+
inputSchema: {
|
|
659
|
+
type: "object",
|
|
660
|
+
properties: {
|
|
661
|
+
limit: { type: "integer", minimum: 1, maximum: 200 },
|
|
662
|
+
},
|
|
663
|
+
additionalProperties: false,
|
|
664
|
+
},
|
|
665
|
+
handler: async (ctx) => await getAxTimeline(ctx, ctx.input?.limit),
|
|
666
|
+
},
|
|
667
|
+
{
|
|
668
|
+
name: "report_capability",
|
|
669
|
+
description: "Report this Copilot host/session capability to the canvas for AX diagnostics.",
|
|
670
|
+
inputSchema: {
|
|
671
|
+
type: "object",
|
|
672
|
+
properties: {
|
|
673
|
+
canvas: { type: "boolean" },
|
|
674
|
+
hooks: { type: "boolean" },
|
|
675
|
+
tools: { type: "boolean" },
|
|
676
|
+
sessionMessaging: { type: "boolean" },
|
|
677
|
+
permissions: { type: "boolean" },
|
|
678
|
+
files: { type: "boolean" },
|
|
679
|
+
uiPrompts: { type: "boolean" },
|
|
680
|
+
},
|
|
681
|
+
additionalProperties: false,
|
|
682
|
+
},
|
|
683
|
+
handler: async (ctx) => {
|
|
684
|
+
const resolved = await resolvePmxServer(ctx, { autoStart: false });
|
|
685
|
+
if (!resolved.ok || !resolved.baseUrl) {
|
|
686
|
+
return { ok: false, error: resolved.error ?? "PMX Canvas server is unavailable." };
|
|
687
|
+
}
|
|
688
|
+
try {
|
|
689
|
+
return await fetchJson(resolved.baseUrl, "/api/canvas/ax/host-capability", {
|
|
690
|
+
method: "PUT",
|
|
691
|
+
headers: { "Content-Type": "application/json" },
|
|
692
|
+
body: JSON.stringify({
|
|
693
|
+
host: "copilot",
|
|
694
|
+
canvas: ctx.input?.canvas === true,
|
|
695
|
+
hooks: ctx.input?.hooks === true,
|
|
696
|
+
tools: ctx.input?.tools === true,
|
|
697
|
+
sessionMessaging: ctx.input?.sessionMessaging === true,
|
|
698
|
+
permissions: ctx.input?.permissions === true,
|
|
699
|
+
files: ctx.input?.files === true,
|
|
700
|
+
uiPrompts: ctx.input?.uiPrompts === true,
|
|
701
|
+
source: "copilot",
|
|
702
|
+
}),
|
|
703
|
+
timeoutMs: 2_000,
|
|
704
|
+
});
|
|
705
|
+
} catch (error) {
|
|
706
|
+
return { ok: false, error: error instanceof Error ? error.message : String(error) };
|
|
707
|
+
}
|
|
708
|
+
},
|
|
709
|
+
},
|
|
519
710
|
],
|
|
520
711
|
open: async (ctx) => {
|
|
521
712
|
let pmx;
|
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,114 @@
|
|
|
3
3
|
All notable changes to `pmx-canvas` are documented here. This project follows
|
|
4
4
|
[Semantic Versioning](https://semver.org/).
|
|
5
5
|
|
|
6
|
+
## [0.1.28] - 2026-06-06
|
|
7
|
+
|
|
8
|
+
### Changed
|
|
9
|
+
|
|
10
|
+
- **BREAKING (SDK): `PmxCanvas.addNode()` now returns the created node**
|
|
11
|
+
(a `CanvasNodeState` with `id`, geometry, and data) instead of a bare
|
|
12
|
+
id string. Use `const { id } = canvas.addNode(...)` or keep the whole
|
|
13
|
+
node. The MCP / HTTP / CLI surfaces and the internal `CanvasAccess`
|
|
14
|
+
contract are unchanged (still id-based).
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- Tufte graph nodes (DotPlot/Bullet/Slopegraph) no longer flicker: the
|
|
19
|
+
chart-height ResizeObserver no longer feeds the document's own scroll
|
|
20
|
+
overflow back into its height.
|
|
21
|
+
- Expanded Tufte graph views now fill the modal instead of staying
|
|
22
|
+
tile-sized with whitespace.
|
|
23
|
+
- Graph node iframes no longer show a doubled scrollbar; a chart that
|
|
24
|
+
fits shows none, a dense chart shows exactly one.
|
|
25
|
+
- Excalidraw / ext-app nodes paint on first mount instead of rendering
|
|
26
|
+
black until a manual expand/collapse (a post-layout host-context
|
|
27
|
+
nudge is delivered once the iframe has settled).
|
|
28
|
+
- `image` and `ledger` nodes get roomier default sizes (480×360 /
|
|
29
|
+
420×280) instead of a cramped 360-wide frame.
|
|
30
|
+
- `pmx-canvas web-artifact build` streams a stderr heartbeat during the
|
|
31
|
+
long install+bundle so agents don't see it as hung.
|
|
32
|
+
- json-render rejects an unknown `$`-directive (e.g. `$path`) with a
|
|
33
|
+
clear error pointing at `$state`, instead of rendering
|
|
34
|
+
`"[object Object]"`.
|
|
35
|
+
- Web-artifact script-path overrides are contained to the workspace with
|
|
36
|
+
a symlink-aware (realpath) check, fixing a false rejection on macOS.
|
|
37
|
+
- **Security:** the `/api/canvas/image/<id>` route now refuses to serve
|
|
38
|
+
files outside the workspace root (returns 403), closing a path-
|
|
39
|
+
traversal read (e.g. an image node pointed at `../../etc/passwd`).
|
|
40
|
+
|
|
41
|
+
## [0.1.27] - 2026-06-06
|
|
42
|
+
|
|
43
|
+
Big release: the full host-agnostic agent-experience (AX) primitive
|
|
44
|
+
contract and a json-render 0.19 upgrade with Tufte charts, directives,
|
|
45
|
+
and live SpecStream rendering. The MCP canvas now exposes 56 tools (was
|
|
46
|
+
45) and four AX resources. Plus the native GitHub Copilot and Codex
|
|
47
|
+
canvas adapters are featured in the README.
|
|
48
|
+
|
|
49
|
+
### Added
|
|
50
|
+
|
|
51
|
+
- **Full AX primitive contract (plan-004 Phases 2-5).** Eleven new MCP
|
|
52
|
+
tools, each with complete parity across CanvasStateManager, SQLite
|
|
53
|
+
persistence, the Bun SDK, HTTP, the MCP server, the RemoteCanvasAccess
|
|
54
|
+
proxy, and the CLI, organized into three lifecycle partitions:
|
|
55
|
+
- **Canvas-bound** (participate in snapshots + restore, cleared by
|
|
56
|
+
`canvas_clear`, read via `canvas_get_ax` / `canvas://ax-work`):
|
|
57
|
+
`canvas_add_work_item`, `canvas_update_work_item`,
|
|
58
|
+
`canvas_request_approval`, `canvas_resolve_approval` (state machine
|
|
59
|
+
`pending → approved/rejected`, double-resolve rejected),
|
|
60
|
+
`canvas_add_review_annotation`.
|
|
61
|
+
- **Timeline** (persist in dedicated DB tables bounded by 500-row
|
|
62
|
+
retention, NOT restored by snapshots, NOT cleared by
|
|
63
|
+
`canvas_clear`, read via `canvas_get_ax_timeline` /
|
|
64
|
+
`canvas://ax-timeline`): `canvas_add_evidence`,
|
|
65
|
+
`canvas_record_ax_event`, `canvas_send_steering`.
|
|
66
|
+
- **Host/session** (survives `canvas_clear`):
|
|
67
|
+
`canvas_report_host_capability`.
|
|
68
|
+
New resources: `canvas://ax-work` and `canvas://ax-timeline` (joining
|
|
69
|
+
`canvas://ax` and `canvas://ax-context`). CLI gains `pmx-canvas ax`
|
|
70
|
+
subcommands.
|
|
71
|
+
- **`canvas_stream_json_render_node` (SpecStream).** Progressively build
|
|
72
|
+
a json-render node by streaming JSON-Patch operations; the server
|
|
73
|
+
accumulates the spec (it is the source of truth) and the live node
|
|
74
|
+
re-renders as patches arrive. Omit `nodeId` to create, pass it back to
|
|
75
|
+
append, set `done:true` to finish.
|
|
76
|
+
- **Tufte chart types.** json-render graph nodes gain `Sparkline`,
|
|
77
|
+
`DotPlot`, `BulletChart`, and `Slopegraph`, wired through the full
|
|
78
|
+
definitions → catalog → component-registry pipeline alongside the
|
|
79
|
+
existing chart types.
|
|
80
|
+
- **json-render 0.19.0 upgrade + directives + devtools.** All
|
|
81
|
+
`@json-render/*` packages move to 0.19.0. Specs can use the standard
|
|
82
|
+
stateless directives (`$format`, `$math`, `$concat`, `$count`,
|
|
83
|
+
`$truncate`, `$pluralize`, `$join`) for server-side derivations; an
|
|
84
|
+
opt-in devtools panel (double-gated behind an env flag + `?devtools=1`)
|
|
85
|
+
is available for debugging.
|
|
86
|
+
- **Native GitHub Copilot and Codex canvas adapters featured in the
|
|
87
|
+
README**, with the `.github/extensions/pmx-canvas` Copilot extension
|
|
88
|
+
and the Codex/Copilot app-adapter skill references.
|
|
89
|
+
|
|
90
|
+
### Fixed
|
|
91
|
+
|
|
92
|
+
- **SpecStream rejects prototype-pollution patch paths.** Streamed
|
|
93
|
+
JSON-Patch paths whose JSON-Pointer contains a `__proto__`,
|
|
94
|
+
`constructor`, or `prototype` segment are now skipped (and counted)
|
|
95
|
+
rather than applied, closing a server-side prototype-pollution vector
|
|
96
|
+
in the new streaming path.
|
|
97
|
+
- **`canvas_add_review_annotation` no longer reports false success for
|
|
98
|
+
invalid node anchors.** A node-anchored review annotation whose
|
|
99
|
+
`nodeId` is missing or not on the canvas was silently dropped by
|
|
100
|
+
normalization yet returned as a populated success object. It now
|
|
101
|
+
rejects up front (`ok:false` / HTTP 400 / MCP error) across every
|
|
102
|
+
layer, so agents can't lose review findings to a typo'd node id.
|
|
103
|
+
|
|
104
|
+
### Internal
|
|
105
|
+
|
|
106
|
+
- Regression coverage added for: SpecStream patch application (happy
|
|
107
|
+
path, malformed-item skipping, and the prototype-pollution guard with
|
|
108
|
+
an explicit `Object.prototype` cleanliness assertion), the Tufte
|
|
109
|
+
Sparkline/Slopegraph spec builders, and node-anchor validation for
|
|
110
|
+
review annotations (missing / unknown / file / valid). Docs updated:
|
|
111
|
+
`docs/mcp.md` adds the `canvas_fit_view` row, and
|
|
112
|
+
`skills/pmx-canvas/SKILL.md` lists the four `canvas://ax*` resources.
|
|
113
|
+
|
|
6
114
|
## [0.1.26] - 2026-06-03
|
|
7
115
|
|
|
8
116
|
Small follow-up to 0.1.25. `canvas_add_node` can now create populated
|
|
@@ -1276,6 +1384,8 @@ otherwise have to discover by trial and error.
|
|
|
1276
1384
|
- Regression coverage for snapshot flat-`id` aliases on both MCP and
|
|
1277
1385
|
HTTP surfaces, plus async / top-level-`await` WebView script bodies.
|
|
1278
1386
|
|
|
1387
|
+
[0.1.28]: https://github.com/pskoett/pmx-canvas/releases/tag/v0.1.28
|
|
1388
|
+
[0.1.27]: https://github.com/pskoett/pmx-canvas/releases/tag/v0.1.27
|
|
1279
1389
|
[0.1.26]: https://github.com/pskoett/pmx-canvas/releases/tag/v0.1.26
|
|
1280
1390
|
[0.1.25]: https://github.com/pskoett/pmx-canvas/releases/tag/v0.1.25
|
|
1281
1391
|
[0.1.24]: https://github.com/pskoett/pmx-canvas/releases/tag/v0.1.24
|
package/Readme.md
CHANGED
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
**A moldable canvas for agent-assisted thinking.** An infinite 2D surface
|
|
4
4
|
where files, plans, status, charts, fetched web pages, annotations, and
|
|
5
5
|
hand-drawn diagrams live side by side. Every node carries its own renderer; agents
|
|
6
|
-
(and you) build new views in the middle of a session
|
|
7
|
-
|
|
8
|
-
curation as
|
|
6
|
+
(and you) build new views in the middle of a session — even streaming a
|
|
7
|
+
structured panel into place as they generate it — not as a separate tooling
|
|
8
|
+
project. Pin what matters and the agent reads your spatial curation as
|
|
9
|
+
structured context.
|
|
9
10
|
|
|
10
11
|
<p align="center">
|
|
11
12
|
<img src="docs/screenshots/welcome-dark.png" alt="Empty canvas — dark theme" width="49%" />
|
|
@@ -50,15 +51,28 @@ agents as compact spatial context: target, bounds, and nearby canvas content.
|
|
|
50
51
|
|
|
51
52
|
### 04 / Control your context
|
|
52
53
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
54
|
+
Steer the agent and see its work, without prompt engineering or copy-paste.
|
|
55
|
+
Pin a node in the browser and the MCP server fires a
|
|
56
|
+
`notifications/resources/updated` event the agent's harness picks up
|
|
57
|
+
immediately — an explicit, low-noise control over what the agent sees next.
|
|
58
|
+
|
|
59
|
+
On top of pins, a host-agnostic **AX (agent-experience) layer** turns the
|
|
60
|
+
canvas into a shared workspace between you and the agent:
|
|
61
|
+
|
|
62
|
+
- **Focus** — promote nodes into the agent's active context without moving the viewport.
|
|
63
|
+
- **Work items & approval gates** — track visible tasks tied to nodes, and gate
|
|
64
|
+
high-impact actions behind a human `pending → approved/rejected` decision.
|
|
65
|
+
- **Steering messages & agent-event timeline** — send instructions to the
|
|
66
|
+
active session, and read a normalized, bounded timeline of prompts, tool
|
|
67
|
+
runs, evidence (logs/diffs/screenshots/test-output), and failures.
|
|
68
|
+
- **Host capability** — adapters report what the host can do, for diagnostics.
|
|
69
|
+
|
|
70
|
+
Canvas-bound state (focus, work items, approvals, review annotations) rides
|
|
71
|
+
canvas snapshots and restore; the timeline persists for continuity but is
|
|
72
|
+
retention-bounded and never restored by a snapshot. Every primitive is reachable
|
|
73
|
+
from MCP, the HTTP API, the SDK, and `pmx-canvas ax …`. The core never depends
|
|
74
|
+
on any host SDK, so adapters (e.g. the GitHub Copilot app) map onto the same
|
|
75
|
+
neutral surfaces without making PMX Canvas vendor-specific.
|
|
62
76
|
|
|
63
77
|
### 05 / Save
|
|
64
78
|
|
|
@@ -71,27 +85,47 @@ the DB so SQLite WAL data is checkpointed into the file.
|
|
|
71
85
|
|
|
72
86
|
### 06 / Any agent
|
|
73
87
|
|
|
74
|
-
Harness-agnostic. Drive the canvas from [MCP](docs/mcp.md) (
|
|
75
|
-
|
|
88
|
+
Harness-agnostic. Drive the canvas from [MCP](docs/mcp.md) (56 tools,
|
|
89
|
+
12 resources, change notifications), the [CLI](docs/cli.md), the
|
|
76
90
|
[HTTP API](docs/http-api.md), or the [Bun SDK](docs/sdk.md). Works with
|
|
77
91
|
Claude Code, GitHub Copilot CLI, Codex, Cursor, Windsurf, or any agent
|
|
78
92
|
that can spawn an MCP stdio server, call a CLI, or hit an HTTP endpoint.
|
|
79
93
|
|
|
80
|
-
|
|
81
|
-
`.github/extensions/pmx-canvas/`. It opens the live PMX workbench in a native
|
|
82
|
-
Copilot canvas panel, injects AX pinned/focused context on prompt submission,
|
|
83
|
-
and exposes adapter actions for status, AX focus, context refresh, and explicit
|
|
84
|
-
session steering.
|
|
94
|
+
### 07 / Native app adapters
|
|
85
95
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
96
|
+
PMX Canvas doesn't just run in a browser tab — it embeds **natively inside the
|
|
97
|
+
agent apps you already use**, as a thin adapter layer over the same neutral AX
|
|
98
|
+
surfaces (the core never imports a host SDK).
|
|
99
|
+
|
|
100
|
+
<p align="center">
|
|
101
|
+
<img src="docs/screenshots/github-copilot-app.png" alt="PMX Canvas as a native canvas panel in the GitHub Copilot app" width="100%" />
|
|
102
|
+
</p>
|
|
103
|
+
<p align="center"><sub>PMX Canvas as a native canvas panel in the GitHub Copilot app.</sub></p>
|
|
104
|
+
|
|
105
|
+
<p align="center">
|
|
106
|
+
<img src="docs/screenshots/codex-app.png" alt="PMX Canvas workbench in the Codex in-app Browser" width="100%" />
|
|
107
|
+
</p>
|
|
108
|
+
<p align="center"><sub>The live PMX workbench in the Codex in-app Browser.</sub></p>
|
|
109
|
+
|
|
110
|
+
- **GitHub Copilot app** — a committed project canvas extension
|
|
111
|
+
(`.github/extensions/pmx-canvas/`) opens the live PMX workbench in a native
|
|
112
|
+
Copilot panel, injects pinned/focused AX context on prompt submission, and
|
|
113
|
+
exposes actions for focus, session steering, work items, approval gates,
|
|
114
|
+
review annotations, the AX timeline, and host-capability reporting. Install it
|
|
115
|
+
into any repo with `pmx-canvas copilot install-extension` (`--dry-run` to
|
|
116
|
+
preview).
|
|
117
|
+
- **Codex app** — native through the Codex in-app Browser (opened to
|
|
118
|
+
`/workbench`) plus the PMX MCP server: agents read `canvas://ax-context` /
|
|
119
|
+
`canvas_get_ax` and label Codex-originated focus with `source: "codex"`. No
|
|
120
|
+
extension API needed — Codex's two native surfaces (MCP + in-app Browser) are
|
|
121
|
+
exactly what the canvas requires.
|
|
122
|
+
|
|
123
|
+
The contract is host-agnostic, so a new host plugs in the same way: map its
|
|
124
|
+
hooks, canvas, and session APIs onto PMX's AX primitives — no core changes.
|
|
91
125
|
|
|
92
126
|
## Prerequisites
|
|
93
127
|
|
|
94
|
-
- [Bun](https://bun.sh) >= 1.3.
|
|
128
|
+
- [Bun](https://bun.sh) >= 1.3.14
|
|
95
129
|
|
|
96
130
|
The published SDK entrypoint is Bun-first. Node.js consumers should use the
|
|
97
131
|
CLI, MCP server, or HTTP API.
|
|
@@ -155,7 +189,20 @@ When loaded by the Copilot app, it opens the PMX workbench natively, starts a
|
|
|
155
189
|
matching local PMX server when needed, and injects `AX` pinned/focused context
|
|
156
190
|
as hidden per-turn context. The adapter is thin: PMX state still lives in
|
|
157
191
|
`.pmx-canvas/canvas.db`, and the same HTTP, MCP, CLI, and SDK surfaces remain
|
|
158
|
-
available to non-GitHub agents.
|
|
192
|
+
available to non-GitHub agents. See
|
|
193
|
+
[`github-copilot-app-adapter.md`](skills/pmx-canvas/references/github-copilot-app-adapter.md)
|
|
194
|
+
for the full setup and live-test checklist.
|
|
195
|
+
|
|
196
|
+
### Use inside the Codex app
|
|
197
|
+
|
|
198
|
+
Codex needs no extension — its two native surfaces are exactly what the canvas
|
|
199
|
+
requires. Add the PMX MCP server to the Codex workspace config (same snippet as
|
|
200
|
+
[Connect your agent](#connect-your-agent-mcp)), then open the returned
|
|
201
|
+
`/workbench` URL in the **Codex in-app Browser** so you can see mutations live.
|
|
202
|
+
Agents read pinned/focused context from `canvas://ax-context` / `canvas_get_ax`
|
|
203
|
+
and label Codex-originated focus with `source: "codex"`. See
|
|
204
|
+
[`codex-app-adapter.md`](skills/pmx-canvas/references/codex-app-adapter.md) for
|
|
205
|
+
the full workflow and live-test checklist.
|
|
159
206
|
|
|
160
207
|
### Install the agent skill (recommended)
|
|
161
208
|
|
|
@@ -188,7 +235,7 @@ the agent can read `canvas://skills` and pull in companion skills
|
|
|
188
235
|
the three-tier visual matrix (json-render → html → web-artifact)
|
|
189
236
|
- **[CLI reference](docs/cli.md)** — full command surface, daemon mode,
|
|
190
237
|
watch streams, WebView automation
|
|
191
|
-
- **[MCP reference](docs/mcp.md)** —
|
|
238
|
+
- **[MCP reference](docs/mcp.md)** — 56 tools, 12 resources, change
|
|
192
239
|
notifications, node-type routing
|
|
193
240
|
- **[HTTP API](docs/http-api.md)** — REST endpoints, SSE, batch operations
|
|
194
241
|
- **[Bun SDK](docs/sdk.md)** — `createCanvas()` for TypeScript on Bun
|