pmx-canvas 0.2.7 → 0.3.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.
Files changed (189) hide show
  1. package/CHANGELOG.md +148 -1
  2. package/Readme.md +13 -11
  3. package/dist/canvas/index.js +2 -2
  4. package/dist/json-render/index.css +1 -1
  5. package/dist/types/cli/daemon.d.ts +74 -0
  6. package/dist/types/cli/watch.d.ts +2 -2
  7. package/dist/types/client/canvas/CanvasViewport.d.ts +1 -1
  8. package/dist/types/client/canvas/CommandPalette.d.ts +1 -1
  9. package/dist/types/client/canvas/Minimap.d.ts +1 -1
  10. package/dist/types/client/nodes/FileNode.d.ts +1 -1
  11. package/dist/types/client/nodes/ImageNode.d.ts +1 -1
  12. package/dist/types/client/nodes/InlineFormatBar.d.ts +1 -1
  13. package/dist/types/client/nodes/MarkdownNode.d.ts +1 -1
  14. package/dist/types/client/nodes/PromptNode.d.ts +1 -1
  15. package/dist/types/client/nodes/ResponseNode.d.ts +1 -1
  16. package/dist/types/mcp/canvas-access.d.ts +0 -7
  17. package/dist/types/server/ax-state-manager.d.ts +3 -2
  18. package/dist/types/server/bundled-skills.d.ts +3 -3
  19. package/dist/types/server/canvas-schema.d.ts +1 -1
  20. package/dist/types/server/canvas-state.d.ts +2 -0
  21. package/dist/types/server/ext-app-lookup.d.ts +1 -3
  22. package/dist/types/server/html-primitives.d.ts +1 -1
  23. package/dist/types/server/index.d.ts +4 -4
  24. package/dist/types/server/operations/composites.d.ts +29 -23
  25. package/dist/types/server/operations/http.d.ts +2 -1
  26. package/dist/types/server/operations/index.d.ts +1 -1
  27. package/dist/types/server/operations/ops/ax-read.d.ts +2 -0
  28. package/dist/types/server/operations/ops/canvas-wire.d.ts +2 -0
  29. package/dist/types/server/operations/ops/ext-app.d.ts +2 -0
  30. package/dist/types/shared/ax-intent.d.ts +1 -1
  31. package/docs/RELEASE.md +23 -8
  32. package/docs/ax-host-adapter-contract.md +7 -7
  33. package/docs/ax-state-contract.md +7 -6
  34. package/docs/bun-webview-integration.md +5 -5
  35. package/docs/cli.md +1 -1
  36. package/docs/http-api.md +35 -3
  37. package/docs/mcp.md +121 -100
  38. package/docs/node-types.md +45 -35
  39. package/docs/plans/plan-006-mcp-tool-consolidation.md +3 -1
  40. package/docs/plans/plan-008-registry-finish.md +2 -0
  41. package/docs/plans/plan-009-tech-debt-backlog.md +51 -0
  42. package/docs/screenshot.png +0 -0
  43. package/docs/tech-debt-assessment-2026-06.md +1 -1
  44. package/docs/tech-debt-assessment-2026-07.md +135 -0
  45. package/package.json +5 -2
  46. package/skills/data-analysis/SKILL.md +3 -3
  47. package/skills/frontend-design/SKILL.md +3 -2
  48. package/skills/json-render-mcp/SKILL.md +4 -3
  49. package/skills/playwright-cli/SKILL.md +1 -1
  50. package/skills/pmx-canvas/SKILL.md +12 -7
  51. package/skills/pmx-canvas/evals/evals.json +2 -2
  52. package/skills/pmx-canvas/references/ax-html-control-surface.md +3 -1
  53. package/skills/pmx-canvas/references/excalidraw-diagram-authoring.md +2 -2
  54. package/skills/pmx-canvas/references/full-reference.md +58 -56
  55. package/skills/pmx-canvas/references/html-primitives.md +3 -3
  56. package/skills/tufte-viz/SKILL.md +5 -4
  57. package/skills/web-artifacts-builder/SKILL.md +4 -4
  58. package/src/cli/agent.ts +1861 -1548
  59. package/src/cli/daemon.ts +460 -0
  60. package/src/cli/index.ts +63 -326
  61. package/src/cli/watch.ts +2 -10
  62. package/src/client/App.tsx +48 -46
  63. package/src/client/canvas/AttentionHistory.tsx +11 -1
  64. package/src/client/canvas/CanvasNode.tsx +41 -29
  65. package/src/client/canvas/CanvasViewport.tsx +101 -66
  66. package/src/client/canvas/CommandPalette.tsx +61 -27
  67. package/src/client/canvas/ContextMenu.tsx +13 -20
  68. package/src/client/canvas/ContextPinBar.tsx +1 -5
  69. package/src/client/canvas/ContextPinHud.tsx +1 -6
  70. package/src/client/canvas/DockedNode.tsx +4 -4
  71. package/src/client/canvas/EdgeLayer.tsx +37 -36
  72. package/src/client/canvas/ExpandedNodeOverlay.tsx +69 -45
  73. package/src/client/canvas/FocusFieldLayer.tsx +20 -22
  74. package/src/client/canvas/IntentLayer.tsx +31 -14
  75. package/src/client/canvas/Minimap.tsx +11 -16
  76. package/src/client/canvas/SelectionBar.tsx +4 -11
  77. package/src/client/canvas/ShortcutOverlay.tsx +3 -1
  78. package/src/client/canvas/SnapshotPanel.tsx +77 -95
  79. package/src/client/canvas/auto-fit.ts +15 -14
  80. package/src/client/canvas/snap-guides.ts +12 -12
  81. package/src/client/canvas/use-node-resize.ts +1 -5
  82. package/src/client/canvas/use-pan-zoom.ts +25 -26
  83. package/src/client/ext-app/bridge.ts +3 -12
  84. package/src/client/icons.tsx +63 -20
  85. package/src/client/nodes/ContextNode.tsx +14 -25
  86. package/src/client/nodes/ExtAppFrame.tsx +60 -39
  87. package/src/client/nodes/FileNode.tsx +74 -62
  88. package/src/client/nodes/GroupNode.tsx +4 -6
  89. package/src/client/nodes/HtmlNode.tsx +76 -46
  90. package/src/client/nodes/ImageNode.tsx +18 -27
  91. package/src/client/nodes/InlineFormatBar.tsx +4 -21
  92. package/src/client/nodes/InlineMarkdownEditor.tsx +0 -1
  93. package/src/client/nodes/LedgerNode.tsx +10 -4
  94. package/src/client/nodes/MarkdownNode.tsx +3 -10
  95. package/src/client/nodes/McpAppNode.tsx +26 -22
  96. package/src/client/nodes/MdFormatBar.tsx +10 -7
  97. package/src/client/nodes/PromptNode.tsx +23 -51
  98. package/src/client/nodes/ResponseNode.tsx +3 -13
  99. package/src/client/nodes/StatusNode.tsx +5 -9
  100. package/src/client/nodes/StatusSummary.tsx +2 -8
  101. package/src/client/nodes/WebpageNode.tsx +20 -14
  102. package/src/client/nodes/iframe-document-url.ts +25 -16
  103. package/src/client/nodes/image-warnings.ts +1 -7
  104. package/src/client/nodes/md-format.ts +20 -5
  105. package/src/client/state/attention-bridge.ts +4 -9
  106. package/src/client/state/attention-store.ts +1 -7
  107. package/src/client/state/canvas-store.ts +52 -36
  108. package/src/client/state/intent-bridge.ts +176 -112
  109. package/src/client/state/intent-store.ts +4 -1
  110. package/src/client/state/sse-bridge.ts +53 -70
  111. package/src/json-render/catalog.ts +12 -16
  112. package/src/json-render/charts/components.tsx +16 -20
  113. package/src/json-render/charts/extra-components.tsx +8 -16
  114. package/src/json-render/charts/extra-definitions.ts +1 -2
  115. package/src/json-render/charts/tufte-components.tsx +37 -20
  116. package/src/json-render/charts/tufte-definitions.ts +8 -2
  117. package/src/json-render/renderer/index.tsx +42 -22
  118. package/src/json-render/schema.ts +6 -3
  119. package/src/json-render/server.ts +33 -39
  120. package/src/mcp/canvas-access.ts +40 -121
  121. package/src/mcp/server.ts +206 -271
  122. package/src/server/agent-context.ts +63 -36
  123. package/src/server/ax-context.ts +7 -5
  124. package/src/server/ax-interaction.ts +176 -43
  125. package/src/server/ax-state-manager.ts +185 -41
  126. package/src/server/ax-state.ts +142 -47
  127. package/src/server/bundled-skills.ts +3 -3
  128. package/src/server/canvas-db.ts +213 -95
  129. package/src/server/canvas-operations.ts +177 -120
  130. package/src/server/canvas-provenance.ts +1 -4
  131. package/src/server/canvas-schema.ts +500 -102
  132. package/src/server/canvas-serialization.ts +27 -35
  133. package/src/server/canvas-state.ts +155 -58
  134. package/src/server/chart-template.ts +4 -5
  135. package/src/server/code-graph.ts +20 -7
  136. package/src/server/diagram-presets.ts +28 -29
  137. package/src/server/ext-app-lookup.ts +4 -20
  138. package/src/server/html-node-summary.ts +19 -10
  139. package/src/server/html-primitives.ts +326 -97
  140. package/src/server/html-surface.ts +6 -9
  141. package/src/server/image-source.ts +6 -4
  142. package/src/server/index.ts +321 -218
  143. package/src/server/intent-registry.ts +3 -6
  144. package/src/server/mcp-app-candidate.ts +5 -10
  145. package/src/server/mcp-app-host.ts +14 -38
  146. package/src/server/mcp-app-runtime.ts +12 -20
  147. package/src/server/mutation-history.ts +15 -5
  148. package/src/server/operations/composites.ts +38 -40
  149. package/src/server/operations/http.ts +5 -5
  150. package/src/server/operations/index.ts +7 -1
  151. package/src/server/operations/invoker.ts +4 -3
  152. package/src/server/operations/mcp.ts +29 -36
  153. package/src/server/operations/ops/annotation.ts +122 -10
  154. package/src/server/operations/ops/app.ts +102 -77
  155. package/src/server/operations/ops/ax-await.ts +17 -10
  156. package/src/server/operations/ops/ax-read.ts +347 -0
  157. package/src/server/operations/ops/ax-shared.ts +2 -7
  158. package/src/server/operations/ops/ax-state.ts +32 -14
  159. package/src/server/operations/ops/ax-timeline.ts +32 -19
  160. package/src/server/operations/ops/ax-work.ts +54 -37
  161. package/src/server/operations/ops/batch.ts +39 -14
  162. package/src/server/operations/ops/canvas-wire.ts +91 -0
  163. package/src/server/operations/ops/edges.ts +37 -25
  164. package/src/server/operations/ops/ext-app.ts +346 -0
  165. package/src/server/operations/ops/groups.ts +49 -20
  166. package/src/server/operations/ops/intent.ts +18 -12
  167. package/src/server/operations/ops/json-render.ts +239 -98
  168. package/src/server/operations/ops/nodes.ts +300 -111
  169. package/src/server/operations/ops/query.ts +62 -33
  170. package/src/server/operations/ops/snapshots.ts +35 -26
  171. package/src/server/operations/ops/validate.ts +2 -1
  172. package/src/server/operations/ops/viewport.ts +60 -16
  173. package/src/server/operations/ops/webview.ts +44 -18
  174. package/src/server/operations/registry.ts +2 -3
  175. package/src/server/operations/types.ts +7 -5
  176. package/src/server/operations/webview-runner.ts +1 -3
  177. package/src/server/placement.ts +8 -18
  178. package/src/server/server.ts +121 -1012
  179. package/src/server/spatial-analysis.ts +39 -25
  180. package/src/server/trace-manager.ts +3 -8
  181. package/src/server/web-artifacts.ts +23 -27
  182. package/src/server/webpage-node.ts +5 -13
  183. package/src/shared/auto-arrange.ts +12 -5
  184. package/src/shared/ax-intent.ts +1 -1
  185. package/src/shared/content-height-reporter.ts +8 -6
  186. package/src/shared/ext-app-tool-result.ts +2 -6
  187. package/src/shared/placement.ts +1 -4
  188. package/src/shared/semantic-attention.ts +39 -37
  189. package/src/shared/surface.ts +8 -4
@@ -12,10 +12,16 @@ export interface PmxAxFocusState {
12
12
 
13
13
  // ── New enums ──────────────────────────────────────────────────────
14
14
  export type PmxAxEventKind =
15
- | 'prompt' | 'assistant-message' | 'tool-start' | 'tool-result'
16
- | 'failure' | 'approval' | 'steering' | 'command' | 'note';
17
- export type PmxAxEvidenceKind =
18
- | 'logs' | 'tool-result' | 'screenshot' | 'file' | 'diff' | 'test-output';
15
+ | 'prompt'
16
+ | 'assistant-message'
17
+ | 'tool-start'
18
+ | 'tool-result'
19
+ | 'failure'
20
+ | 'approval'
21
+ | 'steering'
22
+ | 'command'
23
+ | 'note';
24
+ export type PmxAxEvidenceKind = 'logs' | 'tool-result' | 'screenshot' | 'file' | 'diff' | 'test-output';
19
25
  export type PmxAxWorkItemStatus = 'todo' | 'in-progress' | 'blocked' | 'done' | 'cancelled';
20
26
  export type PmxAxApprovalStatus = 'pending' | 'approved' | 'rejected';
21
27
  export type PmxAxReviewKind = 'comment' | 'finding';
@@ -226,17 +232,38 @@ export function buildPendingAxActivity(state: PmxAxState, consumer?: string): Pe
226
232
  }
227
233
  for (const g of state.approvalGates) {
228
234
  if (g.status === 'pending' && notMine(g.source)) {
229
- out.push({ kind: 'approval-gate', id: g.id, title: g.title, status: g.status, nodeIds: g.nodeIds, source: g.source });
235
+ out.push({
236
+ kind: 'approval-gate',
237
+ id: g.id,
238
+ title: g.title,
239
+ status: g.status,
240
+ nodeIds: g.nodeIds,
241
+ source: g.source,
242
+ });
230
243
  }
231
244
  }
232
245
  for (const e of state.elicitations) {
233
246
  if (e.status === 'pending' && notMine(e.source)) {
234
- out.push({ kind: 'elicitation', id: e.id, title: e.prompt, status: e.status, nodeIds: e.nodeIds, source: e.source });
247
+ out.push({
248
+ kind: 'elicitation',
249
+ id: e.id,
250
+ title: e.prompt,
251
+ status: e.status,
252
+ nodeIds: e.nodeIds,
253
+ source: e.source,
254
+ });
235
255
  }
236
256
  }
237
257
  for (const m of state.modeRequests) {
238
258
  if (m.status === 'pending' && notMine(m.source)) {
239
- out.push({ kind: 'mode-request', id: m.id, title: m.reason ? `${m.mode}: ${m.reason}` : `mode: ${m.mode}`, status: m.status, nodeIds: m.nodeIds, source: m.source });
259
+ out.push({
260
+ kind: 'mode-request',
261
+ id: m.id,
262
+ title: m.reason ? `${m.mode}: ${m.reason}` : `mode: ${m.mode}`,
263
+ status: m.status,
264
+ nodeIds: m.nodeIds,
265
+ source: m.source,
266
+ });
240
267
  }
241
268
  }
242
269
  return out;
@@ -249,9 +276,7 @@ function isRecord(value: unknown): value is Record<string, unknown> {
249
276
  }
250
277
 
251
278
  function normalizeSource(value: unknown): PmxAxSource | null {
252
- return typeof value === 'string' && AX_SOURCES.has(value as PmxAxSource)
253
- ? value as PmxAxSource
254
- : null;
279
+ return typeof value === 'string' && AX_SOURCES.has(value as PmxAxSource) ? (value as PmxAxSource) : null;
255
280
  }
256
281
 
257
282
  function normalizeTimestamp(value: unknown): string | null {
@@ -271,27 +296,50 @@ function normalizeNodeIds(value: unknown, validNodeIds?: Set<string>): string[]
271
296
  return ids;
272
297
  }
273
298
 
274
- const AX_EVENT_KINDS = new Set<PmxAxEventKind>(['prompt', 'assistant-message', 'tool-start', 'tool-result', 'failure', 'approval', 'steering', 'command', 'note']);
299
+ const AX_EVENT_KINDS = new Set<PmxAxEventKind>([
300
+ 'prompt',
301
+ 'assistant-message',
302
+ 'tool-start',
303
+ 'tool-result',
304
+ 'failure',
305
+ 'approval',
306
+ 'steering',
307
+ 'command',
308
+ 'note',
309
+ ]);
275
310
 
276
311
  // ── Activity ingestion (harness-forwarded tool/session events) ─────
277
312
  // A normalized activity the agent's harness forwards; the board auto-reacts.
278
313
  // The precise activity kind is preserved on the recorded event's `data.activityKind`;
279
314
  // only the (coarser) timeline event kind is constrained to PmxAxEventKind.
280
315
  export type PmxAxActivityKind =
281
- | 'tool-start' | 'tool-result' | 'failure' | 'error'
282
- | 'session-start' | 'session-end' | 'command' | 'note';
316
+ | 'tool-start'
317
+ | 'tool-result'
318
+ | 'failure'
319
+ | 'error'
320
+ | 'session-start'
321
+ | 'session-end'
322
+ | 'command'
323
+ | 'note';
283
324
  const AX_ACTIVITY_KINDS = new Set<PmxAxActivityKind>([
284
- 'tool-start', 'tool-result', 'failure', 'error', 'session-start', 'session-end', 'command', 'note',
325
+ 'tool-start',
326
+ 'tool-result',
327
+ 'failure',
328
+ 'error',
329
+ 'session-start',
330
+ 'session-end',
331
+ 'command',
332
+ 'note',
285
333
  ]);
286
334
  const ACTIVITY_TO_EVENT_KIND: Record<PmxAxActivityKind, PmxAxEventKind> = {
287
335
  'tool-start': 'tool-start',
288
336
  'tool-result': 'tool-result',
289
- 'failure': 'failure',
290
- 'error': 'failure',
337
+ failure: 'failure',
338
+ error: 'failure',
291
339
  'session-start': 'assistant-message',
292
340
  'session-end': 'assistant-message',
293
- 'command': 'command',
294
- 'note': 'assistant-message',
341
+ command: 'command',
342
+ note: 'assistant-message',
295
343
  };
296
344
  export function isAxActivityKind(value: unknown): value is PmxAxActivityKind {
297
345
  return typeof value === 'string' && AX_ACTIVITY_KINDS.has(value as PmxAxActivityKind);
@@ -312,13 +360,16 @@ export interface PmxAxCommandDescriptor {
312
360
  export const AX_COMMAND_REGISTRY: Record<string, PmxAxCommandDescriptor> = {
313
361
  'pmx.plan': { name: 'pmx.plan', description: 'Enter planning: outline the approach before executing.' },
314
362
  'pmx.execute': { name: 'pmx.execute', description: 'Proceed from plan to execution.' },
315
- 'pmx.promote-context': { name: 'pmx.promote-context', description: 'Promote focused/pinned nodes into durable agent context.' },
363
+ 'pmx.promote-context': {
364
+ name: 'pmx.promote-context',
365
+ description: 'Promote focused/pinned nodes into durable agent context.',
366
+ },
316
367
  'pmx.summarize': { name: 'pmx.summarize', description: 'Summarize the current canvas/work state.' },
317
368
  'pmx.review': { name: 'pmx.review', description: 'Start a review pass over the focused nodes.' },
318
369
  };
319
370
 
320
371
  export function isAxCommand(name: unknown): name is string {
321
- return typeof name === 'string' && Object.prototype.hasOwnProperty.call(AX_COMMAND_REGISTRY, name);
372
+ return typeof name === 'string' && Object.hasOwn(AX_COMMAND_REGISTRY, name);
322
373
  }
323
374
 
324
375
  export function listAxCommands(): PmxAxCommandDescriptor[] {
@@ -361,7 +412,14 @@ export function normalizeAxPolicy(input: unknown): PmxAxPolicy {
361
412
  },
362
413
  };
363
414
  }
364
- const AX_EVIDENCE_KINDS = new Set<PmxAxEvidenceKind>(['logs', 'tool-result', 'screenshot', 'file', 'diff', 'test-output']);
415
+ const AX_EVIDENCE_KINDS = new Set<PmxAxEvidenceKind>([
416
+ 'logs',
417
+ 'tool-result',
418
+ 'screenshot',
419
+ 'file',
420
+ 'diff',
421
+ 'test-output',
422
+ ]);
365
423
  const AX_WORK_STATUSES = new Set<PmxAxWorkItemStatus>(['todo', 'in-progress', 'blocked', 'done', 'cancelled']);
366
424
  const AX_APPROVAL_STATUSES = new Set<PmxAxApprovalStatus>(['pending', 'approved', 'rejected']);
367
425
  const AX_REVIEW_KINDS = new Set<PmxAxReviewKind>(['comment', 'finding']);
@@ -425,7 +483,9 @@ export function normalizeAxElicitation(input: unknown, validNodeIds?: Set<string
425
483
  id: input.id,
426
484
  prompt: typeof input.prompt === 'string' ? input.prompt : '(input requested)',
427
485
  fields: Array.isArray(input.fields) ? input.fields.filter((f): f is string => typeof f === 'string') : [],
428
- status: AX_ELICITATION_STATUSES.has(input.status as PmxAxElicitationStatus) ? input.status as PmxAxElicitationStatus : 'pending',
486
+ status: AX_ELICITATION_STATUSES.has(input.status as PmxAxElicitationStatus)
487
+ ? (input.status as PmxAxElicitationStatus)
488
+ : 'pending',
429
489
  response: isRecord(input.response) ? input.response : null,
430
490
  nodeIds: normalizeNodeIds(input.nodeIds, validNodeIds),
431
491
  createdAt: normalizeTimestamp(input.createdAt) ?? nowIso(),
@@ -475,9 +535,11 @@ export function normalizeAxModeRequest(input: unknown, validNodeIds?: Set<string
475
535
  if (!isRecord(input) || typeof input.id !== 'string') return null;
476
536
  return {
477
537
  id: input.id,
478
- mode: AX_MODES.has(input.mode as PmxAxMode) ? input.mode as PmxAxMode : 'execute',
538
+ mode: AX_MODES.has(input.mode as PmxAxMode) ? (input.mode as PmxAxMode) : 'execute',
479
539
  reason: optionalString(input.reason),
480
- status: AX_MODE_REQUEST_STATUSES.has(input.status as PmxAxModeRequestStatus) ? input.status as PmxAxModeRequestStatus : 'pending',
540
+ status: AX_MODE_REQUEST_STATUSES.has(input.status as PmxAxModeRequestStatus)
541
+ ? (input.status as PmxAxModeRequestStatus)
542
+ : 'pending',
481
543
  nodeIds: normalizeNodeIds(input.nodeIds, validNodeIds),
482
544
  createdAt: normalizeTimestamp(input.createdAt) ?? nowIso(),
483
545
  resolvedAt: normalizeTimestamp(input.resolvedAt),
@@ -535,9 +597,10 @@ export function createEmptyAxHostCapability(): PmxAxHostCapability {
535
597
  export function normalizeAxFocusState(input: unknown, validNodeIds?: Set<string>): PmxAxFocusState {
536
598
  if (!isRecord(input)) return createEmptyAxFocusState();
537
599
  const nodeIds = normalizeNodeIds(input.nodeIds, validNodeIds);
538
- const primaryNodeId = typeof input.primaryNodeId === 'string' && nodeIds.includes(input.primaryNodeId)
539
- ? input.primaryNodeId
540
- : nodeIds[0] ?? null;
600
+ const primaryNodeId =
601
+ typeof input.primaryNodeId === 'string' && nodeIds.includes(input.primaryNodeId)
602
+ ? input.primaryNodeId
603
+ : (nodeIds[0] ?? null);
541
604
  return {
542
605
  nodeIds,
543
606
  primaryNodeId,
@@ -553,7 +616,7 @@ export function normalizeAxWorkItem(input: unknown, validNodeIds?: Set<string>):
553
616
  return {
554
617
  id: input.id,
555
618
  title: typeof input.title === 'string' ? input.title : '(untitled)',
556
- status: AX_WORK_STATUSES.has(input.status as PmxAxWorkItemStatus) ? input.status as PmxAxWorkItemStatus : 'todo',
619
+ status: AX_WORK_STATUSES.has(input.status as PmxAxWorkItemStatus) ? (input.status as PmxAxWorkItemStatus) : 'todo',
557
620
  detail: optionalString(input.detail),
558
621
  nodeIds: normalizeNodeIds(input.nodeIds, validNodeIds),
559
622
  createdAt,
@@ -569,7 +632,9 @@ export function normalizeAxApprovalGate(input: unknown, validNodeIds?: Set<strin
569
632
  title: typeof input.title === 'string' ? input.title : '(approval)',
570
633
  detail: optionalString(input.detail),
571
634
  action: optionalString(input.action),
572
- status: AX_APPROVAL_STATUSES.has(input.status as PmxAxApprovalStatus) ? input.status as PmxAxApprovalStatus : 'pending',
635
+ status: AX_APPROVAL_STATUSES.has(input.status as PmxAxApprovalStatus)
636
+ ? (input.status as PmxAxApprovalStatus)
637
+ : 'pending',
573
638
  nodeIds: normalizeNodeIds(input.nodeIds, validNodeIds),
574
639
  createdAt: normalizeTimestamp(input.createdAt) ?? nowIso(),
575
640
  resolvedAt: normalizeTimestamp(input.resolvedAt),
@@ -581,7 +646,9 @@ export function normalizeAxApprovalGate(input: unknown, validNodeIds?: Set<strin
581
646
  export function normalizeAxReviewAnnotation(input: unknown, validNodeIds?: Set<string>): PmxAxReviewAnnotation | null {
582
647
  if (!isRecord(input) || typeof input.id !== 'string') return null;
583
648
  const createdAt = normalizeTimestamp(input.createdAt) ?? nowIso();
584
- const anchorType = AX_REVIEW_ANCHORS.has(input.anchorType as PmxAxReviewAnchorType) ? input.anchorType as PmxAxReviewAnchorType : 'node';
649
+ const anchorType = AX_REVIEW_ANCHORS.has(input.anchorType as PmxAxReviewAnchorType)
650
+ ? (input.anchorType as PmxAxReviewAnchorType)
651
+ : 'node';
585
652
  // node anchor pruned to a valid node; if invalid, drop the whole annotation (mirrors focus pruning)
586
653
  let nodeId: string | null = null;
587
654
  if (anchorType === 'node') {
@@ -589,17 +656,21 @@ export function normalizeAxReviewAnnotation(input: unknown, validNodeIds?: Set<s
589
656
  if (validNodeIds && !validNodeIds.has(input.nodeId)) return null;
590
657
  nodeId = input.nodeId;
591
658
  }
592
- const region = isRecord(input.region) ? {
593
- ...(typeof input.region.line === 'number' ? { line: input.region.line } : {}),
594
- ...(typeof input.region.endLine === 'number' ? { endLine: input.region.endLine } : {}),
595
- ...(typeof input.region.label === 'string' ? { label: input.region.label } : {}),
596
- } : null;
659
+ const region = isRecord(input.region)
660
+ ? {
661
+ ...(typeof input.region.line === 'number' ? { line: input.region.line } : {}),
662
+ ...(typeof input.region.endLine === 'number' ? { endLine: input.region.endLine } : {}),
663
+ ...(typeof input.region.label === 'string' ? { label: input.region.label } : {}),
664
+ }
665
+ : null;
597
666
  return {
598
667
  id: input.id,
599
- kind: AX_REVIEW_KINDS.has(input.kind as PmxAxReviewKind) ? input.kind as PmxAxReviewKind : 'comment',
668
+ kind: AX_REVIEW_KINDS.has(input.kind as PmxAxReviewKind) ? (input.kind as PmxAxReviewKind) : 'comment',
600
669
  body: typeof input.body === 'string' ? input.body : '',
601
- severity: AX_REVIEW_SEVERITIES.has(input.severity as PmxAxReviewSeverity) ? input.severity as PmxAxReviewSeverity : 'info',
602
- status: AX_REVIEW_STATUSES.has(input.status as PmxAxReviewStatus) ? input.status as PmxAxReviewStatus : 'open',
670
+ severity: AX_REVIEW_SEVERITIES.has(input.severity as PmxAxReviewSeverity)
671
+ ? (input.severity as PmxAxReviewSeverity)
672
+ : 'info',
673
+ status: AX_REVIEW_STATUSES.has(input.status as PmxAxReviewStatus) ? (input.status as PmxAxReviewStatus) : 'open',
603
674
  anchorType,
604
675
  nodeId,
605
676
  file: anchorType === 'file' ? optionalString(input.file) : null,
@@ -632,7 +703,7 @@ export function normalizeAxHostCapability(input: unknown): PmxAxHostCapability |
632
703
  // ── Timeline normalizers (DB row parse; node ids kept as recorded) ──
633
704
  export function normalizeAxEvent(input: unknown): PmxAxEvent | null {
634
705
  if (!isRecord(input) || typeof input.id !== 'string') return null;
635
- const kind = AX_EVENT_KINDS.has(input.kind as PmxAxEventKind) ? input.kind as PmxAxEventKind : null;
706
+ const kind = AX_EVENT_KINDS.has(input.kind as PmxAxEventKind) ? (input.kind as PmxAxEventKind) : null;
636
707
  if (!kind) return null;
637
708
  return {
638
709
  id: input.id,
@@ -649,7 +720,7 @@ export function normalizeAxEvent(input: unknown): PmxAxEvent | null {
649
720
 
650
721
  export function normalizeAxEvidence(input: unknown): PmxAxEvidence | null {
651
722
  if (!isRecord(input) || typeof input.id !== 'string') return null;
652
- const kind = AX_EVIDENCE_KINDS.has(input.kind as PmxAxEvidenceKind) ? input.kind as PmxAxEvidenceKind : null;
723
+ const kind = AX_EVIDENCE_KINDS.has(input.kind as PmxAxEvidenceKind) ? (input.kind as PmxAxEvidenceKind) : null;
653
724
  if (!kind) return null;
654
725
  return {
655
726
  id: input.id,
@@ -750,7 +821,13 @@ export function createAxReviewAnnotation(
750
821
  }
751
822
 
752
823
  export function createAxEvent(
753
- input: { kind: PmxAxEventKind; summary: string; detail?: string | null; nodeIds?: string[]; data?: Record<string, unknown> | null },
824
+ input: {
825
+ kind: PmxAxEventKind;
826
+ summary: string;
827
+ detail?: string | null;
828
+ nodeIds?: string[];
829
+ data?: Record<string, unknown> | null;
830
+ },
754
831
  source: PmxAxSource | null,
755
832
  ): Omit<PmxAxEvent, 'seq'> {
756
833
  return {
@@ -766,7 +843,14 @@ export function createAxEvent(
766
843
  }
767
844
 
768
845
  export function createAxEvidence(
769
- input: { kind: PmxAxEvidenceKind; title: string; body?: string | null; ref?: string | null; nodeIds?: string[]; data?: Record<string, unknown> | null },
846
+ input: {
847
+ kind: PmxAxEvidenceKind;
848
+ title: string;
849
+ body?: string | null;
850
+ ref?: string | null;
851
+ nodeIds?: string[];
852
+ data?: Record<string, unknown> | null;
853
+ },
770
854
  source: PmxAxSource | null,
771
855
  ): Omit<PmxAxEvidence, 'seq'> {
772
856
  return {
@@ -782,7 +866,10 @@ export function createAxEvidence(
782
866
  };
783
867
  }
784
868
 
785
- export function createAxSteeringMessage(message: string, source: PmxAxSource | null): Omit<PmxAxSteeringMessage, 'seq'> {
869
+ export function createAxSteeringMessage(
870
+ message: string,
871
+ source: PmxAxSource | null,
872
+ ): Omit<PmxAxSteeringMessage, 'seq'> {
786
873
  return {
787
874
  id: axId('steer'),
788
875
  message,
@@ -801,16 +888,24 @@ export function normalizeAxState(input: unknown, validNodeIds?: Set<string>): Pm
801
888
  ? input.workItems.map((w) => normalizeAxWorkItem(w, validNodeIds)).filter((w): w is PmxAxWorkItem => w !== null)
802
889
  : [],
803
890
  approvalGates: Array.isArray(input.approvalGates)
804
- ? input.approvalGates.map((g) => normalizeAxApprovalGate(g, validNodeIds)).filter((g): g is PmxAxApprovalGate => g !== null)
891
+ ? input.approvalGates
892
+ .map((g) => normalizeAxApprovalGate(g, validNodeIds))
893
+ .filter((g): g is PmxAxApprovalGate => g !== null)
805
894
  : [],
806
895
  reviewAnnotations: Array.isArray(input.reviewAnnotations)
807
- ? input.reviewAnnotations.map((r) => normalizeAxReviewAnnotation(r, validNodeIds)).filter((r): r is PmxAxReviewAnnotation => r !== null)
896
+ ? input.reviewAnnotations
897
+ .map((r) => normalizeAxReviewAnnotation(r, validNodeIds))
898
+ .filter((r): r is PmxAxReviewAnnotation => r !== null)
808
899
  : [],
809
900
  elicitations: Array.isArray(input.elicitations)
810
- ? input.elicitations.map((e) => normalizeAxElicitation(e, validNodeIds)).filter((e): e is PmxAxElicitation => e !== null)
901
+ ? input.elicitations
902
+ .map((e) => normalizeAxElicitation(e, validNodeIds))
903
+ .filter((e): e is PmxAxElicitation => e !== null)
811
904
  : [],
812
905
  modeRequests: Array.isArray(input.modeRequests)
813
- ? input.modeRequests.map((m) => normalizeAxModeRequest(m, validNodeIds)).filter((m): m is PmxAxModeRequest => m !== null)
906
+ ? input.modeRequests
907
+ .map((m) => normalizeAxModeRequest(m, validNodeIds))
908
+ .filter((m): m is PmxAxModeRequest => m !== null)
814
909
  : [],
815
910
  policy: normalizeAxPolicy(input.policy),
816
911
  };
@@ -3,9 +3,9 @@
3
3
  *
4
4
  * Skill files ship inside the npm package under `skills/<name>/SKILL.md`
5
5
  * but until 0.1.2 they were not discoverable to the agent — an agent
6
- * calling `canvas_build_web_artifact` had no way to find the companion
7
- * `skills/web-artifacts-builder/SKILL.md` prompt that documents the
8
- * workflow, stack choices, and gotchas.
6
+ * calling `canvas_app` (`build-artifact` action) had no way to find the
7
+ * companion `skills/web-artifacts-builder/SKILL.md` prompt that documents
8
+ * the workflow, stack choices, and gotchas.
9
9
  *
10
10
  * This module locates the bundled `skills/` directory relative to the
11
11
  * package root (works for both repo-local development and global npm