pmx-canvas 0.3.0 → 0.3.2
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 +73 -0
- package/dist/canvas/index.js +65 -65
- package/dist/types/cli/agent.d.ts +9 -1
- package/dist/types/cli/daemon.d.ts +74 -0
- package/dist/types/cli/watch.d.ts +2 -2
- package/dist/types/client/canvas/CanvasViewport.d.ts +1 -1
- package/dist/types/client/canvas/CommandPalette.d.ts +1 -1
- package/dist/types/client/canvas/Minimap.d.ts +1 -1
- package/dist/types/client/nodes/ExtAppFrame.d.ts +9 -1
- package/dist/types/client/nodes/FileNode.d.ts +1 -1
- package/dist/types/client/nodes/ImageNode.d.ts +1 -1
- package/dist/types/client/nodes/InlineFormatBar.d.ts +1 -1
- package/dist/types/client/nodes/MarkdownNode.d.ts +1 -1
- package/dist/types/client/nodes/PromptNode.d.ts +1 -1
- package/dist/types/client/nodes/ResponseNode.d.ts +1 -1
- package/dist/types/server/canvas-schema.d.ts +1 -1
- package/dist/types/server/html-primitives.d.ts +1 -1
- package/dist/types/server/index.d.ts +4 -4
- package/dist/types/server/operations/index.d.ts +1 -1
- package/dist/types/server/operations/ops/ax-read.d.ts +2 -0
- package/dist/types/server/operations/ops/canvas-wire.d.ts +2 -0
- package/dist/types/server/operations/ops/ext-app.d.ts +2 -0
- package/dist/types/server/server.d.ts +8 -0
- package/docs/cli.md +10 -1
- package/docs/http-api.md +28 -0
- package/docs/plans/plan-009-tech-debt-backlog.md +5 -5
- package/docs/screenshot.png +0 -0
- package/docs/tech-debt-assessment-2026-07.md +2 -2
- package/package.json +5 -2
- package/skills/pmx-canvas/SKILL.md +15 -10
- package/skills/pmx-canvas/references/full-reference.md +17 -3
- package/src/cli/agent.ts +1951 -1571
- package/src/cli/daemon.ts +460 -0
- package/src/cli/index.ts +80 -323
- package/src/cli/watch.ts +2 -10
- package/src/client/App.tsx +48 -46
- package/src/client/canvas/AttentionHistory.tsx +11 -1
- package/src/client/canvas/CanvasNode.tsx +41 -29
- package/src/client/canvas/CanvasViewport.tsx +101 -66
- package/src/client/canvas/CommandPalette.tsx +61 -27
- package/src/client/canvas/ContextMenu.tsx +13 -20
- package/src/client/canvas/ContextPinBar.tsx +1 -5
- package/src/client/canvas/ContextPinHud.tsx +1 -6
- package/src/client/canvas/DockedNode.tsx +4 -4
- package/src/client/canvas/EdgeLayer.tsx +37 -36
- package/src/client/canvas/ExpandedNodeOverlay.tsx +69 -45
- package/src/client/canvas/FocusFieldLayer.tsx +20 -22
- package/src/client/canvas/IntentLayer.tsx +31 -14
- package/src/client/canvas/Minimap.tsx +11 -16
- package/src/client/canvas/SelectionBar.tsx +4 -11
- package/src/client/canvas/ShortcutOverlay.tsx +3 -1
- package/src/client/canvas/SnapshotPanel.tsx +77 -95
- package/src/client/canvas/auto-fit.ts +15 -14
- package/src/client/canvas/snap-guides.ts +12 -12
- package/src/client/canvas/use-node-resize.ts +1 -5
- package/src/client/canvas/use-pan-zoom.ts +25 -26
- package/src/client/ext-app/bridge.ts +3 -12
- package/src/client/icons.tsx +63 -20
- package/src/client/nodes/ContextNode.tsx +14 -25
- package/src/client/nodes/ExtAppFrame.tsx +194 -80
- package/src/client/nodes/FileNode.tsx +74 -62
- package/src/client/nodes/GroupNode.tsx +4 -6
- package/src/client/nodes/HtmlNode.tsx +76 -46
- package/src/client/nodes/ImageNode.tsx +18 -27
- package/src/client/nodes/InlineFormatBar.tsx +4 -21
- package/src/client/nodes/InlineMarkdownEditor.tsx +0 -1
- package/src/client/nodes/LedgerNode.tsx +10 -4
- package/src/client/nodes/MarkdownNode.tsx +3 -10
- package/src/client/nodes/McpAppNode.tsx +26 -22
- package/src/client/nodes/MdFormatBar.tsx +10 -7
- package/src/client/nodes/PromptNode.tsx +23 -51
- package/src/client/nodes/ResponseNode.tsx +3 -13
- package/src/client/nodes/StatusNode.tsx +5 -9
- package/src/client/nodes/StatusSummary.tsx +2 -8
- package/src/client/nodes/WebpageNode.tsx +20 -14
- package/src/client/nodes/iframe-document-url.ts +25 -16
- package/src/client/nodes/image-warnings.ts +1 -7
- package/src/client/nodes/md-format.ts +20 -5
- package/src/client/state/attention-bridge.ts +4 -9
- package/src/client/state/attention-store.ts +1 -7
- package/src/client/state/canvas-store.ts +52 -36
- package/src/client/state/intent-bridge.ts +176 -112
- package/src/client/state/intent-store.ts +4 -1
- package/src/client/state/sse-bridge.ts +53 -70
- package/src/json-render/catalog.ts +12 -16
- package/src/json-render/charts/components.tsx +16 -20
- package/src/json-render/charts/extra-components.tsx +8 -16
- package/src/json-render/charts/extra-definitions.ts +1 -2
- package/src/json-render/charts/tufte-components.tsx +37 -20
- package/src/json-render/charts/tufte-definitions.ts +8 -2
- package/src/json-render/renderer/index.tsx +42 -22
- package/src/json-render/schema.ts +6 -3
- package/src/json-render/server.ts +33 -39
- package/src/mcp/canvas-access.ts +35 -21
- package/src/mcp/server.ts +132 -70
- package/src/server/agent-context.ts +63 -36
- package/src/server/ax-context.ts +7 -5
- package/src/server/ax-interaction.ts +176 -43
- package/src/server/ax-state-manager.ts +182 -39
- package/src/server/ax-state.ts +142 -47
- package/src/server/canvas-db.ts +213 -95
- package/src/server/canvas-operations.ts +180 -123
- package/src/server/canvas-provenance.ts +1 -4
- package/src/server/canvas-schema.ts +454 -73
- package/src/server/canvas-serialization.ts +27 -35
- package/src/server/canvas-state.ts +150 -58
- package/src/server/chart-template.ts +4 -5
- package/src/server/code-graph.ts +19 -6
- package/src/server/diagram-presets.ts +28 -29
- package/src/server/ext-app-lookup.ts +3 -12
- package/src/server/html-node-summary.ts +19 -10
- package/src/server/html-primitives.ts +326 -97
- package/src/server/html-surface.ts +6 -9
- package/src/server/image-source.ts +6 -4
- package/src/server/index.ts +320 -217
- package/src/server/intent-registry.ts +2 -5
- package/src/server/mcp-app-candidate.ts +5 -10
- package/src/server/mcp-app-host.ts +14 -38
- package/src/server/mcp-app-runtime.ts +12 -20
- package/src/server/mutation-history.ts +15 -5
- package/src/server/operations/composites.ts +1 -3
- package/src/server/operations/http.ts +2 -3
- package/src/server/operations/index.ts +7 -1
- package/src/server/operations/invoker.ts +4 -3
- package/src/server/operations/mcp.ts +22 -30
- package/src/server/operations/ops/annotation.ts +122 -10
- package/src/server/operations/ops/app.ts +98 -73
- package/src/server/operations/ops/ax-await.ts +17 -10
- package/src/server/operations/ops/ax-read.ts +347 -0
- package/src/server/operations/ops/ax-shared.ts +2 -7
- package/src/server/operations/ops/ax-state.ts +32 -14
- package/src/server/operations/ops/ax-timeline.ts +32 -19
- package/src/server/operations/ops/ax-work.ts +54 -37
- package/src/server/operations/ops/batch.ts +41 -15
- package/src/server/operations/ops/canvas-wire.ts +91 -0
- package/src/server/operations/ops/edges.ts +37 -25
- package/src/server/operations/ops/ext-app.ts +346 -0
- package/src/server/operations/ops/groups.ts +49 -20
- package/src/server/operations/ops/intent.ts +18 -12
- package/src/server/operations/ops/json-render.ts +239 -98
- package/src/server/operations/ops/nodes.ts +298 -109
- package/src/server/operations/ops/query.ts +46 -28
- package/src/server/operations/ops/snapshots.ts +35 -26
- package/src/server/operations/ops/validate.ts +2 -1
- package/src/server/operations/ops/viewport.ts +60 -16
- package/src/server/operations/ops/webview.ts +44 -18
- package/src/server/operations/registry.ts +2 -3
- package/src/server/operations/types.ts +7 -5
- package/src/server/operations/webview-runner.ts +1 -3
- package/src/server/placement.ts +8 -18
- package/src/server/server.ts +122 -1028
- package/src/server/spatial-analysis.ts +39 -25
- package/src/server/trace-manager.ts +3 -8
- package/src/server/web-artifacts.ts +23 -27
- package/src/server/webpage-node.ts +5 -13
- package/src/shared/auto-arrange.ts +12 -5
- package/src/shared/content-height-reporter.ts +8 -6
- package/src/shared/ext-app-tool-result.ts +2 -6
- package/src/shared/placement.ts +1 -4
- package/src/shared/semantic-attention.ts +39 -37
- package/src/shared/surface.ts +8 -4
package/src/server/index.ts
CHANGED
|
@@ -69,28 +69,24 @@ import {
|
|
|
69
69
|
setGroupChildrenFromApi,
|
|
70
70
|
} from './operations/ops/nodes.js';
|
|
71
71
|
import { streamJsonRenderCore } from './operations/ops/json-render.js';
|
|
72
|
-
import {
|
|
73
|
-
executeOperation,
|
|
74
|
-
runCanvasBatchOperation,
|
|
75
|
-
type OpenMcpAppCoreResult,
|
|
76
|
-
} from './operations/index.js';
|
|
72
|
+
import { executeOperation, runCanvasBatchOperation, type OpenMcpAppCoreResult } from './operations/index.js';
|
|
77
73
|
import { validateCanvasLayout } from './canvas-validation.js';
|
|
78
74
|
import { describeCanvasSchema, validateStructuredCanvasPayload } from './canvas-schema.js';
|
|
79
75
|
import { serializeCanvasNode, type SerializedCanvasNode } from './canvas-serialization.js';
|
|
80
|
-
import {
|
|
76
|
+
import {
|
|
77
|
+
buildHtmlPrimitive,
|
|
78
|
+
getHtmlPrimitiveSemanticMetadata,
|
|
79
|
+
isHtmlPrimitiveKind,
|
|
80
|
+
listHtmlPrimitiveDescriptors,
|
|
81
|
+
} from './html-primitives.js';
|
|
81
82
|
import type { HtmlPrimitiveKind } from './html-primitives.js';
|
|
82
83
|
import {
|
|
83
84
|
buildWebArtifactOnCanvas,
|
|
84
85
|
type WebArtifactBuildInput,
|
|
85
86
|
type WebArtifactCanvasBuildResult,
|
|
86
87
|
} from './web-artifacts.js';
|
|
87
|
-
import {
|
|
88
|
-
|
|
89
|
-
type ExternalMcpTransportConfig,
|
|
90
|
-
} from './mcp-app-runtime.js';
|
|
91
|
-
import {
|
|
92
|
-
type DiagramPresetOpenInput,
|
|
93
|
-
} from './diagram-presets.js';
|
|
88
|
+
import { closeMcpAppSession, type ExternalMcpTransportConfig } from './mcp-app-runtime.js';
|
|
89
|
+
import type { DiagramPresetOpenInput } from './diagram-presets.js';
|
|
94
90
|
import {
|
|
95
91
|
buildGraphSpec,
|
|
96
92
|
GRAPH_NODE_SIZE,
|
|
@@ -256,39 +252,44 @@ export class PmxCanvas extends EventEmitter {
|
|
|
256
252
|
height?: number;
|
|
257
253
|
strictSize?: boolean;
|
|
258
254
|
}): SdkCanvasNode {
|
|
259
|
-
return this.runIntentCommit(
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
255
|
+
return this.runIntentCommit(
|
|
256
|
+
input.intentId,
|
|
257
|
+
['create'],
|
|
258
|
+
() => {
|
|
259
|
+
if (input.type === 'webpage') {
|
|
260
|
+
throw new Error('Use addWebpageNode for webpage nodes so page content is fetched and cached on the server.');
|
|
261
|
+
}
|
|
262
|
+
if (input.type === 'group') {
|
|
263
|
+
const groupId = this.createGroup({
|
|
264
|
+
...(typeof input.title === 'string' ? { title: input.title } : {}),
|
|
265
|
+
childIds: input.childIds ?? input.children ?? [],
|
|
266
|
+
...(typeof input.x === 'number' ? { x: input.x } : {}),
|
|
267
|
+
...(typeof input.y === 'number' ? { y: input.y } : {}),
|
|
268
|
+
...(typeof input.width === 'number' ? { width: input.width } : {}),
|
|
269
|
+
...(typeof input.height === 'number' ? { height: input.height } : {}),
|
|
270
|
+
...(typeof input.color === 'string' ? { color: input.color } : {}),
|
|
271
|
+
...(input.childLayout ? { childLayout: input.childLayout } : {}),
|
|
272
|
+
});
|
|
273
|
+
const groupNode = canvasState.getNode(groupId);
|
|
274
|
+
if (!groupNode) throw new Error(`Group node "${groupId}" was not created.`);
|
|
275
|
+
return toSdkNode(groupNode);
|
|
276
|
+
}
|
|
277
|
+
// Thin wrapper over the shared operation core (plan-005); the SDK keeps
|
|
278
|
+
// fileMode 'path' as an explicit visible parameter instead of forked code.
|
|
279
|
+
const { node, needsCodeGraphRecompute } = createBasicCanvasNode(input, { fileMode: 'path' });
|
|
281
280
|
|
|
282
|
-
|
|
281
|
+
emitPrimaryWorkbenchEvent('canvas-layout-update', { layout: canvasState.getLayout() });
|
|
283
282
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
283
|
+
if (needsCodeGraphRecompute) {
|
|
284
|
+
scheduleCodeGraphRecompute(() => {
|
|
285
|
+
emitPrimaryWorkbenchEvent('canvas-layout-update', { layout: canvasState.getLayout() });
|
|
286
|
+
});
|
|
287
|
+
}
|
|
289
288
|
|
|
290
|
-
|
|
291
|
-
|
|
289
|
+
return toSdkNode(node);
|
|
290
|
+
},
|
|
291
|
+
(node) => node.id,
|
|
292
|
+
);
|
|
292
293
|
}
|
|
293
294
|
|
|
294
295
|
async addWebpageNode(input: {
|
|
@@ -320,9 +321,7 @@ export class PmxCanvas extends EventEmitter {
|
|
|
320
321
|
return {
|
|
321
322
|
ok: true,
|
|
322
323
|
id,
|
|
323
|
-
fetch: result.ok
|
|
324
|
-
? { ok: true }
|
|
325
|
-
: { ok: false, error: result.error ?? 'Failed to fetch webpage content.' },
|
|
324
|
+
fetch: result.ok ? { ok: true } : { ok: false, error: result.error ?? 'Failed to fetch webpage content.' },
|
|
326
325
|
...(result.ok ? {} : { error: result.error }),
|
|
327
326
|
};
|
|
328
327
|
};
|
|
@@ -338,34 +337,44 @@ export class PmxCanvas extends EventEmitter {
|
|
|
338
337
|
|
|
339
338
|
updateNode(id: string, patch: Partial<CanvasNodeState> & Record<string, unknown>): void {
|
|
340
339
|
const intentId = typeof patch.intentId === 'string' ? patch.intentId : undefined;
|
|
341
|
-
this.runIntentCommit(
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
340
|
+
this.runIntentCommit(
|
|
341
|
+
intentId,
|
|
342
|
+
['move', 'edit'],
|
|
343
|
+
() => {
|
|
344
|
+
const existing = canvasState.getNode(id);
|
|
345
|
+
if (!existing) {
|
|
346
|
+
if (intentId !== undefined) throw new Error(`Node "${id}" not found.`);
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
// Thin wrapper over the shared patch core (plan-005): the SDK now carries
|
|
350
|
+
// the same superset semantics as HTTP/MCP (webpage titleSource/url, html
|
|
351
|
+
// top-level fields, axCapabilities merge, group children).
|
|
352
|
+
const { patch: resolvedPatch, groupChildIds } = buildNodePatch(existing, patch);
|
|
353
|
+
canvasState.updateNode(id, resolvedPatch);
|
|
354
|
+
if (groupChildIds !== undefined) setGroupChildrenFromApi(id, groupChildIds);
|
|
355
|
+
emitPrimaryWorkbenchEvent('canvas-layout-update', { layout: canvasState.getLayout() });
|
|
356
|
+
},
|
|
357
|
+
() => id,
|
|
358
|
+
);
|
|
355
359
|
}
|
|
356
360
|
|
|
357
361
|
/** Remove a node. Missing id throws (plan-005 unifies this across surfaces). */
|
|
358
362
|
removeNode(id: string, options?: { intentId?: string }): void {
|
|
359
|
-
this.runIntentCommit(
|
|
360
|
-
|
|
361
|
-
|
|
363
|
+
this.runIntentCommit(
|
|
364
|
+
options?.intentId,
|
|
365
|
+
['remove'],
|
|
366
|
+
() => {
|
|
367
|
+
const { needsCodeGraphRecompute } = removeNodeCore(id);
|
|
368
|
+
emitPrimaryWorkbenchEvent('canvas-layout-update', { layout: canvasState.getLayout() });
|
|
362
369
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
370
|
+
if (needsCodeGraphRecompute) {
|
|
371
|
+
scheduleCodeGraphRecompute(() => {
|
|
372
|
+
emitPrimaryWorkbenchEvent('canvas-layout-update', { layout: canvasState.getLayout() });
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
},
|
|
376
|
+
() => undefined,
|
|
377
|
+
);
|
|
369
378
|
}
|
|
370
379
|
|
|
371
380
|
addEdge(input: {
|
|
@@ -379,11 +388,16 @@ export class PmxCanvas extends EventEmitter {
|
|
|
379
388
|
style?: CanvasEdge['style'];
|
|
380
389
|
animated?: boolean;
|
|
381
390
|
}): string {
|
|
382
|
-
return this.runIntentCommit(
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
391
|
+
return this.runIntentCommit(
|
|
392
|
+
input.intentId,
|
|
393
|
+
['connect'],
|
|
394
|
+
() => {
|
|
395
|
+
const { id } = addCanvasEdge(input);
|
|
396
|
+
emitPrimaryWorkbenchEvent('canvas-layout-update', { layout: canvasState.getLayout() });
|
|
397
|
+
return id;
|
|
398
|
+
},
|
|
399
|
+
() => undefined,
|
|
400
|
+
);
|
|
387
401
|
}
|
|
388
402
|
|
|
389
403
|
addAnnotation(input: Omit<CanvasAnnotation, 'id' | 'createdAt'> & { id?: string; createdAt?: string }): string {
|
|
@@ -423,39 +437,58 @@ export class PmxCanvas extends EventEmitter {
|
|
|
423
437
|
color?: string;
|
|
424
438
|
childLayout?: 'grid' | 'column' | 'flow';
|
|
425
439
|
}): string {
|
|
426
|
-
return this.runIntentCommit(
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
440
|
+
return this.runIntentCommit(
|
|
441
|
+
input.intentId,
|
|
442
|
+
['create'],
|
|
443
|
+
() => {
|
|
444
|
+
const { id } = createCanvasGroup(input);
|
|
445
|
+
emitPrimaryWorkbenchEvent('canvas-layout-update', { layout: canvasState.getLayout() });
|
|
446
|
+
return id;
|
|
447
|
+
},
|
|
448
|
+
(id) => id,
|
|
449
|
+
);
|
|
431
450
|
}
|
|
432
451
|
|
|
433
452
|
/** Add nodes to an existing group. */
|
|
434
|
-
groupNodes(
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
453
|
+
groupNodes(
|
|
454
|
+
groupId: string,
|
|
455
|
+
childIds: string[],
|
|
456
|
+
options?: { childLayout?: 'grid' | 'column' | 'flow'; intentId?: string },
|
|
457
|
+
): boolean {
|
|
458
|
+
return this.runIntentCommit(
|
|
459
|
+
options?.intentId,
|
|
460
|
+
['edit'],
|
|
461
|
+
() => {
|
|
462
|
+
const { ok } = groupCanvasNodes(groupId, childIds, options);
|
|
463
|
+
if (!ok && options?.intentId !== undefined) {
|
|
464
|
+
throw new Error(`Group "${groupId}" could not be updated.`);
|
|
465
|
+
}
|
|
466
|
+
if (ok) {
|
|
467
|
+
emitPrimaryWorkbenchEvent('canvas-layout-update', { layout: canvasState.getLayout() });
|
|
468
|
+
}
|
|
469
|
+
return ok;
|
|
470
|
+
},
|
|
471
|
+
() => groupId,
|
|
472
|
+
);
|
|
445
473
|
}
|
|
446
474
|
|
|
447
475
|
/** Remove all children from a group (the group node remains). */
|
|
448
476
|
ungroupNodes(groupId: string, options?: { intentId?: string }): boolean {
|
|
449
|
-
return this.runIntentCommit(
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
477
|
+
return this.runIntentCommit(
|
|
478
|
+
options?.intentId,
|
|
479
|
+
['edit'],
|
|
480
|
+
() => {
|
|
481
|
+
const { ok } = ungroupCanvasNodes(groupId);
|
|
482
|
+
if (!ok && options?.intentId !== undefined) {
|
|
483
|
+
throw new Error(`Group "${groupId}" could not be updated.`);
|
|
484
|
+
}
|
|
485
|
+
if (ok) {
|
|
486
|
+
emitPrimaryWorkbenchEvent('canvas-layout-update', { layout: canvasState.getLayout() });
|
|
487
|
+
}
|
|
488
|
+
return ok;
|
|
489
|
+
},
|
|
490
|
+
() => groupId,
|
|
491
|
+
);
|
|
459
492
|
}
|
|
460
493
|
|
|
461
494
|
clear(): void {
|
|
@@ -508,7 +541,13 @@ export class PmxCanvas extends EventEmitter {
|
|
|
508
541
|
}
|
|
509
542
|
|
|
510
543
|
recordAxEvent(
|
|
511
|
-
input: {
|
|
544
|
+
input: {
|
|
545
|
+
kind: PmxAxEvent['kind'];
|
|
546
|
+
summary: string;
|
|
547
|
+
detail?: string | null;
|
|
548
|
+
nodeIds?: string[];
|
|
549
|
+
data?: Record<string, unknown> | null;
|
|
550
|
+
},
|
|
512
551
|
options?: { source?: PmxAxSource },
|
|
513
552
|
): PmxAxEvent {
|
|
514
553
|
const event = canvasState.recordAxEvent(input, { source: options?.source ?? 'sdk' });
|
|
@@ -616,7 +655,14 @@ export class PmxCanvas extends EventEmitter {
|
|
|
616
655
|
}
|
|
617
656
|
|
|
618
657
|
addEvidence(
|
|
619
|
-
input: {
|
|
658
|
+
input: {
|
|
659
|
+
kind: PmxAxEvidenceKind;
|
|
660
|
+
title: string;
|
|
661
|
+
body?: string | null;
|
|
662
|
+
ref?: string | null;
|
|
663
|
+
nodeIds?: string[];
|
|
664
|
+
data?: Record<string, unknown> | null;
|
|
665
|
+
},
|
|
620
666
|
options?: { source?: PmxAxSource },
|
|
621
667
|
): PmxAxEvidence {
|
|
622
668
|
const evidence = canvasState.addEvidence(input, { source: options?.source ?? 'sdk' });
|
|
@@ -708,7 +754,10 @@ export class PmxCanvas extends EventEmitter {
|
|
|
708
754
|
decision: 'approved' | 'rejected',
|
|
709
755
|
options?: { resolution?: string; source?: PmxAxSource },
|
|
710
756
|
): PmxAxModeRequest | null {
|
|
711
|
-
const modeRequest = canvasState.resolveModeRequest(id, decision, {
|
|
757
|
+
const modeRequest = canvasState.resolveModeRequest(id, decision, {
|
|
758
|
+
...(options ?? {}),
|
|
759
|
+
source: options?.source ?? 'sdk',
|
|
760
|
+
});
|
|
712
761
|
if (modeRequest) emitPrimaryWorkbenchEvent('ax-state-changed', { modeRequest });
|
|
713
762
|
return modeRequest;
|
|
714
763
|
}
|
|
@@ -726,11 +775,23 @@ export class PmxCanvas extends EventEmitter {
|
|
|
726
775
|
reactions?: {
|
|
727
776
|
workItem?: false | { status?: PmxAxWorkItemStatus; detail?: string | null };
|
|
728
777
|
evidence?: false | { kind?: PmxAxEvidenceKind; body?: string | null };
|
|
729
|
-
review?:
|
|
778
|
+
review?:
|
|
779
|
+
| false
|
|
780
|
+
| {
|
|
781
|
+
severity?: PmxAxReviewSeverity;
|
|
782
|
+
kind?: PmxAxReviewKind;
|
|
783
|
+
anchorType?: PmxAxReviewAnchorType;
|
|
784
|
+
nodeId?: string | null;
|
|
785
|
+
};
|
|
730
786
|
};
|
|
731
787
|
},
|
|
732
788
|
options?: { source?: PmxAxSource },
|
|
733
|
-
): {
|
|
789
|
+
): {
|
|
790
|
+
event: PmxAxEvent;
|
|
791
|
+
workItem: PmxAxWorkItem | null;
|
|
792
|
+
evidence: PmxAxEvidence | null;
|
|
793
|
+
review: PmxAxReviewAnnotation | null;
|
|
794
|
+
} {
|
|
734
795
|
const result = canvasState.ingestActivity(input, { source: options?.source ?? 'sdk' });
|
|
735
796
|
emitPrimaryWorkbenchEvent('ax-event-created', { event: result.event });
|
|
736
797
|
if (result.workItem) emitPrimaryWorkbenchEvent('ax-state-changed', { workItem: result.workItem });
|
|
@@ -795,7 +856,11 @@ export class PmxCanvas extends EventEmitter {
|
|
|
795
856
|
return canvasState.getCommandRegistry();
|
|
796
857
|
}
|
|
797
858
|
|
|
798
|
-
invokeCommand(
|
|
859
|
+
invokeCommand(
|
|
860
|
+
name: string,
|
|
861
|
+
args?: Record<string, unknown> | null,
|
|
862
|
+
options?: { source?: PmxAxSource },
|
|
863
|
+
): PmxAxEvent | null {
|
|
799
864
|
const event = canvasState.invokeCommand(name, args ?? null, { source: options?.source ?? 'sdk' });
|
|
800
865
|
if (event) emitPrimaryWorkbenchEvent('ax-event-created', { event });
|
|
801
866
|
return event;
|
|
@@ -873,13 +938,15 @@ export class PmxCanvas extends EventEmitter {
|
|
|
873
938
|
};
|
|
874
939
|
}
|
|
875
940
|
|
|
876
|
-
applyUpdates(
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
941
|
+
applyUpdates(
|
|
942
|
+
updates: Array<{
|
|
943
|
+
id: string;
|
|
944
|
+
position?: { x: number; y: number };
|
|
945
|
+
size?: { width: number; height: number };
|
|
946
|
+
collapsed?: boolean;
|
|
947
|
+
dockPosition?: 'left' | 'right' | null;
|
|
948
|
+
}>,
|
|
949
|
+
): { applied: number; skipped: number } {
|
|
883
950
|
return applyCanvasNodeUpdates(updates);
|
|
884
951
|
}
|
|
885
952
|
|
|
@@ -913,7 +980,12 @@ export class PmxCanvas extends EventEmitter {
|
|
|
913
980
|
return gcCanvasSnapshots(options);
|
|
914
981
|
}
|
|
915
982
|
|
|
916
|
-
diffSnapshot(idOrName: string): {
|
|
983
|
+
diffSnapshot(idOrName: string): {
|
|
984
|
+
ok: boolean;
|
|
985
|
+
text?: string;
|
|
986
|
+
diff?: ReturnType<typeof diffLayouts>;
|
|
987
|
+
error?: string;
|
|
988
|
+
} {
|
|
917
989
|
const snapData = canvasState.getSnapshotData(idOrName);
|
|
918
990
|
if (!snapData) return { ok: false, error: `Snapshot "${idOrName}" not found` };
|
|
919
991
|
|
|
@@ -935,11 +1007,7 @@ export class PmxCanvas extends EventEmitter {
|
|
|
935
1007
|
return describeCanvasSchema();
|
|
936
1008
|
}
|
|
937
1009
|
|
|
938
|
-
validateSpec(input: {
|
|
939
|
-
type: 'json-render' | 'graph';
|
|
940
|
-
spec?: unknown;
|
|
941
|
-
graph?: GraphNodeInput;
|
|
942
|
-
}) {
|
|
1010
|
+
validateSpec(input: { type: 'json-render' | 'graph'; spec?: unknown; graph?: GraphNodeInput }) {
|
|
943
1011
|
return validateStructuredCanvasPayload(input);
|
|
944
1012
|
}
|
|
945
1013
|
|
|
@@ -981,25 +1049,30 @@ export class PmxCanvas extends EventEmitter {
|
|
|
981
1049
|
// close, ext-app-open + ext-app-result via ctx.emit → the registry emitter
|
|
982
1050
|
// wired to emitPrimaryWorkbenchEvent). mutates:false, so the registry adds no
|
|
983
1051
|
// canvas-layout-update; the two ext-app-* frames fire exactly once.
|
|
984
|
-
return await executeOperation('mcpapp.open', input) as OpenMcpAppCoreResult;
|
|
1052
|
+
return (await executeOperation('mcpapp.open', input)) as OpenMcpAppCoreResult;
|
|
985
1053
|
}
|
|
986
1054
|
|
|
987
|
-
async addDiagram(
|
|
988
|
-
input: DiagramPresetOpenInput,
|
|
989
|
-
): Promise<OpenMcpAppCoreResult> {
|
|
1055
|
+
async addDiagram(input: DiagramPresetOpenInput): Promise<OpenMcpAppCoreResult> {
|
|
990
1056
|
// Delegate to the diagram.open registry op, which builds the Excalidraw
|
|
991
1057
|
// OpenMcpApp input and dispatches to the shared open core (one ext-app-* pair).
|
|
992
|
-
return await executeOperation('diagram.open', input) as OpenMcpAppCoreResult;
|
|
1058
|
+
return (await executeOperation('diagram.open', input)) as OpenMcpAppCoreResult;
|
|
993
1059
|
}
|
|
994
1060
|
|
|
995
|
-
addJsonRenderNode(
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1061
|
+
addJsonRenderNode(input: JsonRenderNodeInput & { intentId?: string }): {
|
|
1062
|
+
id: string;
|
|
1063
|
+
url: string;
|
|
1064
|
+
spec: JsonRenderSpec;
|
|
1065
|
+
} {
|
|
1066
|
+
return this.runIntentCommit(
|
|
1067
|
+
input.intentId,
|
|
1068
|
+
['create'],
|
|
1069
|
+
() => {
|
|
1070
|
+
const result = createCanvasJsonRenderNode(input);
|
|
1071
|
+
emitPrimaryWorkbenchEvent('canvas-layout-update', { layout: canvasState.getLayout() });
|
|
1072
|
+
return result;
|
|
1073
|
+
},
|
|
1074
|
+
(result) => result.id,
|
|
1075
|
+
);
|
|
1003
1076
|
}
|
|
1004
1077
|
|
|
1005
1078
|
/**
|
|
@@ -1034,19 +1107,24 @@ export class PmxCanvas extends EventEmitter {
|
|
|
1034
1107
|
// `mutates` path). `streamJsonRenderCore` throws OperationError (an Error
|
|
1035
1108
|
// subclass with the same message) on a bad append target. The core's
|
|
1036
1109
|
// result carries an extra `ok: true`; the SDK's wire shape omits it.
|
|
1037
|
-
return this.runIntentCommit(
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1110
|
+
return this.runIntentCommit(
|
|
1111
|
+
input.intentId,
|
|
1112
|
+
input.nodeId ? ['edit'] : ['create'],
|
|
1113
|
+
() => {
|
|
1114
|
+
const result = streamJsonRenderCore(input);
|
|
1115
|
+
emitPrimaryWorkbenchEvent('canvas-layout-update', { layout: canvasState.getLayout() });
|
|
1116
|
+
return {
|
|
1117
|
+
id: result.id,
|
|
1118
|
+
url: result.url,
|
|
1119
|
+
applied: result.applied,
|
|
1120
|
+
skipped: result.skipped,
|
|
1121
|
+
specVersion: result.specVersion,
|
|
1122
|
+
elementCount: result.elementCount,
|
|
1123
|
+
streamStatus: result.streamStatus,
|
|
1124
|
+
};
|
|
1125
|
+
},
|
|
1126
|
+
(result) => result.id,
|
|
1127
|
+
);
|
|
1050
1128
|
}
|
|
1051
1129
|
|
|
1052
1130
|
addHtmlNode(input: {
|
|
@@ -1069,34 +1147,39 @@ export class PmxCanvas extends EventEmitter {
|
|
|
1069
1147
|
* the html capability ceiling server-side; cannot escalate. */
|
|
1070
1148
|
axCapabilities?: { enabled?: boolean; allowed?: string[] };
|
|
1071
1149
|
}): SdkCanvasNode {
|
|
1072
|
-
return this.runIntentCommit(
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
...(typeof input.
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1150
|
+
return this.runIntentCommit(
|
|
1151
|
+
input.intentId,
|
|
1152
|
+
['create'],
|
|
1153
|
+
() => {
|
|
1154
|
+
const { id } = addCanvasNode({
|
|
1155
|
+
type: 'html',
|
|
1156
|
+
...(typeof input.title === 'string' ? { title: input.title } : {}),
|
|
1157
|
+
data: {
|
|
1158
|
+
html: resolveHtmlContent(input.html),
|
|
1159
|
+
...(typeof input.summary === 'string' ? { summary: input.summary } : {}),
|
|
1160
|
+
...(typeof input.agentSummary === 'string' ? { agentSummary: input.agentSummary } : {}),
|
|
1161
|
+
...(typeof input.description === 'string' ? { description: input.description } : {}),
|
|
1162
|
+
...(input.presentation === true ? { presentation: true } : {}),
|
|
1163
|
+
...(Array.isArray(input.slideTitles) ? { slideTitles: input.slideTitles } : {}),
|
|
1164
|
+
...(Array.isArray(input.embeddedNodeIds) ? { embeddedNodeIds: input.embeddedNodeIds } : {}),
|
|
1165
|
+
...(Array.isArray(input.embeddedUrls) ? { embeddedUrls: input.embeddedUrls } : {}),
|
|
1166
|
+
...(input.axCapabilities ? { axCapabilities: input.axCapabilities } : {}),
|
|
1167
|
+
},
|
|
1168
|
+
...(typeof input.x === 'number' ? { x: input.x } : {}),
|
|
1169
|
+
...(typeof input.y === 'number' ? { y: input.y } : {}),
|
|
1170
|
+
...(typeof input.width === 'number' ? { width: input.width } : {}),
|
|
1171
|
+
...(typeof input.height === 'number' ? { height: input.height } : {}),
|
|
1172
|
+
...(input.strictSize ? { strictSize: true } : {}),
|
|
1173
|
+
defaultWidth: 720,
|
|
1174
|
+
defaultHeight: 640,
|
|
1175
|
+
});
|
|
1176
|
+
emitPrimaryWorkbenchEvent('canvas-layout-update', { layout: canvasState.getLayout() });
|
|
1177
|
+
const node = canvasState.getNode(id);
|
|
1178
|
+
if (!node) throw new Error(`HTML node "${id}" was not created.`);
|
|
1179
|
+
return toSdkNode(node);
|
|
1180
|
+
},
|
|
1181
|
+
(node) => node.id,
|
|
1182
|
+
);
|
|
1100
1183
|
}
|
|
1101
1184
|
|
|
1102
1185
|
addHtmlPrimitive(input: {
|
|
@@ -1110,52 +1193,60 @@ export class PmxCanvas extends EventEmitter {
|
|
|
1110
1193
|
height?: number;
|
|
1111
1194
|
strictSize?: boolean;
|
|
1112
1195
|
}): { id: string; kind: HtmlPrimitiveKind; title: string; htmlBytes: number } {
|
|
1113
|
-
return this.runIntentCommit(
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1196
|
+
return this.runIntentCommit(
|
|
1197
|
+
input.intentId,
|
|
1198
|
+
['create'],
|
|
1199
|
+
() => {
|
|
1200
|
+
const built = buildHtmlPrimitive({
|
|
1201
|
+
kind: input.kind,
|
|
1202
|
+
...(typeof input.title === 'string' ? { title: input.title } : {}),
|
|
1203
|
+
...(input.data ? { data: input.data } : {}),
|
|
1204
|
+
});
|
|
1205
|
+
const { id } = addCanvasNode({
|
|
1206
|
+
type: 'html',
|
|
1207
|
+
title: built.title,
|
|
1208
|
+
data: {
|
|
1209
|
+
html: built.html,
|
|
1210
|
+
htmlPrimitive: built.kind,
|
|
1211
|
+
primitiveData: built.data,
|
|
1212
|
+
description: built.summary,
|
|
1213
|
+
agentSummary: typeof input.data?.agentSummary === 'string' ? input.data.agentSummary : built.summary,
|
|
1214
|
+
...(typeof input.data?.summary === 'string' ? { summary: input.data.summary } : {}),
|
|
1215
|
+
...getHtmlPrimitiveSemanticMetadata(built.data),
|
|
1216
|
+
},
|
|
1217
|
+
...(typeof input.x === 'number' ? { x: input.x } : {}),
|
|
1218
|
+
...(typeof input.y === 'number' ? { y: input.y } : {}),
|
|
1219
|
+
...(typeof input.width === 'number' ? { width: input.width } : {}),
|
|
1220
|
+
...(typeof input.height === 'number' ? { height: input.height } : {}),
|
|
1221
|
+
...(input.strictSize ? { strictSize: true } : {}),
|
|
1222
|
+
defaultWidth: built.defaultSize.width,
|
|
1223
|
+
defaultHeight: built.defaultSize.height,
|
|
1224
|
+
});
|
|
1225
|
+
emitPrimaryWorkbenchEvent('canvas-layout-update', { layout: canvasState.getLayout() });
|
|
1226
|
+
return { id, kind: built.kind, title: built.title, htmlBytes: Buffer.byteLength(built.html, 'utf-8') };
|
|
1227
|
+
},
|
|
1228
|
+
(result) => result.id,
|
|
1229
|
+
);
|
|
1142
1230
|
}
|
|
1143
1231
|
|
|
1144
1232
|
addGraphNode(input: GraphNodeInput & { intentId?: string }): { id: string; url: string; spec: JsonRenderSpec } {
|
|
1145
|
-
return this.runIntentCommit(
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1233
|
+
return this.runIntentCommit(
|
|
1234
|
+
input.intentId,
|
|
1235
|
+
['create'],
|
|
1236
|
+
() => {
|
|
1237
|
+
const result = createCanvasGraphNode(input);
|
|
1238
|
+
emitPrimaryWorkbenchEvent('canvas-layout-update', { layout: canvasState.getLayout() });
|
|
1239
|
+
return result;
|
|
1240
|
+
},
|
|
1241
|
+
(result) => result.id,
|
|
1242
|
+
);
|
|
1150
1243
|
}
|
|
1151
1244
|
|
|
1152
1245
|
get port(): number {
|
|
1153
1246
|
return this._port;
|
|
1154
1247
|
}
|
|
1155
1248
|
|
|
1156
|
-
async startAutomationWebView(
|
|
1157
|
-
options: CanvasAutomationWebViewOptions = {},
|
|
1158
|
-
): Promise<CanvasAutomationWebViewStatus> {
|
|
1249
|
+
async startAutomationWebView(options: CanvasAutomationWebViewOptions = {}): Promise<CanvasAutomationWebViewStatus> {
|
|
1159
1250
|
const base = this._server ?? startCanvasServer({ port: this._port, allowPortFallback: false });
|
|
1160
1251
|
if (!base) {
|
|
1161
1252
|
throw new Error(`Failed to start canvas server on port ${this._port}`);
|
|
@@ -1177,10 +1268,7 @@ export class PmxCanvas extends EventEmitter {
|
|
|
1177
1268
|
return evaluateCanvasAutomationWebView(expression);
|
|
1178
1269
|
}
|
|
1179
1270
|
|
|
1180
|
-
async resizeAutomationWebView(
|
|
1181
|
-
width: number,
|
|
1182
|
-
height: number,
|
|
1183
|
-
): Promise<CanvasAutomationWebViewStatus> {
|
|
1271
|
+
async resizeAutomationWebView(width: number, height: number): Promise<CanvasAutomationWebViewStatus> {
|
|
1184
1272
|
return resizeCanvasAutomationWebView(width, height);
|
|
1185
1273
|
}
|
|
1186
1274
|
|
|
@@ -1217,14 +1305,24 @@ export {
|
|
|
1217
1305
|
screenshotCanvasAutomationWebView,
|
|
1218
1306
|
} from './server.js';
|
|
1219
1307
|
export { canvasState } from './canvas-state.js';
|
|
1220
|
-
export type {
|
|
1308
|
+
export type {
|
|
1309
|
+
CanvasAnnotation,
|
|
1310
|
+
CanvasSnapshot,
|
|
1311
|
+
CanvasSnapshotGcResult,
|
|
1312
|
+
CanvasSnapshotListOptions,
|
|
1313
|
+
} from './canvas-state.js';
|
|
1221
1314
|
export { findOpenCanvasPosition } from './placement.js';
|
|
1222
1315
|
export { searchNodes, buildSpatialContext, detectClusters, findNeighborhoods } from './spatial-analysis.js';
|
|
1223
1316
|
export type { SpatialCluster, SpatialContext, SpatialNeighbor, NodeSpatialInfo } from './spatial-analysis.js';
|
|
1224
1317
|
export { mutationHistory, diffLayouts, formatDiff } from './mutation-history.js';
|
|
1225
1318
|
export { recomputeCodeGraph, buildCodeGraphSummary, formatCodeGraph } from './code-graph.js';
|
|
1226
1319
|
export { describeCanvasSchema, validateStructuredCanvasPayload } from './canvas-schema.js';
|
|
1227
|
-
export {
|
|
1320
|
+
export {
|
|
1321
|
+
buildHtmlPrimitive,
|
|
1322
|
+
getHtmlPrimitiveSemanticMetadata,
|
|
1323
|
+
isHtmlPrimitiveKind,
|
|
1324
|
+
listHtmlPrimitiveDescriptors,
|
|
1325
|
+
} from './html-primitives.js';
|
|
1228
1326
|
export {
|
|
1229
1327
|
buildWebArtifactOnCanvas,
|
|
1230
1328
|
executeWebArtifactBuild,
|
|
@@ -1249,7 +1347,12 @@ export type {
|
|
|
1249
1347
|
WebArtifactCanvasOpenResult,
|
|
1250
1348
|
} from './web-artifacts.js';
|
|
1251
1349
|
export type { GraphNodeInput, JsonRenderNodeInput, JsonRenderSpec } from '../json-render/server.js';
|
|
1252
|
-
export type {
|
|
1350
|
+
export type {
|
|
1351
|
+
HtmlPrimitiveKind,
|
|
1352
|
+
HtmlPrimitiveDescriptor,
|
|
1353
|
+
HtmlPrimitiveInput,
|
|
1354
|
+
HtmlPrimitiveBuildResult,
|
|
1355
|
+
} from './html-primitives.js';
|
|
1253
1356
|
export { traceManager } from './trace-manager.js';
|
|
1254
1357
|
export type {
|
|
1255
1358
|
PmxAxApprovalGate,
|