pmx-canvas 0.2.1 → 0.2.3
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 +119 -0
- package/Readme.md +2 -2
- package/dist/canvas/global.css +260 -0
- package/dist/canvas/index.js +76 -76
- package/dist/json-render/index.js +2 -2
- package/dist/types/client/canvas/IntentLayer.d.ts +1 -0
- package/dist/types/client/state/intent-bridge.d.ts +10 -0
- package/dist/types/client/state/intent-store.d.ts +25 -0
- package/dist/types/json-render/server.d.ts +1 -1
- package/dist/types/server/index.d.ts +34 -4
- package/dist/types/server/intent-registry.d.ts +45 -0
- package/dist/types/server/operations/ops/intent.d.ts +2 -0
- package/dist/types/shared/ax-intent.d.ts +58 -0
- package/docs/mcp.md +21 -2
- package/docs/screenshot.png +0 -0
- package/package.json +1 -1
- package/skills/pmx-canvas/SKILL.md +200 -1305
- package/skills/pmx-canvas/evals/evals.json +255 -1
- package/skills/pmx-canvas/evals/fixtures/code-exploration/src/auth/jwt.ts +17 -0
- package/skills/pmx-canvas/evals/fixtures/code-exploration/src/auth/login.ts +12 -0
- package/skills/pmx-canvas/evals/fixtures/code-exploration/src/auth/middleware.ts +13 -0
- package/skills/pmx-canvas/evals/fixtures/code-exploration/src/routes/auth.ts +13 -0
- package/skills/pmx-canvas/evals/fixtures/investigation-board/src/handlers/users.ts +27 -0
- package/skills/pmx-canvas/references/full-reference.md +1445 -0
- package/src/cli/index.ts +21 -4
- package/src/client/canvas/CanvasNode.tsx +13 -13
- package/src/client/canvas/CanvasViewport.tsx +2 -0
- package/src/client/canvas/ContextMenu.tsx +25 -19
- package/src/client/canvas/IntentLayer.tsx +278 -0
- package/src/client/nodes/ExtAppFrame.tsx +32 -23
- package/src/client/state/intent-bridge.ts +31 -0
- package/src/client/state/intent-store.ts +107 -0
- package/src/client/state/sse-bridge.ts +31 -0
- package/src/client/theme/global.css +260 -0
- package/src/json-render/charts/components.tsx +18 -4
- package/src/json-render/renderer/index.tsx +11 -2
- package/src/json-render/server.ts +1 -1
- package/src/server/index.ts +240 -158
- package/src/server/intent-registry.ts +324 -0
- package/src/server/operations/composites.ts +11 -0
- package/src/server/operations/index.ts +2 -0
- package/src/server/operations/ops/edges.ts +1 -0
- package/src/server/operations/ops/groups.ts +3 -0
- package/src/server/operations/ops/intent.ts +132 -0
- package/src/server/operations/ops/json-render.ts +3 -0
- package/src/server/operations/ops/nodes.ts +3 -0
- package/src/server/operations/ops/webview.ts +15 -4
- package/src/server/operations/registry.ts +68 -3
- package/src/server/server.ts +40 -12
- package/src/shared/ax-intent.ts +64 -0
- package/src/shared/surface.ts +5 -1
package/src/server/index.ts
CHANGED
|
@@ -3,6 +3,8 @@ import { canvasState, IMAGE_MIME_MAP } from './canvas-state.js';
|
|
|
3
3
|
import type { CanvasAnnotation, CanvasNodeState, CanvasEdge, CanvasLayout, ViewportState } from './canvas-state.js';
|
|
4
4
|
import { buildCanvasAxContext } from './ax-context.js';
|
|
5
5
|
import { applyAxInteraction, type AxInteractionInput, type AxInteractionPublicResult } from './ax-interaction.js';
|
|
6
|
+
import { intentRegistry } from './intent-registry.js';
|
|
7
|
+
import type { PmxAxIntent, PmxAxIntentKind } from '../shared/ax-intent.js';
|
|
6
8
|
import { waitForAxResolution } from './ax-wait.js';
|
|
7
9
|
import type {
|
|
8
10
|
PmxAxActivityKind,
|
|
@@ -143,6 +145,24 @@ export class PmxCanvas extends EventEmitter {
|
|
|
143
145
|
this._port = options?.port ?? 4313;
|
|
144
146
|
}
|
|
145
147
|
|
|
148
|
+
private runIntentCommit<T>(
|
|
149
|
+
intentId: string | undefined,
|
|
150
|
+
allowedKinds: readonly PmxAxIntentKind[],
|
|
151
|
+
mutate: () => T,
|
|
152
|
+
settledNodeId: (result: T) => string | undefined,
|
|
153
|
+
): T {
|
|
154
|
+
if (intentId === undefined) return mutate();
|
|
155
|
+
intentRegistry.beginCommit(intentId, allowedKinds);
|
|
156
|
+
try {
|
|
157
|
+
const result = mutate();
|
|
158
|
+
intentRegistry.completeCommit(intentId, settledNodeId(result));
|
|
159
|
+
return result;
|
|
160
|
+
} catch (error) {
|
|
161
|
+
intentRegistry.abortCommit(intentId);
|
|
162
|
+
throw error;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
146
166
|
async start(options?: {
|
|
147
167
|
open?: boolean;
|
|
148
168
|
automationWebView?: boolean | CanvasAutomationWebViewOptions;
|
|
@@ -216,6 +236,7 @@ export class PmxCanvas extends EventEmitter {
|
|
|
216
236
|
* or keep the whole node — both work. (Previously returned a bare id string.)
|
|
217
237
|
*/
|
|
218
238
|
addNode(input: {
|
|
239
|
+
intentId?: string;
|
|
219
240
|
type: CanvasNodeState['type'];
|
|
220
241
|
title?: string;
|
|
221
242
|
content?: string;
|
|
@@ -235,40 +256,43 @@ export class PmxCanvas extends EventEmitter {
|
|
|
235
256
|
height?: number;
|
|
236
257
|
strictSize?: boolean;
|
|
237
258
|
}): SdkCanvasNode {
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
+
return this.runIntentCommit(input.intentId, ['create'], () => {
|
|
260
|
+
if (input.type === 'webpage') {
|
|
261
|
+
throw new Error('Use addWebpageNode for webpage nodes so page content is fetched and cached on the server.');
|
|
262
|
+
}
|
|
263
|
+
if (input.type === 'group') {
|
|
264
|
+
const groupId = this.createGroup({
|
|
265
|
+
...(typeof input.title === 'string' ? { title: input.title } : {}),
|
|
266
|
+
childIds: input.childIds ?? input.children ?? [],
|
|
267
|
+
...(typeof input.x === 'number' ? { x: input.x } : {}),
|
|
268
|
+
...(typeof input.y === 'number' ? { y: input.y } : {}),
|
|
269
|
+
...(typeof input.width === 'number' ? { width: input.width } : {}),
|
|
270
|
+
...(typeof input.height === 'number' ? { height: input.height } : {}),
|
|
271
|
+
...(typeof input.color === 'string' ? { color: input.color } : {}),
|
|
272
|
+
...(input.childLayout ? { childLayout: input.childLayout } : {}),
|
|
273
|
+
});
|
|
274
|
+
const groupNode = canvasState.getNode(groupId);
|
|
275
|
+
if (!groupNode) throw new Error(`Group node "${groupId}" was not created.`);
|
|
276
|
+
return toSdkNode(groupNode);
|
|
277
|
+
}
|
|
278
|
+
// Thin wrapper over the shared operation core (plan-005); the SDK keeps
|
|
279
|
+
// fileMode 'path' as an explicit visible parameter instead of forked code.
|
|
280
|
+
const { node, needsCodeGraphRecompute } = createBasicCanvasNode(input, { fileMode: 'path' });
|
|
259
281
|
|
|
260
|
-
|
|
282
|
+
emitPrimaryWorkbenchEvent('canvas-layout-update', { layout: canvasState.getLayout() });
|
|
261
283
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
284
|
+
if (needsCodeGraphRecompute) {
|
|
285
|
+
scheduleCodeGraphRecompute(() => {
|
|
286
|
+
emitPrimaryWorkbenchEvent('canvas-layout-update', { layout: canvasState.getLayout() });
|
|
287
|
+
});
|
|
288
|
+
}
|
|
267
289
|
|
|
268
|
-
|
|
290
|
+
return toSdkNode(node);
|
|
291
|
+
}, (node) => node.id);
|
|
269
292
|
}
|
|
270
293
|
|
|
271
294
|
async addWebpageNode(input: {
|
|
295
|
+
intentId?: string;
|
|
272
296
|
title?: string;
|
|
273
297
|
url: string;
|
|
274
298
|
x?: number;
|
|
@@ -277,29 +301,33 @@ export class PmxCanvas extends EventEmitter {
|
|
|
277
301
|
height?: number;
|
|
278
302
|
strictSize?: boolean;
|
|
279
303
|
}): Promise<{ ok: boolean; id: string; error?: string; fetch: { ok: boolean; error?: string } }> {
|
|
280
|
-
const
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
304
|
+
const mutate = async () => {
|
|
305
|
+
const { id } = addCanvasNode({
|
|
306
|
+
type: 'webpage',
|
|
307
|
+
...(typeof input.title === 'string' ? { title: input.title } : {}),
|
|
308
|
+
content: input.url,
|
|
309
|
+
...(typeof input.x === 'number' ? { x: input.x } : {}),
|
|
310
|
+
...(typeof input.y === 'number' ? { y: input.y } : {}),
|
|
311
|
+
...(typeof input.width === 'number' ? { width: input.width } : {}),
|
|
312
|
+
...(typeof input.height === 'number' ? { height: input.height } : {}),
|
|
313
|
+
...(input.strictSize ? { strictSize: true } : {}),
|
|
314
|
+
defaultWidth: 520,
|
|
315
|
+
defaultHeight: 420,
|
|
316
|
+
});
|
|
317
|
+
emitPrimaryWorkbenchEvent('canvas-layout-update', { layout: canvasState.getLayout() });
|
|
318
|
+
const result = await refreshCanvasWebpageNode(id);
|
|
319
|
+
emitPrimaryWorkbenchEvent('canvas-layout-update', { layout: canvasState.getLayout() });
|
|
320
|
+
return {
|
|
321
|
+
ok: true,
|
|
322
|
+
id,
|
|
323
|
+
fetch: result.ok
|
|
324
|
+
? { ok: true }
|
|
325
|
+
: { ok: false, error: result.error ?? 'Failed to fetch webpage content.' },
|
|
326
|
+
...(result.ok ? {} : { error: result.error }),
|
|
327
|
+
};
|
|
302
328
|
};
|
|
329
|
+
if (input.intentId === undefined) return await mutate();
|
|
330
|
+
return await intentRegistry.runCommit(input.intentId, ['create'], mutate, (result) => result.id);
|
|
303
331
|
}
|
|
304
332
|
|
|
305
333
|
async refreshWebpageNode(id: string, url?: string): Promise<{ ok: boolean; id: string; error?: string }> {
|
|
@@ -309,30 +337,39 @@ export class PmxCanvas extends EventEmitter {
|
|
|
309
337
|
}
|
|
310
338
|
|
|
311
339
|
updateNode(id: string, patch: Partial<CanvasNodeState> & Record<string, unknown>): void {
|
|
312
|
-
const
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
340
|
+
const intentId = typeof patch.intentId === 'string' ? patch.intentId : undefined;
|
|
341
|
+
this.runIntentCommit(intentId, ['move', 'edit'], () => {
|
|
342
|
+
const existing = canvasState.getNode(id);
|
|
343
|
+
if (!existing) {
|
|
344
|
+
if (intentId !== undefined) throw new Error(`Node "${id}" not found.`);
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
// Thin wrapper over the shared patch core (plan-005): the SDK now carries
|
|
348
|
+
// the same superset semantics as HTTP/MCP (webpage titleSource/url, html
|
|
349
|
+
// top-level fields, axCapabilities merge, group children).
|
|
350
|
+
const { patch: resolvedPatch, groupChildIds } = buildNodePatch(existing, patch);
|
|
351
|
+
canvasState.updateNode(id, resolvedPatch);
|
|
352
|
+
if (groupChildIds !== undefined) setGroupChildrenFromApi(id, groupChildIds);
|
|
353
|
+
emitPrimaryWorkbenchEvent('canvas-layout-update', { layout: canvasState.getLayout() });
|
|
354
|
+
}, () => id);
|
|
321
355
|
}
|
|
322
356
|
|
|
323
357
|
/** Remove a node. Missing id throws (plan-005 unifies this across surfaces). */
|
|
324
|
-
removeNode(id: string): void {
|
|
325
|
-
|
|
326
|
-
|
|
358
|
+
removeNode(id: string, options?: { intentId?: string }): void {
|
|
359
|
+
this.runIntentCommit(options?.intentId, ['remove'], () => {
|
|
360
|
+
const { needsCodeGraphRecompute } = removeNodeCore(id);
|
|
361
|
+
emitPrimaryWorkbenchEvent('canvas-layout-update', { layout: canvasState.getLayout() });
|
|
327
362
|
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
363
|
+
if (needsCodeGraphRecompute) {
|
|
364
|
+
scheduleCodeGraphRecompute(() => {
|
|
365
|
+
emitPrimaryWorkbenchEvent('canvas-layout-update', { layout: canvasState.getLayout() });
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
}, () => undefined);
|
|
333
369
|
}
|
|
334
370
|
|
|
335
371
|
addEdge(input: {
|
|
372
|
+
intentId?: string;
|
|
336
373
|
from?: string;
|
|
337
374
|
to?: string;
|
|
338
375
|
fromSearch?: string;
|
|
@@ -342,9 +379,11 @@ export class PmxCanvas extends EventEmitter {
|
|
|
342
379
|
style?: CanvasEdge['style'];
|
|
343
380
|
animated?: boolean;
|
|
344
381
|
}): string {
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
382
|
+
return this.runIntentCommit(input.intentId, ['connect'], () => {
|
|
383
|
+
const { id } = addCanvasEdge(input);
|
|
384
|
+
emitPrimaryWorkbenchEvent('canvas-layout-update', { layout: canvasState.getLayout() });
|
|
385
|
+
return id;
|
|
386
|
+
}, () => undefined);
|
|
348
387
|
}
|
|
349
388
|
|
|
350
389
|
addAnnotation(input: Omit<CanvasAnnotation, 'id' | 'createdAt'> & { id?: string; createdAt?: string }): string {
|
|
@@ -374,6 +413,7 @@ export class PmxCanvas extends EventEmitter {
|
|
|
374
413
|
* If childIds are provided, the group auto-sizes to contain them with padding.
|
|
375
414
|
*/
|
|
376
415
|
createGroup(input: {
|
|
416
|
+
intentId?: string;
|
|
377
417
|
title?: string;
|
|
378
418
|
childIds?: string[];
|
|
379
419
|
x?: number;
|
|
@@ -383,28 +423,39 @@ export class PmxCanvas extends EventEmitter {
|
|
|
383
423
|
color?: string;
|
|
384
424
|
childLayout?: 'grid' | 'column' | 'flow';
|
|
385
425
|
}): string {
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
426
|
+
return this.runIntentCommit(input.intentId, ['create'], () => {
|
|
427
|
+
const { id } = createCanvasGroup(input);
|
|
428
|
+
emitPrimaryWorkbenchEvent('canvas-layout-update', { layout: canvasState.getLayout() });
|
|
429
|
+
return id;
|
|
430
|
+
}, (id) => id);
|
|
390
431
|
}
|
|
391
432
|
|
|
392
433
|
/** Add nodes to an existing group. */
|
|
393
|
-
groupNodes(groupId: string, childIds: string[], options?: { childLayout?: 'grid' | 'column' | 'flow' }): boolean {
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
434
|
+
groupNodes(groupId: string, childIds: string[], options?: { childLayout?: 'grid' | 'column' | 'flow'; intentId?: string }): boolean {
|
|
435
|
+
return this.runIntentCommit(options?.intentId, ['edit'], () => {
|
|
436
|
+
const { ok } = groupCanvasNodes(groupId, childIds, options);
|
|
437
|
+
if (!ok && options?.intentId !== undefined) {
|
|
438
|
+
throw new Error(`Group "${groupId}" could not be updated.`);
|
|
439
|
+
}
|
|
440
|
+
if (ok) {
|
|
441
|
+
emitPrimaryWorkbenchEvent('canvas-layout-update', { layout: canvasState.getLayout() });
|
|
442
|
+
}
|
|
443
|
+
return ok;
|
|
444
|
+
}, () => groupId);
|
|
399
445
|
}
|
|
400
446
|
|
|
401
447
|
/** Remove all children from a group (the group node remains). */
|
|
402
|
-
ungroupNodes(groupId: string): boolean {
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
448
|
+
ungroupNodes(groupId: string, options?: { intentId?: string }): boolean {
|
|
449
|
+
return this.runIntentCommit(options?.intentId, ['edit'], () => {
|
|
450
|
+
const { ok } = ungroupCanvasNodes(groupId);
|
|
451
|
+
if (!ok && options?.intentId !== undefined) {
|
|
452
|
+
throw new Error(`Group "${groupId}" could not be updated.`);
|
|
453
|
+
}
|
|
454
|
+
if (ok) {
|
|
455
|
+
emitPrimaryWorkbenchEvent('canvas-layout-update', { layout: canvasState.getLayout() });
|
|
456
|
+
}
|
|
457
|
+
return ok;
|
|
458
|
+
}, () => groupId);
|
|
408
459
|
}
|
|
409
460
|
|
|
410
461
|
clear(): void {
|
|
@@ -477,6 +528,24 @@ export class PmxCanvas extends EventEmitter {
|
|
|
477
528
|
return ok;
|
|
478
529
|
}
|
|
479
530
|
|
|
531
|
+
/**
|
|
532
|
+
* Ghost Cursor of Intent — announce a spatial move before making it. The ghost
|
|
533
|
+
* is ephemeral presence (auto-expiring, never snapshotted); the registry emits
|
|
534
|
+
* the `ax-intent` SSE frame so the browser paints a pre-commit placeholder.
|
|
535
|
+
*/
|
|
536
|
+
signalIntent(input: Record<string, unknown>): PmxAxIntent {
|
|
537
|
+
return intentRegistry.signal({ source: 'sdk', ...input });
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
updateIntent(id: string, patch: Record<string, unknown>): PmxAxIntent {
|
|
541
|
+
return intentRegistry.update(id, patch);
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
/** Dissolve a ghost; pass `settledNodeId` once the real node has landed. */
|
|
545
|
+
clearIntent(id: string, options?: { settledNodeId?: string; vetoed?: boolean }): boolean {
|
|
546
|
+
return intentRegistry.clear(id, options ?? {});
|
|
547
|
+
}
|
|
548
|
+
|
|
480
549
|
/** Undelivered steering for a consumer (loop-safe; excludes consumer-originated). */
|
|
481
550
|
getPendingSteering(options?: { consumer?: string; limit?: number }): PmxAxSteeringMessage[] {
|
|
482
551
|
return canvasState.getPendingSteering(options ?? {});
|
|
@@ -924,11 +993,13 @@ export class PmxCanvas extends EventEmitter {
|
|
|
924
993
|
}
|
|
925
994
|
|
|
926
995
|
addJsonRenderNode(
|
|
927
|
-
input: JsonRenderNodeInput,
|
|
996
|
+
input: JsonRenderNodeInput & { intentId?: string },
|
|
928
997
|
): { id: string; url: string; spec: JsonRenderSpec } {
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
998
|
+
return this.runIntentCommit(input.intentId, ['create'], () => {
|
|
999
|
+
const result = createCanvasJsonRenderNode(input);
|
|
1000
|
+
emitPrimaryWorkbenchEvent('canvas-layout-update', { layout: canvasState.getLayout() });
|
|
1001
|
+
return result;
|
|
1002
|
+
}, (result) => result.id);
|
|
932
1003
|
}
|
|
933
1004
|
|
|
934
1005
|
/**
|
|
@@ -938,6 +1009,7 @@ export class PmxCanvas extends EventEmitter {
|
|
|
938
1009
|
* reloads the viewer as the specVersion bumps.
|
|
939
1010
|
*/
|
|
940
1011
|
streamJsonRenderNode(input: {
|
|
1012
|
+
intentId?: string;
|
|
941
1013
|
nodeId?: string;
|
|
942
1014
|
title?: string;
|
|
943
1015
|
patches?: unknown[];
|
|
@@ -962,20 +1034,23 @@ export class PmxCanvas extends EventEmitter {
|
|
|
962
1034
|
// `mutates` path). `streamJsonRenderCore` throws OperationError (an Error
|
|
963
1035
|
// subclass with the same message) on a bad append target. The core's
|
|
964
1036
|
// result carries an extra `ok: true`; the SDK's wire shape omits it.
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
1037
|
+
return this.runIntentCommit(input.intentId, input.nodeId ? ['edit'] : ['create'], () => {
|
|
1038
|
+
const result = streamJsonRenderCore(input);
|
|
1039
|
+
emitPrimaryWorkbenchEvent('canvas-layout-update', { layout: canvasState.getLayout() });
|
|
1040
|
+
return {
|
|
1041
|
+
id: result.id,
|
|
1042
|
+
url: result.url,
|
|
1043
|
+
applied: result.applied,
|
|
1044
|
+
skipped: result.skipped,
|
|
1045
|
+
specVersion: result.specVersion,
|
|
1046
|
+
elementCount: result.elementCount,
|
|
1047
|
+
streamStatus: result.streamStatus,
|
|
1048
|
+
};
|
|
1049
|
+
}, (result) => result.id);
|
|
976
1050
|
}
|
|
977
1051
|
|
|
978
1052
|
addHtmlNode(input: {
|
|
1053
|
+
intentId?: string;
|
|
979
1054
|
html: string;
|
|
980
1055
|
title?: string;
|
|
981
1056
|
summary?: string;
|
|
@@ -994,35 +1069,38 @@ export class PmxCanvas extends EventEmitter {
|
|
|
994
1069
|
* the html capability ceiling server-side; cannot escalate. */
|
|
995
1070
|
axCapabilities?: { enabled?: boolean; allowed?: string[] };
|
|
996
1071
|
}): SdkCanvasNode {
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1072
|
+
return this.runIntentCommit(input.intentId, ['create'], () => {
|
|
1073
|
+
const { id } = addCanvasNode({
|
|
1074
|
+
type: 'html',
|
|
1075
|
+
...(typeof input.title === 'string' ? { title: input.title } : {}),
|
|
1076
|
+
data: {
|
|
1077
|
+
html: resolveHtmlContent(input.html),
|
|
1078
|
+
...(typeof input.summary === 'string' ? { summary: input.summary } : {}),
|
|
1079
|
+
...(typeof input.agentSummary === 'string' ? { agentSummary: input.agentSummary } : {}),
|
|
1080
|
+
...(typeof input.description === 'string' ? { description: input.description } : {}),
|
|
1081
|
+
...(input.presentation === true ? { presentation: true } : {}),
|
|
1082
|
+
...(Array.isArray(input.slideTitles) ? { slideTitles: input.slideTitles } : {}),
|
|
1083
|
+
...(Array.isArray(input.embeddedNodeIds) ? { embeddedNodeIds: input.embeddedNodeIds } : {}),
|
|
1084
|
+
...(Array.isArray(input.embeddedUrls) ? { embeddedUrls: input.embeddedUrls } : {}),
|
|
1085
|
+
...(input.axCapabilities ? { axCapabilities: input.axCapabilities } : {}),
|
|
1086
|
+
},
|
|
1087
|
+
...(typeof input.x === 'number' ? { x: input.x } : {}),
|
|
1088
|
+
...(typeof input.y === 'number' ? { y: input.y } : {}),
|
|
1089
|
+
...(typeof input.width === 'number' ? { width: input.width } : {}),
|
|
1090
|
+
...(typeof input.height === 'number' ? { height: input.height } : {}),
|
|
1091
|
+
...(input.strictSize ? { strictSize: true } : {}),
|
|
1092
|
+
defaultWidth: 720,
|
|
1093
|
+
defaultHeight: 640,
|
|
1094
|
+
});
|
|
1095
|
+
emitPrimaryWorkbenchEvent('canvas-layout-update', { layout: canvasState.getLayout() });
|
|
1096
|
+
const node = canvasState.getNode(id);
|
|
1097
|
+
if (!node) throw new Error(`HTML node "${id}" was not created.`);
|
|
1098
|
+
return toSdkNode(node);
|
|
1099
|
+
}, (node) => node.id);
|
|
1023
1100
|
}
|
|
1024
1101
|
|
|
1025
1102
|
addHtmlPrimitive(input: {
|
|
1103
|
+
intentId?: string;
|
|
1026
1104
|
kind: HtmlPrimitiveKind;
|
|
1027
1105
|
title?: string;
|
|
1028
1106
|
data?: Record<string, unknown>;
|
|
@@ -1032,39 +1110,43 @@ export class PmxCanvas extends EventEmitter {
|
|
|
1032
1110
|
height?: number;
|
|
1033
1111
|
strictSize?: boolean;
|
|
1034
1112
|
}): { id: string; kind: HtmlPrimitiveKind; title: string; htmlBytes: number } {
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1113
|
+
return this.runIntentCommit(input.intentId, ['create'], () => {
|
|
1114
|
+
const built = buildHtmlPrimitive({
|
|
1115
|
+
kind: input.kind,
|
|
1116
|
+
...(typeof input.title === 'string' ? { title: input.title } : {}),
|
|
1117
|
+
...(input.data ? { data: input.data } : {}),
|
|
1118
|
+
});
|
|
1119
|
+
const { id } = addCanvasNode({
|
|
1120
|
+
type: 'html',
|
|
1121
|
+
title: built.title,
|
|
1122
|
+
data: {
|
|
1123
|
+
html: built.html,
|
|
1124
|
+
htmlPrimitive: built.kind,
|
|
1125
|
+
primitiveData: built.data,
|
|
1126
|
+
description: built.summary,
|
|
1127
|
+
agentSummary: typeof input.data?.agentSummary === 'string' ? input.data.agentSummary : built.summary,
|
|
1128
|
+
...(typeof input.data?.summary === 'string' ? { summary: input.data.summary } : {}),
|
|
1129
|
+
...getHtmlPrimitiveSemanticMetadata(built.data),
|
|
1130
|
+
},
|
|
1131
|
+
...(typeof input.x === 'number' ? { x: input.x } : {}),
|
|
1132
|
+
...(typeof input.y === 'number' ? { y: input.y } : {}),
|
|
1133
|
+
...(typeof input.width === 'number' ? { width: input.width } : {}),
|
|
1134
|
+
...(typeof input.height === 'number' ? { height: input.height } : {}),
|
|
1135
|
+
...(input.strictSize ? { strictSize: true } : {}),
|
|
1136
|
+
defaultWidth: built.defaultSize.width,
|
|
1137
|
+
defaultHeight: built.defaultSize.height,
|
|
1138
|
+
});
|
|
1139
|
+
emitPrimaryWorkbenchEvent('canvas-layout-update', { layout: canvasState.getLayout() });
|
|
1140
|
+
return { id, kind: built.kind, title: built.title, htmlBytes: Buffer.byteLength(built.html, 'utf-8') };
|
|
1141
|
+
}, (result) => result.id);
|
|
1062
1142
|
}
|
|
1063
1143
|
|
|
1064
|
-
addGraphNode(input: GraphNodeInput): { id: string; url: string; spec: JsonRenderSpec } {
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1144
|
+
addGraphNode(input: GraphNodeInput & { intentId?: string }): { id: string; url: string; spec: JsonRenderSpec } {
|
|
1145
|
+
return this.runIntentCommit(input.intentId, ['create'], () => {
|
|
1146
|
+
const result = createCanvasGraphNode(input);
|
|
1147
|
+
emitPrimaryWorkbenchEvent('canvas-layout-update', { layout: canvasState.getLayout() });
|
|
1148
|
+
return result;
|
|
1149
|
+
}, (result) => result.id);
|
|
1068
1150
|
}
|
|
1069
1151
|
|
|
1070
1152
|
get port(): number {
|