pmx-canvas 0.1.23 → 0.1.24
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 +591 -0
- package/CHANGELOG.md +70 -0
- package/Readme.md +36 -5
- package/dist/canvas/global.css +36 -3
- package/dist/canvas/index.js +54 -54
- package/dist/types/client/nodes/ExtAppFrame.d.ts +1 -0
- package/dist/types/client/nodes/iframe-document-url.d.ts +8 -0
- package/dist/types/client/state/intent-bridge.d.ts +4 -0
- package/dist/types/client/types.d.ts +1 -0
- package/dist/types/json-render/catalog.d.ts +1 -1
- package/dist/types/mcp/canvas-access.d.ts +9 -0
- package/dist/types/server/ax-context.d.ts +3 -0
- package/dist/types/server/ax-state.d.ts +43 -0
- package/dist/types/server/canvas-db.d.ts +5 -0
- package/dist/types/server/canvas-state.d.ts +19 -3
- package/dist/types/server/index.d.ts +6 -0
- package/dist/types/server/mutation-history.d.ts +1 -1
- package/docs/cli.md +13 -0
- package/docs/http-api.md +24 -0
- package/docs/mcp.md +20 -2
- package/docs/plans/plan-004-pmx-ax-primitives.md +463 -0
- package/docs/screenshot.png +0 -0
- package/docs/sdk.md +5 -0
- package/package.json +2 -1
- package/skills/pmx-canvas/SKILL.md +14 -0
- package/skills/pmx-canvas/references/codex-app-adapter.md +107 -0
- package/skills/pmx-canvas/references/github-copilot-app-adapter.md +111 -0
- package/src/cli/agent.ts +34 -0
- package/src/cli/index.ts +2 -1
- package/src/client/App.tsx +2 -0
- package/src/client/canvas/CanvasNode.tsx +7 -0
- package/src/client/canvas/CommandPalette.tsx +2 -1
- package/src/client/canvas/use-node-drag.ts +29 -7
- package/src/client/canvas/use-node-resize.ts +27 -7
- package/src/client/nodes/ExtAppFrame.tsx +51 -10
- package/src/client/nodes/HtmlNode.tsx +5 -2
- package/src/client/nodes/iframe-document-url.ts +58 -0
- package/src/client/state/intent-bridge.ts +8 -0
- package/src/client/state/sse-bridge.ts +2 -2
- package/src/client/theme/global.css +36 -3
- package/src/client/types.ts +1 -0
- package/src/mcp/canvas-access.ts +38 -0
- package/src/mcp/server.ts +113 -4
- package/src/server/ax-context.ts +38 -0
- package/src/server/ax-state.ts +130 -0
- package/src/server/canvas-db.ts +36 -1
- package/src/server/canvas-operations.ts +79 -0
- package/src/server/canvas-state.ts +113 -2
- package/src/server/index.ts +18 -0
- package/src/server/mutation-history.ts +1 -0
- package/src/server/server.ts +193 -8
|
@@ -24,6 +24,7 @@ export declare function resolveExtAppContainerDimensions(target: ExtAppHostDimen
|
|
|
24
24
|
height: number;
|
|
25
25
|
};
|
|
26
26
|
export declare function shouldApplyExtAppSizeChange(height: unknown, isExpanded: boolean): height is number;
|
|
27
|
+
export declare function resolveExtAppInlineFrameHeight(appHeight: number, hostHeight: number): number;
|
|
27
28
|
export declare function ExtAppFrame({ node, expanded }: {
|
|
28
29
|
node: CanvasNodeState;
|
|
29
30
|
expanded?: boolean;
|
|
@@ -22,6 +22,10 @@ export declare function openWorkbenchFile(path: string): Promise<{
|
|
|
22
22
|
}>;
|
|
23
23
|
/** Fetch canvas state from server. */
|
|
24
24
|
export declare function fetchCanvasState(): Promise<Record<string, unknown>>;
|
|
25
|
+
export declare function saveCanvasTheme(theme: string): Promise<{
|
|
26
|
+
ok: boolean;
|
|
27
|
+
theme?: string;
|
|
28
|
+
}>;
|
|
25
29
|
/** Fetch available slash commands for prompt completion. */
|
|
26
30
|
export declare function fetchSlashCommands(): Promise<Array<{
|
|
27
31
|
name: string;
|
|
@@ -58,6 +58,7 @@ export declare const EXCALIDRAW_CREATE_VIEW_TOOL = "create_view";
|
|
|
58
58
|
export declare function isExcalidrawNode(node: CanvasNodeState): boolean;
|
|
59
59
|
export interface CanvasLayout {
|
|
60
60
|
viewport: ViewportState;
|
|
61
|
+
theme?: 'dark' | 'light' | 'high-contrast';
|
|
61
62
|
nodes: CanvasNodeState[];
|
|
62
63
|
edges: CanvasEdge[];
|
|
63
64
|
annotations?: CanvasAnnotation[];
|
|
@@ -287,8 +287,8 @@ export declare const allComponentDefinitions: {
|
|
|
287
287
|
props: z.ZodObject<{
|
|
288
288
|
text: z.ZodString;
|
|
289
289
|
variant: z.ZodNullable<z.ZodEnum<{
|
|
290
|
-
default: "default";
|
|
291
290
|
error: "error";
|
|
291
|
+
default: "default";
|
|
292
292
|
success: "success";
|
|
293
293
|
secondary: "secondary";
|
|
294
294
|
destructive: "destructive";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type CanvasLayout, type CanvasNodeState, type CanvasSnapshot, type PmxCanvas } from '../server/index.js';
|
|
2
|
+
import type { PmxAxSource } from '../server/ax-state.js';
|
|
2
3
|
type AddNodeInput = Parameters<PmxCanvas['addNode']>[0];
|
|
3
4
|
type AddWebpageNodeInput = Parameters<PmxCanvas['addWebpageNode']>[0];
|
|
4
5
|
type RefreshWebpageNodeResult = Awaited<ReturnType<PmxCanvas['refreshWebpageNode']>>;
|
|
@@ -20,6 +21,9 @@ type ArrangeLayout = Parameters<PmxCanvas['arrange']>[0];
|
|
|
20
21
|
type FocusNodeResult = ReturnType<PmxCanvas['focusNode']>;
|
|
21
22
|
type FitViewOptions = Parameters<PmxCanvas['fitView']>[0];
|
|
22
23
|
type FitViewResult = ReturnType<PmxCanvas['fitView']>;
|
|
24
|
+
type AxStateResult = ReturnType<PmxCanvas['getAxState']>;
|
|
25
|
+
type AxContextResult = ReturnType<PmxCanvas['getAxContext']>;
|
|
26
|
+
type SetAxFocusResult = ReturnType<PmxCanvas['setAxFocus']>;
|
|
23
27
|
type SearchResult = ReturnType<PmxCanvas['search']>;
|
|
24
28
|
type UndoRedoResult = Awaited<ReturnType<PmxCanvas['undo']>>;
|
|
25
29
|
type HistoryResult = ReturnType<PmxCanvas['getHistory']>;
|
|
@@ -68,6 +72,11 @@ export interface CanvasAccess {
|
|
|
68
72
|
noPan?: boolean;
|
|
69
73
|
}): Promise<FocusNodeResult>;
|
|
70
74
|
fitView(options?: FitViewOptions): Promise<FitViewResult>;
|
|
75
|
+
getAxState(): Promise<AxStateResult>;
|
|
76
|
+
getAxContext(): Promise<AxContextResult>;
|
|
77
|
+
setAxFocus(nodeIds: string[], options?: {
|
|
78
|
+
source?: PmxAxSource;
|
|
79
|
+
}): Promise<SetAxFocusResult>;
|
|
71
80
|
clear(): Promise<void>;
|
|
72
81
|
search(query: string): Promise<SearchResult>;
|
|
73
82
|
undo(): Promise<UndoRedoResult>;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { CanvasLayout, CanvasNodeState } from './canvas-state.js';
|
|
2
|
+
import type { AgentContextNode } from './agent-context.js';
|
|
3
|
+
export type PmxAxSource = 'agent' | 'api' | 'browser' | 'cli' | 'codex' | 'copilot' | 'mcp' | 'sdk' | 'system';
|
|
4
|
+
export interface PmxAxFocusState {
|
|
5
|
+
nodeIds: string[];
|
|
6
|
+
primaryNodeId: string | null;
|
|
7
|
+
updatedAt: string | null;
|
|
8
|
+
source: PmxAxSource | null;
|
|
9
|
+
}
|
|
10
|
+
export interface PmxAxState {
|
|
11
|
+
version: 1;
|
|
12
|
+
focus: PmxAxFocusState;
|
|
13
|
+
}
|
|
14
|
+
export interface PmxAxPinnedContext {
|
|
15
|
+
preamble: string;
|
|
16
|
+
nodeIds: string[];
|
|
17
|
+
count: number;
|
|
18
|
+
nodes: AgentContextNode[];
|
|
19
|
+
}
|
|
20
|
+
export interface PmxAxFocusContext extends PmxAxFocusState {
|
|
21
|
+
nodes: AgentContextNode[];
|
|
22
|
+
}
|
|
23
|
+
export interface PmxAxContext {
|
|
24
|
+
version: 1;
|
|
25
|
+
generatedAt: string;
|
|
26
|
+
surface: {
|
|
27
|
+
nodeCount: number;
|
|
28
|
+
edgeCount: number;
|
|
29
|
+
};
|
|
30
|
+
pinned: PmxAxPinnedContext;
|
|
31
|
+
focus: PmxAxFocusContext;
|
|
32
|
+
}
|
|
33
|
+
export declare function createEmptyAxFocusState(): PmxAxFocusState;
|
|
34
|
+
export declare function createEmptyAxState(): PmxAxState;
|
|
35
|
+
export declare function normalizeAxFocusState(input: unknown, validNodeIds?: Set<string>): PmxAxFocusState;
|
|
36
|
+
export declare function normalizeAxState(input: unknown, validNodeIds?: Set<string>): PmxAxState;
|
|
37
|
+
export declare function buildAxContext(input: {
|
|
38
|
+
layout: CanvasLayout;
|
|
39
|
+
pinned: PmxAxPinnedContext;
|
|
40
|
+
focus: PmxAxFocusState;
|
|
41
|
+
focusNodes: AgentContextNode[];
|
|
42
|
+
}): PmxAxContext;
|
|
43
|
+
export declare function nodeSetFromLayout(nodes: CanvasNodeState[]): Set<string>;
|
|
@@ -6,13 +6,18 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { Database } from 'bun:sqlite';
|
|
8
8
|
import type { CanvasAnnotation, CanvasEdge, CanvasNodeState, CanvasSnapshot, CanvasSnapshotListOptions, ViewportState } from './canvas-state.js';
|
|
9
|
+
import { type PmxAxState } from './ax-state.js';
|
|
10
|
+
export type CanvasTheme = 'dark' | 'light' | 'high-contrast';
|
|
11
|
+
export declare function normalizeCanvasTheme(value: unknown, fallback?: CanvasTheme): CanvasTheme;
|
|
9
12
|
export interface PersistedCanvasState {
|
|
10
13
|
version: number;
|
|
14
|
+
theme?: CanvasTheme;
|
|
11
15
|
viewport: ViewportState;
|
|
12
16
|
nodes: CanvasNodeState[];
|
|
13
17
|
edges: CanvasEdge[];
|
|
14
18
|
annotations?: CanvasAnnotation[];
|
|
15
19
|
contextPins: string[];
|
|
20
|
+
ax?: PmxAxState;
|
|
16
21
|
}
|
|
17
22
|
export declare function openCanvasDb(dbPath: string): Database;
|
|
18
23
|
export declare function checkpointCanvasDb(db: Database): void;
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
* in the workspace root on every mutation (debounced). Auto-loads on `loadFromDisk()`.
|
|
10
10
|
* Legacy `.pmx-canvas/state.json` is auto-migrated on first boot.
|
|
11
11
|
*/
|
|
12
|
-
import { type PersistedCanvasState } from './canvas-db.js';
|
|
12
|
+
import { type PersistedCanvasState, type CanvasTheme } from './canvas-db.js';
|
|
13
|
+
import { type PmxAxFocusState, type PmxAxSource, type PmxAxState } from './ax-state.js';
|
|
13
14
|
export declare const PMX_CANVAS_DIR = ".pmx-canvas";
|
|
14
15
|
export interface PersistedBlobRef {
|
|
15
16
|
__pmxCanvasBlob: 'v1';
|
|
@@ -101,6 +102,7 @@ export interface CanvasAnnotation {
|
|
|
101
102
|
}
|
|
102
103
|
export interface CanvasLayout {
|
|
103
104
|
viewport: ViewportState;
|
|
105
|
+
theme: CanvasTheme;
|
|
104
106
|
nodes: CanvasNodeState[];
|
|
105
107
|
edges: CanvasEdge[];
|
|
106
108
|
annotations: CanvasAnnotation[];
|
|
@@ -118,9 +120,9 @@ export interface CanvasNodeUpdate {
|
|
|
118
120
|
collapsed?: boolean;
|
|
119
121
|
dockPosition?: 'left' | 'right' | null;
|
|
120
122
|
}
|
|
121
|
-
export type CanvasChangeType = 'pins' | 'nodes';
|
|
123
|
+
export type CanvasChangeType = 'pins' | 'nodes' | 'ax';
|
|
122
124
|
export interface MutationRecordInfo {
|
|
123
|
-
operationType: 'addNode' | 'updateNode' | 'removeNode' | 'addEdge' | 'removeEdge' | 'addAnnotation' | 'removeAnnotation' | 'clear' | 'restoreSnapshot' | 'setPins' | 'arrange' | 'batch' | 'groupNodes' | 'ungroupNodes' | 'viewport';
|
|
125
|
+
operationType: 'addNode' | 'updateNode' | 'removeNode' | 'addEdge' | 'removeEdge' | 'addAnnotation' | 'removeAnnotation' | 'clear' | 'restoreSnapshot' | 'setPins' | 'setAxFocus' | 'arrange' | 'batch' | 'groupNodes' | 'ungroupNodes' | 'viewport';
|
|
124
126
|
description: string;
|
|
125
127
|
forward: () => void;
|
|
126
128
|
inverse: () => void;
|
|
@@ -138,7 +140,9 @@ declare class CanvasStateManager {
|
|
|
138
140
|
private edges;
|
|
139
141
|
private annotations;
|
|
140
142
|
private _viewport;
|
|
143
|
+
private _theme;
|
|
141
144
|
private _contextPinnedNodeIds;
|
|
145
|
+
private _axState;
|
|
142
146
|
private _workspaceRoot;
|
|
143
147
|
private _changeListeners;
|
|
144
148
|
/** Register a listener for state changes. Used by MCP server to emit resource notifications. */
|
|
@@ -153,6 +157,9 @@ declare class CanvasStateManager {
|
|
|
153
157
|
/** Create a closure that runs with recording suppressed. */
|
|
154
158
|
private suppressed;
|
|
155
159
|
private recordMutation;
|
|
160
|
+
private currentNodeIdSet;
|
|
161
|
+
private normalizeAxForCurrentNodes;
|
|
162
|
+
private applyAxState;
|
|
156
163
|
private applyResolvedGroupBounds;
|
|
157
164
|
private getGroupSnapshot;
|
|
158
165
|
private normalizeNode;
|
|
@@ -245,7 +252,16 @@ declare class CanvasStateManager {
|
|
|
245
252
|
skipped: number;
|
|
246
253
|
};
|
|
247
254
|
setViewport(v: Partial<ViewportState>): void;
|
|
255
|
+
get theme(): CanvasTheme;
|
|
256
|
+
setTheme(theme: CanvasTheme): CanvasTheme;
|
|
248
257
|
get contextPinnedNodeIds(): Set<string>;
|
|
258
|
+
getAxState(): PmxAxState;
|
|
259
|
+
getAxFocus(): PmxAxFocusState;
|
|
260
|
+
setAxFocus(nodeIds: string[], options?: {
|
|
261
|
+
source?: PmxAxSource;
|
|
262
|
+
recordHistory?: boolean;
|
|
263
|
+
}): PmxAxFocusState;
|
|
264
|
+
clearAxFocus(): PmxAxFocusState;
|
|
249
265
|
setContextPins(nodeIds: string[]): void;
|
|
250
266
|
clearContextPins(): void;
|
|
251
267
|
/** Move child nodes into a group. Sets data.parentGroup on children and data.children on the group. */
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { EventEmitter } from 'node:events';
|
|
2
2
|
import type { CanvasAnnotation, CanvasNodeState, CanvasEdge, CanvasLayout } from './canvas-state.js';
|
|
3
|
+
import type { PmxAxContext, PmxAxFocusState, PmxAxSource, PmxAxState } from './ax-state.js';
|
|
3
4
|
import { searchNodes } from './spatial-analysis.js';
|
|
4
5
|
import { diffLayouts } from './mutation-history.js';
|
|
5
6
|
import { fitCanvasView, gcCanvasSnapshots, listCanvasSnapshots } from './canvas-operations.js';
|
|
@@ -104,6 +105,11 @@ export declare class PmxCanvas extends EventEmitter {
|
|
|
104
105
|
focused: string;
|
|
105
106
|
panned: boolean;
|
|
106
107
|
} | null;
|
|
108
|
+
getAxState(): PmxAxState;
|
|
109
|
+
getAxContext(): PmxAxContext;
|
|
110
|
+
setAxFocus(nodeIds: string[], options?: {
|
|
111
|
+
source?: PmxAxSource;
|
|
112
|
+
}): PmxAxFocusState;
|
|
107
113
|
fitView(options?: {
|
|
108
114
|
width?: number;
|
|
109
115
|
height?: number;
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* - _replaying flag prevents undo/redo from recording new entries
|
|
13
13
|
*/
|
|
14
14
|
import type { CanvasNodeState, CanvasEdge } from './canvas-state.js';
|
|
15
|
-
export type MutationOp = 'addNode' | 'updateNode' | 'removeNode' | 'addEdge' | 'removeEdge' | 'addAnnotation' | 'removeAnnotation' | 'clear' | 'arrange' | 'restoreSnapshot' | 'setPins' | 'batch' | 'viewport' | 'groupNodes' | 'ungroupNodes';
|
|
15
|
+
export type MutationOp = 'addNode' | 'updateNode' | 'removeNode' | 'addEdge' | 'removeEdge' | 'addAnnotation' | 'removeAnnotation' | 'clear' | 'arrange' | 'restoreSnapshot' | 'setPins' | 'setAxFocus' | 'batch' | 'viewport' | 'groupNodes' | 'ungroupNodes';
|
|
16
16
|
export interface MutationEntry {
|
|
17
17
|
id: string;
|
|
18
18
|
timestamp: string;
|
package/docs/cli.md
CHANGED
|
@@ -112,6 +112,19 @@ pmx-canvas focus <node-id> # Pan viewport to a node
|
|
|
112
112
|
pmx-canvas focus <node-id> --no-pan # Select/raise without panning
|
|
113
113
|
```
|
|
114
114
|
|
|
115
|
+
## AX context
|
|
116
|
+
|
|
117
|
+
AX commands expose the host-agnostic context contract used by adapters. Pins
|
|
118
|
+
remain the explicit human-curated context set; AX focus is the current
|
|
119
|
+
attention target and persists with canvas state and snapshots.
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
pmx-canvas ax status # Persisted AX state
|
|
123
|
+
pmx-canvas ax context # Pinned + focused agent context
|
|
124
|
+
pmx-canvas ax focus node-1 node-2 # Set AX focus
|
|
125
|
+
pmx-canvas ax focus --clear # Clear AX focus
|
|
126
|
+
```
|
|
127
|
+
|
|
115
128
|
## WebView automation
|
|
116
129
|
|
|
117
130
|
Drive a headless Bun.WebView (Chromium or WebKit) pointed at the workbench:
|
package/docs/http-api.md
CHANGED
|
@@ -93,6 +93,30 @@ curl -X POST http://localhost:4313/api/canvas/context-pins \
|
|
|
93
93
|
curl http://localhost:4313/api/canvas/pinned-context
|
|
94
94
|
```
|
|
95
95
|
|
|
96
|
+
## AX context and focus
|
|
97
|
+
|
|
98
|
+
AX context is the host-agnostic agent-experience layer. It combines existing
|
|
99
|
+
context pins with a persisted focus node set that adapters can inject into
|
|
100
|
+
their native prompt/context hooks.
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
# Get persisted AX state
|
|
104
|
+
curl http://localhost:4313/api/canvas/ax
|
|
105
|
+
|
|
106
|
+
# Get agent-readable pinned + focused context
|
|
107
|
+
curl http://localhost:4313/api/canvas/ax/context
|
|
108
|
+
|
|
109
|
+
# Set AX focus
|
|
110
|
+
curl -X POST http://localhost:4313/api/canvas/ax/focus \
|
|
111
|
+
-H "Content-Type: application/json" \
|
|
112
|
+
-d '{"nodeIds":["node-1"],"source":"api"}'
|
|
113
|
+
|
|
114
|
+
# Patch AX focus through the state endpoint
|
|
115
|
+
curl -X PATCH http://localhost:4313/api/canvas/ax \
|
|
116
|
+
-H "Content-Type: application/json" \
|
|
117
|
+
-d '{"focus":{"nodeIds":["node-1"],"source":"api"}}'
|
|
118
|
+
```
|
|
119
|
+
|
|
96
120
|
## Diagrams (Excalidraw preset)
|
|
97
121
|
|
|
98
122
|
```bash
|
package/docs/mcp.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# MCP reference
|
|
2
2
|
|
|
3
|
-
PMX Canvas ships an MCP stdio server with **
|
|
3
|
+
PMX Canvas ships an MCP stdio server with **45 tools** + **9 core resources**,
|
|
4
4
|
plus per-skill resources at `canvas://skills/<name>`. The server emits
|
|
5
5
|
`notifications/resources/updated` when canvas state changes — humans pin
|
|
6
6
|
nodes in the browser, agents are notified immediately.
|
|
@@ -51,6 +51,8 @@ searchable and readable in pinned/spatial context.
|
|
|
51
51
|
| `canvas_arrange` | Auto-arrange (grid/column/flow) |
|
|
52
52
|
| `canvas_validate` | Validate collisions, containment, and missing edge endpoints |
|
|
53
53
|
| `canvas_focus_node` | Pan viewport to a node; use CLI `focus --no-pan` when you only need to select/raise |
|
|
54
|
+
| `canvas_get_ax` | Read the PMX AX state plus pinned/focused context |
|
|
55
|
+
| `canvas_set_ax_focus` | Set the host-agnostic AX focus node set; adapters can pass a source such as `codex` |
|
|
54
56
|
| `canvas_pin_nodes` | Pin nodes to include in agent context |
|
|
55
57
|
| `canvas_clear` | Clear all nodes and edges |
|
|
56
58
|
| `canvas_snapshot` | Save current canvas as a named snapshot |
|
|
@@ -80,6 +82,8 @@ Individual bundled skills are also readable at `canvas://skills/<name>`.
|
|
|
80
82
|
| Resource | Description |
|
|
81
83
|
|----------|-------------|
|
|
82
84
|
| `canvas://pinned-context` | Content of pinned nodes + nearby unpinned neighbors |
|
|
85
|
+
| `canvas://ax` | PMX AX state, currently including persisted focus |
|
|
86
|
+
| `canvas://ax-context` | Agent-readable pinned and focused AX context |
|
|
83
87
|
| `canvas://schema` | Running-server create schemas and json-render catalog metadata |
|
|
84
88
|
| `canvas://layout` | Full canvas state (all nodes, edges, viewport) |
|
|
85
89
|
| `canvas://summary` | Compact overview: counts, pinned titles, viewport |
|
|
@@ -93,13 +97,27 @@ Individual bundled skills are also readable at `canvas://skills/<name>`.
|
|
|
93
97
|
The MCP server emits `notifications/resources/updated` whenever canvas state
|
|
94
98
|
changes:
|
|
95
99
|
|
|
96
|
-
- Pin changes notify `canvas://pinned-context`
|
|
100
|
+
- Pin changes notify `canvas://pinned-context`, `canvas://ax`, and `canvas://ax-context`
|
|
101
|
+
- AX focus changes notify `canvas://ax` and `canvas://ax-context`
|
|
97
102
|
- All mutations notify `canvas://layout`, `canvas://summary`,
|
|
98
103
|
`canvas://spatial-context`, `canvas://history`, and `canvas://code-graph`
|
|
99
104
|
|
|
100
105
|
This closes the human-to-agent loop: spatial curation in the browser becomes
|
|
101
106
|
an immediate signal in the agent's context.
|
|
102
107
|
|
|
108
|
+
## Codex App Adapter
|
|
109
|
+
|
|
110
|
+
In the Codex app, PMX Canvas runs natively through the existing Codex surfaces:
|
|
111
|
+
MCP for tools/resources and the in-app Browser for the live `/workbench` view.
|
|
112
|
+
No separate PMX renderer is needed. Prefer MCP over the CLI for Codex-native
|
|
113
|
+
operation; keep the CLI for fallback scripts and manual debugging.
|
|
114
|
+
|
|
115
|
+
Use `canvas://ax-context` or `canvas_get_ax` to read pinned/focused context.
|
|
116
|
+
When Codex-hosted steering sets the current attention target, call
|
|
117
|
+
`canvas_set_ax_focus` with `source: "codex"` so the AX state records where the
|
|
118
|
+
focus came from. The full workflow lives in
|
|
119
|
+
`skills/pmx-canvas/references/codex-app-adapter.md`.
|
|
120
|
+
|
|
103
121
|
## Annotation Visibility
|
|
104
122
|
|
|
105
123
|
Human-drawn canvas annotations are rendered as browser SVG ink. MCP resources
|