pmx-canvas 0.1.26 → 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.
Files changed (63) hide show
  1. package/.github/extensions/pmx-canvas/extension.mjs +191 -0
  2. package/CHANGELOG.md +74 -0
  3. package/Readme.md +74 -27
  4. package/dist/canvas/index.js +82 -82
  5. package/dist/json-render/index.css +1 -1
  6. package/dist/json-render/index.js +944 -164
  7. package/dist/types/json-render/catalog.d.ts +195 -20
  8. package/dist/types/json-render/charts/components.d.ts +7 -0
  9. package/dist/types/json-render/charts/definitions.d.ts +13 -1
  10. package/dist/types/json-render/charts/tufte-components.d.ts +65 -0
  11. package/dist/types/json-render/charts/tufte-definitions.d.ts +164 -0
  12. package/dist/types/json-render/directives.d.ts +23 -0
  13. package/dist/types/json-render/renderer/index.d.ts +1 -0
  14. package/dist/types/json-render/server.d.ts +32 -1
  15. package/dist/types/mcp/canvas-access.d.ts +62 -0
  16. package/dist/types/server/ax-state.d.ts +170 -0
  17. package/dist/types/server/canvas-db.d.ts +17 -1
  18. package/dist/types/server/canvas-operations.d.ts +45 -0
  19. package/dist/types/server/canvas-schema.d.ts +5 -1
  20. package/dist/types/server/canvas-state.d.ts +95 -4
  21. package/dist/types/server/index.d.ts +114 -2
  22. package/dist/types/server/mutation-history.d.ts +1 -1
  23. package/docs/cli.md +42 -0
  24. package/docs/http-api.md +64 -0
  25. package/docs/mcp.md +23 -5
  26. package/docs/node-types.md +1 -1
  27. package/docs/screenshots/codex-app.png +0 -0
  28. package/docs/screenshots/github-copilot-app.png +0 -0
  29. package/docs/sdk.md +19 -1
  30. package/package.json +10 -7
  31. package/skills/control-session-orchestrator/SKILL.md +359 -0
  32. package/skills/control-session-orchestrator/evals/evals.json +75 -0
  33. package/skills/data-analysis/SKILL.md +6 -0
  34. package/skills/pmx-canvas/SKILL.md +50 -4
  35. package/skills/pmx-canvas/references/github-copilot-app-adapter.md +6 -0
  36. package/skills/tufte-viz/SKILL.md +157 -0
  37. package/skills/tufte-viz/references/analytical-design.md +217 -0
  38. package/skills/tufte-viz/references/tufte-principles.md +147 -0
  39. package/src/cli/agent.ts +280 -2
  40. package/src/cli/index.ts +2 -1
  41. package/src/client/nodes/ExtAppFrame.tsx +23 -1
  42. package/src/client/nodes/McpAppNode.tsx +6 -2
  43. package/src/json-render/catalog.ts +22 -1
  44. package/src/json-render/charts/components.tsx +97 -10
  45. package/src/json-render/charts/definitions.ts +19 -2
  46. package/src/json-render/charts/extra-components.tsx +5 -4
  47. package/src/json-render/charts/tufte-components.tsx +383 -0
  48. package/src/json-render/charts/tufte-definitions.ts +128 -0
  49. package/src/json-render/directives.ts +29 -0
  50. package/src/json-render/renderer/index.css +101 -0
  51. package/src/json-render/renderer/index.tsx +33 -0
  52. package/src/json-render/server.ts +257 -5
  53. package/src/mcp/canvas-access.ts +261 -0
  54. package/src/mcp/server.ts +496 -7
  55. package/src/server/ax-context.ts +8 -3
  56. package/src/server/ax-state.ts +447 -0
  57. package/src/server/canvas-db.ts +184 -1
  58. package/src/server/canvas-operations.ts +107 -0
  59. package/src/server/canvas-schema.ts +26 -3
  60. package/src/server/canvas-state.ts +349 -2
  61. package/src/server/index.ts +234 -2
  62. package/src/server/mutation-history.ts +6 -0
  63. package/src/server/server.ts +419 -2
@@ -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 { PmxAxContext, PmxAxFocusState, PmxAxSource, PmxAxState } from './ax-state.js';
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,
@@ -453,6 +476,132 @@ export class PmxCanvas extends EventEmitter {
453
476
  return focus;
454
477
  }
455
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
+
456
605
  fitView(options?: {
457
606
  width?: number;
458
607
  height?: number;
@@ -687,6 +836,65 @@ export class PmxCanvas extends EventEmitter {
687
836
  return result;
688
837
  }
689
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
+
690
898
  addHtmlNode(input: {
691
899
  html: string;
692
900
  title?: string;
@@ -707,7 +915,7 @@ export class PmxCanvas extends EventEmitter {
707
915
  type: 'html',
708
916
  ...(typeof input.title === 'string' ? { title: input.title } : {}),
709
917
  data: {
710
- html: input.html,
918
+ html: resolveHtmlContent(input.html),
711
919
  ...(typeof input.summary === 'string' ? { summary: input.summary } : {}),
712
920
  ...(typeof input.agentSummary === 'string' ? { agentSummary: input.agentSummary } : {}),
713
921
  ...(typeof input.description === 'string' ? { description: input.description } : {}),
@@ -875,3 +1083,27 @@ export type {
875
1083
  export type { GraphNodeInput, JsonRenderNodeInput, JsonRenderSpec } from '../json-render/server.js';
876
1084
  export type { HtmlPrimitiveKind, HtmlPrimitiveDescriptor, HtmlPrimitiveInput, HtmlPrimitiveBuildResult } from './html-primitives.js';
877
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'