pmx-canvas 0.1.36 → 0.2.1
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 +447 -0
- package/Readme.md +2 -2
- package/dist/json-render/index.js +89 -334
- package/dist/types/mcp/canvas-access.d.ts +5 -171
- package/dist/types/server/ax-state-manager.d.ts +267 -0
- package/dist/types/server/ax-state.d.ts +3 -1
- package/dist/types/server/canvas-db.d.ts +13 -0
- package/dist/types/server/canvas-operations.d.ts +1 -12
- package/dist/types/server/canvas-state.d.ts +8 -23
- package/dist/types/server/index.d.ts +6 -24
- 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 +19 -1
- package/docs/ax-state-contract.md +72 -0
- package/docs/http-api.md +4 -0
- package/docs/mcp.md +61 -12
- 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/tech-debt-assessment-2026-06.md +90 -0
- package/package.json +3 -3
- package/skills/pmx-canvas/SKILL.md +221 -193
- package/skills/pmx-canvas/evals/evals.json +3 -3
- package/skills/pmx-canvas/references/ax-html-control-surface.md +93 -0
- package/skills/pmx-canvas/references/codex-app-adapter.md +13 -14
- package/skills/pmx-canvas/references/github-copilot-app-adapter.md +26 -11
- package/src/cli/agent.ts +52 -31
- package/src/mcp/canvas-access.ts +30 -830
- package/src/mcp/server.ts +162 -2014
- package/src/server/ax-context.ts +8 -1
- package/src/server/ax-state-manager.ts +826 -0
- package/src/server/ax-state.ts +10 -2
- package/src/server/canvas-db.ts +35 -0
- package/src/server/canvas-operations.ts +2 -328
- package/src/server/canvas-schema.ts +2 -2
- package/src/server/canvas-state.ts +103 -465
- package/src/server/index.ts +54 -190
- 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 +158 -2255
- package/src/server/web-artifacts.ts +6 -2
package/src/mcp/canvas-access.ts
CHANGED
|
@@ -6,100 +6,48 @@ import {
|
|
|
6
6
|
type CanvasEdge,
|
|
7
7
|
type CanvasLayout,
|
|
8
8
|
type CanvasNodeState,
|
|
9
|
-
type CanvasSnapshot,
|
|
10
9
|
type PmxCanvas,
|
|
11
10
|
} from '../server/index.js';
|
|
12
11
|
import type { PmxAxSource } from '../server/ax-state.js';
|
|
12
|
+
import {
|
|
13
|
+
HttpOperationInvoker,
|
|
14
|
+
LocalOperationInvoker,
|
|
15
|
+
type OperationInvoker,
|
|
16
|
+
} from '../server/operations/index.js';
|
|
13
17
|
|
|
14
|
-
type AddNodeInput = Parameters<PmxCanvas['addNode']>[0];
|
|
15
|
-
type AddWebpageNodeInput = Parameters<PmxCanvas['addWebpageNode']>[0];
|
|
16
18
|
type RefreshWebpageNodeResult = Awaited<ReturnType<PmxCanvas['refreshWebpageNode']>>;
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
type StreamJsonRenderNodeInput = Parameters<PmxCanvas['streamJsonRenderNode']>[0];
|
|
23
|
-
type StreamJsonRenderNodeResult = ReturnType<PmxCanvas['streamJsonRenderNode']>;
|
|
19
|
+
// openMcpApp / addDiagram / buildWebArtifact CanvasAccess methods + their type
|
|
20
|
+
// aliases removed with the standalone MCP tools (plan-008 Wave 4): those tools
|
|
21
|
+
// migrated to the operation registry (mcpapp.open / diagram.open /
|
|
22
|
+
// webartifact.build) and the composite/registry tools dispatch via the invoker,
|
|
23
|
+
// not CanvasAccess. The public SDK PmxCanvas methods are unchanged.
|
|
24
24
|
type AddHtmlNodeInput = Parameters<PmxCanvas['addHtmlNode']>[0];
|
|
25
25
|
type AddHtmlPrimitiveInput = Parameters<PmxCanvas['addHtmlPrimitive']>[0];
|
|
26
26
|
type AddHtmlPrimitiveResult = ReturnType<PmxCanvas['addHtmlPrimitive']>;
|
|
27
|
-
type AddGraphNodeInput = Parameters<PmxCanvas['addGraphNode']>[0];
|
|
28
|
-
type AddGraphNodeResult = ReturnType<PmxCanvas['addGraphNode']>;
|
|
29
|
-
type UpdateNodePatch = Parameters<PmxCanvas['updateNode']>[1];
|
|
30
|
-
type AddEdgeInput = Parameters<PmxCanvas['addEdge']>[0];
|
|
31
|
-
type CreateGroupInput = Parameters<PmxCanvas['createGroup']>[0];
|
|
32
|
-
type GroupNodesOptions = Parameters<PmxCanvas['groupNodes']>[2];
|
|
33
|
-
type ArrangeLayout = Parameters<PmxCanvas['arrange']>[0];
|
|
34
|
-
type FocusNodeResult = ReturnType<PmxCanvas['focusNode']>;
|
|
35
|
-
type FitViewOptions = Parameters<PmxCanvas['fitView']>[0];
|
|
36
|
-
type FitViewResult = ReturnType<PmxCanvas['fitView']>;
|
|
37
27
|
type AxStateResult = ReturnType<PmxCanvas['getAxState']>;
|
|
38
28
|
type AxContextResult = ReturnType<PmxCanvas['getAxContext']>;
|
|
39
|
-
type SetAxFocusResult = ReturnType<PmxCanvas['setAxFocus']>;
|
|
40
|
-
type RecordAxEventInput = Parameters<PmxCanvas['recordAxEvent']>[0];
|
|
41
|
-
type RecordAxEventResult = ReturnType<PmxCanvas['recordAxEvent']>;
|
|
42
|
-
type SendSteeringResult = ReturnType<PmxCanvas['sendSteering']>;
|
|
43
29
|
type SubmitAxInteractionInput = Parameters<PmxCanvas['submitAxInteraction']>[0];
|
|
44
30
|
type SubmitAxInteractionResult = ReturnType<PmxCanvas['submitAxInteraction']>;
|
|
45
31
|
type GetPendingSteeringResult = ReturnType<PmxCanvas['getPendingSteering']>;
|
|
46
32
|
type ListElicitationsResult = ReturnType<PmxCanvas['listElicitations']>;
|
|
47
|
-
type RequestElicitationInput = Parameters<PmxCanvas['requestElicitation']>[0];
|
|
48
|
-
type RequestElicitationResult = ReturnType<PmxCanvas['requestElicitation']>;
|
|
49
|
-
type RespondElicitationResult = ReturnType<PmxCanvas['respondElicitation']>;
|
|
50
33
|
type ListModeRequestsResult = ReturnType<PmxCanvas['listModeRequests']>;
|
|
51
|
-
type RequestModeInput = Parameters<PmxCanvas['requestMode']>[0];
|
|
52
|
-
type RequestModeResult = ReturnType<PmxCanvas['requestMode']>;
|
|
53
|
-
type ResolveModeRequestResult = ReturnType<PmxCanvas['resolveModeRequest']>;
|
|
54
34
|
type IngestActivityInput = Parameters<PmxCanvas['ingestActivity']>[0];
|
|
55
35
|
type IngestActivityResult = ReturnType<PmxCanvas['ingestActivity']>;
|
|
56
|
-
type AwaitApprovalResult = Awaited<ReturnType<PmxCanvas['awaitApproval']>>;
|
|
57
|
-
type AwaitElicitationResult = Awaited<ReturnType<PmxCanvas['awaitElicitation']>>;
|
|
58
|
-
type AwaitModeResult = Awaited<ReturnType<PmxCanvas['awaitMode']>>;
|
|
59
|
-
type GetCommandRegistryResult = ReturnType<PmxCanvas['getCommandRegistry']>;
|
|
60
|
-
type InvokeCommandResult = ReturnType<PmxCanvas['invokeCommand']>;
|
|
61
36
|
type GetPolicyResult = ReturnType<PmxCanvas['getPolicy']>;
|
|
62
|
-
type SetPolicyInput = Parameters<PmxCanvas['setPolicy']>[0];
|
|
63
|
-
type SetPolicyResult = ReturnType<PmxCanvas['setPolicy']>;
|
|
64
37
|
type GetAxTimelineQuery = Parameters<PmxCanvas['getAxTimeline']>[0];
|
|
65
38
|
type GetAxTimelineResult = ReturnType<PmxCanvas['getAxTimeline']>;
|
|
66
|
-
type AddWorkItemInput = Parameters<PmxCanvas['addWorkItem']>[0];
|
|
67
|
-
type AddWorkItemResult = ReturnType<PmxCanvas['addWorkItem']>;
|
|
68
|
-
type UpdateWorkItemPatch = Parameters<PmxCanvas['updateWorkItem']>[1];
|
|
69
|
-
type UpdateWorkItemResult = ReturnType<PmxCanvas['updateWorkItem']>;
|
|
70
39
|
type ListWorkItemsResult = ReturnType<PmxCanvas['listWorkItems']>;
|
|
71
|
-
type RequestApprovalInput = Parameters<PmxCanvas['requestApproval']>[0];
|
|
72
|
-
type RequestApprovalResult = ReturnType<PmxCanvas['requestApproval']>;
|
|
73
|
-
type ResolveApprovalResult = ReturnType<PmxCanvas['resolveApproval']>;
|
|
74
40
|
type ListApprovalGatesResult = ReturnType<PmxCanvas['listApprovalGates']>;
|
|
75
|
-
type AddEvidenceInput = Parameters<PmxCanvas['addEvidence']>[0];
|
|
76
|
-
type AddEvidenceResult = ReturnType<PmxCanvas['addEvidence']>;
|
|
77
|
-
type AddReviewAnnotationInput = Parameters<PmxCanvas['addReviewAnnotation']>[0];
|
|
78
|
-
type AddReviewAnnotationResult = ReturnType<PmxCanvas['addReviewAnnotation']>;
|
|
79
|
-
type UpdateReviewAnnotationPatch = Parameters<PmxCanvas['updateReviewAnnotation']>[1];
|
|
80
|
-
type UpdateReviewAnnotationResult = ReturnType<PmxCanvas['updateReviewAnnotation']>;
|
|
81
41
|
type ListReviewAnnotationsResult = ReturnType<PmxCanvas['listReviewAnnotations']>;
|
|
82
|
-
type GetHostCapabilityResult = ReturnType<PmxCanvas['getHostCapability']>;
|
|
83
|
-
type ReportHostCapabilityResult = ReturnType<PmxCanvas['reportHostCapability']>;
|
|
84
|
-
type SearchResult = ReturnType<PmxCanvas['search']>;
|
|
85
|
-
type UndoRedoResult = Awaited<ReturnType<PmxCanvas['undo']>>;
|
|
86
42
|
type HistoryResult = ReturnType<PmxCanvas['getHistory']>;
|
|
87
|
-
type SetContextPinsResult = ReturnType<PmxCanvas['setContextPins']>;
|
|
88
43
|
type RunBatchInput = Parameters<PmxCanvas['runBatch']>[0];
|
|
89
44
|
type RunBatchResult = Awaited<ReturnType<PmxCanvas['runBatch']>>;
|
|
90
|
-
type SnapshotListOptions = Parameters<PmxCanvas['listSnapshots']>[0];
|
|
91
|
-
type SnapshotList = ReturnType<PmxCanvas['listSnapshots']>;
|
|
92
|
-
type DeleteSnapshotResult = ReturnType<PmxCanvas['deleteSnapshot']>;
|
|
93
|
-
type GcSnapshotsOptions = Parameters<PmxCanvas['gcSnapshots']>[0];
|
|
94
|
-
type GcSnapshotsResult = ReturnType<PmxCanvas['gcSnapshots']>;
|
|
95
|
-
type DiffSnapshotResult = ReturnType<PmxCanvas['diffSnapshot']>;
|
|
96
45
|
type CodeGraphResult = ReturnType<PmxCanvas['getCodeGraph']>;
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
type AutomationWebViewStatus = Awaited<ReturnType<PmxCanvas['
|
|
102
|
-
type AutomationEvaluateResult = Awaited<ReturnType<PmxCanvas['evaluateAutomationWebView']>>;
|
|
46
|
+
// canvas_screenshot (the only webview tool still hand-written) needs the status
|
|
47
|
+
// + screenshot accessors; the other four webview methods (start/stop/evaluate/
|
|
48
|
+
// resize) migrated to the operation registry (plan-008 Wave 3) and were removed
|
|
49
|
+
// from CanvasAccess.
|
|
50
|
+
type AutomationWebViewStatus = Awaited<ReturnType<PmxCanvas['getAutomationWebViewStatus']>>;
|
|
103
51
|
type AutomationScreenshotOptions = Parameters<PmxCanvas['screenshotAutomationWebView']>[0];
|
|
104
52
|
|
|
105
53
|
interface HealthResponse {
|
|
@@ -112,124 +60,41 @@ interface NodeResponse {
|
|
|
112
60
|
node?: { id?: string };
|
|
113
61
|
}
|
|
114
62
|
|
|
115
|
-
interface JsonRenderNodeResponse extends NodeResponse {
|
|
116
|
-
url: string;
|
|
117
|
-
spec: AddJsonRenderNodeResult['spec'];
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
interface GraphNodeResponse extends NodeResponse {
|
|
121
|
-
url: string;
|
|
122
|
-
spec: AddGraphNodeResult['spec'];
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
interface SearchResponse {
|
|
126
|
-
results?: SearchResult;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
interface SnapshotSaveResponse {
|
|
130
|
-
snapshot?: CanvasSnapshot;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
interface WebViewEnvelope {
|
|
134
|
-
webview?: AutomationWebViewStatus;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
interface WebViewStopEnvelope extends WebViewEnvelope {
|
|
138
|
-
stopped?: boolean;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
interface WebViewEvaluateEnvelope {
|
|
142
|
-
value?: AutomationEvaluateResult;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
63
|
export interface CanvasAccess {
|
|
146
64
|
readonly port: number;
|
|
147
65
|
readonly remoteBaseUrl: string | null;
|
|
66
|
+
/** Operation-registry invoker (plan-005): local in-process or HTTP, matching the access mode. */
|
|
67
|
+
invoker(): OperationInvoker;
|
|
148
68
|
getLayout(): Promise<CanvasLayout>;
|
|
149
69
|
getNode(id: string): Promise<CanvasNodeState | undefined>;
|
|
150
|
-
addNode(input: AddNodeInput): Promise<string>;
|
|
151
|
-
addWebpageNode(input: AddWebpageNodeInput): Promise<Awaited<ReturnType<PmxCanvas['addWebpageNode']>>>;
|
|
152
70
|
refreshWebpageNode(id: string, url?: string): Promise<RefreshWebpageNodeResult>;
|
|
153
|
-
openMcpApp(input: OpenMcpAppInput): Promise<OpenMcpAppResult>;
|
|
154
|
-
addDiagram(input: AddDiagramInput): Promise<OpenMcpAppResult>;
|
|
155
|
-
addJsonRenderNode(input: AddJsonRenderNodeInput): Promise<AddJsonRenderNodeResult>;
|
|
156
|
-
streamJsonRenderNode(input: StreamJsonRenderNodeInput): Promise<StreamJsonRenderNodeResult>;
|
|
157
71
|
addHtmlNode(input: AddHtmlNodeInput): Promise<string>;
|
|
158
72
|
addHtmlPrimitive(input: AddHtmlPrimitiveInput): Promise<AddHtmlPrimitiveResult>;
|
|
159
|
-
addGraphNode(input: AddGraphNodeInput): Promise<AddGraphNodeResult>;
|
|
160
|
-
buildWebArtifact(input: WebArtifactInput): Promise<WebArtifactResult>;
|
|
161
|
-
updateNode(id: string, patch: UpdateNodePatch): Promise<void>;
|
|
162
|
-
removeNode(id: string): Promise<void>;
|
|
163
|
-
removeAnnotation(id: string): Promise<boolean>;
|
|
164
|
-
addEdge(input: AddEdgeInput): Promise<string>;
|
|
165
|
-
removeEdge(id: string): Promise<void>;
|
|
166
|
-
createGroup(input: CreateGroupInput): Promise<string>;
|
|
167
|
-
groupNodes(groupId: string, childIds: string[], options?: GroupNodesOptions): Promise<boolean>;
|
|
168
|
-
ungroupNodes(groupId: string): Promise<boolean>;
|
|
169
|
-
arrange(layout?: ArrangeLayout): Promise<void>;
|
|
170
|
-
focusNode(id: string, options?: { noPan?: boolean }): Promise<FocusNodeResult>;
|
|
171
|
-
fitView(options?: FitViewOptions): Promise<FitViewResult>;
|
|
172
73
|
getAxState(): Promise<AxStateResult>;
|
|
173
74
|
getAxContext(options?: { consumer?: string }): Promise<AxContextResult>;
|
|
174
|
-
setAxFocus(nodeIds: string[], options?: { source?: PmxAxSource }): Promise<SetAxFocusResult>;
|
|
175
|
-
recordAxEvent(input: RecordAxEventInput, options?: { source?: PmxAxSource }): Promise<RecordAxEventResult>;
|
|
176
|
-
sendSteering(message: string, options?: { source?: PmxAxSource }): Promise<SendSteeringResult>;
|
|
177
75
|
getAxTimeline(query?: GetAxTimelineQuery): Promise<GetAxTimelineResult>;
|
|
178
|
-
addWorkItem(input: AddWorkItemInput, options?: { source?: PmxAxSource }): Promise<AddWorkItemResult>;
|
|
179
|
-
updateWorkItem(id: string, patch: UpdateWorkItemPatch, options?: { source?: PmxAxSource }): Promise<UpdateWorkItemResult>;
|
|
180
76
|
listWorkItems(): Promise<ListWorkItemsResult>;
|
|
181
|
-
requestApproval(input: RequestApprovalInput, options?: { source?: PmxAxSource }): Promise<RequestApprovalResult>;
|
|
182
|
-
resolveApproval(id: string, decision: 'approved' | 'rejected', options?: { resolution?: string; source?: PmxAxSource }): Promise<ResolveApprovalResult>;
|
|
183
77
|
listApprovalGates(): Promise<ListApprovalGatesResult>;
|
|
184
|
-
addEvidence(input: AddEvidenceInput, options?: { source?: PmxAxSource }): Promise<AddEvidenceResult>;
|
|
185
|
-
addReviewAnnotation(input: AddReviewAnnotationInput, options?: { source?: PmxAxSource }): Promise<AddReviewAnnotationResult>;
|
|
186
|
-
updateReviewAnnotation(id: string, patch: UpdateReviewAnnotationPatch, options?: { source?: PmxAxSource }): Promise<UpdateReviewAnnotationResult>;
|
|
187
78
|
listReviewAnnotations(): Promise<ListReviewAnnotationsResult>;
|
|
188
|
-
getHostCapability(): Promise<GetHostCapabilityResult>;
|
|
189
|
-
reportHostCapability(input: unknown, options?: { source?: PmxAxSource }): Promise<ReportHostCapabilityResult>;
|
|
190
79
|
submitAxInteraction(input: SubmitAxInteractionInput, options?: { source?: PmxAxSource }): Promise<SubmitAxInteractionResult>;
|
|
191
80
|
getPendingSteering(options?: { consumer?: string; limit?: number }): Promise<GetPendingSteeringResult>;
|
|
192
|
-
markSteeringDelivered(id: string): Promise<boolean>;
|
|
193
81
|
listElicitations(): Promise<ListElicitationsResult>;
|
|
194
|
-
requestElicitation(input: RequestElicitationInput, options?: { source?: PmxAxSource }): Promise<RequestElicitationResult>;
|
|
195
|
-
respondElicitation(id: string, response: Record<string, unknown>, options?: { source?: PmxAxSource }): Promise<RespondElicitationResult>;
|
|
196
82
|
listModeRequests(): Promise<ListModeRequestsResult>;
|
|
197
|
-
requestMode(input: RequestModeInput, options?: { source?: PmxAxSource }): Promise<RequestModeResult>;
|
|
198
|
-
resolveModeRequest(id: string, decision: 'approved' | 'rejected', options?: { resolution?: string; source?: PmxAxSource }): Promise<ResolveModeRequestResult>;
|
|
199
83
|
ingestActivity(input: IngestActivityInput, options?: { source?: PmxAxSource }): Promise<IngestActivityResult>;
|
|
200
|
-
awaitApproval(id: string, options?: { timeoutMs?: number }): Promise<AwaitApprovalResult>;
|
|
201
|
-
awaitElicitation(id: string, options?: { timeoutMs?: number }): Promise<AwaitElicitationResult>;
|
|
202
|
-
awaitMode(id: string, options?: { timeoutMs?: number }): Promise<AwaitModeResult>;
|
|
203
|
-
getCommandRegistry(): Promise<GetCommandRegistryResult>;
|
|
204
|
-
invokeCommand(name: string, args?: Record<string, unknown> | null, options?: { source?: PmxAxSource }): Promise<InvokeCommandResult>;
|
|
205
84
|
getPolicy(): Promise<GetPolicyResult>;
|
|
206
|
-
setPolicy(patch: SetPolicyInput, options?: { source?: PmxAxSource }): Promise<SetPolicyResult>;
|
|
207
|
-
clear(): Promise<void>;
|
|
208
|
-
search(query: string): Promise<SearchResult>;
|
|
209
|
-
undo(): Promise<UndoRedoResult>;
|
|
210
|
-
redo(): Promise<UndoRedoResult>;
|
|
211
85
|
getHistory(): Promise<HistoryResult>;
|
|
212
|
-
setContextPins(nodeIds: string[], mode?: 'set' | 'add' | 'remove'): Promise<SetContextPinsResult>;
|
|
213
86
|
getPinnedNodeIds(): Promise<string[]>;
|
|
214
87
|
runBatch(operations: RunBatchInput): Promise<RunBatchResult>;
|
|
215
|
-
listSnapshots(options?: SnapshotListOptions): Promise<SnapshotList>;
|
|
216
|
-
saveSnapshot(name: string): Promise<CanvasSnapshot | null>;
|
|
217
|
-
restoreSnapshot(id: string): Promise<{ ok: boolean }>;
|
|
218
|
-
deleteSnapshot(id: string): Promise<DeleteSnapshotResult>;
|
|
219
|
-
gcSnapshots(options?: GcSnapshotsOptions): Promise<GcSnapshotsResult>;
|
|
220
|
-
diffSnapshot(idOrName: string): Promise<DiffSnapshotResult>;
|
|
221
88
|
getCodeGraph(): Promise<CodeGraphResult>;
|
|
222
|
-
|
|
89
|
+
// canvas_screenshot (still hand-written — binary payload) is the only webview
|
|
90
|
+
// tool left on CanvasAccess; it needs the status + screenshot accessors.
|
|
223
91
|
getAutomationWebViewStatus(): Promise<AutomationWebViewStatus>;
|
|
224
|
-
startAutomationWebView(options?: AutomationWebViewOptions): Promise<AutomationWebViewStatus>;
|
|
225
|
-
stopAutomationWebView(): Promise<boolean>;
|
|
226
|
-
evaluateAutomationWebView(expression: string): Promise<AutomationEvaluateResult>;
|
|
227
|
-
resizeAutomationWebView(width: number, height: number): Promise<AutomationWebViewStatus>;
|
|
228
92
|
screenshotAutomationWebView(options?: AutomationScreenshotOptions): Promise<Uint8Array>;
|
|
229
93
|
}
|
|
230
94
|
|
|
231
95
|
class LocalCanvasAccess implements CanvasAccess {
|
|
232
96
|
readonly remoteBaseUrl = null;
|
|
97
|
+
private readonly operationInvoker = new LocalOperationInvoker();
|
|
233
98
|
|
|
234
99
|
constructor(
|
|
235
100
|
private readonly canvas: PmxCanvas,
|
|
@@ -241,6 +106,10 @@ class LocalCanvasAccess implements CanvasAccess {
|
|
|
241
106
|
return this.canvas.port;
|
|
242
107
|
}
|
|
243
108
|
|
|
109
|
+
invoker(): OperationInvoker {
|
|
110
|
+
return this.operationInvoker;
|
|
111
|
+
}
|
|
112
|
+
|
|
244
113
|
async getLayout(): Promise<CanvasLayout> {
|
|
245
114
|
return this.canvas.getLayout();
|
|
246
115
|
}
|
|
@@ -249,36 +118,10 @@ class LocalCanvasAccess implements CanvasAccess {
|
|
|
249
118
|
return this.canvas.getNode(id);
|
|
250
119
|
}
|
|
251
120
|
|
|
252
|
-
async addNode(input: AddNodeInput): Promise<string> {
|
|
253
|
-
// PmxCanvas.addNode returns the created node; the CanvasAccess contract
|
|
254
|
-
// (shared with the remote proxy + MCP) stays id-only.
|
|
255
|
-
return this.canvas.addNode(input).id;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
async addWebpageNode(input: AddWebpageNodeInput): Promise<Awaited<ReturnType<PmxCanvas['addWebpageNode']>>> {
|
|
259
|
-
return await this.canvas.addWebpageNode(input);
|
|
260
|
-
}
|
|
261
|
-
|
|
262
121
|
async refreshWebpageNode(id: string, url?: string): Promise<RefreshWebpageNodeResult> {
|
|
263
122
|
return await this.canvas.refreshWebpageNode(id, url);
|
|
264
123
|
}
|
|
265
124
|
|
|
266
|
-
async openMcpApp(input: OpenMcpAppInput): Promise<OpenMcpAppResult> {
|
|
267
|
-
return await this.canvas.openMcpApp(input);
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
async addDiagram(input: AddDiagramInput): Promise<OpenMcpAppResult> {
|
|
271
|
-
return await this.canvas.addDiagram(input);
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
async addJsonRenderNode(input: AddJsonRenderNodeInput): Promise<AddJsonRenderNodeResult> {
|
|
275
|
-
return this.canvas.addJsonRenderNode(input);
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
async streamJsonRenderNode(input: StreamJsonRenderNodeInput): Promise<StreamJsonRenderNodeResult> {
|
|
279
|
-
return this.canvas.streamJsonRenderNode(input);
|
|
280
|
-
}
|
|
281
|
-
|
|
282
125
|
async addHtmlNode(input: AddHtmlNodeInput): Promise<string> {
|
|
283
126
|
// PmxCanvas.addHtmlNode returns the created node; the CanvasAccess contract
|
|
284
127
|
// is a bare id string, so extract it (mirrors addNode above).
|
|
@@ -289,58 +132,6 @@ class LocalCanvasAccess implements CanvasAccess {
|
|
|
289
132
|
return this.canvas.addHtmlPrimitive(input);
|
|
290
133
|
}
|
|
291
134
|
|
|
292
|
-
async addGraphNode(input: AddGraphNodeInput): Promise<AddGraphNodeResult> {
|
|
293
|
-
return this.canvas.addGraphNode(input);
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
async buildWebArtifact(input: WebArtifactInput): Promise<WebArtifactResult> {
|
|
297
|
-
return await this.canvas.buildWebArtifact(input);
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
async updateNode(id: string, patch: UpdateNodePatch): Promise<void> {
|
|
301
|
-
this.canvas.updateNode(id, patch);
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
async removeNode(id: string): Promise<void> {
|
|
305
|
-
this.canvas.removeNode(id);
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
async removeAnnotation(id: string): Promise<boolean> {
|
|
309
|
-
return this.canvas.removeAnnotation(id);
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
async addEdge(input: AddEdgeInput): Promise<string> {
|
|
313
|
-
return this.canvas.addEdge(input);
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
async removeEdge(id: string): Promise<void> {
|
|
317
|
-
this.canvas.removeEdge(id);
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
async createGroup(input: CreateGroupInput): Promise<string> {
|
|
321
|
-
return this.canvas.createGroup(input);
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
async groupNodes(groupId: string, childIds: string[], options?: GroupNodesOptions): Promise<boolean> {
|
|
325
|
-
return this.canvas.groupNodes(groupId, childIds, options);
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
async ungroupNodes(groupId: string): Promise<boolean> {
|
|
329
|
-
return this.canvas.ungroupNodes(groupId);
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
async arrange(layout?: ArrangeLayout): Promise<void> {
|
|
333
|
-
this.canvas.arrange(layout);
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
async focusNode(id: string, options?: { noPan?: boolean }): Promise<FocusNodeResult> {
|
|
337
|
-
return this.canvas.focusNode(id, options);
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
async fitView(options?: FitViewOptions): Promise<FitViewResult> {
|
|
341
|
-
return this.canvas.fitView(options);
|
|
342
|
-
}
|
|
343
|
-
|
|
344
135
|
async getAxState(): Promise<AxStateResult> {
|
|
345
136
|
return this.canvas.getAxState();
|
|
346
137
|
}
|
|
@@ -349,26 +140,10 @@ class LocalCanvasAccess implements CanvasAccess {
|
|
|
349
140
|
return this.canvas.getAxContext(options);
|
|
350
141
|
}
|
|
351
142
|
|
|
352
|
-
async setAxFocus(nodeIds: string[], options?: { source?: PmxAxSource }): Promise<SetAxFocusResult> {
|
|
353
|
-
return this.canvas.setAxFocus(nodeIds, { source: options?.source ?? 'mcp' });
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
async recordAxEvent(input: RecordAxEventInput, options?: { source?: PmxAxSource }): Promise<RecordAxEventResult> {
|
|
357
|
-
return this.canvas.recordAxEvent(input, { source: options?.source ?? 'mcp' });
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
async sendSteering(message: string, options?: { source?: PmxAxSource }): Promise<SendSteeringResult> {
|
|
361
|
-
return this.canvas.sendSteering(message, { source: options?.source ?? 'mcp' });
|
|
362
|
-
}
|
|
363
|
-
|
|
364
143
|
async getAxTimeline(query?: GetAxTimelineQuery): Promise<GetAxTimelineResult> {
|
|
365
144
|
return this.canvas.getAxTimeline(query);
|
|
366
145
|
}
|
|
367
146
|
|
|
368
|
-
async addWorkItem(input: AddWorkItemInput, options?: { source?: PmxAxSource }): Promise<AddWorkItemResult> {
|
|
369
|
-
return this.canvas.addWorkItem(input, { source: options?.source ?? 'mcp' });
|
|
370
|
-
}
|
|
371
|
-
|
|
372
147
|
async submitAxInteraction(input: SubmitAxInteractionInput, options?: { source?: PmxAxSource }): Promise<SubmitAxInteractionResult> {
|
|
373
148
|
return this.canvas.submitAxInteraction(input, { source: options?.source ?? 'mcp' });
|
|
374
149
|
}
|
|
@@ -377,137 +152,38 @@ class LocalCanvasAccess implements CanvasAccess {
|
|
|
377
152
|
return this.canvas.getPendingSteering(options);
|
|
378
153
|
}
|
|
379
154
|
|
|
380
|
-
async markSteeringDelivered(id: string): Promise<boolean> {
|
|
381
|
-
return this.canvas.markSteeringDelivered(id);
|
|
382
|
-
}
|
|
383
|
-
|
|
384
155
|
async listElicitations(): Promise<ListElicitationsResult> {
|
|
385
156
|
return this.canvas.listElicitations();
|
|
386
157
|
}
|
|
387
158
|
|
|
388
|
-
async requestElicitation(input: RequestElicitationInput, options?: { source?: PmxAxSource }): Promise<RequestElicitationResult> {
|
|
389
|
-
return this.canvas.requestElicitation(input, { source: options?.source ?? 'mcp' });
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
async respondElicitation(id: string, response: Record<string, unknown>, options?: { source?: PmxAxSource }): Promise<RespondElicitationResult> {
|
|
393
|
-
return this.canvas.respondElicitation(id, response, { source: options?.source ?? 'mcp' });
|
|
394
|
-
}
|
|
395
|
-
|
|
396
159
|
async listModeRequests(): Promise<ListModeRequestsResult> {
|
|
397
160
|
return this.canvas.listModeRequests();
|
|
398
161
|
}
|
|
399
162
|
|
|
400
|
-
async requestMode(input: RequestModeInput, options?: { source?: PmxAxSource }): Promise<RequestModeResult> {
|
|
401
|
-
return this.canvas.requestMode(input, { source: options?.source ?? 'mcp' });
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
async resolveModeRequest(id: string, decision: 'approved' | 'rejected', options?: { resolution?: string; source?: PmxAxSource }): Promise<ResolveModeRequestResult> {
|
|
405
|
-
return this.canvas.resolveModeRequest(id, decision, { ...(options ?? {}), source: options?.source ?? 'mcp' });
|
|
406
|
-
}
|
|
407
|
-
|
|
408
163
|
async ingestActivity(input: IngestActivityInput, options?: { source?: PmxAxSource }): Promise<IngestActivityResult> {
|
|
409
164
|
return this.canvas.ingestActivity(input, { source: options?.source ?? 'mcp' });
|
|
410
165
|
}
|
|
411
166
|
|
|
412
|
-
async awaitApproval(id: string, options?: { timeoutMs?: number }): Promise<AwaitApprovalResult> {
|
|
413
|
-
return this.canvas.awaitApproval(id, options);
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
async awaitElicitation(id: string, options?: { timeoutMs?: number }): Promise<AwaitElicitationResult> {
|
|
417
|
-
return this.canvas.awaitElicitation(id, options);
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
async awaitMode(id: string, options?: { timeoutMs?: number }): Promise<AwaitModeResult> {
|
|
421
|
-
return this.canvas.awaitMode(id, options);
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
async getCommandRegistry(): Promise<GetCommandRegistryResult> {
|
|
425
|
-
return this.canvas.getCommandRegistry();
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
async invokeCommand(name: string, args?: Record<string, unknown> | null, options?: { source?: PmxAxSource }): Promise<InvokeCommandResult> {
|
|
429
|
-
return this.canvas.invokeCommand(name, args ?? null, { source: options?.source ?? 'mcp' });
|
|
430
|
-
}
|
|
431
|
-
|
|
432
167
|
async getPolicy(): Promise<GetPolicyResult> {
|
|
433
168
|
return this.canvas.getPolicy();
|
|
434
169
|
}
|
|
435
170
|
|
|
436
|
-
async setPolicy(patch: SetPolicyInput, options?: { source?: PmxAxSource }): Promise<SetPolicyResult> {
|
|
437
|
-
return this.canvas.setPolicy(patch, { source: options?.source ?? 'mcp' });
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
async updateWorkItem(id: string, patch: UpdateWorkItemPatch, options?: { source?: PmxAxSource }): Promise<UpdateWorkItemResult> {
|
|
441
|
-
return this.canvas.updateWorkItem(id, patch, { source: options?.source ?? 'mcp' });
|
|
442
|
-
}
|
|
443
|
-
|
|
444
171
|
async listWorkItems(): Promise<ListWorkItemsResult> {
|
|
445
172
|
return this.canvas.listWorkItems();
|
|
446
173
|
}
|
|
447
174
|
|
|
448
|
-
async requestApproval(input: RequestApprovalInput, options?: { source?: PmxAxSource }): Promise<RequestApprovalResult> {
|
|
449
|
-
return this.canvas.requestApproval(input, { source: options?.source ?? 'mcp' });
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
async resolveApproval(id: string, decision: 'approved' | 'rejected', options?: { resolution?: string; source?: PmxAxSource }): Promise<ResolveApprovalResult> {
|
|
453
|
-
return this.canvas.resolveApproval(id, decision, {
|
|
454
|
-
...(options?.resolution !== undefined ? { resolution: options.resolution } : {}),
|
|
455
|
-
source: options?.source ?? 'mcp',
|
|
456
|
-
});
|
|
457
|
-
}
|
|
458
|
-
|
|
459
175
|
async listApprovalGates(): Promise<ListApprovalGatesResult> {
|
|
460
176
|
return this.canvas.listApprovalGates();
|
|
461
177
|
}
|
|
462
178
|
|
|
463
|
-
async addEvidence(input: AddEvidenceInput, options?: { source?: PmxAxSource }): Promise<AddEvidenceResult> {
|
|
464
|
-
return this.canvas.addEvidence(input, { source: options?.source ?? 'mcp' });
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
async addReviewAnnotation(input: AddReviewAnnotationInput, options?: { source?: PmxAxSource }): Promise<AddReviewAnnotationResult> {
|
|
468
|
-
return this.canvas.addReviewAnnotation(input, { source: options?.source ?? 'mcp' });
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
async updateReviewAnnotation(id: string, patch: UpdateReviewAnnotationPatch, options?: { source?: PmxAxSource }): Promise<UpdateReviewAnnotationResult> {
|
|
472
|
-
return this.canvas.updateReviewAnnotation(id, patch, { source: options?.source ?? 'mcp' });
|
|
473
|
-
}
|
|
474
|
-
|
|
475
179
|
async listReviewAnnotations(): Promise<ListReviewAnnotationsResult> {
|
|
476
180
|
return this.canvas.listReviewAnnotations();
|
|
477
181
|
}
|
|
478
182
|
|
|
479
|
-
async getHostCapability(): Promise<GetHostCapabilityResult> {
|
|
480
|
-
return this.canvas.getHostCapability();
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
async reportHostCapability(input: unknown, options?: { source?: PmxAxSource }): Promise<ReportHostCapabilityResult> {
|
|
484
|
-
return this.canvas.reportHostCapability(input, { source: options?.source ?? 'mcp' });
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
async clear(): Promise<void> {
|
|
488
|
-
this.canvas.clear();
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
async search(query: string): Promise<SearchResult> {
|
|
492
|
-
return this.canvas.search(query);
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
async undo(): Promise<UndoRedoResult> {
|
|
496
|
-
return await this.canvas.undo();
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
async redo(): Promise<UndoRedoResult> {
|
|
500
|
-
return await this.canvas.redo();
|
|
501
|
-
}
|
|
502
|
-
|
|
503
183
|
async getHistory(): Promise<HistoryResult> {
|
|
504
184
|
return this.canvas.getHistory();
|
|
505
185
|
}
|
|
506
186
|
|
|
507
|
-
async setContextPins(nodeIds: string[], mode: 'set' | 'add' | 'remove' = 'set'): Promise<SetContextPinsResult> {
|
|
508
|
-
return this.canvas.setContextPins(nodeIds, mode);
|
|
509
|
-
}
|
|
510
|
-
|
|
511
187
|
async getPinnedNodeIds(): Promise<string[]> {
|
|
512
188
|
return Array.from(canvasState.contextPinnedNodeIds);
|
|
513
189
|
}
|
|
@@ -516,58 +192,14 @@ class LocalCanvasAccess implements CanvasAccess {
|
|
|
516
192
|
return await this.canvas.runBatch(operations);
|
|
517
193
|
}
|
|
518
194
|
|
|
519
|
-
async listSnapshots(options?: SnapshotListOptions): Promise<SnapshotList> {
|
|
520
|
-
return this.canvas.listSnapshots(options);
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
async saveSnapshot(name: string): Promise<CanvasSnapshot | null> {
|
|
524
|
-
return this.canvas.saveSnapshot(name);
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
async restoreSnapshot(id: string): Promise<{ ok: boolean }> {
|
|
528
|
-
return await this.canvas.restoreSnapshot(id);
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
async deleteSnapshot(id: string): Promise<DeleteSnapshotResult> {
|
|
532
|
-
return this.canvas.deleteSnapshot(id);
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
async gcSnapshots(options?: GcSnapshotsOptions): Promise<GcSnapshotsResult> {
|
|
536
|
-
return this.canvas.gcSnapshots(options);
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
async diffSnapshot(idOrName: string): Promise<DiffSnapshotResult> {
|
|
540
|
-
return this.canvas.diffSnapshot(idOrName);
|
|
541
|
-
}
|
|
542
|
-
|
|
543
195
|
async getCodeGraph(): Promise<CodeGraphResult> {
|
|
544
196
|
return this.canvas.getCodeGraph();
|
|
545
197
|
}
|
|
546
198
|
|
|
547
|
-
async validate(): Promise<ValidationResult> {
|
|
548
|
-
return this.canvas.validate();
|
|
549
|
-
}
|
|
550
|
-
|
|
551
199
|
async getAutomationWebViewStatus(): Promise<AutomationWebViewStatus> {
|
|
552
200
|
return this.canvas.getAutomationWebViewStatus();
|
|
553
201
|
}
|
|
554
202
|
|
|
555
|
-
async startAutomationWebView(options: AutomationWebViewOptions = {}): Promise<AutomationWebViewStatus> {
|
|
556
|
-
return await this.canvas.startAutomationWebView(options);
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
async stopAutomationWebView(): Promise<boolean> {
|
|
560
|
-
return await this.canvas.stopAutomationWebView();
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
async evaluateAutomationWebView(expression: string): Promise<AutomationEvaluateResult> {
|
|
564
|
-
return await this.canvas.evaluateAutomationWebView(expression);
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
async resizeAutomationWebView(width: number, height: number): Promise<AutomationWebViewStatus> {
|
|
568
|
-
return await this.canvas.resizeAutomationWebView(width, height);
|
|
569
|
-
}
|
|
570
|
-
|
|
571
203
|
async screenshotAutomationWebView(options: AutomationScreenshotOptions = {}): Promise<Uint8Array> {
|
|
572
204
|
return await this.canvas.screenshotAutomationWebView(options);
|
|
573
205
|
}
|
|
@@ -576,11 +208,17 @@ class LocalCanvasAccess implements CanvasAccess {
|
|
|
576
208
|
class RemoteCanvasAccess implements CanvasAccess {
|
|
577
209
|
readonly remoteBaseUrl: string;
|
|
578
210
|
readonly port: number;
|
|
211
|
+
private readonly operationInvoker: HttpOperationInvoker;
|
|
579
212
|
|
|
580
213
|
constructor(baseUrl: string) {
|
|
581
214
|
this.remoteBaseUrl = baseUrl.replace(/\/$/, '');
|
|
582
215
|
const parsed = new URL(this.remoteBaseUrl);
|
|
583
216
|
this.port = Number(parsed.port || '80');
|
|
217
|
+
this.operationInvoker = new HttpOperationInvoker(this.remoteBaseUrl);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
invoker(): OperationInvoker {
|
|
221
|
+
return this.operationInvoker;
|
|
584
222
|
}
|
|
585
223
|
|
|
586
224
|
private async requestJson<T>(method: string, path: string, body?: unknown): Promise<T> {
|
|
@@ -646,61 +284,12 @@ class RemoteCanvasAccess implements CanvasAccess {
|
|
|
646
284
|
return parsed as CanvasNodeState;
|
|
647
285
|
}
|
|
648
286
|
|
|
649
|
-
async addNode(input: AddNodeInput): Promise<string> {
|
|
650
|
-
return await this.requestNodeId('POST', '/api/canvas/node', input);
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
async addWebpageNode(input: AddWebpageNodeInput): Promise<Awaited<ReturnType<PmxCanvas['addWebpageNode']>>> {
|
|
654
|
-
return await this.requestJson<Awaited<ReturnType<PmxCanvas['addWebpageNode']>>>('POST', '/api/canvas/node', {
|
|
655
|
-
type: 'webpage',
|
|
656
|
-
...input,
|
|
657
|
-
});
|
|
658
|
-
}
|
|
659
|
-
|
|
660
287
|
async refreshWebpageNode(id: string, url?: string): Promise<RefreshWebpageNodeResult> {
|
|
661
288
|
return await this.requestJson<RefreshWebpageNodeResult>('POST', `/api/canvas/node/${encodeURIComponent(id)}/refresh`, {
|
|
662
289
|
...(url ? { url } : {}),
|
|
663
290
|
});
|
|
664
291
|
}
|
|
665
292
|
|
|
666
|
-
async openMcpApp(input: OpenMcpAppInput): Promise<OpenMcpAppResult> {
|
|
667
|
-
return await this.requestJson<OpenMcpAppResult>('POST', '/api/canvas/mcp-app/open', input);
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
async addDiagram(input: AddDiagramInput): Promise<OpenMcpAppResult> {
|
|
671
|
-
return await this.requestJson<OpenMcpAppResult>('POST', '/api/canvas/diagram', input);
|
|
672
|
-
}
|
|
673
|
-
|
|
674
|
-
async addJsonRenderNode(input: AddJsonRenderNodeInput): Promise<AddJsonRenderNodeResult> {
|
|
675
|
-
const response = await this.requestJson<JsonRenderNodeResponse>('POST', '/api/canvas/json-render', input);
|
|
676
|
-
const id = typeof response.id === 'string' ? response.id : response.node?.id;
|
|
677
|
-
if (!id) throw new Error('json-render response did not include a node id.');
|
|
678
|
-
return { id, url: response.url, spec: response.spec };
|
|
679
|
-
}
|
|
680
|
-
|
|
681
|
-
async streamJsonRenderNode(input: StreamJsonRenderNodeInput): Promise<StreamJsonRenderNodeResult> {
|
|
682
|
-
const response = await this.requestJson<{
|
|
683
|
-
id?: string;
|
|
684
|
-
url?: string;
|
|
685
|
-
applied?: number;
|
|
686
|
-
skipped?: number;
|
|
687
|
-
specVersion?: number;
|
|
688
|
-
elementCount?: number;
|
|
689
|
-
streamStatus?: 'open' | 'closed';
|
|
690
|
-
}>('POST', '/api/canvas/json-render/stream', input);
|
|
691
|
-
const id = typeof response.id === 'string' ? response.id : undefined;
|
|
692
|
-
if (!id) throw new Error('json-render stream response did not include a node id.');
|
|
693
|
-
return {
|
|
694
|
-
id,
|
|
695
|
-
url: response.url ?? '',
|
|
696
|
-
applied: response.applied ?? 0,
|
|
697
|
-
skipped: response.skipped ?? 0,
|
|
698
|
-
specVersion: response.specVersion ?? 0,
|
|
699
|
-
elementCount: response.elementCount ?? 0,
|
|
700
|
-
streamStatus: response.streamStatus ?? 'open',
|
|
701
|
-
};
|
|
702
|
-
}
|
|
703
|
-
|
|
704
293
|
async addHtmlNode(input: AddHtmlNodeInput): Promise<string> {
|
|
705
294
|
const {
|
|
706
295
|
summary,
|
|
@@ -754,98 +343,6 @@ class RemoteCanvasAccess implements CanvasAccess {
|
|
|
754
343
|
};
|
|
755
344
|
}
|
|
756
345
|
|
|
757
|
-
async addGraphNode(input: AddGraphNodeInput): Promise<AddGraphNodeResult> {
|
|
758
|
-
const response = await this.requestJson<GraphNodeResponse>('POST', '/api/canvas/graph', {
|
|
759
|
-
...input,
|
|
760
|
-
...(typeof input.heightPx === 'number' ? { nodeHeight: input.heightPx } : {}),
|
|
761
|
-
});
|
|
762
|
-
const id = typeof response.id === 'string' ? response.id : response.node?.id;
|
|
763
|
-
if (!id) throw new Error('graph response did not include a node id.');
|
|
764
|
-
return { id, url: response.url, spec: response.spec };
|
|
765
|
-
}
|
|
766
|
-
|
|
767
|
-
async buildWebArtifact(input: WebArtifactInput): Promise<WebArtifactResult> {
|
|
768
|
-
return await this.requestJson<WebArtifactResult>('POST', '/api/canvas/web-artifact', input);
|
|
769
|
-
}
|
|
770
|
-
|
|
771
|
-
async updateNode(id: string, patch: UpdateNodePatch): Promise<void> {
|
|
772
|
-
await this.requestJson<unknown>('PATCH', `/api/canvas/node/${encodeURIComponent(id)}`, patch);
|
|
773
|
-
}
|
|
774
|
-
|
|
775
|
-
async removeNode(id: string): Promise<void> {
|
|
776
|
-
await this.requestJson<unknown>('DELETE', `/api/canvas/node/${encodeURIComponent(id)}`);
|
|
777
|
-
}
|
|
778
|
-
|
|
779
|
-
async removeAnnotation(id: string): Promise<boolean> {
|
|
780
|
-
const response = await this.requestJson<{ ok?: boolean }>('DELETE', `/api/canvas/annotation/${encodeURIComponent(id)}`);
|
|
781
|
-
return response.ok === true;
|
|
782
|
-
}
|
|
783
|
-
|
|
784
|
-
async addEdge(input: AddEdgeInput): Promise<string> {
|
|
785
|
-
const response = await this.requestJson<{ id?: string }>('POST', '/api/canvas/edge', input);
|
|
786
|
-
if (!response.id) throw new Error('Canvas edge response did not include an edge id.');
|
|
787
|
-
return response.id;
|
|
788
|
-
}
|
|
789
|
-
|
|
790
|
-
async removeEdge(id: string): Promise<void> {
|
|
791
|
-
await this.requestJson<unknown>('DELETE', '/api/canvas/edge', { edge_id: id });
|
|
792
|
-
}
|
|
793
|
-
|
|
794
|
-
async createGroup(input: CreateGroupInput): Promise<string> {
|
|
795
|
-
return await this.requestNodeId('POST', '/api/canvas/group', input);
|
|
796
|
-
}
|
|
797
|
-
|
|
798
|
-
async groupNodes(groupId: string, childIds: string[], options?: GroupNodesOptions): Promise<boolean> {
|
|
799
|
-
const response = await this.requestJson<{ ok?: boolean }>('POST', '/api/canvas/group/add', {
|
|
800
|
-
groupId,
|
|
801
|
-
childIds,
|
|
802
|
-
...(options?.childLayout ? { childLayout: options.childLayout } : {}),
|
|
803
|
-
});
|
|
804
|
-
return response.ok === true;
|
|
805
|
-
}
|
|
806
|
-
|
|
807
|
-
async ungroupNodes(groupId: string): Promise<boolean> {
|
|
808
|
-
const response = await this.requestJson<{ ok?: boolean }>('POST', '/api/canvas/group/ungroup', { groupId });
|
|
809
|
-
return response.ok === true;
|
|
810
|
-
}
|
|
811
|
-
|
|
812
|
-
async arrange(layout?: ArrangeLayout): Promise<void> {
|
|
813
|
-
await this.requestJson<unknown>('POST', '/api/canvas/arrange', { ...(layout ? { layout } : {}) });
|
|
814
|
-
}
|
|
815
|
-
|
|
816
|
-
async focusNode(id: string, options?: { noPan?: boolean }): Promise<FocusNodeResult> {
|
|
817
|
-
const response = await fetch(`${this.remoteBaseUrl}/api/canvas/focus`, {
|
|
818
|
-
method: 'POST',
|
|
819
|
-
headers: { 'Content-Type': 'application/json' },
|
|
820
|
-
body: JSON.stringify({ id, ...(options?.noPan === true ? { noPan: true } : {}) }),
|
|
821
|
-
});
|
|
822
|
-
if (response.status === 404) return null;
|
|
823
|
-
const parsed = await response.json() as { focused?: string; panned?: boolean };
|
|
824
|
-
if (!response.ok || typeof parsed.focused !== 'string' || typeof parsed.panned !== 'boolean') return null;
|
|
825
|
-
return { focused: parsed.focused, panned: parsed.panned };
|
|
826
|
-
}
|
|
827
|
-
|
|
828
|
-
async fitView(options?: FitViewOptions): Promise<FitViewResult> {
|
|
829
|
-
return await this.requestJson<FitViewResult>('POST', '/api/canvas/fit', options ?? {});
|
|
830
|
-
}
|
|
831
|
-
|
|
832
|
-
async clear(): Promise<void> {
|
|
833
|
-
await this.requestJson<unknown>('POST', '/api/canvas/clear', {});
|
|
834
|
-
}
|
|
835
|
-
|
|
836
|
-
async search(query: string): Promise<SearchResult> {
|
|
837
|
-
const response = await this.requestJson<SearchResponse>('GET', `/api/canvas/search?q=${encodeURIComponent(query)}`);
|
|
838
|
-
return response.results ?? [];
|
|
839
|
-
}
|
|
840
|
-
|
|
841
|
-
async undo(): Promise<UndoRedoResult> {
|
|
842
|
-
return await this.requestJson<UndoRedoResult>('POST', '/api/canvas/undo', {});
|
|
843
|
-
}
|
|
844
|
-
|
|
845
|
-
async redo(): Promise<UndoRedoResult> {
|
|
846
|
-
return await this.requestJson<UndoRedoResult>('POST', '/api/canvas/redo', {});
|
|
847
|
-
}
|
|
848
|
-
|
|
849
346
|
async getHistory(): Promise<HistoryResult> {
|
|
850
347
|
return await this.requestJson<HistoryResult>('GET', '/api/canvas/history');
|
|
851
348
|
}
|
|
@@ -861,47 +358,11 @@ class RemoteCanvasAccess implements CanvasAccess {
|
|
|
861
358
|
return await this.requestJson<AxContextResult>('GET', `/api/canvas/ax/context${qs}`);
|
|
862
359
|
}
|
|
863
360
|
|
|
864
|
-
async setAxFocus(nodeIds: string[], options?: { source?: PmxAxSource }): Promise<SetAxFocusResult> {
|
|
865
|
-
const response = await this.requestJson<{ focus?: SetAxFocusResult }>('POST', '/api/canvas/ax/focus', {
|
|
866
|
-
nodeIds,
|
|
867
|
-
source: options?.source ?? 'mcp',
|
|
868
|
-
});
|
|
869
|
-
if (!response.focus) throw new Error('Remote canvas did not return AX focus.');
|
|
870
|
-
return response.focus;
|
|
871
|
-
}
|
|
872
|
-
|
|
873
|
-
async recordAxEvent(input: RecordAxEventInput, options?: { source?: PmxAxSource }): Promise<RecordAxEventResult> {
|
|
874
|
-
const response = await this.requestJson<{ event?: RecordAxEventResult }>('POST', '/api/canvas/ax/event', {
|
|
875
|
-
...input,
|
|
876
|
-
source: options?.source ?? 'mcp',
|
|
877
|
-
});
|
|
878
|
-
if (!response.event) throw new Error('Remote canvas did not return an AX event.');
|
|
879
|
-
return response.event;
|
|
880
|
-
}
|
|
881
|
-
|
|
882
|
-
async sendSteering(message: string, options?: { source?: PmxAxSource }): Promise<SendSteeringResult> {
|
|
883
|
-
const response = await this.requestJson<{ steering?: SendSteeringResult }>('POST', '/api/canvas/ax/steer', {
|
|
884
|
-
message,
|
|
885
|
-
source: options?.source ?? 'mcp',
|
|
886
|
-
});
|
|
887
|
-
if (!response.steering) throw new Error('Remote canvas did not return a steering message.');
|
|
888
|
-
return response.steering;
|
|
889
|
-
}
|
|
890
|
-
|
|
891
361
|
async getAxTimeline(query?: GetAxTimelineQuery): Promise<GetAxTimelineResult> {
|
|
892
362
|
const qs = query?.limit ? `?limit=${query.limit}` : '';
|
|
893
363
|
return await this.requestJson<GetAxTimelineResult>('GET', `/api/canvas/ax/timeline${qs}`);
|
|
894
364
|
}
|
|
895
365
|
|
|
896
|
-
async addWorkItem(input: AddWorkItemInput, options?: { source?: PmxAxSource }): Promise<AddWorkItemResult> {
|
|
897
|
-
const response = await this.requestJson<{ workItem?: AddWorkItemResult }>('POST', '/api/canvas/ax/work', {
|
|
898
|
-
...input,
|
|
899
|
-
source: options?.source ?? 'mcp',
|
|
900
|
-
});
|
|
901
|
-
if (!response.workItem) throw new Error('Remote canvas did not return a work item.');
|
|
902
|
-
return response.workItem;
|
|
903
|
-
}
|
|
904
|
-
|
|
905
366
|
async submitAxInteraction(input: SubmitAxInteractionInput, options?: { source?: PmxAxSource }): Promise<SubmitAxInteractionResult> {
|
|
906
367
|
// The interaction endpoint returns its structured outcome (ok/code/error) in
|
|
907
368
|
// the body for both accepted and rejected interactions, so read the body
|
|
@@ -928,65 +389,16 @@ class RemoteCanvasAccess implements CanvasAccess {
|
|
|
928
389
|
return response.pending ?? [];
|
|
929
390
|
}
|
|
930
391
|
|
|
931
|
-
async markSteeringDelivered(id: string): Promise<boolean> {
|
|
932
|
-
const response = await this.requestJson<{ delivered?: boolean }>(
|
|
933
|
-
'POST',
|
|
934
|
-
`/api/canvas/ax/delivery/${encodeURIComponent(id)}/mark`,
|
|
935
|
-
{},
|
|
936
|
-
);
|
|
937
|
-
return response.delivered ?? false;
|
|
938
|
-
}
|
|
939
|
-
|
|
940
392
|
async listElicitations(): Promise<ListElicitationsResult> {
|
|
941
393
|
const r = await this.requestJson<{ elicitations?: ListElicitationsResult }>('GET', '/api/canvas/ax/elicitation');
|
|
942
394
|
return r.elicitations ?? [];
|
|
943
395
|
}
|
|
944
396
|
|
|
945
|
-
async requestElicitation(input: RequestElicitationInput, options?: { source?: PmxAxSource }): Promise<RequestElicitationResult> {
|
|
946
|
-
const r = await this.requestJson<{ elicitation?: RequestElicitationResult }>('POST', '/api/canvas/ax/elicitation', {
|
|
947
|
-
...input,
|
|
948
|
-
source: options?.source ?? 'mcp',
|
|
949
|
-
});
|
|
950
|
-
if (!r.elicitation) throw new Error('Remote canvas did not return an elicitation.');
|
|
951
|
-
return r.elicitation;
|
|
952
|
-
}
|
|
953
|
-
|
|
954
|
-
async respondElicitation(id: string, response: Record<string, unknown>, options?: { source?: PmxAxSource }): Promise<RespondElicitationResult> {
|
|
955
|
-
const res = await fetch(`${this.remoteBaseUrl}/api/canvas/ax/elicitation/${encodeURIComponent(id)}/respond`, {
|
|
956
|
-
method: 'POST',
|
|
957
|
-
headers: { 'Content-Type': 'application/json' },
|
|
958
|
-
body: JSON.stringify({ response, source: options?.source ?? 'mcp' }),
|
|
959
|
-
});
|
|
960
|
-
if (res.status === 404) return null;
|
|
961
|
-
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
962
|
-
return (await res.json() as { elicitation?: RespondElicitationResult }).elicitation ?? null;
|
|
963
|
-
}
|
|
964
|
-
|
|
965
397
|
async listModeRequests(): Promise<ListModeRequestsResult> {
|
|
966
398
|
const r = await this.requestJson<{ modeRequests?: ListModeRequestsResult }>('GET', '/api/canvas/ax/mode');
|
|
967
399
|
return r.modeRequests ?? [];
|
|
968
400
|
}
|
|
969
401
|
|
|
970
|
-
async requestMode(input: RequestModeInput, options?: { source?: PmxAxSource }): Promise<RequestModeResult> {
|
|
971
|
-
const r = await this.requestJson<{ modeRequest?: RequestModeResult }>('POST', '/api/canvas/ax/mode', {
|
|
972
|
-
...input,
|
|
973
|
-
source: options?.source ?? 'mcp',
|
|
974
|
-
});
|
|
975
|
-
if (!r.modeRequest) throw new Error('Remote canvas did not return a mode request.');
|
|
976
|
-
return r.modeRequest;
|
|
977
|
-
}
|
|
978
|
-
|
|
979
|
-
async resolveModeRequest(id: string, decision: 'approved' | 'rejected', options?: { resolution?: string; source?: PmxAxSource }): Promise<ResolveModeRequestResult> {
|
|
980
|
-
const res = await fetch(`${this.remoteBaseUrl}/api/canvas/ax/mode/${encodeURIComponent(id)}/resolve`, {
|
|
981
|
-
method: 'POST',
|
|
982
|
-
headers: { 'Content-Type': 'application/json' },
|
|
983
|
-
body: JSON.stringify({ decision, ...(options?.resolution ? { resolution: options.resolution } : {}), source: options?.source ?? 'mcp' }),
|
|
984
|
-
});
|
|
985
|
-
if (res.status === 404) return null;
|
|
986
|
-
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
987
|
-
return (await res.json() as { modeRequest?: ResolveModeRequestResult }).modeRequest ?? null;
|
|
988
|
-
}
|
|
989
|
-
|
|
990
402
|
async ingestActivity(input: IngestActivityInput, options?: { source?: PmxAxSource }): Promise<IngestActivityResult> {
|
|
991
403
|
return await this.requestJson<IngestActivityResult>('POST', '/api/canvas/ax/activity', {
|
|
992
404
|
...input,
|
|
@@ -994,181 +406,27 @@ class RemoteCanvasAccess implements CanvasAccess {
|
|
|
994
406
|
});
|
|
995
407
|
}
|
|
996
408
|
|
|
997
|
-
async awaitApproval(id: string, options?: { timeoutMs?: number }): Promise<AwaitApprovalResult> {
|
|
998
|
-
// Mirror PmxCanvas's `?? 30000` default so the remote transport blocks like the
|
|
999
|
-
// local one (an omitted timeout must still long-poll). Explicit 0 = immediate read.
|
|
1000
|
-
const ms = options?.timeoutMs ?? 30000;
|
|
1001
|
-
const qs = ms > 0 ? `?waitMs=${ms}` : '';
|
|
1002
|
-
const res = await fetch(`${this.remoteBaseUrl}/api/canvas/ax/approval/${encodeURIComponent(id)}${qs}`);
|
|
1003
|
-
if (res.status === 404) return { approvalGate: null, pending: false };
|
|
1004
|
-
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
1005
|
-
const body = await res.json() as { approvalGate?: AwaitApprovalResult['approvalGate']; pending?: boolean };
|
|
1006
|
-
return { approvalGate: body.approvalGate ?? null, pending: body.pending ?? false };
|
|
1007
|
-
}
|
|
1008
|
-
|
|
1009
|
-
async awaitElicitation(id: string, options?: { timeoutMs?: number }): Promise<AwaitElicitationResult> {
|
|
1010
|
-
// Mirror PmxCanvas's `?? 30000` default so the remote transport blocks like the
|
|
1011
|
-
// local one (an omitted timeout must still long-poll). Explicit 0 = immediate read.
|
|
1012
|
-
const ms = options?.timeoutMs ?? 30000;
|
|
1013
|
-
const qs = ms > 0 ? `?waitMs=${ms}` : '';
|
|
1014
|
-
const res = await fetch(`${this.remoteBaseUrl}/api/canvas/ax/elicitation/${encodeURIComponent(id)}${qs}`);
|
|
1015
|
-
if (res.status === 404) return { elicitation: null, pending: false };
|
|
1016
|
-
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
1017
|
-
const body = await res.json() as { elicitation?: AwaitElicitationResult['elicitation']; pending?: boolean };
|
|
1018
|
-
return { elicitation: body.elicitation ?? null, pending: body.pending ?? false };
|
|
1019
|
-
}
|
|
1020
|
-
|
|
1021
|
-
async awaitMode(id: string, options?: { timeoutMs?: number }): Promise<AwaitModeResult> {
|
|
1022
|
-
// Mirror PmxCanvas's `?? 30000` default so the remote transport blocks like the
|
|
1023
|
-
// local one (an omitted timeout must still long-poll). Explicit 0 = immediate read.
|
|
1024
|
-
const ms = options?.timeoutMs ?? 30000;
|
|
1025
|
-
const qs = ms > 0 ? `?waitMs=${ms}` : '';
|
|
1026
|
-
const res = await fetch(`${this.remoteBaseUrl}/api/canvas/ax/mode/${encodeURIComponent(id)}${qs}`);
|
|
1027
|
-
if (res.status === 404) return { modeRequest: null, pending: false };
|
|
1028
|
-
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
1029
|
-
const body = await res.json() as { modeRequest?: AwaitModeResult['modeRequest']; pending?: boolean };
|
|
1030
|
-
return { modeRequest: body.modeRequest ?? null, pending: body.pending ?? false };
|
|
1031
|
-
}
|
|
1032
|
-
|
|
1033
|
-
async getCommandRegistry(): Promise<GetCommandRegistryResult> {
|
|
1034
|
-
const r = await this.requestJson<{ commands?: GetCommandRegistryResult }>('GET', '/api/canvas/ax/command');
|
|
1035
|
-
return r.commands ?? [];
|
|
1036
|
-
}
|
|
1037
|
-
|
|
1038
|
-
async invokeCommand(name: string, args?: Record<string, unknown> | null, options?: { source?: PmxAxSource }): Promise<InvokeCommandResult> {
|
|
1039
|
-
const r = await this.requestJson<{ event?: InvokeCommandResult }>('POST', '/api/canvas/ax/command', {
|
|
1040
|
-
name,
|
|
1041
|
-
...(args ? { args } : {}),
|
|
1042
|
-
source: options?.source ?? 'mcp',
|
|
1043
|
-
});
|
|
1044
|
-
return r.event ?? null;
|
|
1045
|
-
}
|
|
1046
|
-
|
|
1047
409
|
async getPolicy(): Promise<GetPolicyResult> {
|
|
1048
410
|
const r = await this.requestJson<{ policy?: GetPolicyResult }>('GET', '/api/canvas/ax/policy');
|
|
1049
411
|
if (!r.policy) throw new Error('Remote canvas did not return a policy.');
|
|
1050
412
|
return r.policy;
|
|
1051
413
|
}
|
|
1052
414
|
|
|
1053
|
-
async setPolicy(patch: SetPolicyInput, options?: { source?: PmxAxSource }): Promise<SetPolicyResult> {
|
|
1054
|
-
const r = await this.requestJson<{ policy?: SetPolicyResult }>('POST', '/api/canvas/ax/policy', {
|
|
1055
|
-
...patch,
|
|
1056
|
-
source: options?.source ?? 'mcp',
|
|
1057
|
-
});
|
|
1058
|
-
if (!r.policy) throw new Error('Remote canvas did not return a policy.');
|
|
1059
|
-
return r.policy;
|
|
1060
|
-
}
|
|
1061
|
-
|
|
1062
|
-
async updateWorkItem(id: string, patch: UpdateWorkItemPatch, options?: { source?: PmxAxSource }): Promise<UpdateWorkItemResult> {
|
|
1063
|
-
const response = await fetch(`${this.remoteBaseUrl}/api/canvas/ax/work/${encodeURIComponent(id)}`, {
|
|
1064
|
-
method: 'PATCH',
|
|
1065
|
-
headers: { 'Content-Type': 'application/json' },
|
|
1066
|
-
body: JSON.stringify({ ...patch, source: options?.source ?? 'mcp' }),
|
|
1067
|
-
});
|
|
1068
|
-
if (response.status === 404) return null;
|
|
1069
|
-
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
|
1070
|
-
return (await response.json() as { workItem?: AddWorkItemResult }).workItem ?? null;
|
|
1071
|
-
}
|
|
1072
|
-
|
|
1073
415
|
async listWorkItems(): Promise<ListWorkItemsResult> {
|
|
1074
416
|
const response = await this.requestJson<{ workItems?: ListWorkItemsResult }>('GET', '/api/canvas/ax/work');
|
|
1075
417
|
return response.workItems ?? [];
|
|
1076
418
|
}
|
|
1077
419
|
|
|
1078
|
-
async requestApproval(input: RequestApprovalInput, options?: { source?: PmxAxSource }): Promise<RequestApprovalResult> {
|
|
1079
|
-
const response = await this.requestJson<{ approvalGate?: RequestApprovalResult }>('POST', '/api/canvas/ax/approval', {
|
|
1080
|
-
...input,
|
|
1081
|
-
source: options?.source ?? 'mcp',
|
|
1082
|
-
});
|
|
1083
|
-
if (!response.approvalGate) throw new Error('Remote canvas did not return an approval gate.');
|
|
1084
|
-
return response.approvalGate;
|
|
1085
|
-
}
|
|
1086
|
-
|
|
1087
|
-
async resolveApproval(id: string, decision: 'approved' | 'rejected', options?: { resolution?: string; source?: PmxAxSource }): Promise<ResolveApprovalResult> {
|
|
1088
|
-
const response = await fetch(`${this.remoteBaseUrl}/api/canvas/ax/approval/${encodeURIComponent(id)}/resolve`, {
|
|
1089
|
-
method: 'POST',
|
|
1090
|
-
headers: { 'Content-Type': 'application/json' },
|
|
1091
|
-
body: JSON.stringify({
|
|
1092
|
-
decision,
|
|
1093
|
-
...(options?.resolution !== undefined ? { resolution: options.resolution } : {}),
|
|
1094
|
-
source: options?.source ?? 'mcp',
|
|
1095
|
-
}),
|
|
1096
|
-
});
|
|
1097
|
-
if (response.status === 404) return null;
|
|
1098
|
-
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
|
1099
|
-
return (await response.json() as { approvalGate?: RequestApprovalResult }).approvalGate ?? null;
|
|
1100
|
-
}
|
|
1101
|
-
|
|
1102
420
|
async listApprovalGates(): Promise<ListApprovalGatesResult> {
|
|
1103
421
|
const response = await this.requestJson<{ approvalGates?: ListApprovalGatesResult }>('GET', '/api/canvas/ax/approval');
|
|
1104
422
|
return response.approvalGates ?? [];
|
|
1105
423
|
}
|
|
1106
424
|
|
|
1107
|
-
async addEvidence(input: AddEvidenceInput, options?: { source?: PmxAxSource }): Promise<AddEvidenceResult> {
|
|
1108
|
-
const response = await this.requestJson<{ evidence?: AddEvidenceResult }>('POST', '/api/canvas/ax/evidence', {
|
|
1109
|
-
...input,
|
|
1110
|
-
source: options?.source ?? 'mcp',
|
|
1111
|
-
});
|
|
1112
|
-
if (!response.evidence) throw new Error('Remote canvas did not return an evidence item.');
|
|
1113
|
-
return response.evidence;
|
|
1114
|
-
}
|
|
1115
|
-
|
|
1116
|
-
async addReviewAnnotation(input: AddReviewAnnotationInput, options?: { source?: PmxAxSource }): Promise<AddReviewAnnotationResult> {
|
|
1117
|
-
const response = await fetch(`${this.remoteBaseUrl}/api/canvas/ax/review`, {
|
|
1118
|
-
method: 'POST',
|
|
1119
|
-
headers: { 'Content-Type': 'application/json' },
|
|
1120
|
-
body: JSON.stringify({ ...input, source: options?.source ?? 'mcp' }),
|
|
1121
|
-
});
|
|
1122
|
-
// 400 = validation rejection (e.g. node-anchored review with an unknown
|
|
1123
|
-
// nodeId); mirror the local path and return null rather than throwing.
|
|
1124
|
-
if (response.status === 400) return null;
|
|
1125
|
-
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
|
1126
|
-
return (await response.json() as { reviewAnnotation?: AddReviewAnnotationResult }).reviewAnnotation ?? null;
|
|
1127
|
-
}
|
|
1128
|
-
|
|
1129
|
-
async updateReviewAnnotation(id: string, patch: UpdateReviewAnnotationPatch, options?: { source?: PmxAxSource }): Promise<UpdateReviewAnnotationResult> {
|
|
1130
|
-
const response = await fetch(`${this.remoteBaseUrl}/api/canvas/ax/review/${encodeURIComponent(id)}`, {
|
|
1131
|
-
method: 'PATCH',
|
|
1132
|
-
headers: { 'Content-Type': 'application/json' },
|
|
1133
|
-
body: JSON.stringify({ ...patch, source: options?.source ?? 'mcp' }),
|
|
1134
|
-
});
|
|
1135
|
-
if (response.status === 404) return null;
|
|
1136
|
-
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
|
1137
|
-
return (await response.json() as { reviewAnnotation?: AddReviewAnnotationResult }).reviewAnnotation ?? null;
|
|
1138
|
-
}
|
|
1139
|
-
|
|
1140
425
|
async listReviewAnnotations(): Promise<ListReviewAnnotationsResult> {
|
|
1141
426
|
const response = await this.requestJson<{ reviewAnnotations?: ListReviewAnnotationsResult }>('GET', '/api/canvas/ax/review');
|
|
1142
427
|
return response.reviewAnnotations ?? [];
|
|
1143
428
|
}
|
|
1144
429
|
|
|
1145
|
-
async getHostCapability(): Promise<GetHostCapabilityResult> {
|
|
1146
|
-
const response = await this.requestJson<{ host?: GetHostCapabilityResult }>('GET', '/api/canvas/ax/host-capability');
|
|
1147
|
-
return response.host ?? null;
|
|
1148
|
-
}
|
|
1149
|
-
|
|
1150
|
-
async reportHostCapability(input: unknown, options?: { source?: PmxAxSource }): Promise<ReportHostCapabilityResult> {
|
|
1151
|
-
const body = input !== null && typeof input === 'object' && !Array.isArray(input) ? { ...input } : {};
|
|
1152
|
-
const response = await this.requestJson<{ host?: ReportHostCapabilityResult }>('PUT', '/api/canvas/ax/host-capability', {
|
|
1153
|
-
...body,
|
|
1154
|
-
source: options?.source ?? 'mcp',
|
|
1155
|
-
});
|
|
1156
|
-
if (!response.host) throw new Error('Remote canvas did not return host capability.');
|
|
1157
|
-
return response.host;
|
|
1158
|
-
}
|
|
1159
|
-
|
|
1160
|
-
async setContextPins(nodeIds: string[], mode: 'set' | 'add' | 'remove' = 'set'): Promise<SetContextPinsResult> {
|
|
1161
|
-
const existing = mode === 'set' ? [] : await this.getPinnedNodeIds();
|
|
1162
|
-
const requested = new Set(nodeIds);
|
|
1163
|
-
const next = mode === 'set'
|
|
1164
|
-
? nodeIds
|
|
1165
|
-
: mode === 'add'
|
|
1166
|
-
? [...new Set([...existing, ...nodeIds])]
|
|
1167
|
-
: existing.filter((id) => !requested.has(id));
|
|
1168
|
-
const response = await this.requestJson<{ count?: number }>('POST', '/api/canvas/context-pins', { nodeIds: next });
|
|
1169
|
-
return { count: response.count ?? next.length, nodeIds: next };
|
|
1170
|
-
}
|
|
1171
|
-
|
|
1172
430
|
async getPinnedNodeIds(): Promise<string[]> {
|
|
1173
431
|
const response = await this.requestJson<{ nodeIds?: string[] }>('GET', '/api/canvas/pinned-context');
|
|
1174
432
|
return Array.isArray(response.nodeIds) ? response.nodeIds : [];
|
|
@@ -1178,73 +436,15 @@ class RemoteCanvasAccess implements CanvasAccess {
|
|
|
1178
436
|
return await this.requestJson<RunBatchResult>('POST', '/api/canvas/batch', { operations });
|
|
1179
437
|
}
|
|
1180
438
|
|
|
1181
|
-
async listSnapshots(options?: SnapshotListOptions): Promise<SnapshotList> {
|
|
1182
|
-
const params = new URLSearchParams();
|
|
1183
|
-
if (typeof options?.limit === 'number') params.set('limit', String(options.limit));
|
|
1184
|
-
if (options?.query) params.set('q', options.query);
|
|
1185
|
-
if (options?.before) params.set('before', options.before);
|
|
1186
|
-
if (options?.after) params.set('after', options.after);
|
|
1187
|
-
if (options?.all) params.set('all', 'true');
|
|
1188
|
-
const query = params.size > 0 ? `?${params.toString()}` : '';
|
|
1189
|
-
return await this.requestJson<SnapshotList>('GET', `/api/canvas/snapshots${query}`);
|
|
1190
|
-
}
|
|
1191
|
-
|
|
1192
|
-
async saveSnapshot(name: string): Promise<CanvasSnapshot | null> {
|
|
1193
|
-
const response = await this.requestJson<SnapshotSaveResponse>('POST', '/api/canvas/snapshots', { name });
|
|
1194
|
-
return response.snapshot ?? null;
|
|
1195
|
-
}
|
|
1196
|
-
|
|
1197
|
-
async restoreSnapshot(id: string): Promise<{ ok: boolean }> {
|
|
1198
|
-
return await this.requestJson<{ ok: boolean }>('POST', `/api/canvas/snapshots/${encodeURIComponent(id)}`, {});
|
|
1199
|
-
}
|
|
1200
|
-
|
|
1201
|
-
async deleteSnapshot(id: string): Promise<DeleteSnapshotResult> {
|
|
1202
|
-
return await this.requestJson<DeleteSnapshotResult>('DELETE', `/api/canvas/snapshots/${encodeURIComponent(id)}`);
|
|
1203
|
-
}
|
|
1204
|
-
|
|
1205
|
-
async gcSnapshots(options?: GcSnapshotsOptions): Promise<GcSnapshotsResult> {
|
|
1206
|
-
return await this.requestJson<GcSnapshotsResult>('POST', '/api/canvas/snapshots/gc', options ?? {});
|
|
1207
|
-
}
|
|
1208
|
-
|
|
1209
|
-
async diffSnapshot(idOrName: string): Promise<DiffSnapshotResult> {
|
|
1210
|
-
return await this.requestJson<DiffSnapshotResult>('GET', `/api/canvas/snapshots/${encodeURIComponent(idOrName)}/diff`);
|
|
1211
|
-
}
|
|
1212
|
-
|
|
1213
439
|
async getCodeGraph(): Promise<CodeGraphResult> {
|
|
1214
440
|
const summary = await this.requestJson<CodeGraphResult['summary']>('GET', '/api/canvas/code-graph');
|
|
1215
441
|
return { text: JSON.stringify(summary, null, 2), summary };
|
|
1216
442
|
}
|
|
1217
443
|
|
|
1218
|
-
async validate(): Promise<ValidationResult> {
|
|
1219
|
-
return await this.requestJson<ValidationResult>('GET', '/api/canvas/validate');
|
|
1220
|
-
}
|
|
1221
|
-
|
|
1222
444
|
async getAutomationWebViewStatus(): Promise<AutomationWebViewStatus> {
|
|
1223
445
|
return await this.requestJson<AutomationWebViewStatus>('GET', '/api/workbench/webview');
|
|
1224
446
|
}
|
|
1225
447
|
|
|
1226
|
-
async startAutomationWebView(options: AutomationWebViewOptions = {}): Promise<AutomationWebViewStatus> {
|
|
1227
|
-
const response = await this.requestJson<WebViewEnvelope>('POST', '/api/workbench/webview/start', options);
|
|
1228
|
-
if (!response.webview) throw new Error('WebView start response did not include status.');
|
|
1229
|
-
return response.webview;
|
|
1230
|
-
}
|
|
1231
|
-
|
|
1232
|
-
async stopAutomationWebView(): Promise<boolean> {
|
|
1233
|
-
const response = await this.requestJson<WebViewStopEnvelope>('DELETE', '/api/workbench/webview');
|
|
1234
|
-
return response.stopped === true;
|
|
1235
|
-
}
|
|
1236
|
-
|
|
1237
|
-
async evaluateAutomationWebView(expression: string): Promise<AutomationEvaluateResult> {
|
|
1238
|
-
const response = await this.requestJson<WebViewEvaluateEnvelope>('POST', '/api/workbench/webview/evaluate', { expression });
|
|
1239
|
-
return response.value as AutomationEvaluateResult;
|
|
1240
|
-
}
|
|
1241
|
-
|
|
1242
|
-
async resizeAutomationWebView(width: number, height: number): Promise<AutomationWebViewStatus> {
|
|
1243
|
-
const response = await this.requestJson<WebViewEnvelope>('POST', '/api/workbench/webview/resize', { width, height });
|
|
1244
|
-
if (!response.webview) throw new Error('WebView resize response did not include status.');
|
|
1245
|
-
return response.webview;
|
|
1246
|
-
}
|
|
1247
|
-
|
|
1248
448
|
async screenshotAutomationWebView(options: AutomationScreenshotOptions = {}): Promise<Uint8Array> {
|
|
1249
449
|
const response = await fetch(`${this.remoteBaseUrl}/api/workbench/webview/screenshot`, {
|
|
1250
450
|
method: 'POST',
|