pmx-canvas 0.3.3 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +99 -0
- package/Readme.md +13 -4
- package/dist/canvas/index.js +71 -71
- package/dist/json-render/index.js +47 -47
- package/dist/types/cli/agent.d.ts +13 -8
- package/dist/types/cli/commands/apps.d.ts +1 -0
- package/dist/types/cli/commands/ax.d.ts +1 -0
- package/dist/types/cli/commands/copilot.d.ts +1 -0
- package/dist/types/cli/commands/edges.d.ts +1 -0
- package/dist/types/cli/commands/groups.d.ts +1 -0
- package/dist/types/cli/commands/history.d.ts +1 -0
- package/dist/types/cli/commands/nodes.d.ts +1 -0
- package/dist/types/cli/commands/pins.d.ts +1 -0
- package/dist/types/cli/commands/query.d.ts +1 -0
- package/dist/types/cli/commands/view.d.ts +1 -0
- package/dist/types/cli/commands/webview.d.ts +1 -0
- package/dist/types/cli/shared.d.ts +73 -0
- package/dist/types/client/canvas/ExpandedNodeOverlay.d.ts +1 -1
- package/dist/types/client/index.d.ts +1 -1
- package/dist/types/client/nodes/ExtAppFrame.d.ts +10 -0
- package/dist/types/client/nodes/HtmlNode.d.ts +1 -1
- package/dist/types/client/nodes/McpAppNode.d.ts +1 -1
- package/dist/types/client/nodes/use-ax-surface-bridge.d.ts +20 -0
- package/dist/types/client/state/node-factory.d.ts +29 -0
- package/dist/types/client/uuid-polyfill.d.ts +0 -0
- package/dist/types/server/canvas-db.d.ts +0 -1
- package/dist/types/server/canvas-operations.d.ts +2 -0
- package/dist/types/server/canvas-state.d.ts +14 -15
- package/dist/types/server/diagram-presets.d.ts +8 -0
- package/dist/types/server/operations/composites.d.ts +6 -30
- package/dist/types/server/server.d.ts +1 -0
- package/dist/types/shared/ax-surface-protocol.d.ts +18 -0
- package/docs/bun-webview-integration.md +5 -0
- package/docs/cli.md +5 -0
- package/docs/environment.md +48 -0
- package/docs/http-api.md +25 -1
- package/docs/mcp.md +21 -30
- package/docs/node-types.md +5 -0
- package/docs/plans/plan-009-tech-debt-backlog.md +34 -15
- package/docs/screenshot.png +0 -0
- package/docs/tech-debt-assessment-2026-06.md +5 -5
- package/package.json +13 -10
- package/skills/pmx-canvas/SKILL.md +16 -6
- package/skills/pmx-canvas/evals/evals.json +7 -7
- package/skills/pmx-canvas/references/full-reference.md +25 -16
- package/src/cli/agent.ts +22 -3512
- package/src/cli/commands/apps.ts +165 -0
- package/src/cli/commands/ax.ts +604 -0
- package/src/cli/commands/copilot.ts +43 -0
- package/src/cli/commands/edges.ts +73 -0
- package/src/cli/commands/groups.ts +81 -0
- package/src/cli/commands/history.ts +220 -0
- package/src/cli/commands/nodes.ts +984 -0
- package/src/cli/commands/pins.ts +42 -0
- package/src/cli/commands/query.ts +223 -0
- package/src/cli/commands/view.ts +186 -0
- package/src/cli/commands/webview.ts +227 -0
- package/src/cli/index.ts +8 -2
- package/src/cli/shared.ts +861 -0
- package/src/client/canvas/ExpandedNodeOverlay.tsx +3 -2
- package/src/client/index.tsx +2 -0
- package/src/client/nodes/ExtAppFrame.tsx +70 -51
- package/src/client/nodes/HtmlNode.tsx +8 -51
- package/src/client/nodes/McpAppNode.tsx +12 -47
- package/src/client/nodes/use-ax-surface-bridge.ts +71 -0
- package/src/client/state/node-factory.ts +72 -0
- package/src/client/state/sse-bridge.ts +209 -86
- package/src/client/uuid-polyfill.ts +14 -0
- package/src/json-render/renderer/index.tsx +3 -2
- package/src/mcp/server.ts +0 -47
- package/src/server/canvas-db.ts +0 -8
- package/src/server/canvas-operations.ts +8 -0
- package/src/server/canvas-schema.ts +2 -8
- package/src/server/canvas-state.ts +51 -151
- package/src/server/diagram-presets.ts +15 -1
- package/src/server/html-surface.ts +11 -6
- package/src/server/index.ts +3 -9
- package/src/server/operations/composites.ts +25 -34
- package/src/server/operations/invoker.ts +10 -3
- package/src/server/operations/mcp.ts +51 -1
- package/src/server/operations/ops/app.ts +5 -0
- package/src/server/operations/ops/snapshots.ts +6 -7
- package/src/server/operations/registry.ts +4 -1
- package/src/server/server.ts +172 -74
- package/src/shared/ax-surface-protocol.ts +22 -0
- package/dist/types/client/canvas/ContextPinHud.d.ts +0 -1
- package/src/client/canvas/ContextPinHud.tsx +0 -17
|
@@ -10,12 +10,17 @@
|
|
|
10
10
|
* - Idempotent operations where possible
|
|
11
11
|
* - --yes for destructive actions, --dry-run for preview
|
|
12
12
|
*/
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
13
|
+
import { extractGlobalTargetFlags } from './shared.js';
|
|
14
|
+
import './commands/nodes.js';
|
|
15
|
+
import './commands/edges.js';
|
|
16
|
+
import './commands/groups.js';
|
|
17
|
+
import './commands/view.js';
|
|
18
|
+
import './commands/query.js';
|
|
19
|
+
import './commands/pins.js';
|
|
20
|
+
import './commands/history.js';
|
|
21
|
+
import './commands/ax.js';
|
|
22
|
+
import './commands/webview.js';
|
|
23
|
+
import './commands/apps.js';
|
|
24
|
+
import './commands/copilot.js';
|
|
25
|
+
export { extractGlobalTargetFlags };
|
|
21
26
|
export declare function runAgentCli(rawArgs: string[]): Promise<void>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared core for the agent-native CLI.
|
|
3
|
+
*
|
|
4
|
+
* Holds the command registry (COMMANDS + cmd()), flag parsing, output/die,
|
|
5
|
+
* target resolution (getBaseUrl + global --port/--server-url handling), the
|
|
6
|
+
* operation invoker, and every helper used by two or more command domains.
|
|
7
|
+
* Command modules in src/cli/commands/ import from here only — this module
|
|
8
|
+
* must never import from agent.ts or any command module (cycle-free).
|
|
9
|
+
*/
|
|
10
|
+
declare function getBaseUrl(): string;
|
|
11
|
+
/**
|
|
12
|
+
* Extract the global `--port <n>` / `--server-url <url>` flags (any position,
|
|
13
|
+
* `=` or space-separated value) and set the invocation's target override.
|
|
14
|
+
* Returns the remaining args for command dispatch. Invalid values are a loud
|
|
15
|
+
* `die` — never a silent fallback to the default port. `--server-url` wins
|
|
16
|
+
* over `--port` when both are given.
|
|
17
|
+
*/
|
|
18
|
+
export declare function extractGlobalTargetFlags(args: string[]): string[];
|
|
19
|
+
declare function die(message: string, hint?: string): never;
|
|
20
|
+
declare function output(data: unknown): void;
|
|
21
|
+
declare function invokeOperation(name: string, input: Record<string, unknown>): Promise<unknown>;
|
|
22
|
+
declare function parseFlags(args: string[]): {
|
|
23
|
+
positional: string[];
|
|
24
|
+
flags: Record<string, string | true>;
|
|
25
|
+
};
|
|
26
|
+
declare function requireFlag(flags: Record<string, string | true>, name: string, hint: string): string;
|
|
27
|
+
declare function getStringFlag(flags: Record<string, string | true>, ...names: string[]): string | undefined;
|
|
28
|
+
declare function optionalNumberFlag(flags: Record<string, string | true>, name: string, hint: string): number | undefined;
|
|
29
|
+
/**
|
|
30
|
+
* AX `source` for a CLI-originated action. Defaults to `cli`, but honors an
|
|
31
|
+
* explicit `--source <label>` so an adapterless agent using the CLI as a fallback
|
|
32
|
+
* transport (e.g. `--source codex`) attributes its actions correctly — keeping
|
|
33
|
+
* loop-safety (a consumer never gets back its own steering) accurate (report #69).
|
|
34
|
+
*/
|
|
35
|
+
declare function resolveAxSource(flags: Record<string, string | true>): string;
|
|
36
|
+
declare function optionalFiniteFlag(flags: Record<string, string | true>, name: string, hint: string): number | undefined;
|
|
37
|
+
declare function optionalPositiveFiniteFlag(flags: Record<string, string | true>, name: string, hint: string): number | undefined;
|
|
38
|
+
declare function optionalPositiveFiniteFlagWithAliases(flags: Record<string, string | true>, hint: string, ...names: string[]): number | undefined;
|
|
39
|
+
declare function optionalBooleanFlag(flags: Record<string, string | true>, name: string, hint: string): boolean | undefined;
|
|
40
|
+
declare function applyStrictSizeFlags(body: Record<string, unknown>, flags: Record<string, string | true>): void;
|
|
41
|
+
declare function isRecord(value: unknown): value is Record<string, unknown>;
|
|
42
|
+
declare function parseJsonValue(raw: string, label: string, hint: string): unknown;
|
|
43
|
+
declare function readOptionalTextInput(flags: Record<string, string | true>, options: {
|
|
44
|
+
fileFlags?: string[];
|
|
45
|
+
valueFlags?: string[];
|
|
46
|
+
allowStdin?: boolean;
|
|
47
|
+
label: string;
|
|
48
|
+
hint: string;
|
|
49
|
+
}): Promise<string | undefined>;
|
|
50
|
+
declare function applyCommonGeometryFlags(body: Record<string, unknown>, flags: Record<string, string | true>, hints: {
|
|
51
|
+
x: string;
|
|
52
|
+
y: string;
|
|
53
|
+
width: string;
|
|
54
|
+
height: string;
|
|
55
|
+
}): void;
|
|
56
|
+
declare function buildJsonRenderRequestBody(flags: Record<string, string | true>): Promise<Record<string, unknown>>;
|
|
57
|
+
declare function buildHtmlPrimitiveRequestBody(flags: Record<string, string | true>): Promise<Record<string, unknown>>;
|
|
58
|
+
declare function buildGraphRequestBody(flags: Record<string, string | true>, options?: {
|
|
59
|
+
requireData?: boolean;
|
|
60
|
+
allowStdin?: boolean;
|
|
61
|
+
}): Promise<Record<string, unknown>>;
|
|
62
|
+
declare function runWebArtifactBuildCommand(flags: Record<string, string | true>): Promise<void>;
|
|
63
|
+
declare const COMMANDS: Record<string, {
|
|
64
|
+
run: (args: string[]) => Promise<void>;
|
|
65
|
+
help: string;
|
|
66
|
+
examples: string[];
|
|
67
|
+
}>;
|
|
68
|
+
declare const RESOURCE_COMMAND_ALIASES: Record<string, Record<string, string>>;
|
|
69
|
+
declare const RESOURCE_SUBCOMMAND_HINTS: Record<string, Record<string, string>>;
|
|
70
|
+
declare function cmd(name: string, help: string, examples: string[], run: (args: string[]) => Promise<void>): void;
|
|
71
|
+
declare function showCommandHelp(name: string): void;
|
|
72
|
+
declare function readStdin(): Promise<string>;
|
|
73
|
+
export { COMMANDS, RESOURCE_COMMAND_ALIASES, RESOURCE_SUBCOMMAND_HINTS, applyCommonGeometryFlags, applyStrictSizeFlags, buildGraphRequestBody, buildHtmlPrimitiveRequestBody, buildJsonRenderRequestBody, cmd, die, getBaseUrl, getStringFlag, invokeOperation, isRecord, optionalBooleanFlag, optionalFiniteFlag, optionalNumberFlag, optionalPositiveFiniteFlag, optionalPositiveFiniteFlagWithAliases, output, parseFlags, parseJsonValue, readOptionalTextInput, readStdin, requireFlag, resolveAxSource, runWebArtifactBuildCommand, showCommandHelp, };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare function ExpandedNodeOverlay(): import("preact/
|
|
1
|
+
export declare function ExpandedNodeOverlay(): import("preact/jsx-runtime").JSX.Element | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
import './uuid-polyfill';
|
|
@@ -51,6 +51,16 @@ export declare function buildExtAppAxBridgeScript(axToken: string, nodeId: strin
|
|
|
51
51
|
* the host also checks event.source against the live iframe.
|
|
52
52
|
*/
|
|
53
53
|
export declare function buildExtAppBootBeaconScript(frameToken: string, nodeId: string): string;
|
|
54
|
+
/**
|
|
55
|
+
* Base styles injected into every ext-app document (Finding Q, 0.3.4 report):
|
|
56
|
+
* apps aspect-fit their drawn surface to the frame width, and on narrow/tall
|
|
57
|
+
* tiles the leftover region shows the app document's own body background —
|
|
58
|
+
* pure black for the hosted Excalidraw bundle, in every engine. Making the
|
|
59
|
+
* app document transparent lets the host iframe's theme background
|
|
60
|
+
* (var(--c-panel)) show through the letterbox instead. Background only — app
|
|
61
|
+
* content, its drawn scene, and its own foreground styling are untouched.
|
|
62
|
+
*/
|
|
63
|
+
export declare function buildExtAppSurfaceBaseStyles(): string;
|
|
54
64
|
export declare function injectExtAppAxBridgeScript(html: string, axBridgeScript: string): string;
|
|
55
65
|
export declare function resolveExtAppContainerDimensions(target: ExtAppHostDimensionsTarget | null | undefined, fallback: {
|
|
56
66
|
width: number;
|
|
@@ -3,4 +3,4 @@ export declare function isSameOriginFrameDocumentUrl(url: string, origin?: strin
|
|
|
3
3
|
export declare function McpAppNode({ node, expanded }: {
|
|
4
4
|
node: CanvasNodeState;
|
|
5
5
|
expanded?: boolean;
|
|
6
|
-
}): import("preact/
|
|
6
|
+
}): import("preact/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { RefObject } from 'preact';
|
|
2
|
+
/** Sandboxed surfaces that emit through this bridge (clamped to their own node server-side). */
|
|
3
|
+
export type AxSurfaceBridgeSurface = 'json-render' | 'html-node' | 'mcp-app';
|
|
4
|
+
/**
|
|
5
|
+
* The sandboxed-surface AX trust boundary, single-sited (plan-009 M2; the
|
|
6
|
+
* listener was copy-pasted across HtmlNode, McpAppNode, and ExtAppFrame — a
|
|
7
|
+
* prior near-miss lived exactly in that duplication). Receives a
|
|
8
|
+
* `window.PMX_AX.emit(...)` message from THIS node's iframe, validates the
|
|
9
|
+
* event source against the live contentWindow plus the per-mount nonce token
|
|
10
|
+
* and node id, submits the interaction through the capability-gated endpoint
|
|
11
|
+
* (the server re-validates capabilities and clamps sandboxed surfaces to their
|
|
12
|
+
* own node), and acks the result back so the surface can self-confirm (#55).
|
|
13
|
+
*/
|
|
14
|
+
export declare function useAxSurfaceBridge(options: {
|
|
15
|
+
enabled: boolean;
|
|
16
|
+
token: string;
|
|
17
|
+
nodeId: string;
|
|
18
|
+
sourceSurface: AxSurfaceBridgeSurface;
|
|
19
|
+
iframeRef: RefObject<HTMLIFrameElement>;
|
|
20
|
+
}): void;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { CanvasNodeState } from '../types';
|
|
2
|
+
export declare const DEFAULT_POSITIONS: Record<CanvasNodeState['type'], {
|
|
3
|
+
x: number;
|
|
4
|
+
y: number;
|
|
5
|
+
w: number;
|
|
6
|
+
h: number;
|
|
7
|
+
}> & Record<'prompt' | 'response', {
|
|
8
|
+
x: number;
|
|
9
|
+
y: number;
|
|
10
|
+
w: number;
|
|
11
|
+
h: number;
|
|
12
|
+
}>;
|
|
13
|
+
/**
|
|
14
|
+
* Build a canvas node with the shared client defaults. `position`/`size`
|
|
15
|
+
* default to the type's DEFAULT_POSITIONS entry; callers that compute
|
|
16
|
+
* placement (auto-placement, event-supplied geometry) pass explicit values.
|
|
17
|
+
* Status nodes sit at zIndex 0 (background chrome), everything else at 1.
|
|
18
|
+
*/
|
|
19
|
+
export declare function makeNodeState(id: string, type: CanvasNodeState['type'], data: Record<string, unknown>, options?: {
|
|
20
|
+
position?: {
|
|
21
|
+
x: number;
|
|
22
|
+
y: number;
|
|
23
|
+
};
|
|
24
|
+
size?: {
|
|
25
|
+
width: number;
|
|
26
|
+
height: number;
|
|
27
|
+
};
|
|
28
|
+
dockPosition?: 'left' | 'right' | null;
|
|
29
|
+
}): CanvasNodeState;
|
|
File without changes
|
|
@@ -35,7 +35,6 @@ export declare function listSnapshotsFromDB(db: Database, options?: CanvasSnapsh
|
|
|
35
35
|
export declare function deleteSnapshotFromDB(db: Database, id: string): boolean;
|
|
36
36
|
export declare function writeBlobToDB(db: Database, sha256: string, jsonValue: string): number;
|
|
37
37
|
export declare function readBlobFromDB(db: Database, sha256: string): string | null;
|
|
38
|
-
export declare function hasBlobInDB(db: Database, sha256: string): boolean;
|
|
39
38
|
export interface AxTimelineQuery {
|
|
40
39
|
limit?: number;
|
|
41
40
|
sessionId?: string;
|
|
@@ -128,6 +128,8 @@ export declare function validateCanvasNodePatch(patch: {
|
|
|
128
128
|
export declare function mergeTraceNodeDataFields(base: Record<string, unknown>, input: Record<string, unknown>): Record<string, unknown>;
|
|
129
129
|
export declare function hasTraceNodeDataFields(input: Record<string, unknown>): boolean;
|
|
130
130
|
export declare function scheduleCodeGraphRecompute(onComplete?: () => void): void;
|
|
131
|
+
/** Clear a pending recompute so the timer cannot outlive its server (start/stop cycles, tests). */
|
|
132
|
+
export declare function cancelCodeGraphRecompute(): void;
|
|
131
133
|
/**
|
|
132
134
|
* Resolve an html-node `html` field that may be a path to a local .html/.htm file.
|
|
133
135
|
*
|
|
@@ -7,7 +7,9 @@
|
|
|
7
7
|
*
|
|
8
8
|
* Persistence: canvas state auto-saves to `.pmx-canvas/canvas.db` (SQLite WAL mode)
|
|
9
9
|
* in the workspace root on every mutation (debounced). Auto-loads on `loadFromDisk()`.
|
|
10
|
-
* Legacy `.pmx-canvas/state.json
|
|
10
|
+
* Legacy pre-0.2 formats (`.pmx-canvas/state.json`, `.pmx-canvas.json`,
|
|
11
|
+
* `.pmx-canvas-snapshots/`, loose blob files) are no longer imported as of 0.4.0 —
|
|
12
|
+
* the one-shot boot migration into SQLite was retired.
|
|
11
13
|
*/
|
|
12
14
|
import { type PersistedCanvasState, type CanvasTheme, type AxTimelineQuery } from './canvas-db.js';
|
|
13
15
|
import { type PmxAxActivityKind, type PmxAxElicitation, type PmxAxModeRequest, type PmxAxMode, type PmxAxCommandDescriptor, type PmxAxPolicy, type PmxAxFocusState, type PmxAxSource, type PmxAxState, type PmxAxWorkItem, type PmxAxWorkItemStatus, type PmxAxApprovalGate, type PmxAxReviewAnnotation, type PmxAxReviewKind, type PmxAxReviewSeverity, type PmxAxReviewStatus, type PmxAxReviewAnchorType, type PmxAxReviewRegion, type PmxAxEvent, type PmxAxEventKind, type PmxAxEvidence, type PmxAxEvidenceKind, type PmxAxSteeringMessage, type PmxAxHostCapability, type PmxAxTimelineSummary } from './ax-state.js';
|
|
@@ -155,7 +157,7 @@ declare class CanvasStateManager {
|
|
|
155
157
|
private notifyChange;
|
|
156
158
|
private _mutationRecorder;
|
|
157
159
|
private _suppressRecordingDepth;
|
|
158
|
-
/** Register
|
|
160
|
+
/** Register THE mutation recorder (single slot, last-write-wins — see note above). */
|
|
159
161
|
onMutation(cb: (info: MutationRecordInfo) => void): void;
|
|
160
162
|
/** Run a function with mutation recording suppressed (for undo/redo replay and computed edges). */
|
|
161
163
|
withSuppressedRecording(fn: () => void): void;
|
|
@@ -171,7 +173,6 @@ declare class CanvasStateManager {
|
|
|
171
173
|
private translateGroupChildren;
|
|
172
174
|
private recomputeParentGroupBounds;
|
|
173
175
|
private compactGroupChildren;
|
|
174
|
-
private _stateFilePath;
|
|
175
176
|
private _db;
|
|
176
177
|
private _saveTimer;
|
|
177
178
|
/** Workspace root backing persistence and workspace-relative path resolution. */
|
|
@@ -188,20 +189,9 @@ declare class CanvasStateManager {
|
|
|
188
189
|
isBlobReference(value: unknown): value is PersistedBlobRef;
|
|
189
190
|
resolveBlobReference(value: unknown): unknown;
|
|
190
191
|
private externalizePersistedStateBlobs;
|
|
191
|
-
/**
|
|
192
|
-
* One-time migration: rename files from the pre-consolidation layout
|
|
193
|
-
* (`.pmx-canvas.json` + `.pmx-canvas-snapshots/`) into `.pmx-canvas/`.
|
|
194
|
-
* No-op when the new layout already exists.
|
|
195
|
-
*/
|
|
196
|
-
private migrateLegacyLayout;
|
|
197
|
-
/**
|
|
198
|
-
* One-time migration: import state.json + snapshot JSON files + blob files
|
|
199
|
-
* into the SQLite database. Renames originals to `.bak`.
|
|
200
|
-
*/
|
|
201
|
-
private migrateJsonToSqlite;
|
|
202
192
|
getWorkspaceRoot(): string;
|
|
203
193
|
private emptyPersistedState;
|
|
204
|
-
/** Load canvas state from SQLite
|
|
194
|
+
/** Load canvas state from SQLite. Call once on server startup. */
|
|
205
195
|
loadFromDisk(options?: LoadFromDiskOptions): boolean;
|
|
206
196
|
/**
|
|
207
197
|
* Whether this workspace's canvas DB already holds saved state. Used to gate
|
|
@@ -215,6 +205,15 @@ declare class CanvasStateManager {
|
|
|
215
205
|
flushToDisk(): void;
|
|
216
206
|
/** Write current state to SQLite immediately. */
|
|
217
207
|
private saveToDisk;
|
|
208
|
+
private _lastPersistenceError;
|
|
209
|
+
/** Health view of state persistence: ok until a save fails, ok again after the next success. */
|
|
210
|
+
get persistenceHealth(): {
|
|
211
|
+
ok: boolean;
|
|
212
|
+
lastError: {
|
|
213
|
+
message: string;
|
|
214
|
+
at: string;
|
|
215
|
+
} | null;
|
|
216
|
+
};
|
|
218
217
|
/** Close the SQLite database cleanly. Call on server shutdown. */
|
|
219
218
|
close(): void;
|
|
220
219
|
private get snapshotsDir();
|
|
@@ -7,6 +7,14 @@ export declare const EXCALIDRAW_SAVE_CHECKPOINT_TOOL = "save_checkpoint";
|
|
|
7
7
|
export declare const EXCALIDRAW_READ_CHECKPOINT_TOOL = "read_checkpoint";
|
|
8
8
|
export declare const DEFAULT_EXCALIDRAW_ELEMENTS: ReadonlyArray<Record<string, unknown>>;
|
|
9
9
|
export declare const EXCALIDRAW_MCP_TRANSPORT: ExternalMcpTransportConfig;
|
|
10
|
+
/**
|
|
11
|
+
* The diagram preset targets the hosted Excalidraw MCP server. Tests set
|
|
12
|
+
* PMX_CANVAS_EXCALIDRAW_MCP_COMMAND (a stdio command line, e.g.
|
|
13
|
+
* "bun run tests/fixtures/mcp-app-fixture.ts") so the unit suite never does a
|
|
14
|
+
* real network round-trip — the hosted dependency made diagram tests time out
|
|
15
|
+
* under parallel load (plan-009 M8).
|
|
16
|
+
*/
|
|
17
|
+
export declare function resolveExcalidrawTransport(): ExternalMcpTransportConfig;
|
|
10
18
|
export interface DiagramPresetOpenInput {
|
|
11
19
|
elements: unknown;
|
|
12
20
|
nodeId?: string;
|
|
@@ -16,27 +16,12 @@
|
|
|
16
16
|
* operation (plan-005 slices 1–7 + plan-008 Wave 1) that is now reachable ONLY
|
|
17
17
|
* through its composite (or `canvas_batch`).
|
|
18
18
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
* Wave 3 via runner injection; `canvas_app` shipped in Wave 4 — open-mcp-app /
|
|
26
|
-
* diagram / build-artifact. Wave 5 folded the last three legacy tools
|
|
27
|
-
* deprecate-only — NO per-action input-injection mechanism was needed:
|
|
28
|
-
* `canvas_add_html_node` / `canvas_add_html_primitive` → `canvas_node` action
|
|
29
|
-
* "add" (type:"html" [+ primitive]); `canvas_refresh_webpage_node` → `canvas_node`
|
|
30
|
-
* action "update" (refresh:true). `canvas_screenshot` stays standalone — it
|
|
31
|
-
* returns a binary image payload the composite/registry JSON wire shape does not
|
|
32
|
-
* model.)
|
|
33
|
-
*
|
|
34
|
-
* Not shipped here: the `canvas_snapshot` composite (plan-006 #7). Its target
|
|
35
|
-
* name is ALREADY a legacy standalone tool (the save-snapshot tool, op
|
|
36
|
-
* `snapshot.save`), so it cannot be added additively without a name clash, and
|
|
37
|
-
* repurposing `canvas_snapshot` to be action-discriminated now would break
|
|
38
|
-
* existing callers. It lands in v0.4, in the same change that removes the 6
|
|
39
|
-
* kept-but-deprecated legacy snapshot tools and frees the name.
|
|
19
|
+
* v0.4.0 completed the fold: the `canvas_snapshot` composite shipped (its name
|
|
20
|
+
* was held by the legacy save-snapshot standalone through v0.3.x, which — with
|
|
21
|
+
* the other 5 snapshot standalones — was deprecated in 0.3.0 and removed here
|
|
22
|
+
* per docs/api-stability.md's deprecate-one-minor-before-removal rule).
|
|
23
|
+
* `canvas_screenshot` stays standalone — it returns a binary image payload the
|
|
24
|
+
* composite/registry JSON wire shape does not model.
|
|
40
25
|
*
|
|
41
26
|
* This module must never import server.ts or index.ts.
|
|
42
27
|
*/
|
|
@@ -95,15 +80,6 @@ export interface CompositeToolDefinition {
|
|
|
95
80
|
kind: string;
|
|
96
81
|
action: string;
|
|
97
82
|
}) => string | undefined;
|
|
98
|
-
/**
|
|
99
|
-
* Two-discriminator extension: human-readable `(kind, action)` for a member op
|
|
100
|
-
* (the inverse of `resolveOp`), used to build that op's deprecation note. The
|
|
101
|
-
* `kind` field-collision is resolved here (see `gateFieldRemap`).
|
|
102
|
-
*/
|
|
103
|
-
describeOp?: (opName: string) => {
|
|
104
|
-
kind: string;
|
|
105
|
-
action: string;
|
|
106
|
-
} | undefined;
|
|
107
83
|
/**
|
|
108
84
|
* Field-name remap applied to the composite's advertised schema and undone at
|
|
109
85
|
* dispatch. Resolves a collision between a discriminator name and a member-op
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
* - GET /api/canvas/json-render/view?nodeId=... -> local json-render viewer
|
|
25
25
|
* - POST /api/canvas/web-artifact -> build bundled HTML artifact + optional canvas node
|
|
26
26
|
* - GET /api/workbench/events -> SSE event stream
|
|
27
|
+
* - GET /api/workbench/poll -> proxy-safe polling transport (same events, JSON)
|
|
27
28
|
* - GET /api/workbench/state -> workbench state snapshot
|
|
28
29
|
* - POST /api/workbench/intent -> workbench intents
|
|
29
30
|
* - GET /api/workbench/webview -> Bun.WebView automation status
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire-protocol source tags for sandboxed-surface ↔ canvas postMessage traffic
|
|
3
|
+
* (plan-009 M2): one module owns the strings that used to be spread across the
|
|
4
|
+
* client node components, the server-side surface script generators, the
|
|
5
|
+
* ext-app script builders, and the json-render viewer. These are the trust
|
|
6
|
+
* boundary between opaque-origin iframes and the canvas — a typo'd tag fails
|
|
7
|
+
* SILENTLY (the listener just ignores the message), so single-siting them is a
|
|
8
|
+
* correctness measure, not cosmetics. The values are a persisted wire contract
|
|
9
|
+
* with already-generated surface documents: never change them.
|
|
10
|
+
*/
|
|
11
|
+
/** A sandboxed surface emitting an AX interaction to the parent canvas. */
|
|
12
|
+
export declare const AX_SURFACE_EMIT_SOURCE = "pmx-canvas-ax";
|
|
13
|
+
/** The parent canvas acking an AX interaction back to the emitting surface (#55). */
|
|
14
|
+
export declare const AX_SURFACE_ACK_SOURCE = "pmx-canvas-ax-ack";
|
|
15
|
+
/** Parent→surface pushes (theme updates, live AX state) into html/viewer iframes. */
|
|
16
|
+
export declare const HTML_SURFACE_PUSH_SOURCE = "pmx-canvas-html-node";
|
|
17
|
+
/** Ext-app boot beacon: the iframe's scripts executed (WebKit watchdog liveness). */
|
|
18
|
+
export declare const EXT_APP_BOOT_BEACON_SOURCE = "pmx-canvas-ext-app-alive";
|
|
@@ -173,6 +173,11 @@ PMX Canvas follows Bun's current stable backend reality.
|
|
|
173
173
|
- required on Linux and Windows
|
|
174
174
|
- also supported on macOS
|
|
175
175
|
- preferred when backend consistency or future CDP-based tooling matters
|
|
176
|
+
- can trigger a native "Allow remote debugging?" dialog on first start in some
|
|
177
|
+
hosts — approve it promptly or the start times out with `ok:false`. Raise
|
|
178
|
+
`PMX_CANVAS_WEBVIEW_TIMEOUT_MS` (e.g. `30000`) when the prompt or a slow
|
|
179
|
+
Chrome launch is expected, and retry once before classifying a timeout as a
|
|
180
|
+
failure.
|
|
176
181
|
|
|
177
182
|
### Current default behavior
|
|
178
183
|
|
package/docs/cli.md
CHANGED
|
@@ -51,6 +51,11 @@ pmx-canvas node add --help --type webpage --json
|
|
|
51
51
|
pmx-canvas external-app add --kind excalidraw --title "Diagram"
|
|
52
52
|
|
|
53
53
|
pmx-canvas edge add --from-search "DVT O3 — GitOps" --to-search "deep work trend" --type relation
|
|
54
|
+
|
|
55
|
+
# Updates return a compact { ok, id, position, size, updatedFields } envelope;
|
|
56
|
+
# pass --full for the complete node payload (ext-app payloads can be huge).
|
|
57
|
+
pmx-canvas node update <node-id> --width 840 --height 620
|
|
58
|
+
pmx-canvas node update <node-id> --title "Renamed" --full
|
|
54
59
|
```
|
|
55
60
|
|
|
56
61
|
`--from-search` / `--to-search` must each resolve to exactly one node — broad
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Environment variables
|
|
2
|
+
|
|
3
|
+
Every `PMX_*` variable the server, CLI, MCP transport, and build read. All are
|
|
4
|
+
optional; defaults are listed.
|
|
5
|
+
|
|
6
|
+
## Ports and workspace targeting
|
|
7
|
+
|
|
8
|
+
| Variable | Read by | Effect |
|
|
9
|
+
|---|---|---|
|
|
10
|
+
| `PMX_WEB_CANVAS_PORT` | server, CLI `serve` | Preferred server port (default `4313`). CLI `--port` wins over it. |
|
|
11
|
+
| `PMX_CANVAS_PORT` | all entry points | Client-side target port for CLI commands and the `--mcp` lookup; as of 0.4.0 the server also falls back to it when `--port`/`PMX_WEB_CANVAS_PORT` are unset, so one var can drive the whole stack. |
|
|
12
|
+
| `PMX_CANVAS_URL` | agent CLI, MCP transport | Full base URL target (wins over `PMX_CANVAS_PORT`). |
|
|
13
|
+
| `PMX_CANVAS_WORKSPACE_ROOT` | server, MCP transport | Pins the workspace root for daemon binds and the MCP same-workspace lookup, overriding the launch cwd. Set it when a host spawns `--mcp` from an incidental dir. |
|
|
14
|
+
| `PMX_CANVAS_ALLOW_WORKSPACE_SPLIT` | MCP transport | `1` forces a separate canvas instead of attaching to a different-workspace daemon on the preferred port. |
|
|
15
|
+
|
|
16
|
+
## Persistence
|
|
17
|
+
|
|
18
|
+
| Variable | Read by | Effect |
|
|
19
|
+
|---|---|---|
|
|
20
|
+
| `PMX_CANVAS_DB_PATH` | server | Overrides the SQLite path (default `.pmx-canvas/canvas.db`). |
|
|
21
|
+
| `PMX_CANVAS_STATE_FILE` | server | `.db`-path alias only as of 0.4.0 (non-`.db` values are ignored with a boot warning; the pre-0.2 JSON import was removed). |
|
|
22
|
+
| `PMX_CANVAS_BLOB_THRESHOLD_BYTES` | server | Node payloads above this many JSON bytes are stored as blobs (default `2048`). |
|
|
23
|
+
|
|
24
|
+
## Server behavior
|
|
25
|
+
|
|
26
|
+
| Variable | Read by | Effect |
|
|
27
|
+
|---|---|---|
|
|
28
|
+
| `PMX_CANVAS_THEME` | server | Startup theme: `dark` (default), `light`, `high-contrast`. |
|
|
29
|
+
| `PMX_CANVAS_DISABLE_BROWSER_OPEN` | server | `1` suppresses auto-opening the browser (used by tests/CI). |
|
|
30
|
+
| `PMX_CANVAS_DIST` | server | Explicit client bundle directory to serve instead of the packaged `dist/canvas`. |
|
|
31
|
+
| `PMX_CANVAS_WEBVIEW_TIMEOUT_MS` | server | Startup timeout for the Bun.WebView automation session. |
|
|
32
|
+
|
|
33
|
+
## MCP app host (security-relevant)
|
|
34
|
+
|
|
35
|
+
| Variable | Read by | Effect |
|
|
36
|
+
|---|---|---|
|
|
37
|
+
| `PMX_MCP_APP_HOST_MODE` | server | Gates which hosted MCP app servers may be opened. |
|
|
38
|
+
| `PMX_MCP_APP_HOST_ALLOWLIST` | server | Additional allowed MCP app server origins. |
|
|
39
|
+
| `PMX_MCP_APP_HOST_STATE_FILE` | server | Overrides the app-host session state file. |
|
|
40
|
+
|
|
41
|
+
## Build and diagnostics
|
|
42
|
+
|
|
43
|
+
| Variable | Read by | Effect |
|
|
44
|
+
|---|---|---|
|
|
45
|
+
| `PMX_CANVAS_JSON_RENDER_DEVTOOLS` | server | `1` (plus `?devtools=1` on the viewer URL) enables the json-render devtools overlay. |
|
|
46
|
+
| `PMX_CANVAS_FORCE_JSON_RENDER_REBUILD` | json-render build | `1` forces the viewer bundle rebuild even when outputs exist. |
|
|
47
|
+
| `PMX_CANVAS_EXCALIDRAW_MCP_COMMAND` | server (tests) | Stdio command replacing the hosted Excalidraw MCP server for the diagram preset, e.g. `bun run tests/fixtures/mcp-app-fixture.ts`. |
|
|
48
|
+
| `PMX_SESSION_LOG` / `PMX_TEST_LOG` | server | Path for MCP-app host session diagnostics logging (session wins over test). |
|
package/docs/http-api.md
CHANGED
|
@@ -5,7 +5,9 @@ any language. Default base URL: `http://localhost:4313`.
|
|
|
5
5
|
|
|
6
6
|
A non-empty request body that is not valid JSON returns
|
|
7
7
|
`400 { "ok": false, "error": "Malformed JSON body." }` on every route; empty
|
|
8
|
-
bodies are treated as an empty request.
|
|
8
|
+
bodies are treated as an empty request. As of 0.4.0 every error response is a
|
|
9
|
+
JSON envelope of that same shape (`{ ok: false, error }`, status unchanged) —
|
|
10
|
+
no plain-text errors remain.
|
|
9
11
|
|
|
10
12
|
## Canvas state
|
|
11
13
|
|
|
@@ -321,6 +323,28 @@ curl -N http://localhost:4313/api/workbench/events
|
|
|
321
323
|
The browser, the CLI `watch` command, and the MCP resource notifications
|
|
322
324
|
all consume this stream. Auto-reconnect with exponential backoff.
|
|
323
325
|
|
|
326
|
+
## Polling transport (proxy-safe)
|
|
327
|
+
|
|
328
|
+
Some proxies (e.g. the Amp orb portal) buffer streaming responses and only
|
|
329
|
+
flush them on close, so the SSE stream above delivers nothing. The polling
|
|
330
|
+
transport returns the same events as short-lived JSON responses that pass
|
|
331
|
+
through any proxy:
|
|
332
|
+
|
|
333
|
+
```bash
|
|
334
|
+
# No `since`: a full connect snapshot (same events an SSE connect sends) + the
|
|
335
|
+
# current cursor. With `since=<seq>`: only events after that cursor.
|
|
336
|
+
curl "http://localhost:4313/api/workbench/poll"
|
|
337
|
+
curl "http://localhost:4313/api/workbench/poll?since=42"
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
Responses are `{ ok, transport: "poll", snapshot, seq, events }` — poll again
|
|
341
|
+
with `since=<seq>` every couple of seconds. A `since` from a previous server
|
|
342
|
+
run or one that fell off the bounded event ring recovers with a fresh
|
|
343
|
+
snapshot. The browser client uses this automatically: if the SSE stream
|
|
344
|
+
produces no event within 3 seconds of connecting, it switches to polling.
|
|
345
|
+
Force a transport with `/workbench?transport=poll` (or `transport=sse` to
|
|
346
|
+
disable the fallback).
|
|
347
|
+
|
|
324
348
|
## Time travel
|
|
325
349
|
|
|
326
350
|
```bash
|
package/docs/mcp.md
CHANGED
|
@@ -1,19 +1,17 @@
|
|
|
1
1
|
# MCP reference
|
|
2
2
|
|
|
3
|
-
PMX Canvas ships an MCP stdio server with **
|
|
3
|
+
PMX Canvas ships an MCP stdio server with **22 tools** + **14 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.
|
|
7
7
|
|
|
8
|
-
> **Consolidation
|
|
9
|
-
>
|
|
10
|
-
>
|
|
11
|
-
>
|
|
12
|
-
>
|
|
13
|
-
>
|
|
14
|
-
>
|
|
15
|
-
> `canvas_snapshot` composite in v0.4 (see [Standalone tools](#standalone-tools)
|
|
16
|
-
> below). **Prefer the composites.**
|
|
8
|
+
> **Consolidation complete (plan-006/008).** The MCP surface shrank from 84
|
|
9
|
+
> tools to 22: 16 action-discriminated **composites** (recommended — see
|
|
10
|
+
> below) plus 6 standalone tools. The 57 legacy single-purpose tools the
|
|
11
|
+
> composites replaced were removed in v0.3.0, and v0.4.0 finished the fold by
|
|
12
|
+
> shipping the `canvas_snapshot` composite and removing the 6 deprecated
|
|
13
|
+
> snapshot standalones — each step per [`api-stability.md`](api-stability.md)'s
|
|
14
|
+
> deprecate-one-minor-before-removal rule. **Prefer the composites.**
|
|
17
15
|
|
|
18
16
|
## Connect
|
|
19
17
|
|
|
@@ -54,6 +52,7 @@ its `action` to the same operation the legacy tool used, so results are identica
|
|
|
54
52
|
| `canvas_ax_timeline` | `read` · `record-event` · `add-evidence` · `send-steering` | `canvas_get_ax_timeline`, `canvas_record_ax_event`, `canvas_add_evidence`, `canvas_send_steering` |
|
|
55
53
|
| `canvas_ax_delivery` | `claim` · `mark` | `canvas_claim_ax_delivery`, `canvas_mark_ax_delivery` |
|
|
56
54
|
| `canvas_intent` | `signal` · `update` · `clear` | _(new — Ghost Cursor of Intent; no legacy standalone tool)_ |
|
|
55
|
+
| `canvas_snapshot` | `save` · `list` · `restore` · `delete` · `gc` · `diff` | `canvas_snapshot` (legacy save tool), `canvas_list_snapshots`, `canvas_restore`, `canvas_delete_snapshot`, `canvas_gc_snapshots`, `canvas_diff` — removed in v0.4.0 after one deprecated minor |
|
|
57
56
|
|
|
58
57
|
### `canvas_intent` — Ghost Cursor of Intent
|
|
59
58
|
|
|
@@ -89,20 +88,16 @@ tools). `canvas_screenshot` also stays standalone — it returns a binary image
|
|
|
89
88
|
the composite/registry JSON wire shape does not model. (Wave 5 folded
|
|
90
89
|
`canvas_refresh_webpage_node` → `canvas_node { action: "update", refresh: true }` after
|
|
91
90
|
fixing `node.update`'s `formatResult` to surface a FAILED refresh as `isError` +
|
|
92
|
-
`{ ok:false, error }` instead of masking it as a false `{ ok:true }`.) The
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
tool, and [`api-stability.md`](api-stability.md) requires deprecating a tool
|
|
96
|
-
for one minor before removing it) — they stay registered as deprecated
|
|
97
|
-
standalones until then.
|
|
91
|
+
`{ ok:false, error }` instead of masking it as a false `{ ok:true }`.) The snapshot
|
|
92
|
+
fold completed in v0.4.0: `canvas_snapshot { action: "save" | "list" | "restore" |
|
|
93
|
+
"delete" | "gc" | "diff" }` replaced the 6 deprecated snapshot standalones.
|
|
98
94
|
|
|
99
95
|
## Standalone tools
|
|
100
96
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
57 tools these composites replaced.
|
|
97
|
+
6 tools that intentionally stay outside the composites — folding them would
|
|
98
|
+
hurt (distinct callers, binary payloads, trust-boundary or execution-intent
|
|
99
|
+
semantics). See [Migration reference](#migration-reference) below for the
|
|
100
|
+
legacy tools the composites replaced.
|
|
106
101
|
|
|
107
102
|
| Tool | Description |
|
|
108
103
|
|------|-------------|
|
|
@@ -112,12 +107,6 @@ v0.4 composite. See [Migration reference](#migration-reference) below for the
|
|
|
112
107
|
| `canvas_ax_interaction` | Submit one capability-gated AX interaction envelope (`{ type, sourceNodeId, payload }`) that maps onto an AX operation; the server re-validates and clamps sandboxed surfaces to their own node |
|
|
113
108
|
| `canvas_ingest_activity` | Ingest a harness-forwarded agent activity (tool/session event); the board auto-reacts with kind-driven, overridable defaults (failure → work item + review + evidence; `tool-result`+success → evidence). Makes AX bidirectional |
|
|
114
109
|
| `canvas_screenshot` | Capture a screenshot from the active workbench automation session |
|
|
115
|
-
| `canvas_snapshot` | **Deprecated** → folds into the `canvas_snapshot` composite in v0.4 (actions `save\|list\|restore\|delete\|gc\|diff`). Save current canvas as a named snapshot |
|
|
116
|
-
| `canvas_list_snapshots` | **Deprecated** → folds into the `canvas_snapshot` composite in v0.4 (actions `save\|list\|restore\|delete\|gc\|diff`). List saved snapshots, bounded to the newest 20 by default |
|
|
117
|
-
| `canvas_restore` | **Deprecated** → folds into the `canvas_snapshot` composite in v0.4 (actions `save\|list\|restore\|delete\|gc\|diff`). Restore canvas from a saved snapshot |
|
|
118
|
-
| `canvas_delete_snapshot` | **Deprecated** → folds into the `canvas_snapshot` composite in v0.4 (actions `save\|list\|restore\|delete\|gc\|diff`). Delete a saved snapshot |
|
|
119
|
-
| `canvas_gc_snapshots` | **Deprecated** → folds into the `canvas_snapshot` composite in v0.4 (actions `save\|list\|restore\|delete\|gc\|diff`). Delete old snapshots while keeping the newest N |
|
|
120
|
-
| `canvas_diff` | **Deprecated** → folds into the `canvas_snapshot` composite in v0.4 (actions `save\|list\|restore\|delete\|gc\|diff`). Compare current canvas vs a saved snapshot |
|
|
121
110
|
|
|
122
111
|
`canvas_node { action: "add", type: "html" }` accepts optional `summary`, `agentSummary`,
|
|
123
112
|
`embeddedNodeIds`, and `embeddedUrls`. PMX also derives a bounded text summary from visible
|
|
@@ -125,7 +114,9 @@ HTML, so rich HTML nodes stay searchable and readable in pinned/spatial context.
|
|
|
125
114
|
|
|
126
115
|
## Migration reference
|
|
127
116
|
|
|
128
|
-
The 57 legacy single-purpose tools below were removed in v0.3.0
|
|
117
|
+
The 57 legacy single-purpose tools below were removed in v0.3.0, and v0.4.0
|
|
118
|
+
additionally removed the 6 deprecated snapshot standalones (see the
|
|
119
|
+
`canvas_snapshot` composite row above for their replacements). Each row is
|
|
129
120
|
the composite call that replaces it — kept as a lookup table for anyone
|
|
130
121
|
migrating an older integration.
|
|
131
122
|
|
|
@@ -304,5 +295,5 @@ CLI and MCP are kept aligned for the main canvas operations: node and edge
|
|
|
304
295
|
creation, graph/json-render/html/html-primitive nodes, web artifacts, external apps, groups,
|
|
305
296
|
batch builds, layout validation, snapshots, search, focus, pins, undo/redo,
|
|
306
297
|
semantic watch streams, WebView automation, and daemon/server control where
|
|
307
|
-
it applies. A few agent-native capabilities —
|
|
308
|
-
|
|
298
|
+
it applies. A few agent-native capabilities — such as resource
|
|
299
|
+
subscriptions — remain MCP-only.
|