pmx-canvas 0.1.25 → 0.1.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/extensions/pmx-canvas/extension.mjs +191 -0
- package/CHANGELOG.md +116 -0
- package/Readme.md +74 -27
- package/dist/canvas/index.js +82 -82
- package/dist/json-render/index.css +1 -1
- package/dist/json-render/index.js +944 -164
- package/dist/types/json-render/catalog.d.ts +195 -20
- package/dist/types/json-render/charts/components.d.ts +7 -0
- package/dist/types/json-render/charts/definitions.d.ts +13 -1
- package/dist/types/json-render/charts/tufte-components.d.ts +65 -0
- package/dist/types/json-render/charts/tufte-definitions.d.ts +164 -0
- package/dist/types/json-render/directives.d.ts +23 -0
- package/dist/types/json-render/renderer/index.d.ts +1 -0
- package/dist/types/json-render/server.d.ts +32 -1
- package/dist/types/mcp/canvas-access.d.ts +62 -0
- package/dist/types/server/ax-state.d.ts +170 -0
- package/dist/types/server/canvas-db.d.ts +17 -1
- package/dist/types/server/canvas-operations.d.ts +45 -0
- package/dist/types/server/canvas-schema.d.ts +5 -1
- package/dist/types/server/canvas-state.d.ts +95 -4
- package/dist/types/server/index.d.ts +118 -2
- package/dist/types/server/mutation-history.d.ts +1 -1
- package/docs/cli.md +42 -0
- package/docs/http-api.md +64 -0
- package/docs/mcp.md +23 -5
- package/docs/node-types.md +1 -1
- package/docs/screenshots/codex-app.png +0 -0
- package/docs/screenshots/github-copilot-app.png +0 -0
- package/docs/sdk.md +19 -1
- package/package.json +10 -7
- package/skills/control-session-orchestrator/SKILL.md +359 -0
- package/skills/control-session-orchestrator/evals/evals.json +75 -0
- package/skills/data-analysis/SKILL.md +6 -0
- package/skills/pmx-canvas/SKILL.md +63 -4
- package/skills/pmx-canvas/references/github-copilot-app-adapter.md +6 -0
- package/skills/tufte-viz/SKILL.md +157 -0
- package/skills/tufte-viz/references/analytical-design.md +217 -0
- package/skills/tufte-viz/references/tufte-principles.md +147 -0
- package/src/cli/agent.ts +280 -2
- package/src/cli/index.ts +2 -1
- package/src/client/nodes/ExtAppFrame.tsx +23 -1
- package/src/client/nodes/McpAppNode.tsx +6 -2
- package/src/json-render/catalog.ts +22 -1
- package/src/json-render/charts/components.tsx +97 -10
- package/src/json-render/charts/definitions.ts +19 -2
- package/src/json-render/charts/extra-components.tsx +5 -4
- package/src/json-render/charts/tufte-components.tsx +383 -0
- package/src/json-render/charts/tufte-definitions.ts +128 -0
- package/src/json-render/directives.ts +29 -0
- package/src/json-render/renderer/index.css +101 -0
- package/src/json-render/renderer/index.tsx +33 -0
- package/src/json-render/server.ts +257 -5
- package/src/mcp/canvas-access.ts +261 -0
- package/src/mcp/server.ts +500 -7
- package/src/server/ax-context.ts +8 -3
- package/src/server/ax-state.ts +447 -0
- package/src/server/canvas-db.ts +184 -1
- package/src/server/canvas-operations.ts +107 -0
- package/src/server/canvas-schema.ts +26 -3
- package/src/server/canvas-state.ts +349 -2
- package/src/server/index.ts +250 -2
- package/src/server/mutation-history.ts +6 -0
- package/src/server/server.ts +428 -2
package/src/server/index.ts
CHANGED
|
@@ -2,7 +2,27 @@ import { EventEmitter } from 'node:events';
|
|
|
2
2
|
import { canvasState, IMAGE_MIME_MAP } from './canvas-state.js';
|
|
3
3
|
import type { CanvasAnnotation, CanvasNodeState, CanvasEdge, CanvasLayout, ViewportState } from './canvas-state.js';
|
|
4
4
|
import { buildCanvasAxContext } from './ax-context.js';
|
|
5
|
-
import type {
|
|
5
|
+
import type {
|
|
6
|
+
PmxAxApprovalGate,
|
|
7
|
+
PmxAxContext,
|
|
8
|
+
PmxAxEvent,
|
|
9
|
+
PmxAxEvidence,
|
|
10
|
+
PmxAxEvidenceKind,
|
|
11
|
+
PmxAxFocusState,
|
|
12
|
+
PmxAxHostCapability,
|
|
13
|
+
PmxAxReviewAnchorType,
|
|
14
|
+
PmxAxReviewAnnotation,
|
|
15
|
+
PmxAxReviewKind,
|
|
16
|
+
PmxAxReviewRegion,
|
|
17
|
+
PmxAxReviewSeverity,
|
|
18
|
+
PmxAxReviewStatus,
|
|
19
|
+
PmxAxSource,
|
|
20
|
+
PmxAxState,
|
|
21
|
+
PmxAxSteeringMessage,
|
|
22
|
+
PmxAxWorkItem,
|
|
23
|
+
PmxAxWorkItemStatus,
|
|
24
|
+
} from './ax-state.js';
|
|
25
|
+
import type { AxTimelineQuery } from './canvas-db.js';
|
|
6
26
|
import { findCanvasExtAppNodeId } from './ext-app-lookup.js';
|
|
7
27
|
import { onFileNodeChanged } from './file-watcher.js';
|
|
8
28
|
import { findOpenCanvasPosition, computeGroupBounds } from './placement.js';
|
|
@@ -12,6 +32,8 @@ import { recomputeCodeGraph, buildCodeGraphSummary, formatCodeGraph } from './co
|
|
|
12
32
|
import {
|
|
13
33
|
addCanvasNode,
|
|
14
34
|
addCanvasEdge,
|
|
35
|
+
appendCanvasJsonRenderStream,
|
|
36
|
+
createCanvasStreamingJsonRenderNode,
|
|
15
37
|
MARKDOWN_NODE_DEFAULT_SIZE,
|
|
16
38
|
MCP_APP_NODE_DEFAULT_SIZE,
|
|
17
39
|
applyCanvasNodeUpdates,
|
|
@@ -30,6 +52,7 @@ import {
|
|
|
30
52
|
refreshCanvasWebpageNode,
|
|
31
53
|
removeCanvasNode,
|
|
32
54
|
removeCanvasEdge,
|
|
55
|
+
resolveHtmlContent,
|
|
33
56
|
restoreCanvasSnapshot,
|
|
34
57
|
saveCanvasSnapshot,
|
|
35
58
|
scheduleCodeGraphRecompute,
|
|
@@ -167,6 +190,10 @@ export class PmxCanvas extends EventEmitter {
|
|
|
167
190
|
type: CanvasNodeState['type'];
|
|
168
191
|
title?: string;
|
|
169
192
|
content?: string;
|
|
193
|
+
children?: string[];
|
|
194
|
+
childIds?: string[];
|
|
195
|
+
childLayout?: 'grid' | 'column' | 'flow';
|
|
196
|
+
color?: string;
|
|
170
197
|
toolName?: string;
|
|
171
198
|
category?: string;
|
|
172
199
|
status?: string;
|
|
@@ -182,6 +209,18 @@ export class PmxCanvas extends EventEmitter {
|
|
|
182
209
|
if (input.type === 'webpage') {
|
|
183
210
|
throw new Error('Use addWebpageNode for webpage nodes so page content is fetched and cached on the server.');
|
|
184
211
|
}
|
|
212
|
+
if (input.type === 'group') {
|
|
213
|
+
return this.createGroup({
|
|
214
|
+
...(typeof input.title === 'string' ? { title: input.title } : {}),
|
|
215
|
+
childIds: input.childIds ?? input.children ?? [],
|
|
216
|
+
...(typeof input.x === 'number' ? { x: input.x } : {}),
|
|
217
|
+
...(typeof input.y === 'number' ? { y: input.y } : {}),
|
|
218
|
+
...(typeof input.width === 'number' ? { width: input.width } : {}),
|
|
219
|
+
...(typeof input.height === 'number' ? { height: input.height } : {}),
|
|
220
|
+
...(typeof input.color === 'string' ? { color: input.color } : {}),
|
|
221
|
+
...(input.childLayout ? { childLayout: input.childLayout } : {}),
|
|
222
|
+
});
|
|
223
|
+
}
|
|
185
224
|
const { id, needsCodeGraphRecompute } = addCanvasNode({
|
|
186
225
|
...input,
|
|
187
226
|
defaultWidth: input.type === 'markdown'
|
|
@@ -437,6 +476,132 @@ export class PmxCanvas extends EventEmitter {
|
|
|
437
476
|
return focus;
|
|
438
477
|
}
|
|
439
478
|
|
|
479
|
+
recordAxEvent(
|
|
480
|
+
input: { kind: PmxAxEvent['kind']; summary: string; detail?: string | null; nodeIds?: string[]; data?: Record<string, unknown> | null },
|
|
481
|
+
options?: { source?: PmxAxSource },
|
|
482
|
+
): PmxAxEvent {
|
|
483
|
+
const event = canvasState.recordAxEvent(input, { source: options?.source ?? 'sdk' });
|
|
484
|
+
emitPrimaryWorkbenchEvent('ax-event-created', { event });
|
|
485
|
+
return event;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
sendSteering(message: string, options?: { source?: PmxAxSource }): PmxAxSteeringMessage {
|
|
489
|
+
const steering = canvasState.recordSteeringMessage(message, { source: options?.source ?? 'sdk' });
|
|
490
|
+
emitPrimaryWorkbenchEvent('ax-event-created', { steering });
|
|
491
|
+
return steering;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
markSteeringDelivered(id: string): boolean {
|
|
495
|
+
const ok = canvasState.markSteeringDelivered(id);
|
|
496
|
+
if (ok) emitPrimaryWorkbenchEvent('ax-event-created', { steeringDelivered: id });
|
|
497
|
+
return ok;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
getAxTimeline(query?: AxTimelineQuery): ReturnType<typeof canvasState.getAxTimeline> {
|
|
501
|
+
return canvasState.getAxTimeline(query);
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
listWorkItems(): PmxAxWorkItem[] {
|
|
505
|
+
return canvasState.getWorkItems();
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
addWorkItem(
|
|
509
|
+
input: { title: string; status?: PmxAxWorkItemStatus; detail?: string | null; nodeIds?: string[] },
|
|
510
|
+
options?: { source?: PmxAxSource },
|
|
511
|
+
): PmxAxWorkItem {
|
|
512
|
+
const workItem = canvasState.addWorkItem(input, { source: options?.source ?? 'sdk' });
|
|
513
|
+
emitPrimaryWorkbenchEvent('ax-state-changed', { workItem });
|
|
514
|
+
return workItem;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
updateWorkItem(
|
|
518
|
+
id: string,
|
|
519
|
+
patch: { title?: string; status?: PmxAxWorkItemStatus; detail?: string | null; nodeIds?: string[] },
|
|
520
|
+
options?: { source?: PmxAxSource },
|
|
521
|
+
): PmxAxWorkItem | null {
|
|
522
|
+
const workItem = canvasState.updateWorkItem(id, patch, { source: options?.source ?? 'sdk' });
|
|
523
|
+
if (workItem) emitPrimaryWorkbenchEvent('ax-state-changed', { workItem });
|
|
524
|
+
return workItem;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
listApprovalGates(): PmxAxApprovalGate[] {
|
|
528
|
+
return canvasState.getApprovalGates();
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
requestApproval(
|
|
532
|
+
input: { title: string; detail?: string | null; action?: string | null; nodeIds?: string[] },
|
|
533
|
+
options?: { source?: PmxAxSource },
|
|
534
|
+
): PmxAxApprovalGate {
|
|
535
|
+
const approvalGate = canvasState.requestApproval(input, { source: options?.source ?? 'sdk' });
|
|
536
|
+
emitPrimaryWorkbenchEvent('ax-state-changed', { approvalGate });
|
|
537
|
+
return approvalGate;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
resolveApproval(
|
|
541
|
+
id: string,
|
|
542
|
+
decision: 'approved' | 'rejected',
|
|
543
|
+
options?: { resolution?: string; source?: PmxAxSource },
|
|
544
|
+
): PmxAxApprovalGate | null {
|
|
545
|
+
const approvalGate = canvasState.resolveApproval(id, decision, {
|
|
546
|
+
...(options?.resolution !== undefined ? { resolution: options.resolution } : {}),
|
|
547
|
+
source: options?.source ?? 'sdk',
|
|
548
|
+
});
|
|
549
|
+
if (approvalGate) emitPrimaryWorkbenchEvent('ax-state-changed', { approvalGate });
|
|
550
|
+
return approvalGate;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
addEvidence(
|
|
554
|
+
input: { kind: PmxAxEvidenceKind; title: string; body?: string | null; ref?: string | null; nodeIds?: string[]; data?: Record<string, unknown> | null },
|
|
555
|
+
options?: { source?: PmxAxSource },
|
|
556
|
+
): PmxAxEvidence {
|
|
557
|
+
const evidence = canvasState.addEvidence(input, { source: options?.source ?? 'sdk' });
|
|
558
|
+
emitPrimaryWorkbenchEvent('ax-event-created', { evidence });
|
|
559
|
+
return evidence;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
listReviewAnnotations(): PmxAxReviewAnnotation[] {
|
|
563
|
+
return canvasState.getReviewAnnotations();
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
addReviewAnnotation(
|
|
567
|
+
input: {
|
|
568
|
+
body: string;
|
|
569
|
+
kind?: PmxAxReviewKind;
|
|
570
|
+
severity?: PmxAxReviewSeverity;
|
|
571
|
+
anchorType?: PmxAxReviewAnchorType;
|
|
572
|
+
nodeId?: string | null;
|
|
573
|
+
file?: string | null;
|
|
574
|
+
region?: PmxAxReviewRegion | null;
|
|
575
|
+
author?: string | null;
|
|
576
|
+
},
|
|
577
|
+
options?: { source?: PmxAxSource },
|
|
578
|
+
): PmxAxReviewAnnotation | null {
|
|
579
|
+
const reviewAnnotation = canvasState.addReviewAnnotation(input, { source: options?.source ?? 'sdk' });
|
|
580
|
+
if (!reviewAnnotation) return null;
|
|
581
|
+
emitPrimaryWorkbenchEvent('ax-state-changed', { reviewAnnotation });
|
|
582
|
+
return reviewAnnotation;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
updateReviewAnnotation(
|
|
586
|
+
id: string,
|
|
587
|
+
patch: { body?: string; status?: PmxAxReviewStatus; severity?: PmxAxReviewSeverity; kind?: PmxAxReviewKind },
|
|
588
|
+
options?: { source?: PmxAxSource },
|
|
589
|
+
): PmxAxReviewAnnotation | null {
|
|
590
|
+
const reviewAnnotation = canvasState.updateReviewAnnotation(id, patch, { source: options?.source ?? 'sdk' });
|
|
591
|
+
if (reviewAnnotation) emitPrimaryWorkbenchEvent('ax-state-changed', { reviewAnnotation });
|
|
592
|
+
return reviewAnnotation;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
getHostCapability(): PmxAxHostCapability | null {
|
|
596
|
+
return canvasState.getHostCapability();
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
reportHostCapability(input: unknown, options?: { source?: PmxAxSource }): PmxAxHostCapability {
|
|
600
|
+
const host = canvasState.setHostCapability(input, { source: options?.source ?? 'sdk' });
|
|
601
|
+
emitPrimaryWorkbenchEvent('ax-state-changed', { host });
|
|
602
|
+
return host;
|
|
603
|
+
}
|
|
604
|
+
|
|
440
605
|
fitView(options?: {
|
|
441
606
|
width?: number;
|
|
442
607
|
height?: number;
|
|
@@ -671,6 +836,65 @@ export class PmxCanvas extends EventEmitter {
|
|
|
671
836
|
return result;
|
|
672
837
|
}
|
|
673
838
|
|
|
839
|
+
/**
|
|
840
|
+
* Progressively build a json-render node from SpecStream patches. Omit nodeId
|
|
841
|
+
* to create a new streaming node; pass the same nodeId on later calls to
|
|
842
|
+
* append more patches. The server accumulates the spec and the browser
|
|
843
|
+
* reloads the viewer as the specVersion bumps.
|
|
844
|
+
*/
|
|
845
|
+
streamJsonRenderNode(input: {
|
|
846
|
+
nodeId?: string;
|
|
847
|
+
title?: string;
|
|
848
|
+
patches?: unknown[];
|
|
849
|
+
done?: boolean;
|
|
850
|
+
x?: number;
|
|
851
|
+
y?: number;
|
|
852
|
+
width?: number;
|
|
853
|
+
height?: number;
|
|
854
|
+
strictSize?: boolean;
|
|
855
|
+
}): {
|
|
856
|
+
id: string;
|
|
857
|
+
url: string;
|
|
858
|
+
applied: number;
|
|
859
|
+
skipped: number;
|
|
860
|
+
specVersion: number;
|
|
861
|
+
elementCount: number;
|
|
862
|
+
streamStatus: 'open' | 'closed';
|
|
863
|
+
} {
|
|
864
|
+
let nodeId = input.nodeId;
|
|
865
|
+
let url = '';
|
|
866
|
+
if (!nodeId) {
|
|
867
|
+
const created = createCanvasStreamingJsonRenderNode({
|
|
868
|
+
...(input.title !== undefined ? { title: input.title } : {}),
|
|
869
|
+
...(input.x !== undefined ? { x: input.x } : {}),
|
|
870
|
+
...(input.y !== undefined ? { y: input.y } : {}),
|
|
871
|
+
...(input.width !== undefined ? { width: input.width } : {}),
|
|
872
|
+
...(input.height !== undefined ? { height: input.height } : {}),
|
|
873
|
+
...(input.strictSize ? { strictSize: true } : {}),
|
|
874
|
+
});
|
|
875
|
+
nodeId = created.id;
|
|
876
|
+
url = created.url;
|
|
877
|
+
} else {
|
|
878
|
+
url = String(canvasState.getNode(nodeId)?.data.url ?? '');
|
|
879
|
+
}
|
|
880
|
+
const result = appendCanvasJsonRenderStream(
|
|
881
|
+
nodeId,
|
|
882
|
+
Array.isArray(input.patches) ? input.patches : [],
|
|
883
|
+
input.done === true,
|
|
884
|
+
);
|
|
885
|
+
if (!result.ok) throw new Error(result.error);
|
|
886
|
+
emitPrimaryWorkbenchEvent('canvas-layout-update', { layout: canvasState.getLayout() });
|
|
887
|
+
return {
|
|
888
|
+
id: nodeId,
|
|
889
|
+
url,
|
|
890
|
+
applied: result.applied,
|
|
891
|
+
skipped: result.skipped,
|
|
892
|
+
specVersion: result.specVersion,
|
|
893
|
+
elementCount: result.elementCount,
|
|
894
|
+
streamStatus: result.streamStatus,
|
|
895
|
+
};
|
|
896
|
+
}
|
|
897
|
+
|
|
674
898
|
addHtmlNode(input: {
|
|
675
899
|
html: string;
|
|
676
900
|
title?: string;
|
|
@@ -691,7 +915,7 @@ export class PmxCanvas extends EventEmitter {
|
|
|
691
915
|
type: 'html',
|
|
692
916
|
...(typeof input.title === 'string' ? { title: input.title } : {}),
|
|
693
917
|
data: {
|
|
694
|
-
html: input.html,
|
|
918
|
+
html: resolveHtmlContent(input.html),
|
|
695
919
|
...(typeof input.summary === 'string' ? { summary: input.summary } : {}),
|
|
696
920
|
...(typeof input.agentSummary === 'string' ? { agentSummary: input.agentSummary } : {}),
|
|
697
921
|
...(typeof input.description === 'string' ? { description: input.description } : {}),
|
|
@@ -859,3 +1083,27 @@ export type {
|
|
|
859
1083
|
export type { GraphNodeInput, JsonRenderNodeInput, JsonRenderSpec } from '../json-render/server.js';
|
|
860
1084
|
export type { HtmlPrimitiveKind, HtmlPrimitiveDescriptor, HtmlPrimitiveInput, HtmlPrimitiveBuildResult } from './html-primitives.js';
|
|
861
1085
|
export { traceManager } from './trace-manager.js';
|
|
1086
|
+
export type {
|
|
1087
|
+
PmxAxApprovalGate,
|
|
1088
|
+
PmxAxApprovalStatus,
|
|
1089
|
+
PmxAxContext,
|
|
1090
|
+
PmxAxEvent,
|
|
1091
|
+
PmxAxEventKind,
|
|
1092
|
+
PmxAxEvidence,
|
|
1093
|
+
PmxAxEvidenceKind,
|
|
1094
|
+
PmxAxFocusState,
|
|
1095
|
+
PmxAxHostCapability,
|
|
1096
|
+
PmxAxReviewAnchorType,
|
|
1097
|
+
PmxAxReviewAnnotation,
|
|
1098
|
+
PmxAxReviewKind,
|
|
1099
|
+
PmxAxReviewRegion,
|
|
1100
|
+
PmxAxReviewSeverity,
|
|
1101
|
+
PmxAxReviewStatus,
|
|
1102
|
+
PmxAxSource,
|
|
1103
|
+
PmxAxState,
|
|
1104
|
+
PmxAxSteeringMessage,
|
|
1105
|
+
PmxAxTimelineSummary,
|
|
1106
|
+
PmxAxWorkItem,
|
|
1107
|
+
PmxAxWorkItemStatus,
|
|
1108
|
+
} from './ax-state.js';
|
|
1109
|
+
export type { AxTimelineQuery } from './canvas-db.js';
|
|
@@ -29,6 +29,12 @@ export type MutationOp =
|
|
|
29
29
|
| 'restoreSnapshot'
|
|
30
30
|
| 'setPins'
|
|
31
31
|
| 'setAxFocus'
|
|
32
|
+
| 'addWorkItem'
|
|
33
|
+
| 'updateWorkItem'
|
|
34
|
+
| 'requestApproval'
|
|
35
|
+
| 'resolveApproval'
|
|
36
|
+
| 'addReviewAnnotation'
|
|
37
|
+
| 'updateReviewAnnotation'
|
|
32
38
|
| 'batch'
|
|
33
39
|
| 'viewport'
|
|
34
40
|
| 'groupNodes'
|