pmx-canvas 0.1.35 → 0.2.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 +461 -0
- package/Readme.md +14 -2
- package/dist/canvas/index.js +82 -41
- package/dist/json-render/index.js +89 -334
- package/dist/types/client/nodes/ExtAppFrame.d.ts +2 -0
- package/dist/types/mcp/canvas-access.d.ts +12 -159
- package/dist/types/server/ax-context.d.ts +1 -1
- package/dist/types/server/ax-state-manager.d.ts +256 -0
- package/dist/types/server/ax-state.d.ts +29 -1
- package/dist/types/server/ax-wait.d.ts +23 -0
- package/dist/types/server/canvas-operations.d.ts +1 -12
- package/dist/types/server/canvas-state.d.ts +46 -14
- package/dist/types/server/html-surface.d.ts +7 -0
- package/dist/types/server/index.d.ts +66 -26
- package/dist/types/server/operations/composites.d.ts +121 -0
- package/dist/types/server/operations/http.d.ts +7 -0
- package/dist/types/server/operations/index.d.ts +8 -0
- package/dist/types/server/operations/invoker.d.ts +13 -0
- package/dist/types/server/operations/mcp.d.ts +15 -0
- package/dist/types/server/operations/ops/annotation.d.ts +2 -0
- package/dist/types/server/operations/ops/app.d.ts +33 -0
- package/dist/types/server/operations/ops/ax-await.d.ts +2 -0
- package/dist/types/server/operations/ops/ax-shared.d.ts +31 -0
- package/dist/types/server/operations/ops/ax-state.d.ts +2 -0
- package/dist/types/server/operations/ops/ax-timeline.d.ts +2 -0
- package/dist/types/server/operations/ops/ax-work.d.ts +2 -0
- package/dist/types/server/operations/ops/batch.d.ts +19 -0
- package/dist/types/server/operations/ops/edges.d.ts +2 -0
- package/dist/types/server/operations/ops/groups.d.ts +2 -0
- package/dist/types/server/operations/ops/json-render.d.ts +31 -0
- package/dist/types/server/operations/ops/nodes.d.ts +62 -0
- package/dist/types/server/operations/ops/query.d.ts +2 -0
- package/dist/types/server/operations/ops/snapshots.d.ts +2 -0
- package/dist/types/server/operations/ops/validate.d.ts +2 -0
- package/dist/types/server/operations/ops/viewport.d.ts +2 -0
- package/dist/types/server/operations/ops/webview.d.ts +2 -0
- package/dist/types/server/operations/registry.d.ts +15 -0
- package/dist/types/server/operations/types.d.ts +116 -0
- package/dist/types/server/operations/webview-runner.d.ts +69 -0
- package/docs/RELEASE.md +5 -0
- package/docs/adr-001-bun-only-runtime.md +46 -0
- package/docs/api-stability.md +57 -0
- package/docs/ax-host-adapter-contract.md +65 -0
- package/docs/ax-state-contract.md +72 -0
- package/docs/http-api.md +34 -2
- package/docs/mcp.md +64 -11
- package/docs/plans/plan-005-operation-registry.md +84 -0
- package/docs/plans/plan-006-mcp-tool-consolidation.md +109 -0
- package/docs/plans/plan-007-ax-domain.md +99 -0
- package/docs/plans/plan-008-registry-finish.md +91 -0
- package/docs/screenshot.png +0 -0
- package/docs/tech-debt-assessment-2026-06.md +90 -0
- package/package.json +3 -3
- package/skills/pmx-canvas/SKILL.md +233 -185
- package/skills/pmx-canvas/evals/evals.json +3 -3
- package/skills/pmx-canvas/references/codex-app-adapter.md +24 -11
- package/skills/pmx-canvas/references/github-copilot-app-adapter.md +31 -1
- package/src/cli/agent.ts +52 -31
- package/src/client/nodes/ExtAppFrame.tsx +73 -5
- package/src/client/nodes/HtmlNode.tsx +12 -3
- package/src/client/nodes/McpAppNode.tsx +12 -3
- package/src/json-render/renderer/index.tsx +3 -0
- package/src/mcp/canvas-access.ts +43 -774
- package/src/mcp/server.ts +190 -2001
- package/src/server/ax-context.ts +7 -1
- package/src/server/ax-state-manager.ts +808 -0
- package/src/server/ax-state.ts +89 -2
- package/src/server/ax-wait.ts +56 -0
- package/src/server/canvas-operations.ts +2 -328
- package/src/server/canvas-schema.ts +2 -2
- package/src/server/canvas-state.ts +140 -382
- package/src/server/html-surface.ts +49 -11
- package/src/server/index.ts +136 -192
- package/src/server/operations/composites.ts +355 -0
- package/src/server/operations/http.ts +103 -0
- package/src/server/operations/index.ts +65 -0
- package/src/server/operations/invoker.ts +87 -0
- package/src/server/operations/mcp.ts +221 -0
- package/src/server/operations/ops/annotation.ts +60 -0
- package/src/server/operations/ops/app.ts +447 -0
- package/src/server/operations/ops/ax-await.ts +216 -0
- package/src/server/operations/ops/ax-shared.ts +38 -0
- package/src/server/operations/ops/ax-state.ts +249 -0
- package/src/server/operations/ops/ax-timeline.ts +381 -0
- package/src/server/operations/ops/ax-work.ts +635 -0
- package/src/server/operations/ops/batch.ts +365 -0
- package/src/server/operations/ops/edges.ts +166 -0
- package/src/server/operations/ops/groups.ts +176 -0
- package/src/server/operations/ops/json-render.ts +691 -0
- package/src/server/operations/ops/nodes.ts +1047 -0
- package/src/server/operations/ops/query.ts +281 -0
- package/src/server/operations/ops/snapshots.ts +366 -0
- package/src/server/operations/ops/validate.ts +37 -0
- package/src/server/operations/ops/viewport.ts +219 -0
- package/src/server/operations/ops/webview.ts +339 -0
- package/src/server/operations/registry.ts +79 -0
- package/src/server/operations/types.ts +150 -0
- package/src/server/operations/webview-runner.ts +77 -0
- package/src/server/server.ts +253 -2170
- package/src/server/web-artifacts.ts +6 -2
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* Legacy `.pmx-canvas/state.json` is auto-migrated on first boot.
|
|
11
11
|
*/
|
|
12
12
|
import { type PersistedCanvasState, type CanvasTheme, type AxTimelineQuery } from './canvas-db.js';
|
|
13
|
-
import { 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';
|
|
13
|
+
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';
|
|
14
14
|
export declare const PMX_CANVAS_DIR = ".pmx-canvas";
|
|
15
15
|
export interface PersistedBlobRef {
|
|
16
16
|
__pmxCanvasBlob: 'v1';
|
|
@@ -142,12 +142,16 @@ declare class CanvasStateManager {
|
|
|
142
142
|
private _viewport;
|
|
143
143
|
private _theme;
|
|
144
144
|
private _contextPinnedNodeIds;
|
|
145
|
-
private _axState;
|
|
146
|
-
private _axHostCapability;
|
|
147
145
|
private _workspaceRoot;
|
|
146
|
+
private readonly ax;
|
|
148
147
|
private _changeListeners;
|
|
149
|
-
/**
|
|
150
|
-
|
|
148
|
+
/**
|
|
149
|
+
* Register a listener for state changes. Used by MCP server to emit resource
|
|
150
|
+
* notifications and by the blocking-wait endpoints to await an AX transition.
|
|
151
|
+
* Returns a disposer that unregisters the listener (callers that don't need it
|
|
152
|
+
* — e.g. the long-lived MCP subscription — may ignore the return value).
|
|
153
|
+
*/
|
|
154
|
+
onChange(cb: (type: CanvasChangeType) => void): () => void;
|
|
151
155
|
private notifyChange;
|
|
152
156
|
private _mutationRecorder;
|
|
153
157
|
private _suppressRecordingDepth;
|
|
@@ -159,8 +163,6 @@ declare class CanvasStateManager {
|
|
|
159
163
|
private suppressed;
|
|
160
164
|
private recordMutation;
|
|
161
165
|
private currentNodeIdSet;
|
|
162
|
-
private normalizeAxForCurrentNodes;
|
|
163
|
-
private applyAxState;
|
|
164
166
|
private applyResolvedGroupBounds;
|
|
165
167
|
private getGroupSnapshot;
|
|
166
168
|
private normalizeNode;
|
|
@@ -346,6 +348,9 @@ declare class CanvasStateManager {
|
|
|
346
348
|
resolution?: string;
|
|
347
349
|
source?: PmxAxSource;
|
|
348
350
|
}): PmxAxModeRequest | null;
|
|
351
|
+
getApproval(id: string): PmxAxApprovalGate | null;
|
|
352
|
+
getElicitation(id: string): PmxAxElicitation | null;
|
|
353
|
+
getModeRequest(id: string): PmxAxModeRequest | null;
|
|
349
354
|
getCommandRegistry(): PmxAxCommandDescriptor[];
|
|
350
355
|
/** Invoke a registry-gated PMX command intent — records a timeline event (no execution). */
|
|
351
356
|
invokeCommand(name: string, args?: Record<string, unknown> | null, options?: {
|
|
@@ -356,10 +361,10 @@ declare class CanvasStateManager {
|
|
|
356
361
|
setPolicy(patch: {
|
|
357
362
|
tools?: Partial<PmxAxPolicy['tools']>;
|
|
358
363
|
prompt?: Partial<PmxAxPolicy['prompt']>;
|
|
359
|
-
},
|
|
364
|
+
}, options?: {
|
|
360
365
|
source?: PmxAxSource;
|
|
361
366
|
}): PmxAxPolicy;
|
|
362
|
-
setHostCapability(input: unknown,
|
|
367
|
+
setHostCapability(input: unknown, options?: {
|
|
363
368
|
source?: PmxAxSource;
|
|
364
369
|
}): PmxAxHostCapability;
|
|
365
370
|
recordAxEvent(input: {
|
|
@@ -385,16 +390,43 @@ declare class CanvasStateManager {
|
|
|
385
390
|
source?: PmxAxSource;
|
|
386
391
|
}): PmxAxSteeringMessage;
|
|
387
392
|
markSteeringDelivered(id: string): boolean;
|
|
393
|
+
ingestActivity(input: {
|
|
394
|
+
kind: PmxAxActivityKind;
|
|
395
|
+
title: string;
|
|
396
|
+
summary?: string | null;
|
|
397
|
+
outcome?: 'success' | 'failure';
|
|
398
|
+
ref?: string | null;
|
|
399
|
+
nodeIds?: string[];
|
|
400
|
+
data?: Record<string, unknown> | null;
|
|
401
|
+
reactions?: {
|
|
402
|
+
workItem?: false | {
|
|
403
|
+
status?: PmxAxWorkItemStatus;
|
|
404
|
+
detail?: string | null;
|
|
405
|
+
};
|
|
406
|
+
evidence?: false | {
|
|
407
|
+
kind?: PmxAxEvidenceKind;
|
|
408
|
+
body?: string | null;
|
|
409
|
+
};
|
|
410
|
+
review?: false | {
|
|
411
|
+
severity?: PmxAxReviewSeverity;
|
|
412
|
+
kind?: PmxAxReviewKind;
|
|
413
|
+
anchorType?: PmxAxReviewAnchorType;
|
|
414
|
+
nodeId?: string | null;
|
|
415
|
+
};
|
|
416
|
+
};
|
|
417
|
+
}, options?: {
|
|
418
|
+
source?: PmxAxSource;
|
|
419
|
+
}): {
|
|
420
|
+
event: PmxAxEvent;
|
|
421
|
+
workItem: PmxAxWorkItem | null;
|
|
422
|
+
evidence: PmxAxEvidence | null;
|
|
423
|
+
review: PmxAxReviewAnnotation | null;
|
|
424
|
+
};
|
|
388
425
|
getAxEvents(q?: AxTimelineQuery): PmxAxEvent[];
|
|
389
426
|
getAxEvidence(q?: AxTimelineQuery): PmxAxEvidence[];
|
|
390
427
|
getAxSteering(q?: AxTimelineQuery & {
|
|
391
428
|
onlyPending?: boolean;
|
|
392
429
|
}): PmxAxSteeringMessage[];
|
|
393
|
-
/**
|
|
394
|
-
* Undelivered steering for a consumer (Phase 4 delivery). Excludes messages
|
|
395
|
-
* whose source equals the consumer to prevent delivery loops (e.g. Copilot
|
|
396
|
-
* should not be handed back steering it originated).
|
|
397
|
-
*/
|
|
398
430
|
getPendingSteering(options?: {
|
|
399
431
|
consumer?: string;
|
|
400
432
|
limit?: number;
|
|
@@ -27,6 +27,13 @@ export declare function normalizeSurfaceTheme(value: string | null | undefined):
|
|
|
27
27
|
* injected when the node's AX capabilities are enabled (opt-in for `html`), and
|
|
28
28
|
* the server re-validates every interaction — so this is a convenience surface,
|
|
29
29
|
* not a trust boundary.
|
|
30
|
+
*
|
|
31
|
+
* `emit` returns a Promise that resolves with the interaction result once the
|
|
32
|
+
* parent acks it (report #55 — built-in confirmation so a click no longer looks
|
|
33
|
+
* like "nothing happened"). Authors can also `window.PMX_AX.on('ack', cb)` or
|
|
34
|
+
* listen for the `pmx-ax-ack` CustomEvent. Resolves with an `ax-ack-timeout`
|
|
35
|
+
* result after 10s if no ack arrives (e.g. an older parent), so `await emit()`
|
|
36
|
+
* never hangs.
|
|
30
37
|
*/
|
|
31
38
|
export declare function buildAxBridge(axToken: string, nodeId: string): string;
|
|
32
39
|
/**
|
|
@@ -2,11 +2,12 @@ import { EventEmitter } from 'node:events';
|
|
|
2
2
|
import { canvasState } from './canvas-state.js';
|
|
3
3
|
import type { CanvasAnnotation, CanvasNodeState, CanvasEdge, CanvasLayout } from './canvas-state.js';
|
|
4
4
|
import { type AxInteractionInput, type AxInteractionPublicResult } from './ax-interaction.js';
|
|
5
|
-
import type { PmxAxApprovalGate, PmxAxCommandDescriptor, PmxAxContext, PmxAxElicitation, PmxAxEvent, PmxAxEvidence, PmxAxEvidenceKind, PmxAxFocusState, PmxAxHostCapability, PmxAxMode, PmxAxModeRequest, PmxAxPolicy, PmxAxReviewAnchorType, PmxAxReviewAnnotation, PmxAxReviewKind, PmxAxReviewRegion, PmxAxReviewSeverity, PmxAxReviewStatus, PmxAxSource, PmxAxState, PmxAxSteeringMessage, PmxAxWorkItem, PmxAxWorkItemStatus } from './ax-state.js';
|
|
5
|
+
import type { PmxAxActivityKind, PmxAxApprovalGate, PmxAxCommandDescriptor, PmxAxContext, PmxAxElicitation, PmxAxEvent, PmxAxEvidence, PmxAxEvidenceKind, PmxAxFocusState, PmxAxHostCapability, PmxAxMode, PmxAxModeRequest, PmxAxPolicy, PmxAxReviewAnchorType, PmxAxReviewAnnotation, PmxAxReviewKind, PmxAxReviewRegion, PmxAxReviewSeverity, PmxAxReviewStatus, PmxAxSource, PmxAxState, PmxAxSteeringMessage, PmxAxWorkItem, PmxAxWorkItemStatus } from './ax-state.js';
|
|
6
6
|
import type { AxTimelineQuery } from './canvas-db.js';
|
|
7
7
|
import { searchNodes } from './spatial-analysis.js';
|
|
8
8
|
import { diffLayouts } from './mutation-history.js';
|
|
9
9
|
import { fitCanvasView, gcCanvasSnapshots, listCanvasSnapshots } from './canvas-operations.js';
|
|
10
|
+
import { type OpenMcpAppCoreResult } from './operations/index.js';
|
|
10
11
|
import { type SerializedCanvasNode } from './canvas-serialization.js';
|
|
11
12
|
import type { HtmlPrimitiveKind } from './html-primitives.js';
|
|
12
13
|
import { type WebArtifactBuildInput, type WebArtifactCanvasBuildResult } from './web-artifacts.js';
|
|
@@ -88,6 +89,7 @@ export declare class PmxCanvas extends EventEmitter {
|
|
|
88
89
|
error?: string;
|
|
89
90
|
}>;
|
|
90
91
|
updateNode(id: string, patch: Partial<CanvasNodeState> & Record<string, unknown>): void;
|
|
92
|
+
/** Remove a node. Missing id throws (plan-005 unifies this across surfaces). */
|
|
91
93
|
removeNode(id: string): void;
|
|
92
94
|
addEdge(input: {
|
|
93
95
|
from?: string;
|
|
@@ -134,7 +136,9 @@ export declare class PmxCanvas extends EventEmitter {
|
|
|
134
136
|
panned: boolean;
|
|
135
137
|
} | null;
|
|
136
138
|
getAxState(): PmxAxState;
|
|
137
|
-
getAxContext(
|
|
139
|
+
getAxContext(options?: {
|
|
140
|
+
consumer?: string;
|
|
141
|
+
}): PmxAxContext;
|
|
138
142
|
setAxFocus(nodeIds: string[], options?: {
|
|
139
143
|
source?: PmxAxSource;
|
|
140
144
|
}): PmxAxFocusState;
|
|
@@ -253,6 +257,62 @@ export declare class PmxCanvas extends EventEmitter {
|
|
|
253
257
|
resolution?: string;
|
|
254
258
|
source?: PmxAxSource;
|
|
255
259
|
}): PmxAxModeRequest | null;
|
|
260
|
+
ingestActivity(input: {
|
|
261
|
+
kind: PmxAxActivityKind;
|
|
262
|
+
title: string;
|
|
263
|
+
summary?: string | null;
|
|
264
|
+
outcome?: 'success' | 'failure';
|
|
265
|
+
ref?: string | null;
|
|
266
|
+
nodeIds?: string[];
|
|
267
|
+
data?: Record<string, unknown> | null;
|
|
268
|
+
reactions?: {
|
|
269
|
+
workItem?: false | {
|
|
270
|
+
status?: PmxAxWorkItemStatus;
|
|
271
|
+
detail?: string | null;
|
|
272
|
+
};
|
|
273
|
+
evidence?: false | {
|
|
274
|
+
kind?: PmxAxEvidenceKind;
|
|
275
|
+
body?: string | null;
|
|
276
|
+
};
|
|
277
|
+
review?: false | {
|
|
278
|
+
severity?: PmxAxReviewSeverity;
|
|
279
|
+
kind?: PmxAxReviewKind;
|
|
280
|
+
anchorType?: PmxAxReviewAnchorType;
|
|
281
|
+
nodeId?: string | null;
|
|
282
|
+
};
|
|
283
|
+
};
|
|
284
|
+
}, options?: {
|
|
285
|
+
source?: PmxAxSource;
|
|
286
|
+
}): {
|
|
287
|
+
event: PmxAxEvent;
|
|
288
|
+
workItem: PmxAxWorkItem | null;
|
|
289
|
+
evidence: PmxAxEvidence | null;
|
|
290
|
+
review: PmxAxReviewAnnotation | null;
|
|
291
|
+
};
|
|
292
|
+
getApproval(id: string): PmxAxApprovalGate | null;
|
|
293
|
+
getElicitation(id: string): PmxAxElicitation | null;
|
|
294
|
+
getModeRequest(id: string): PmxAxModeRequest | null;
|
|
295
|
+
awaitApproval(id: string, options?: {
|
|
296
|
+
timeoutMs?: number;
|
|
297
|
+
signal?: AbortSignal;
|
|
298
|
+
}): Promise<{
|
|
299
|
+
approvalGate: PmxAxApprovalGate | null;
|
|
300
|
+
pending: boolean;
|
|
301
|
+
}>;
|
|
302
|
+
awaitElicitation(id: string, options?: {
|
|
303
|
+
timeoutMs?: number;
|
|
304
|
+
signal?: AbortSignal;
|
|
305
|
+
}): Promise<{
|
|
306
|
+
elicitation: PmxAxElicitation | null;
|
|
307
|
+
pending: boolean;
|
|
308
|
+
}>;
|
|
309
|
+
awaitMode(id: string, options?: {
|
|
310
|
+
timeoutMs?: number;
|
|
311
|
+
signal?: AbortSignal;
|
|
312
|
+
}): Promise<{
|
|
313
|
+
modeRequest: PmxAxModeRequest | null;
|
|
314
|
+
pending: boolean;
|
|
315
|
+
}>;
|
|
256
316
|
getCommandRegistry(): PmxAxCommandDescriptor[];
|
|
257
317
|
invokeCommand(name: string, args?: Record<string, unknown> | null, options?: {
|
|
258
318
|
source?: PmxAxSource;
|
|
@@ -329,7 +389,6 @@ export declare class PmxCanvas extends EventEmitter {
|
|
|
329
389
|
summary: import("./code-graph.js").CodeGraphSummary;
|
|
330
390
|
};
|
|
331
391
|
validate(): import("./canvas-validation.js").CanvasValidationResult;
|
|
332
|
-
private findCanvasExtAppNodeId;
|
|
333
392
|
describeSchema(): {
|
|
334
393
|
ok: true;
|
|
335
394
|
source: "running-server";
|
|
@@ -362,15 +421,10 @@ export declare class PmxCanvas extends EventEmitter {
|
|
|
362
421
|
op: string;
|
|
363
422
|
assign?: string;
|
|
364
423
|
args?: Record<string, unknown>;
|
|
365
|
-
}>): Promise<
|
|
366
|
-
ok: boolean;
|
|
367
|
-
results: Array<Record<string, unknown>>;
|
|
368
|
-
refs: Record<string, unknown>;
|
|
369
|
-
failedIndex?: number;
|
|
370
|
-
error?: string;
|
|
371
|
-
}>;
|
|
424
|
+
}>): Promise<import("./operations/index.js").BatchEnvelope>;
|
|
372
425
|
buildWebArtifact(input: WebArtifactBuildInput & {
|
|
373
426
|
openInCanvas?: boolean;
|
|
427
|
+
includeLogs?: boolean;
|
|
374
428
|
}): Promise<WebArtifactCanvasBuildResult>;
|
|
375
429
|
openMcpApp(input: {
|
|
376
430
|
transport: ExternalMcpTransportConfig;
|
|
@@ -384,22 +438,8 @@ export declare class PmxCanvas extends EventEmitter {
|
|
|
384
438
|
width?: number;
|
|
385
439
|
height?: number;
|
|
386
440
|
timeoutMs?: number;
|
|
387
|
-
}): Promise<
|
|
388
|
-
|
|
389
|
-
id?: string;
|
|
390
|
-
nodeId: string | null;
|
|
391
|
-
toolCallId: string;
|
|
392
|
-
sessionId: string;
|
|
393
|
-
resourceUri: string;
|
|
394
|
-
}>;
|
|
395
|
-
addDiagram(input: DiagramPresetOpenInput): Promise<{
|
|
396
|
-
ok: true;
|
|
397
|
-
id?: string;
|
|
398
|
-
nodeId: string | null;
|
|
399
|
-
toolCallId: string;
|
|
400
|
-
sessionId: string;
|
|
401
|
-
resourceUri: string;
|
|
402
|
-
}>;
|
|
441
|
+
}): Promise<OpenMcpAppCoreResult>;
|
|
442
|
+
addDiagram(input: DiagramPresetOpenInput): Promise<OpenMcpAppCoreResult>;
|
|
403
443
|
addJsonRenderNode(input: JsonRenderNodeInput): {
|
|
404
444
|
id: string;
|
|
405
445
|
url: string;
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Composite MCP tools (plan-006: MCP tool consolidation).
|
|
3
|
+
*
|
|
4
|
+
* A composite tool folds several single-purpose MCP tools into one tool with an
|
|
5
|
+
* `action` discriminator. It is a PRESENTATION-LAYER construct only: each action
|
|
6
|
+
* dispatches to an already-registered operation (`src/server/operations/ops/*`)
|
|
7
|
+
* via the same invoker, reusing that operation's own `mcp.buildInput` and
|
|
8
|
+
* `mcp.formatResult`. So `canvas_edge { action: "add", ... }` is byte-identical
|
|
9
|
+
* to the standalone `canvas_add_edge` — same op, same arg mapping, same result
|
|
10
|
+
* shape — by construction. No handler logic lives here.
|
|
11
|
+
*
|
|
12
|
+
* Migration (docs/api-stability.md + plan-006): composites land ADDITIVELY in
|
|
13
|
+
* v0.2 alongside the legacy single-purpose tools (the tool surface grows, then
|
|
14
|
+
* shrinks when the legacy tools are removed in v0.3). Every action here maps to a
|
|
15
|
+
* registry-backed operation (plan-005 slices 1–7 + plan-008 Wave 1).
|
|
16
|
+
*
|
|
17
|
+
* Still deferred (its legacy standalone tool keeps working; see plan-008): the
|
|
18
|
+
* `canvas_snapshot` composite (the v0.3 name collision). The action enums are
|
|
19
|
+
* forward-compatible: adding an action later is additive. (`canvas_webview`
|
|
20
|
+
* shipped in plan-008 Wave 3 via runner injection; `canvas_app` shipped in Wave 4
|
|
21
|
+
* — open-mcp-app / diagram / build-artifact. Wave 5 folded the last three legacy
|
|
22
|
+
* tools deprecate-only — NO per-action input-injection mechanism was needed:
|
|
23
|
+
* `canvas_add_html_node` / `canvas_add_html_primitive` → `canvas_node` action
|
|
24
|
+
* "add" (type:"html" [+ primitive]); `canvas_refresh_webpage_node` → `canvas_node`
|
|
25
|
+
* action "update" (refresh:true). `canvas_screenshot` stays standalone — it
|
|
26
|
+
* returns a binary image payload the composite/registry JSON wire shape does not
|
|
27
|
+
* model.)
|
|
28
|
+
*
|
|
29
|
+
* Not shipped here: the `canvas_snapshot` composite (plan-006 #7). Its target
|
|
30
|
+
* name is ALREADY a legacy standalone tool (the save-snapshot tool, op
|
|
31
|
+
* `snapshot.save`), so it cannot be added additively without a name clash, and
|
|
32
|
+
* repurposing `canvas_snapshot` to be action-discriminated now would break
|
|
33
|
+
* existing callers. It lands in v0.3, in the same change that removes the legacy
|
|
34
|
+
* single-purpose snapshot tools and frees the name.
|
|
35
|
+
*
|
|
36
|
+
* This module must never import server.ts or index.ts.
|
|
37
|
+
*/
|
|
38
|
+
import { type ZodRawShape } from 'zod';
|
|
39
|
+
/**
|
|
40
|
+
* One composite MCP tool: a frozen tool name + its action→operation routing.
|
|
41
|
+
*
|
|
42
|
+
* Two flavours:
|
|
43
|
+
* - Single-discriminator (the wave-1 composites + the 4 single-discriminator AX
|
|
44
|
+
* composites): the flat `actions` map routes one `action` value → one op.
|
|
45
|
+
* - Two-discriminator (`canvas_ax_gate`, plan-007 Slice C): a `kind` × `action`
|
|
46
|
+
* matrix folds 9 ops into one tool. Set `extraDiscriminatorShape` (the `kind`
|
|
47
|
+
* enum), `memberOps` (the op names — used to derive the schema union + the
|
|
48
|
+
* deprecation notes), `actionEnum` (the action discriminator values), and
|
|
49
|
+
* `resolveOp` (maps `{ kind, action }` → op name, or undefined for an invalid
|
|
50
|
+
* combo → a loud error at dispatch). The flat `actions` map is left empty for
|
|
51
|
+
* these; the matrix path uses `resolveOp` instead.
|
|
52
|
+
*/
|
|
53
|
+
export interface CompositeToolDefinition {
|
|
54
|
+
/** Frozen public tool name (see tests/unit/mcp-tool-freeze.test.ts). */
|
|
55
|
+
toolName: string;
|
|
56
|
+
description: string;
|
|
57
|
+
/** Human-readable action list for the `action` enum description. */
|
|
58
|
+
actionSummary: string;
|
|
59
|
+
/**
|
|
60
|
+
* Map of `action` value → registry operation name (single-discriminator
|
|
61
|
+
* composites). Empty for two-discriminator composites. Every referenced op
|
|
62
|
+
* MUST have an `mcp` block — its `buildInput`/`formatResult` are reused so the
|
|
63
|
+
* composite action matches the legacy standalone tool exactly.
|
|
64
|
+
*/
|
|
65
|
+
actions: Record<string, string>;
|
|
66
|
+
/**
|
|
67
|
+
* Two-discriminator extension (e.g. `canvas_ax_gate`). The extra discriminator
|
|
68
|
+
* shape — a single `kind` enum — merged into the advertised schema alongside
|
|
69
|
+
* `action`.
|
|
70
|
+
*/
|
|
71
|
+
extraDiscriminatorShape?: ZodRawShape;
|
|
72
|
+
/**
|
|
73
|
+
* Two-discriminator extension: the action enum values (used to build the
|
|
74
|
+
* `action` discriminator when there is no flat `actions` map to derive it from).
|
|
75
|
+
*/
|
|
76
|
+
actionEnum?: readonly string[];
|
|
77
|
+
/**
|
|
78
|
+
* Two-discriminator extension: every member op name. Used to build the schema
|
|
79
|
+
* union (all member-op fields, optional) and to derive a deprecation note per
|
|
80
|
+
* member op (each mapped back to its (kind, action) by `describeOp`).
|
|
81
|
+
*/
|
|
82
|
+
memberOps?: string[];
|
|
83
|
+
/**
|
|
84
|
+
* Two-discriminator extension: resolve the op name from the validated
|
|
85
|
+
* discriminators. Returns `undefined` for an invalid combo so dispatch can
|
|
86
|
+
* raise a loud error instead of silently no-op'ing.
|
|
87
|
+
*/
|
|
88
|
+
resolveOp?: (input: {
|
|
89
|
+
kind: string;
|
|
90
|
+
action: string;
|
|
91
|
+
}) => string | undefined;
|
|
92
|
+
/**
|
|
93
|
+
* Two-discriminator extension: human-readable `(kind, action)` for a member op
|
|
94
|
+
* (the inverse of `resolveOp`), used to build that op's deprecation note. The
|
|
95
|
+
* `kind` field-collision is resolved here (see `gateFieldRemap`).
|
|
96
|
+
*/
|
|
97
|
+
describeOp?: (opName: string) => {
|
|
98
|
+
kind: string;
|
|
99
|
+
action: string;
|
|
100
|
+
} | undefined;
|
|
101
|
+
/**
|
|
102
|
+
* Field-name remap applied to the composite's advertised schema and undone at
|
|
103
|
+
* dispatch. Resolves a collision between a discriminator name and a member-op
|
|
104
|
+
* field of the same name (e.g. `ax.approval.request` has its own `action`
|
|
105
|
+
* field — namespaced to `approvalAction` in the composite so the `action`
|
|
106
|
+
* discriminator wins, then mapped back before invoking the op). Keys are the
|
|
107
|
+
* composite (public) field names; values are the op field names.
|
|
108
|
+
*/
|
|
109
|
+
fieldRemap?: Record<string, string>;
|
|
110
|
+
}
|
|
111
|
+
export declare const compositeToolDefinitions: CompositeToolDefinition[];
|
|
112
|
+
/**
|
|
113
|
+
* Deprecation notes for the legacy single-purpose tools, DERIVED from the
|
|
114
|
+
* composites: every operation a composite folds gets a `Deprecated: use
|
|
115
|
+
* canvas_x with action "y".` prefix on its standalone tool description, steering
|
|
116
|
+
* agents to the composite during the v0.2 overlap window (the legacy tools and
|
|
117
|
+
* these notes are removed together in v0.3). Keyed by registry operation name.
|
|
118
|
+
* Deriving it keeps the deprecation list in lockstep with the composites — a new
|
|
119
|
+
* folded action automatically deprecates the tool it replaces.
|
|
120
|
+
*/
|
|
121
|
+
export declare function buildCompositeDeprecationNotes(definitions?: CompositeToolDefinition[]): Map<string, string>;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared body reader: preserves the parsed JSON value as-is (object, array,
|
|
3
|
+
* or primitive) — per-op `readInput` decides what to do with non-object
|
|
4
|
+
* bodies; the shared reader never coerces.
|
|
5
|
+
*/
|
|
6
|
+
export declare function readJsonValue(req: Request): Promise<unknown>;
|
|
7
|
+
export declare function dispatchOperationRoute(req: Request, url: URL): Promise<Response | null>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { executeOperation, getOperation, listOperations, registerOperation, setOperationEventEmitter, } from './registry.js';
|
|
2
|
+
export { dispatchOperationRoute } from './http.js';
|
|
3
|
+
export { runCanvasBatchOperation, type BatchEnvelope } from './ops/batch.js';
|
|
4
|
+
export { type OpenMcpAppCoreResult } from './ops/app.js';
|
|
5
|
+
export { LocalOperationInvoker, HttpOperationInvoker, type OperationInvoker } from './invoker.js';
|
|
6
|
+
export { registerOperationTools, registerCompositeTools, type OperationToolHost } from './mcp.js';
|
|
7
|
+
export { compositeToolDefinitions, type CompositeToolDefinition } from './composites.js';
|
|
8
|
+
export { OperationError, defineOperation, type Operation, type OperationContext, type OperationDefinition, type OperationErrorStatus, } from './types.js';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface OperationInvoker {
|
|
2
|
+
invoke(name: string, input: Record<string, unknown>): Promise<unknown>;
|
|
3
|
+
}
|
|
4
|
+
/** Runs operations in-process against the shared canvasState singleton. */
|
|
5
|
+
export declare class LocalOperationInvoker implements OperationInvoker {
|
|
6
|
+
invoke(name: string, input: Record<string, unknown>): Promise<unknown>;
|
|
7
|
+
}
|
|
8
|
+
/** Builds the HTTP request from the op's route template (`:id` from input, GET flags to query). */
|
|
9
|
+
export declare class HttpOperationInvoker implements OperationInvoker {
|
|
10
|
+
private readonly baseUrl;
|
|
11
|
+
constructor(baseUrl: string);
|
|
12
|
+
invoke(name: string, input: Record<string, unknown>): Promise<unknown>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import type { OperationInvoker } from './invoker.js';
|
|
3
|
+
import { type OperationMcpToolHost } from './types.js';
|
|
4
|
+
import { type CompositeToolDefinition } from './composites.js';
|
|
5
|
+
export interface OperationToolHost extends OperationMcpToolHost {
|
|
6
|
+
invoker(): OperationInvoker;
|
|
7
|
+
}
|
|
8
|
+
export declare function registerOperationTools(server: McpServer, getHost: () => Promise<OperationToolHost>): void;
|
|
9
|
+
/**
|
|
10
|
+
* Register composite (action-discriminated) MCP tools (plan-006). Each action
|
|
11
|
+
* dispatches to a registered operation, reusing that op's `mcp.buildInput` and
|
|
12
|
+
* `mcp.formatResult` so the composite action is byte-identical to the standalone
|
|
13
|
+
* tool it folds. Defaults to `compositeToolDefinitions`.
|
|
14
|
+
*/
|
|
15
|
+
export declare function registerCompositeTools(server: McpServer, getHost: () => Promise<OperationToolHost>, definitions?: CompositeToolDefinition[]): void;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type ExternalMcpTransportConfig } from '../../mcp-app-runtime.js';
|
|
2
|
+
import { type Operation, type OperationContext } from '../types.js';
|
|
3
|
+
export interface OpenMcpAppCoreInput {
|
|
4
|
+
transport: ExternalMcpTransportConfig;
|
|
5
|
+
toolName: string;
|
|
6
|
+
toolArguments?: Record<string, unknown>;
|
|
7
|
+
nodeId?: string;
|
|
8
|
+
serverName?: string;
|
|
9
|
+
title?: string;
|
|
10
|
+
x?: number;
|
|
11
|
+
y?: number;
|
|
12
|
+
width?: number;
|
|
13
|
+
height?: number;
|
|
14
|
+
timeoutMs?: number;
|
|
15
|
+
}
|
|
16
|
+
export interface OpenMcpAppCoreResult {
|
|
17
|
+
ok: true;
|
|
18
|
+
id?: string;
|
|
19
|
+
nodeId: string | null;
|
|
20
|
+
toolCallId: string;
|
|
21
|
+
sessionId: string;
|
|
22
|
+
resourceUri: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Open an external MCP app: connect + call + read resource (openExternalMcpApp),
|
|
26
|
+
* close any prior session on an in-place node, emit `ext-app-open` +
|
|
27
|
+
* `ext-app-result`, then resolve the resulting canvas node id. This is the exact
|
|
28
|
+
* legacy SDK `openMcpApp` body, relocated; both the mcpapp.open op AND the SDK
|
|
29
|
+
* call it. The diagram.open op delegates here after building the Excalidraw input
|
|
30
|
+
* (the SSE pair fires ONCE — diagram.open does not re-emit).
|
|
31
|
+
*/
|
|
32
|
+
export declare function openMcpAppCore(input: OpenMcpAppCoreInput, ctx: OperationContext): Promise<OpenMcpAppCoreResult>;
|
|
33
|
+
export declare const appOperations: Operation[];
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared helpers for the AX operation modules (ax-state.ts, ax-work.ts, and the
|
|
3
|
+
* later timeline/delivery waves). These were replicated per-file during the
|
|
4
|
+
* plan-007 Slice B migration; centralizing them here keeps one definition site
|
|
5
|
+
* as more AX op files land.
|
|
6
|
+
*
|
|
7
|
+
* `normalizeAxSource` / `normalizeAxNodeIds` are reimplemented from server.ts
|
|
8
|
+
* because `operations/` must never import server.ts (the SSE emitter is injected;
|
|
9
|
+
* see plan-005). This module likewise must not import server.ts or index.ts.
|
|
10
|
+
*/
|
|
11
|
+
import { z } from 'zod';
|
|
12
|
+
import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
|
13
|
+
import type { PmxAxSource } from '../../ax-state.js';
|
|
14
|
+
export declare const AX_SOURCES: readonly ["agent", "api", "browser", "cli", "codex", "copilot", "mcp", "sdk", "system"];
|
|
15
|
+
/** Zod schema for the optional `source` field shared by AX MCP tool shapes. */
|
|
16
|
+
export declare const AX_SOURCE_SHAPE: z.ZodOptional<z.ZodEnum<{
|
|
17
|
+
agent: "agent";
|
|
18
|
+
api: "api";
|
|
19
|
+
browser: "browser";
|
|
20
|
+
cli: "cli";
|
|
21
|
+
codex: "codex";
|
|
22
|
+
copilot: "copilot";
|
|
23
|
+
mcp: "mcp";
|
|
24
|
+
sdk: "sdk";
|
|
25
|
+
system: "system";
|
|
26
|
+
}>>;
|
|
27
|
+
/** An absent or unrecognized source falls back to the per-surface default. */
|
|
28
|
+
export declare function normalizeAxSource(value: unknown, fallback: PmxAxSource): PmxAxSource;
|
|
29
|
+
export declare function normalizeAxNodeIds(value: unknown): string[];
|
|
30
|
+
/** The plain JSON tool result shared by AX ops whose MCP body is the wire body. */
|
|
31
|
+
export declare function axJsonResult(result: unknown): CallToolResult;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type Operation } from '../types.js';
|
|
2
|
+
export interface BatchEnvelope {
|
|
3
|
+
ok: boolean;
|
|
4
|
+
results: Array<Record<string, unknown>>;
|
|
5
|
+
refs: Record<string, unknown>;
|
|
6
|
+
failedIndex?: number;
|
|
7
|
+
error?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare const batchOperations: Operation[];
|
|
10
|
+
/**
|
|
11
|
+
* Typed SDK entry point: run a batch through the registry's single execution
|
|
12
|
+
* path (`executeOperation('canvas.batch')`). The op emits the one final
|
|
13
|
+
* canvas-layout-update itself, so callers must NOT emit again.
|
|
14
|
+
*/
|
|
15
|
+
export declare function runCanvasBatchOperation(operations: Array<{
|
|
16
|
+
op: string;
|
|
17
|
+
assign?: string;
|
|
18
|
+
args?: Record<string, unknown>;
|
|
19
|
+
}>): Promise<BatchEnvelope>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type Operation } from '../types.js';
|
|
2
|
+
/** Legacy server.ts parseGraphPayloadData: a graph dataset must be an array of records. */
|
|
3
|
+
export declare function parseGraphPayloadData(value: unknown): Array<Record<string, unknown>> | null;
|
|
4
|
+
export interface StreamJsonRenderInput {
|
|
5
|
+
nodeId?: string;
|
|
6
|
+
title?: string;
|
|
7
|
+
patches?: unknown[];
|
|
8
|
+
done?: boolean;
|
|
9
|
+
x?: number;
|
|
10
|
+
y?: number;
|
|
11
|
+
width?: number;
|
|
12
|
+
height?: number;
|
|
13
|
+
strictSize?: boolean;
|
|
14
|
+
}
|
|
15
|
+
export interface StreamJsonRenderResult {
|
|
16
|
+
id: string;
|
|
17
|
+
url: string;
|
|
18
|
+
ok: true;
|
|
19
|
+
applied: number;
|
|
20
|
+
skipped: number;
|
|
21
|
+
specVersion: number;
|
|
22
|
+
elementCount: number;
|
|
23
|
+
streamStatus: 'open' | 'closed';
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Create-or-append core for streaming json-render nodes (the SDK's
|
|
27
|
+
* streamJsonRenderNode wraps this directly). Throws OperationError(400) when
|
|
28
|
+
* the append target is missing or not a json-render node.
|
|
29
|
+
*/
|
|
30
|
+
export declare function streamJsonRenderCore(input: StreamJsonRenderInput): StreamJsonRenderResult;
|
|
31
|
+
export declare const jsonRenderOperations: Operation[];
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { type CanvasLayout, type CanvasNodeState } from '../../canvas-state.js';
|
|
2
|
+
import { type Operation } from '../types.js';
|
|
3
|
+
export declare const NODE_TYPES: readonly ["markdown", "status", "context", "ledger", "trace", "file", "image", "mcp-app", "webpage", "html", "group"];
|
|
4
|
+
/** Per-type default node frame size (formerly copy-pasted ladders). */
|
|
5
|
+
export declare function defaultNodeSize(type: string): {
|
|
6
|
+
width: number;
|
|
7
|
+
height: number;
|
|
8
|
+
};
|
|
9
|
+
export declare function isRecord(value: unknown): value is Record<string, unknown>;
|
|
10
|
+
export declare function pickFiniteNumber(record: Record<string, unknown>, key: string): number | undefined;
|
|
11
|
+
export declare function getRecord(value: unknown): Record<string, unknown> | undefined;
|
|
12
|
+
export declare function pickPositiveNumber(record: Record<string, unknown>, key: string): number | undefined;
|
|
13
|
+
export declare function resolveCreateGeometry(body: Record<string, unknown>): {
|
|
14
|
+
x?: number;
|
|
15
|
+
y?: number;
|
|
16
|
+
width?: number;
|
|
17
|
+
height?: number;
|
|
18
|
+
};
|
|
19
|
+
export declare function setGroupChildrenFromApi(groupId: string, childIds: string[]): boolean;
|
|
20
|
+
export declare function nodeAppSessionId(node: CanvasNodeState | undefined): string | null;
|
|
21
|
+
export declare function closeNodeAppSession(node: CanvasNodeState | undefined): void;
|
|
22
|
+
export declare function buildNodeResponse(node: CanvasNodeState): Record<string, unknown>;
|
|
23
|
+
export declare function wantsFullPayload(input?: Record<string, unknown>): boolean;
|
|
24
|
+
export declare function compactNodePayload(node: CanvasNodeState | undefined): Record<string, unknown> | null;
|
|
25
|
+
export declare function buildSummaryFromLayout(layout: CanvasLayout, pinnedIds: string[]): Record<string, unknown>;
|
|
26
|
+
export declare function compactLayoutPayload(layout: CanvasLayout, pinnedIds: string[]): Record<string, unknown>;
|
|
27
|
+
export declare function agentSafeFullLayoutPayload(layout: CanvasLayout): Record<string, unknown>;
|
|
28
|
+
/**
|
|
29
|
+
* Node-create/update MCP payload: exposes both `id` and a `nodeId` alias so
|
|
30
|
+
* agents using either key (or a cached schema) work — matching the
|
|
31
|
+
* external-app / web-artifact responses that already return both.
|
|
32
|
+
*/
|
|
33
|
+
export declare function createdNodePayloadFromNode(node: CanvasNodeState, options?: Record<string, unknown>): Record<string, unknown>;
|
|
34
|
+
/**
|
|
35
|
+
* Create a basic (non-webpage / non-group / non-primitive) node. Union of the
|
|
36
|
+
* legacy handleCanvasAddNode generic branch; the SDK passes fileMode 'path',
|
|
37
|
+
* the HTTP/MCP operation passes fileMode 'auto'.
|
|
38
|
+
*/
|
|
39
|
+
export declare function createBasicCanvasNode(body: Record<string, unknown>, options: {
|
|
40
|
+
fileMode: 'auto' | 'path';
|
|
41
|
+
}): {
|
|
42
|
+
node: CanvasNodeState;
|
|
43
|
+
needsCodeGraphRecompute: boolean;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Build a node patch with the full HTTP superset semantics (webpage
|
|
47
|
+
* titleSource, html top-level fields, axCapabilities merge, group children,
|
|
48
|
+
* structured spec/graph updates, trace fields). Throws OperationError on
|
|
49
|
+
* validation failures. The SDK's updateNode delegates here.
|
|
50
|
+
*/
|
|
51
|
+
export declare function buildNodePatch(existing: CanvasNodeState, body: Record<string, unknown>): {
|
|
52
|
+
patch: Partial<CanvasNodeState>;
|
|
53
|
+
groupChildIds?: string[];
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Remove a node (closing any mcp-app session). Missing id → OperationError 404
|
|
57
|
+
* on ALL surfaces (plan-005 deliberately unifies the old silent local success).
|
|
58
|
+
*/
|
|
59
|
+
export declare function removeNodeCore(id: string): {
|
|
60
|
+
needsCodeGraphRecompute: boolean;
|
|
61
|
+
};
|
|
62
|
+
export declare const nodeOperations: Operation[];
|