pmx-canvas 0.7.2 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (251) hide show
  1. package/.github/extensions/pmx-canvas/THIRD_PARTY_LICENSES.txt +331 -0
  2. package/.github/extensions/pmx-canvas/extension.mjs +25 -172
  3. package/.github/extensions/pmx-canvas/mcp-bootstrap.ts +198 -0
  4. package/.github/extensions/pmx-canvas/runtime.d.mts +41 -0
  5. package/.github/extensions/pmx-canvas/runtime.json +3 -0
  6. package/.github/extensions/pmx-canvas/runtime.mjs +194 -0
  7. package/.github/extensions/pmx-canvas/start-mcp.mjs +51 -0
  8. package/.github/extensions/pmx-canvas/tools.json +2560 -0
  9. package/CHANGELOG.md +60 -0
  10. package/Readme.md +44 -16
  11. package/dist/canvas/fonts/OFL.txt +93 -0
  12. package/dist/canvas/fonts/ibm-plex-mono-latin-400-normal.woff2 +0 -0
  13. package/dist/canvas/fonts/ibm-plex-mono-latin-500-normal.woff2 +0 -0
  14. package/dist/canvas/fonts/ibm-plex-mono-latin-ext-400-normal.woff2 +0 -0
  15. package/dist/canvas/fonts/ibm-plex-mono-latin-ext-500-normal.woff2 +0 -0
  16. package/dist/canvas/fonts/ibm-plex-sans-latin-400-normal.woff2 +0 -0
  17. package/dist/canvas/fonts/ibm-plex-sans-latin-500-normal.woff2 +0 -0
  18. package/dist/canvas/fonts/ibm-plex-sans-latin-600-normal.woff2 +0 -0
  19. package/dist/canvas/fonts/ibm-plex-sans-latin-ext-400-normal.woff2 +0 -0
  20. package/dist/canvas/fonts/ibm-plex-sans-latin-ext-500-normal.woff2 +0 -0
  21. package/dist/canvas/fonts/ibm-plex-sans-latin-ext-600-normal.woff2 +0 -0
  22. package/dist/canvas/global.css +844 -710
  23. package/dist/canvas/index.js +92 -90
  24. package/dist/canvas/mcp-app.html +7878 -0
  25. package/dist/canvas/mermaid-entry.js +1 -1
  26. package/dist/canvas/surface-theme.css +151 -46
  27. package/dist/json-render/index.css +1 -1
  28. package/dist/json-render/index.js +55 -55
  29. package/dist/types/cli/commands/record.d.ts +1 -1
  30. package/dist/types/client/canvas/ChoiceMenu.d.ts +13 -0
  31. package/dist/types/client/canvas/NodeContextMark.d.ts +24 -0
  32. package/dist/types/client/canvas/SessionReceipt.d.ts +3 -1
  33. package/dist/types/client/icons.d.ts +1 -2
  34. package/dist/types/client/mcp-app/index.d.ts +1 -0
  35. package/dist/types/client/nodes/McpAppNode.d.ts +2 -1
  36. package/dist/types/client/nodes/ax-node-actions.d.ts +2 -2
  37. package/dist/types/client/nodes/markdown-sanitize.d.ts +2 -0
  38. package/dist/types/client/nodes/use-workbench-asset.d.ts +2 -0
  39. package/dist/types/client/nodes/viewer-runtime-state.d.ts +1 -0
  40. package/dist/types/client/state/attention-store.d.ts +0 -5
  41. package/dist/types/client/state/canvas-store.d.ts +2 -0
  42. package/dist/types/client/state/context-status-store.d.ts +53 -0
  43. package/dist/types/client/state/intent-bridge.d.ts +4 -1
  44. package/dist/types/client/state/near-pin-store.d.ts +16 -0
  45. package/dist/types/client/state/presence-store.d.ts +5 -0
  46. package/dist/types/client/state/session-store.d.ts +33 -3
  47. package/dist/types/client/state/workbench-transport.d.ts +16 -0
  48. package/dist/types/client/theme/tokens.d.ts +1 -3
  49. package/dist/types/client/types.d.ts +9 -0
  50. package/dist/types/json-render/renderer/index.d.ts +2 -1
  51. package/dist/types/json-render/server.d.ts +3 -1
  52. package/dist/types/mcp/app-server.d.ts +3 -0
  53. package/dist/types/mcp/canvas-access.d.ts +1 -1
  54. package/dist/types/mcp/canvas-app.d.ts +4 -0
  55. package/dist/types/mcp/workbench-app.d.ts +4 -0
  56. package/dist/types/server/agent-presence.d.ts +1 -1
  57. package/dist/types/server/ax-state.d.ts +1 -1
  58. package/dist/types/server/canvas-db.d.ts +8 -0
  59. package/dist/types/server/canvas-geometry.d.ts +25 -0
  60. package/dist/types/server/canvas-operations.d.ts +1 -11
  61. package/dist/types/server/canvas-state.d.ts +25 -3
  62. package/dist/types/server/context-brief.d.ts +8 -1
  63. package/dist/types/server/context-reads.d.ts +30 -7
  64. package/dist/types/server/index.d.ts +6 -1
  65. package/dist/types/server/mcp-app-runtime.d.ts +1 -0
  66. package/dist/types/server/operations/http.d.ts +2 -0
  67. package/dist/types/server/operations/invoker.d.ts +4 -2
  68. package/dist/types/server/operations/ops/nodes.d.ts +0 -6
  69. package/dist/types/server/server.d.ts +1 -0
  70. package/dist/types/server/spatial-analysis.d.ts +2 -0
  71. package/dist/types/shared/agent-context.d.ts +22 -0
  72. package/dist/types/shared/agent-presence.d.ts +3 -10
  73. package/dist/types/shared/ax-surface-protocol.d.ts +2 -0
  74. package/dist/types/shared/canvas-app.d.ts +54 -0
  75. package/dist/types/shared/themes.d.ts +1 -1
  76. package/docs/RELEASE.md +7 -3
  77. package/docs/agent-plugin.md +123 -0
  78. package/docs/ax-host-adapter-contract.md +13 -2
  79. package/docs/ax-state-contract.md +40 -0
  80. package/docs/cli.md +7 -2
  81. package/docs/design/AgentContext.dc.html +186 -0
  82. package/docs/design/Before.dc.html +208 -0
  83. package/docs/design/BoardPins.dc.html +151 -0
  84. package/docs/design/Chrome.dc.html +208 -0
  85. package/docs/design/Context.dc.html +239 -0
  86. package/docs/design/Flows.dc.html +181 -0
  87. package/docs/design/Home.dc.html +209 -0
  88. package/docs/design/HomeGraph.dc.html +211 -0
  89. package/docs/design/HomeMap.dc.html +117 -0
  90. package/docs/design/HomeTeam.dc.html +176 -0
  91. package/docs/design/Light.dc.html +28 -0
  92. package/docs/design/Main.dc.html +280 -0
  93. package/docs/design/NearPin.dc.html +260 -0
  94. package/docs/design/Pane600.dc.html +120 -0
  95. package/docs/design/Relations.dc.html +297 -0
  96. package/docs/design/Themes.dc.html +121 -0
  97. package/docs/design/TokenSystem.dc.html +136 -0
  98. package/docs/design/Tokens.dc.html +163 -0
  99. package/docs/design/Types1.dc.html +177 -0
  100. package/docs/design/Types2.dc.html +226 -0
  101. package/docs/design/Types3.dc.html +195 -0
  102. package/docs/design/Uses.dc.html +152 -0
  103. package/docs/design/Vision.dc.html +116 -0
  104. package/docs/design/Zoom.dc.html +82 -0
  105. package/docs/design/canvas.json +274 -0
  106. package/docs/design.md +214 -0
  107. package/docs/environment.md +1 -1
  108. package/docs/http-api.md +80 -15
  109. package/docs/mcp.md +198 -3
  110. package/docs/node-types.md +34 -10
  111. package/docs/plans/plan-009-tech-debt-backlog.md +1 -1
  112. package/docs/plans/plan-015-design-foundation-wave-0.md +177 -0
  113. package/docs/plans/plan-016-context-made-visible-wave-1.md +148 -0
  114. package/docs/product-vision-2026-09.md +47 -7
  115. package/docs/screenshot.png +0 -0
  116. package/docs/sdk.md +1 -0
  117. package/package.json +10 -4
  118. package/plugins/pmx-canvas/LICENSE +21 -0
  119. package/plugins/pmx-canvas/THIRD_PARTY_LICENSES.txt +331 -0
  120. package/plugins/pmx-canvas/assets/preview.png +0 -0
  121. package/plugins/pmx-canvas/com.github.copilot/extensions/pmx-canvas/extension.mjs +930 -0
  122. package/plugins/pmx-canvas/com.github.copilot/extensions/pmx-canvas/runtime.json +3 -0
  123. package/plugins/pmx-canvas/com.github.copilot/extensions/pmx-canvas/runtime.mjs +194 -0
  124. package/plugins/pmx-canvas/com.github.copilot/extensions/pmx-canvas/steering-delivery.mjs +79 -0
  125. package/plugins/pmx-canvas/mcp.json +12 -0
  126. package/plugins/pmx-canvas/plugin.json +24 -0
  127. package/plugins/pmx-canvas/runtime.json +3 -0
  128. package/plugins/pmx-canvas/runtime.mjs +194 -0
  129. package/plugins/pmx-canvas/start-mcp.mjs +51 -0
  130. package/plugins/pmx-canvas/tools.json +2560 -0
  131. package/skills/pmx-canvas/SKILL.md +31 -16
  132. package/skills/pmx-canvas/evals/evals.json +69 -0
  133. package/skills/pmx-canvas/references/full-reference.md +14 -10
  134. package/skills/pmx-canvas/references/github-copilot-app-adapter.md +20 -8
  135. package/skills/pmx-canvas/references/installing-pmx-canvas.md +76 -4
  136. package/skills/pmx-canvas-testing/SKILL.md +54 -4
  137. package/src/cli/commands/copilot.ts +5 -0
  138. package/src/cli/commands/view.ts +1 -1
  139. package/src/cli/index.ts +8 -3
  140. package/src/client/App.tsx +6 -1
  141. package/src/client/canvas/AgentPresenceLayer.tsx +3 -3
  142. package/src/client/canvas/AnnotationLayer.tsx +1 -1
  143. package/src/client/canvas/CanvasNode.tsx +208 -220
  144. package/src/client/canvas/CanvasViewport.tsx +6 -2
  145. package/src/client/canvas/ChoiceMenu.tsx +122 -0
  146. package/src/client/canvas/CommandBar.tsx +25 -23
  147. package/src/client/canvas/CommandPalette.tsx +3 -2
  148. package/src/client/canvas/ContextMenu.tsx +11 -0
  149. package/src/client/canvas/EdgeLayer.tsx +1 -1
  150. package/src/client/canvas/ExportDialog.tsx +33 -6
  151. package/src/client/canvas/FeedbackDialog.tsx +10 -8
  152. package/src/client/canvas/IntentLayer.tsx +2 -2
  153. package/src/client/canvas/Minimap.tsx +12 -7
  154. package/src/client/canvas/NodeContextMark.tsx +156 -0
  155. package/src/client/canvas/SessionPanel.tsx +4 -7
  156. package/src/client/canvas/SessionReceipt.tsx +114 -17
  157. package/src/client/canvas/ShortcutOverlay.tsx +6 -1
  158. package/src/client/canvas/SnapshotPanel.tsx +11 -2
  159. package/src/client/canvas/ToolRail.tsx +58 -108
  160. package/src/client/canvas/TopBar.tsx +16 -11
  161. package/src/client/icons.tsx +2 -12
  162. package/src/client/mcp-app/index.tsx +137 -0
  163. package/src/client/mcp-app/style.css +10 -0
  164. package/src/client/nodes/AttachmentNode.tsx +8 -1
  165. package/src/client/nodes/AxStepControls.tsx +1 -1
  166. package/src/client/nodes/ContextNode.tsx +9 -9
  167. package/src/client/nodes/ExtAppFrame.tsx +13 -8
  168. package/src/client/nodes/FileNode.tsx +8 -5
  169. package/src/client/nodes/ImageNode.tsx +4 -2
  170. package/src/client/nodes/InlineMarkdownEditor.tsx +2 -1
  171. package/src/client/nodes/LedgerNode.tsx +2 -2
  172. package/src/client/nodes/MarkdownNode.tsx +44 -9
  173. package/src/client/nodes/McpAppNode.tsx +22 -4
  174. package/src/client/nodes/PromptNode.tsx +5 -17
  175. package/src/client/nodes/ResponseNode.tsx +3 -15
  176. package/src/client/nodes/StatusNode.tsx +2 -2
  177. package/src/client/nodes/StatusSummary.tsx +3 -1
  178. package/src/client/nodes/TraceNode.tsx +6 -4
  179. package/src/client/nodes/WebpageNode.tsx +1 -1
  180. package/src/client/nodes/ax-node-actions.ts +2 -2
  181. package/src/client/nodes/iframe-document-url.ts +3 -2
  182. package/src/client/nodes/markdown-sanitize.ts +10 -0
  183. package/src/client/nodes/surface-url.ts +10 -0
  184. package/src/client/nodes/use-ax-surface-bridge.ts +4 -2
  185. package/src/client/nodes/use-surface-frame.ts +3 -1
  186. package/src/client/nodes/use-workbench-asset.ts +26 -0
  187. package/src/client/nodes/viewer-runtime-state.ts +78 -0
  188. package/src/client/state/attention-bridge.ts +0 -8
  189. package/src/client/state/attention-store.ts +0 -17
  190. package/src/client/state/canvas-store.ts +7 -2
  191. package/src/client/state/context-status-store.ts +66 -0
  192. package/src/client/state/human-store.ts +2 -0
  193. package/src/client/state/iframe-mode.ts +5 -0
  194. package/src/client/state/intent-bridge.ts +24 -6
  195. package/src/client/state/near-pin-store.ts +53 -0
  196. package/src/client/state/presence-store.ts +5 -10
  197. package/src/client/state/session-store.ts +106 -9
  198. package/src/client/state/sse-bridge.ts +26 -7
  199. package/src/client/state/theme-override.ts +1 -1
  200. package/src/client/state/workbench-transport.ts +36 -0
  201. package/src/client/theme/global.css +844 -710
  202. package/src/client/theme/surface-theme.css +151 -46
  203. package/src/client/theme/tokens.ts +7 -11
  204. package/src/client/types.ts +10 -0
  205. package/src/json-render/renderer/index.tsx +58 -38
  206. package/src/json-render/server.ts +79 -15
  207. package/src/mcp/app-server.ts +64 -0
  208. package/src/mcp/canvas-access.ts +14 -11
  209. package/src/mcp/canvas-app.ts +318 -0
  210. package/src/mcp/server.ts +1 -1
  211. package/src/mcp/workbench-app.ts +211 -0
  212. package/src/server/agent-presence.ts +45 -6
  213. package/src/server/ax-context.ts +1 -1
  214. package/src/server/ax-state.ts +1 -1
  215. package/src/server/board-export.ts +5 -2
  216. package/src/server/canvas-db.ts +46 -12
  217. package/src/server/canvas-geometry.ts +64 -0
  218. package/src/server/canvas-operations.ts +6 -24
  219. package/src/server/canvas-state.ts +105 -15
  220. package/src/server/canvas-validation.ts +19 -4
  221. package/src/server/context-brief.ts +39 -2
  222. package/src/server/context-reads.ts +86 -15
  223. package/src/server/demo-state.json +31 -31
  224. package/src/server/html-surface.ts +4 -5
  225. package/src/server/index.ts +19 -3
  226. package/src/server/mcp-app-runtime.ts +11 -0
  227. package/src/server/operations/composites.ts +4 -3
  228. package/src/server/operations/http.ts +4 -4
  229. package/src/server/operations/invoker.ts +13 -4
  230. package/src/server/operations/ops/ax-read.ts +1 -1
  231. package/src/server/operations/ops/ax-timeline.ts +37 -0
  232. package/src/server/operations/ops/boards.ts +1 -1
  233. package/src/server/operations/ops/canvas-wire.ts +3 -6
  234. package/src/server/operations/ops/intent.ts +31 -2
  235. package/src/server/operations/ops/json-render.ts +1 -1
  236. package/src/server/operations/ops/nodes.ts +8 -76
  237. package/src/server/operations/ops/query.ts +8 -2
  238. package/src/server/operations/ops/snapshots.ts +4 -1
  239. package/src/server/operations/ops/viewport.ts +29 -5
  240. package/src/server/operations/registry.ts +38 -4
  241. package/src/server/scope-fence.ts +55 -10
  242. package/src/server/server.ts +86 -6
  243. package/src/server/spatial-analysis.ts +2 -2
  244. package/src/server/workboard.ts +6 -1
  245. package/src/{server → shared}/agent-context.ts +2 -2
  246. package/src/shared/agent-presence.ts +3 -15
  247. package/src/shared/ax-surface-protocol.ts +3 -0
  248. package/src/shared/canvas-app.ts +62 -0
  249. package/src/shared/themes.ts +5 -5
  250. package/src/client/canvas/FocusFieldLayer.tsx +0 -116
  251. package/src/client/canvas/kind-colors.ts +0 -23
@@ -1,5 +1,5 @@
1
1
  export declare function parseRecordOptions(flags: Record<string, string | boolean>): {
2
- theme: "dark" | "light" | "high-contrast" | "midnight" | "sepia" | "arctic" | "ember" | "forest" | "volt" | undefined;
2
+ theme: "harbor" | "daylight" | "high-contrast" | "midnight" | "sepia" | "arctic" | "ember" | "forest" | "volt" | undefined;
3
3
  present: boolean;
4
4
  tourFile: string | undefined;
5
5
  chromePath: string | undefined;
@@ -0,0 +1,13 @@
1
+ /** Themed single-choice menu shared by the feedback form and steering composer. */
2
+ export declare function ChoiceMenu({ label, value, options, onChange, className, above, }: {
3
+ label: string;
4
+ value: string;
5
+ options: Array<{
6
+ value: string;
7
+ label: string;
8
+ disabled?: boolean;
9
+ }>;
10
+ onChange: (value: string) => void;
11
+ className?: string;
12
+ above?: boolean;
13
+ }): import("preact/src").JSX.Element;
@@ -0,0 +1,24 @@
1
+ import type { CanvasNodeState } from '../types';
2
+ export declare const GLYPHS: {
3
+ readonly eye: "M2 12s3.5-6 10-6 10 6 10 6-3.5 6-10 6S2 12 2 12zM12 9.5a2.5 2.5 0 1 0 0 5a2.5 2.5 0 1 0 0-5";
4
+ readonly eyeOff: "M3 3l18 18M10.6 6.1A10 10 0 0 1 12 6c6.5 0 10 6 10 6a17 17 0 0 1-3 3.6M6.6 6.6C3.8 8.3 2 12 2 12s3.5 6 10 6a9.6 9.6 0 0 0 4.4-1";
5
+ readonly spark: "M12 3l1.8 5.2L19 10l-5.2 1.8L12 17l-1.8-5.2L5 10l5.2-1.8z";
6
+ readonly pen: "M4 20l4.2-1L19 8.2 15.8 5 5 15.8z";
7
+ readonly warn: "M12 4l9 16H3zM12 10v4M12 17v.5";
8
+ };
9
+ /** The header chip saying what agents did with this node (one per node; glyph + word). */
10
+ export declare function NodeContextMark({ node, pinned }: {
11
+ node: CanvasNodeState;
12
+ pinned: boolean;
13
+ }): import("preact/src").JSX.Element | null;
14
+ /** Pinned by an agent: the violet dot on the pin badge. */
15
+ export declare function isAgentPin(nodeId: string): boolean;
16
+ /**
17
+ * Near a pin (docs/design/NearPin.dc.html): a dotted pin-blue chip on an
18
+ * unpinned node the brief carries as title + short summary. Weaker than "in
19
+ * context" on purpose: the agent never gets this node's full content.
20
+ */
21
+ export declare function NearPinMark({ node, pinned }: {
22
+ node: CanvasNodeState;
23
+ pinned: boolean;
24
+ }): import("preact/src").JSX.Element | null;
@@ -3,7 +3,9 @@
3
3
  * at the canvas region's top-right after a session ends — what the session did
4
4
  * (items / done / vetoed), the pre-session snapshot (taken at attach, so View
5
5
  * diff shows the session's changes and a restore undoes them), and History
6
- * (the snapshots panel). Client-side state, cleared on dismiss.
6
+ * (the snapshots panel). Client-side state, cleared on dismiss (see
7
+ * applySessionReceipt for which endings show at all and how a burst merges
8
+ * into one card).
7
9
  */
8
10
  export interface DiffSummary {
9
11
  added: number;
@@ -13,7 +13,6 @@ export declare function IconExpand(p: IconProps): JSX.Element;
13
13
  export declare function IconArrowLeft(p: IconProps): JSX.Element;
14
14
  export declare function IconRefresh(p: IconProps): JSX.Element;
15
15
  export declare function IconUndo(p: IconProps): JSX.Element;
16
- export declare function IconSparkle(p: IconProps): JSX.Element;
17
16
  /** Upload into a tray — attach a document. */
18
17
  export declare function IconUpload(p: IconProps): JSX.Element;
19
18
  /** Dropdown disclosure, sized like the other toolbar icons. */
@@ -50,7 +49,7 @@ export declare function IconSearch(p: IconProps): JSX.Element;
50
49
  export declare function IconShortcuts(p: IconProps): JSX.Element;
51
50
  /** Speech bubble — steer the agent (command bar composer). */
52
51
  export declare function IconSteer(p: IconProps): JSX.Element;
53
- /** Framed pin — context pinning. */
52
+ /** Push pin — context pinning (docs/design/Chrome.dc.html). */
54
53
  export declare function IconPin(p: IconProps): JSX.Element;
55
54
  /** Focus Field — PMX Canvas brand mark (concentric rounded squares → lit core). */
56
55
  export declare function IconLogo({ size, class: className }: IconProps): JSX.Element;
@@ -0,0 +1 @@
1
+ import '../uuid-polyfill';
@@ -12,10 +12,11 @@ type ViewerFrameSource = {
12
12
  * white navigation paint. Two animation frames after load gives the new document
13
13
  * a composited paint before the old one is removed.
14
14
  */
15
- export declare function RefreshingViewerFrame({ source, iframeRef, onLoad, title, className, sandbox, allow, tabIndex, }: {
15
+ export declare function RefreshingViewerFrame({ source, iframeRef, onLoad, onDocumentLoad, title, className, sandbox, allow, tabIndex, }: {
16
16
  source: ViewerFrameSource;
17
17
  iframeRef: RefObject<HTMLIFrameElement>;
18
18
  onLoad: () => void;
19
+ onDocumentLoad?: (frame: HTMLIFrameElement) => void;
19
20
  title: string;
20
21
  className?: string;
21
22
  sandbox?: string;
@@ -9,8 +9,8 @@ export declare function runNodeAxInteraction(node: CanvasNodeState, type: string
9
9
  export declare const axNodeActionButtonStyle: {
10
10
  readonly padding: "3px 8px";
11
11
  readonly fontSize: "10px";
12
- readonly background: "var(--c-accent-12)";
13
- readonly border: "1px solid var(--c-accent-25)";
12
+ readonly background: "color-mix(in srgb, var(--c-accent) 12%, transparent)";
13
+ readonly border: "1px solid color-mix(in srgb, var(--c-accent) 25%, transparent)";
14
14
  readonly borderRadius: "4px";
15
15
  readonly color: "var(--c-text-soft)";
16
16
  readonly cursor: "pointer";
@@ -0,0 +1,2 @@
1
+ /** Sanitize rendered Markdown before it enters the privileged workbench DOM. */
2
+ export declare function sanitizeMarkdownHtml(html: string): string;
@@ -0,0 +1,2 @@
1
+ /** Asset bytes travel through the host, not a localhost URL in the user's browser. */
2
+ export declare function useWorkbenchAsset(path: string): string | undefined;
@@ -0,0 +1 @@
1
+ export declare function restoreViewerRuntimeState(nodeId: string, token: string, source: Window): void;
@@ -1,4 +1,3 @@
1
- import type { SemanticAttentionRegion } from '../../shared/semantic-attention.js';
2
1
  export type AttentionTone = 'context' | 'relationship' | 'group' | 'cluster' | 'neighborhood' | 'remove';
3
2
  export interface AttentionEntry {
4
3
  id: string;
@@ -10,16 +9,12 @@ export interface AttentionEntry {
10
9
  }
11
10
  export declare const attentionToast: import("@preact/signals-core").Signal<AttentionEntry | null>;
12
11
  export declare const attentionHistory: import("@preact/signals-core").Signal<AttentionEntry[]>;
13
- export declare const attentionPrimaryNodeIds: import("@preact/signals-core").Signal<Set<string>>;
14
- export declare const attentionSecondaryNodeIds: import("@preact/signals-core").Signal<Set<string>>;
15
- export declare const attentionRegions: import("@preact/signals-core").Signal<SemanticAttentionRegion[]>;
16
12
  export declare const attentionPulseNodeIds: import("@preact/signals-core").Signal<Set<string>>;
17
13
  export declare const attentionHistoryOpen: import("@preact/signals-core").Signal<boolean>;
18
14
  export declare const attentionHistoryUnread: import("@preact/signals-core").Signal<number>;
19
15
  export declare function resetAttentionState(): void;
20
16
  export declare function openAttentionHistory(): void;
21
17
  export declare function closeAttentionHistory(): void;
22
- export declare function setAttentionFocus(primaryNodeIds: string[], secondaryNodeIds: string[], regions: SemanticAttentionRegion[]): void;
23
18
  export declare function setAttentionToast(entry: AttentionEntry | null): void;
24
19
  export declare function pushAttentionHistory(entry: AttentionEntry, limit?: number): void;
25
20
  export declare function setAttentionPulse(nodeIds: string[]): void;
@@ -25,6 +25,8 @@ export declare const pendingExpandedNodeCloseId: import("@preact/signals-core").
25
25
  export declare const pendingConnection: import("@preact/signals-core").Signal<{
26
26
  from: string;
27
27
  } | null>;
28
+ /** Invalidates in-flight interaction replies when board navigation resets the canvas. */
29
+ export declare const canvasInteractionEpoch: import("@preact/signals-core").Signal<number>;
28
30
  export declare const draggingEdge: import("@preact/signals-core").Signal<{
29
31
  fromId: string;
30
32
  fromX: number;
@@ -0,0 +1,53 @@
1
+ /**
2
+ * What agents did with the board's context (docs/design/AgentContext.dc.html):
3
+ * per node, the latest agent read of its content and the revision it read;
4
+ * per pin, who pinned it, when and why. Server truth from
5
+ * `GET /api/canvas/ax/context-status`, refetched when a read lands
6
+ * (`context-status-changed`), when pins change, and on (re)connect.
7
+ */
8
+ export interface NodeReadStatus {
9
+ nodeId: string;
10
+ lastReadAt: string;
11
+ lastReadBy: string;
12
+ readRevision: number;
13
+ readCount: number;
14
+ }
15
+ export interface ContextPinMeta {
16
+ pinnedBy: {
17
+ actor: 'human' | 'agent' | 'system' | 'unknown';
18
+ source: string;
19
+ agentId?: string;
20
+ };
21
+ pinnedAt: string;
22
+ reason?: string;
23
+ }
24
+ interface ContextStatusResponse {
25
+ ok?: boolean;
26
+ boardId?: string | null;
27
+ nodes?: NodeReadStatus[];
28
+ pins?: Record<string, ContextPinMeta>;
29
+ }
30
+ export declare const nodeReadStatus: import("@preact/signals-core").Signal<Map<string, NodeReadStatus>>;
31
+ export declare const contextPinMeta: import("@preact/signals-core").Signal<Record<string, ContextPinMeta>>;
32
+ export declare function applyContextStatus(response: ContextStatusResponse): void;
33
+ export declare function refreshContextStatus(): Promise<void>;
34
+ /** How an agent's context relates to one pinned node — the mark its header shows. */
35
+ export type PinnedReadState = {
36
+ kind: 'not-read';
37
+ } | {
38
+ kind: 'read';
39
+ by: string;
40
+ at: string;
41
+ count: number;
42
+ } | {
43
+ kind: 'changed';
44
+ by: string;
45
+ at: string;
46
+ };
47
+ export declare function pinnedReadState(nodeId: string, currentRevision: number): PinnedReadState;
48
+ /** Display name for an attributed writer: its agent id, else its transport label. */
49
+ export declare function writerName(actor: {
50
+ source: string;
51
+ agentId?: string;
52
+ }): string;
53
+ export {};
@@ -84,7 +84,7 @@ export declare function pushCanvasUpdate(updates: Array<{
84
84
  }>, options?: {
85
85
  recordHistory?: boolean;
86
86
  }): Promise<void>;
87
- /** Create a canvas edge via the server. */
87
+ /** Render the server-confirmed edge immediately, without waiting for SSE/polling. */
88
88
  export declare function createEdgeFromClient(from: string, to: string, type: string, label?: string): Promise<{
89
89
  ok: boolean;
90
90
  id?: string;
@@ -120,9 +120,12 @@ export declare function updateNodeFromClient(id: string, patch: {
120
120
  data?: Record<string, unknown>;
121
121
  /** Groups: replace the membership list (positions preserved). */
122
122
  children?: string[];
123
+ expectedContentRevision?: number;
124
+ expectedBoardId?: string | null;
123
125
  }): Promise<{
124
126
  ok: boolean;
125
127
  id?: string;
128
+ contentRevision?: number;
126
129
  }>;
127
130
  /** Refresh a webpage node from its persisted URL on the server. */
128
131
  export declare function refreshWebpageNodeFromClient(id: string, url?: string): Promise<{
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Near a pin (docs/design/NearPin.dc.html): each pinned node pulls up to five
3
+ * unpinned nodes within 600 px into the agent's brief as title + short
4
+ * summary. Same rule as the server's brief (`findNeighborhoods`), so the mark
5
+ * claims exactly what the agent receives.
6
+ */
7
+ export interface NearPin {
8
+ pinNodeId: string;
9
+ pinTitle: string;
10
+ }
11
+ /**
12
+ * Unpinned node id → the pins it is near, nearest first. Every drag frame
13
+ * moves a node, so the result keeps its identity while no node's set of pins
14
+ * changes: the chips subscribed to it re-render only when a neighbourhood does.
15
+ */
16
+ export declare const nearPins: import("@preact/signals-core").ReadonlySignal<Map<string, NearPin[]>>;
@@ -17,6 +17,11 @@ export declare const activityFeedOpen: import("@preact/signals-core").Signal<boo
17
17
  export declare const writersSheetOpen: import("@preact/signals-core").Signal<boolean>;
18
18
  /** Feed filter: a writer's sessionId, or null for all. */
19
19
  export declare const activityFilter: import("@preact/signals-core").Signal<string | null>;
20
+ /**
21
+ * A writer's colour says what it is, not who: agents take the agent violet,
22
+ * subagents (fleet workers) the subagent fuchsia. Writers are told apart by
23
+ * name and initial (docs/design.md, "Kinds carry no colour").
24
+ */
20
25
  export declare function writerColor(sessionId: string): string;
21
26
  /** Avatar initial: first letter of the label, upper-cased. */
22
27
  export declare function writerInitial(label: string): string;
@@ -155,12 +155,13 @@ export declare function endSession(session: {
155
155
  agentId: string | null;
156
156
  }): Promise<boolean>;
157
157
  export interface SessionReceipt {
158
- label: string;
158
+ /** Distinct labels of the sessions on this card (one unless merged). */
159
+ labels: string[];
160
+ /** Endings folded into this card (see applySessionReceipt). */
161
+ sessions: number;
159
162
  endedAt: string;
160
163
  /** Why it ended — the receipt should answer this, not leave the human asking. */
161
164
  endedBy?: 'human' | 'agent' | 'idle-timeout';
162
- /** The session changed nothing on the board (its pre-session snapshot was dropped). */
163
- unchanged?: boolean;
164
165
  /** Cancelled (withdrawn items), rejected (human's explicit no on a gate), and
165
166
  * held (TTL expired unanswered) are three different outcomes — never one
166
167
  * "vetoed" pile. */
@@ -171,13 +172,42 @@ export interface SessionReceipt {
171
172
  rejected: number;
172
173
  held: number;
173
174
  };
175
+ /** The pre-session snapshot; null when the board was empty at attach, or on a
176
+ * merged receipt (each session's snapshot is in History). */
174
177
  snapshot: {
175
178
  id: string;
176
179
  name: string;
177
180
  } | null;
181
+ /** What the session did with context (docs/design/AgentContext.dc.html receipt). */
182
+ context: SessionContextActivity;
183
+ }
184
+ export interface ReceiptNode {
185
+ id: string;
186
+ title: string;
187
+ reason?: string;
188
+ }
189
+ export interface SessionContextActivity {
190
+ read: ReceiptNode[];
191
+ pinned: ReceiptNode[];
192
+ created: ReceiptNode[];
193
+ edited: ReceiptNode[];
194
+ changedSinceRead: ReceiptNode[];
178
195
  }
196
+ /**
197
+ * The agent-activity lens: while on, nodes the last session did not touch
198
+ * (read, pin, create, edit) are dimmed. Null when off.
199
+ */
200
+ export declare const activityLensNodeIds: import("@preact/signals-core").Signal<Set<string> | null>;
201
+ export declare function setActivityLens(on: boolean): void;
179
202
  /** The last ended session's receipt (design item 2); client-side, cleared on dismiss. */
180
203
  export declare const sessionReceipt: import("@preact/signals-core").Signal<SessionReceipt | null>;
204
+ /**
205
+ * The receipt rule: a pop-up only for a top-level session that changed the
206
+ * board or read/pinned context. `unchanged` endings and worker endings
207
+ * (`parentAgentId` set — their orchestrator's receipt covers the board since
208
+ * it attached) stay in the timeline and History only, and never replace or
209
+ * extend an open receipt. Qualifying endings while one is up merge into it.
210
+ */
181
211
  export declare function applySessionReceipt(data: Record<string, unknown>): void;
182
212
  export declare function dismissSessionReceipt(): void;
183
213
  export declare function resetSessionStore(): void;
@@ -0,0 +1,16 @@
1
+ /** The normal workbench uses HTTP; an MCP App installs its host transport before mounting. */
2
+ type WorkbenchFetch = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
3
+ export declare function installWorkbenchTransport(transport: WorkbenchFetch | undefined): void;
4
+ export declare function isHostedWorkbench(): boolean;
5
+ export declare const workbenchFetch: WorkbenchFetch;
6
+ type WorkbenchDownload = (file: {
7
+ name: string;
8
+ mimeType: string;
9
+ text: string;
10
+ }) => Promise<{
11
+ isError?: boolean;
12
+ }>;
13
+ export declare function installWorkbenchDownload(download: WorkbenchDownload | undefined): void;
14
+ /** Export files live on PMX, not on the embedded frame's sandbox origin. */
15
+ export declare function downloadWorkbenchExport(path: string): Promise<void>;
16
+ export {};
@@ -11,10 +11,8 @@ export interface CanvasTokens {
11
11
  accent: string;
12
12
  ok: string;
13
13
  warn: string;
14
- warnAlt: string;
15
14
  danger: string;
16
- purple: string;
17
- thinking: string;
15
+ agent: string;
18
16
  subagent: string;
19
17
  font: string;
20
18
  mono: string;
@@ -18,8 +18,17 @@ export interface CanvasNodeState {
18
18
  zIndex: number;
19
19
  collapsed: boolean;
20
20
  pinned: boolean;
21
+ contentRevision?: number;
22
+ /** Who created / last edited the node's content (server attribution). */
23
+ createdBy?: NodeActor;
24
+ lastEditedBy?: NodeActor;
21
25
  data: Record<string, unknown>;
22
26
  }
27
+ export interface NodeActor {
28
+ actor: 'human' | 'agent' | 'system' | 'unknown';
29
+ source: string;
30
+ agentId?: string;
31
+ }
23
32
  export interface CanvasEdge {
24
33
  id: string;
25
34
  from: string;
@@ -5,7 +5,7 @@
5
5
  * Runs inside a pmx-canvas iframe and reads the normalized json-render spec
6
6
  * from an inline global injected by the server-side viewer route.
7
7
  */
8
- import type { Spec } from '@json-render/core';
8
+ import { type Spec } from '@json-render/core';
9
9
  declare global {
10
10
  interface Window {
11
11
  __PMX_CANVAS_JSON_RENDER_SPEC__?: Spec & {
@@ -17,5 +17,6 @@ declare global {
17
17
  __PMX_CANVAS_JSON_RENDER_NODE_ID__?: string;
18
18
  __PMX_CANVAS_AX_TOKEN__?: string;
19
19
  __PMX_CANVAS_AX_STATE__?: unknown;
20
+ __PMX_CANVAS_UI_STATE_TOKEN__?: string;
20
21
  }
21
22
  }
@@ -66,7 +66,7 @@ export type GraphChartType = 'LineChart' | 'BarChart' | 'PieChart' | 'AreaChart'
66
66
  export declare function escapeInlineScriptSource(source: string): string;
67
67
  export declare function inferJsonRenderNodeTitle(spec: JsonRenderSpec, fallback?: string): string;
68
68
  export declare function normalizeAndValidateJsonRenderSpec(spec: unknown): JsonRenderSpec;
69
- /** shadcn 0.21 ignores these props unless the renderer supplies a two-way binding. */
69
+ /** Binding-only form props that normalization could not bind (see bindLiteralFormValues). */
70
70
  export declare function jsonRenderFormWarnings(spec: JsonRenderSpec): string[];
71
71
  export declare function normalizeGraphType(value: string): GraphChartType;
72
72
  export declare function buildGraphSpec(input: GraphNodeInput): JsonRenderSpec;
@@ -101,6 +101,8 @@ export declare function buildJsonRenderViewerHtml(options: {
101
101
  nodeId?: string;
102
102
  axToken?: string;
103
103
  axState?: unknown;
104
+ /** Independent nonce for tab-local runtime state across focus transitions. */
105
+ stateToken?: string;
104
106
  /** Nonce for the content-height reporter so the node can grow to fit the chart. */
105
107
  frameToken?: string;
106
108
  /** When true, charts render at their natural (intrinsic) height instead of
@@ -0,0 +1,3 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ /** Private, single-workspace profile. No public HTTP listener or tenant routing. */
3
+ export declare function createCanvasAppServer(): McpServer;
@@ -88,5 +88,5 @@ export declare function shouldAttachToExistingDaemon(occupant: {
88
88
  * FS-safe (defaults to false on any error).
89
89
  */
90
90
  export declare function looksLikeIncidentalCwd(cwd: string): boolean;
91
- export declare function createCanvasAccess(): Promise<CanvasAccess>;
91
+ export declare function createCanvasAccess(allowExternalMcp?: boolean): Promise<CanvasAccess>;
92
92
  export {};
@@ -0,0 +1,4 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { CanvasAccess } from './canvas-access.js';
3
+ /** Focused app profile; deliberately does not register the general-purpose composites. */
4
+ export declare function registerCanvasApp(server: McpServer, ensureCanvas: () => Promise<CanvasAccess>): void;
@@ -0,0 +1,4 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { CanvasAccess } from './canvas-access.js';
3
+ /** HTTP-shaped replies let the real workbench retain its existing API contracts. */
4
+ export declare function registerWorkbenchApp(server: McpServer, ensureCanvas: () => Promise<CanvasAccess>): void;
@@ -99,7 +99,7 @@ export declare function estimateContextBudget(): ContextBudget;
99
99
  /** Returns the id of the pre-session snapshot the server took, if any. */
100
100
  type SessionStartListener = (presence: AgentPresence) => string | null;
101
101
  export type SessionEndReason = 'human' | 'agent' | 'idle-timeout';
102
- type SessionEndListener = (presence: AgentPresence, startSnapshotId: string | null, endedBy: SessionEndReason) => void;
102
+ type SessionEndListener = (presence: AgentPresence, startSnapshotId: string | null, endedBy: SessionEndReason, startedAt: string | null) => void;
103
103
  export declare class AgentPresenceRegistry {
104
104
  private readonly presences;
105
105
  /** Newest first; bounded. Survives a writer fading — the feed is history, the writer list is presence. */
@@ -1,6 +1,6 @@
1
1
  import type { CanvasLayout, CanvasNodeState } from './canvas-state.js';
2
2
  import type { AxApprovalStatus, AxEventKind, AxWorkItemStatus } from '../shared/ax-kinds.js';
3
- import type { AgentContextNode } from './agent-context.js';
3
+ import type { AgentContextNode } from '../shared/agent-context.js';
4
4
  import type { ActorAttribution } from './attribution.js';
5
5
  export type PmxAxSource = 'agent' | 'amp' | 'api' | 'browser' | 'cli' | 'codex' | 'copilot' | 'mcp' | 'sdk' | 'system';
6
6
  export interface PmxAxFocusState {
@@ -5,6 +5,7 @@
5
5
  * WAL-mode persistence. Replaces the previous JSON file-based approach.
6
6
  */
7
7
  import { Database } from 'bun:sqlite';
8
+ import type { ActorAttribution } from './attribution.js';
8
9
  import { type Tour } from '../shared/tour.js';
9
10
  import { type CanvasThemeName } from '../shared/themes.js';
10
11
  import type { CanvasAnnotation, CanvasEdge, CanvasNodeState, CanvasSnapshot, CanvasSnapshotListOptions, ViewportState } from './canvas-state.js';
@@ -20,9 +21,16 @@ export interface PersistedCanvasState {
20
21
  edges: CanvasEdge[];
21
22
  annotations?: CanvasAnnotation[];
22
23
  contextPins: string[];
24
+ /** Who pinned each context pin, when and why; pins without an entry have an unknown pinner. */
25
+ contextPinMeta?: Record<string, ContextPinMeta>;
23
26
  ax?: PmxAxState;
24
27
  revisionState?: PersistedRevisionState;
25
28
  }
29
+ export interface ContextPinMeta {
30
+ pinnedBy: ActorAttribution;
31
+ pinnedAt: string;
32
+ reason?: string;
33
+ }
26
34
  export interface PersistedRevisionState {
27
35
  revision: number;
28
36
  floor: number;
@@ -0,0 +1,25 @@
1
+ import type { CanvasNodeState, CanvasNodeUpdate } from './canvas-state.js';
2
+ /** Flat fields take precedence over nested aliases; absent axes remain absent. */
3
+ export declare function resolveCreateGeometry(body: Record<string, unknown>): {
4
+ x: number | undefined;
5
+ y: number | undefined;
6
+ width: number | undefined;
7
+ height: number | undefined;
8
+ };
9
+ /** Guards and PATCH execution must resolve aliases and single-axis moves identically. */
10
+ export declare function resolvePatchGeometry(body: Record<string, unknown>, existing: CanvasNodeState): {
11
+ size?: {
12
+ width: number;
13
+ height: number;
14
+ } | undefined;
15
+ position?: {
16
+ x: number;
17
+ y: number;
18
+ } | undefined;
19
+ };
20
+ export declare function validateCanvasNodePatch(patch: {
21
+ position?: unknown;
22
+ size?: unknown;
23
+ }): string | null;
24
+ /** Invalid patches cannot count as explicit child-position overrides. */
25
+ export declare function validCanvasNodeUpdates(input: unknown): CanvasNodeUpdate[];
@@ -130,16 +130,6 @@ export declare function syncCanvasRuntimeBackends(options?: {
130
130
  rehydrated: number;
131
131
  failed: number;
132
132
  }>;
133
- export declare function validateCanvasNodePatch(patch: {
134
- position?: {
135
- x: number;
136
- y: number;
137
- };
138
- size?: {
139
- width: number;
140
- height: number;
141
- };
142
- }): string | null;
143
133
  export declare function mergeTraceNodeDataFields(base: Record<string, unknown>, input: Record<string, unknown>): Record<string, unknown>;
144
134
  export declare function hasTraceNodeDataFields(input: Record<string, unknown>): boolean;
145
135
  export declare function scheduleCodeGraphRecompute(onComplete?: () => void): void;
@@ -189,7 +179,7 @@ export declare function applyCanvasNodeUpdates(updates: CanvasNodeUpdate[]): {
189
179
  applied: number;
190
180
  skipped: number;
191
181
  };
192
- export declare function setCanvasContextPins(nodeIds: string[], mode?: CanvasPinMode): {
182
+ export declare function setCanvasContextPins(nodeIds: string[], mode?: CanvasPinMode, reason?: string): {
193
183
  count: number;
194
184
  nodeIds: string[];
195
185
  };
@@ -12,11 +12,11 @@
12
12
  * the one-shot boot migration into SQLite was retired.
13
13
  */
14
14
  import { type Tour } from '../shared/tour.js';
15
- import { type CanvasBoard, type PersistedCanvasState, type CanvasTheme, type AxTimelineQuery } from './canvas-db.js';
15
+ import { type CanvasBoard, type ContextPinMeta, type PersistedCanvasState, type CanvasTheme, type AxTimelineQuery } from './canvas-db.js';
16
16
  import { type DocumentImport, type DocumentImportStatus, type ImportSection, type Attachment } from './document-import.js';
17
17
  import { type PmxAxActivityKind, type PmxAxElicitation, type PmxAxModeRequest, type PmxAxMode, type PmxAxCommandDescriptor, type PmxAxPolicy, type PmxAxFocusState, type PmxAxSource, type PmxAxState, type PmxAxWorkItem, type PmxAxWorkItemStatus, type PmxAxApprovalGate, type PmxAxReviewAnnotation, type PmxAxReviewKind, type PmxAxReviewSeverity, type PmxAxReviewStatus, type PmxAxReviewAnchorType, type PmxAxReviewRegion, type PmxAxEvent, type PmxAxEventKind, type PmxAxEvidence, type PmxAxEvidenceKind, type PmxAxSteeringMessage, type PmxAxHostCapability, type PmxAxTimelineSummary } from './ax-state.js';
18
18
  import { type ActorAttribution } from './attribution.js';
19
- import { type ContextRead, type ContextReadConsumerSummary, type ContextReadInput } from './context-reads.js';
19
+ import { type ContextRead, type ContextReadConsumerSummary, type ContextReadInput, type NodeReadStatus } from './context-reads.js';
20
20
  export declare const PMX_CANVAS_DIR = ".pmx-canvas";
21
21
  export interface PersistedBlobRef {
22
22
  __pmxCanvasBlob: 'v1';
@@ -171,6 +171,8 @@ declare class CanvasStateManager {
171
171
  private _tour;
172
172
  private _theme;
173
173
  private _contextPinnedNodeIds;
174
+ /** Who pinned each pin, when and why; kept only for ids in `_contextPinnedNodeIds`. */
175
+ private _contextPinMeta;
174
176
  private _workspaceRoot;
175
177
  private _contentRevision;
176
178
  private _revisionFloor;
@@ -185,12 +187,15 @@ declare class CanvasStateManager {
185
187
  */
186
188
  onChange(cb: (type: CanvasChangeType) => void): () => void;
187
189
  private _workItemsChangedListener;
190
+ /** Single slot (architecture rule 8): server.ts tells the workbench a read landed. Never MCP. */
191
+ private _contextReadListener;
188
192
  /**
189
193
  * Register THE work-item change listener (single slot, last-write-wins).
190
194
  * Fired after addWorkItem/updateWorkItem completes (including the node
191
195
  * status mirror), so live views like the workboard can rebuild from the
192
196
  * fresh work-item list.
193
197
  */
198
+ setContextReadListener(listener: ((boardId: string | null) => void) | null): void;
194
199
  setWorkItemsChangedListener(listener: (() => void) | null): void;
195
200
  private notifyWorkItemsChanged;
196
201
  private notifyChange;
@@ -609,6 +614,12 @@ declare class CanvasStateManager {
609
614
  getAxTimelineSummary(): PmxAxTimelineSummary;
610
615
  /** Records one agent context read (diagnostics; never notifies, so a read cannot trigger reads). */
611
616
  recordContextRead(input: ContextReadInput, boardId?: string | null): ContextRead | null;
617
+ /** The delivered ids that are nodes on the read board, each with its content revision now. */
618
+ private readRevisions;
619
+ /** Per node on a board, the latest agent read that delivered its content. */
620
+ getNodeReadStatus(boardId?: string | null): NodeReadStatus[];
621
+ /** Nodes on a board whose content an agent read at or after `since` (ISO). */
622
+ getReadNodeIdsSince(boardId: string | null, since: string): string[];
612
623
  getContextReads(limit?: number): {
613
624
  reads: ContextRead[];
614
625
  summary: ContextReadConsumerSummary[];
@@ -619,7 +630,18 @@ declare class CanvasStateManager {
619
630
  steering: PmxAxSteeringMessage[];
620
631
  summary: PmxAxTimelineSummary;
621
632
  };
622
- setContextPins(nodeIds: string[]): void;
633
+ /**
634
+ * Replace the pin set. Newly pinned nodes are attributed to the current
635
+ * actor (with `reason` when given); pins that stay keep their attribution.
636
+ * `restore` re-applies saved attribution, so undo does not re-attribute.
637
+ */
638
+ setContextPins(nodeIds: string[], options?: {
639
+ reason?: string;
640
+ restore?: Map<string, ContextPinMeta>;
641
+ }): void;
642
+ /** Who pinned each current pin, when and why (pins with an unknown pinner are absent). */
643
+ getContextPinMeta(): Record<string, ContextPinMeta>;
644
+ private pinMetaRecord;
623
645
  clearContextPins(): void;
624
646
  /** Move child nodes into a group. Sets data.parentGroup on children and data.children on the group. */
625
647
  groupNodes(groupId: string, childIds: string[], options?: GroupNodesOptions): boolean;
@@ -1,5 +1,7 @@
1
1
  import type { CanvasNodeState, NodeDeletionTombstone } from './canvas-state.js';
2
- export type ContextBriefReason = 'pinned' | 'changed' | 'human' | 'ask' | 'steer' | 'linked' | 'category';
2
+ export type ContextBriefReason = 'pinned' | 'near' | 'changed' | 'human' | 'ask' | 'steer' | 'linked' | 'category';
3
+ /** A near entry carries a short summary, never full content: pin the node to send that. */
4
+ export declare const NEAR_SUMMARY_LENGTH = 280;
3
5
  export interface ContextBriefSourceEntry {
4
6
  sourceBoardId: string;
5
7
  nodeId: string;
@@ -57,6 +59,11 @@ export interface CompiledContextEntry {
57
59
  text: string;
58
60
  /** A linked board's pin title is discovery metadata, not delivery of that pinned card. */
59
61
  titleOnly?: true;
62
+ /** reason "near": the pin this node sits next to on the board (docs/design/NearPin.dc.html). */
63
+ near?: {
64
+ pinNodeId: string;
65
+ pinTitle: string;
66
+ };
60
67
  /** The body was shortened to fit; the same revision remains eligible on the next pull. */
61
68
  truncated?: true;
62
69
  provenance?: {