pmx-canvas 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/extensions/pmx-canvas/runtime.json +1 -1
- package/.github/extensions/pmx-canvas/tools.json +601 -22
- package/CHANGELOG.md +66 -0
- package/Readme.md +131 -532
- package/dist/canvas/global.css +2759 -510
- package/dist/canvas/index.js +168 -107
- package/dist/canvas/mcp-app.html +2936 -632
- package/dist/json-render/index.css +81 -1
- package/dist/json-render/index.js +20 -20
- package/dist/types/client/canvas/BarHint.d.ts +12 -2
- package/dist/types/client/canvas/BoardLinkDialog.d.ts +3 -1
- package/dist/types/client/canvas/BoardPinButton.d.ts +10 -0
- package/dist/types/client/canvas/BoardSwitcher.d.ts +1 -1
- package/dist/types/client/canvas/CanvasViewport.d.ts +1 -1
- package/dist/types/client/canvas/CommandBar.d.ts +3 -4
- package/dist/types/client/canvas/ConnectionBanner.d.ts +2 -1
- package/dist/types/client/canvas/ContextChip.d.ts +3 -0
- package/dist/types/client/canvas/CrossBoardReferences.d.ts +5 -0
- package/dist/types/client/canvas/EdgeLayer.d.ts +14 -3
- package/dist/types/client/canvas/EmptyState.d.ts +4 -4
- package/dist/types/client/canvas/HomeGraphView.d.ts +2 -0
- package/dist/types/client/canvas/HomeMapView.d.ts +1 -0
- package/dist/types/client/canvas/HomeReviewView.d.ts +6 -0
- package/dist/types/client/canvas/HomeView.d.ts +9 -7
- package/dist/types/client/canvas/KnowledgeDialog.d.ts +4 -0
- package/dist/types/client/canvas/LifecycleChrome.d.ts +5 -0
- package/dist/types/client/canvas/LifecycleFields.d.ts +7 -0
- package/dist/types/client/canvas/LifecyclePanel.d.ts +1 -0
- package/dist/types/client/canvas/MemoryInspector.d.ts +7 -0
- package/dist/types/client/canvas/NearPinLayer.d.ts +14 -0
- package/dist/types/client/canvas/NodeContextMark.d.ts +40 -7
- package/dist/types/client/canvas/RelationPresetsDialog.d.ts +4 -0
- package/dist/types/client/canvas/RelationsPanel.d.ts +4 -0
- package/dist/types/client/canvas/SessionPanel.d.ts +2 -0
- package/dist/types/client/canvas/canvas-area.d.ts +1 -1
- package/dist/types/client/canvas/graph-geometry.d.ts +27 -0
- package/dist/types/client/canvas/graph-model.d.ts +37 -0
- package/dist/types/client/canvas/memory-layout.d.ts +23 -0
- package/dist/types/client/canvas/use-chrome-height.d.ts +2 -0
- package/dist/types/client/canvas/use-focus-trap.d.ts +1 -0
- package/dist/types/client/canvas/use-memory-graph.d.ts +8 -0
- package/dist/types/client/canvas/use-pan-zoom.d.ts +4 -1
- package/dist/types/client/icons.d.ts +0 -10
- package/dist/types/client/nodes/AxStepControls.d.ts +1 -1
- package/dist/types/client/nodes/HtmlNode.d.ts +1 -0
- package/dist/types/client/nodes/InlineMarkdownEditor.d.ts +4 -4
- package/dist/types/client/nodes/MarkdownNode.d.ts +5 -1
- package/dist/types/client/nodes/McpAppNode.d.ts +4 -4
- package/dist/types/client/nodes/viewer-runtime-state.d.ts +1 -1
- package/dist/types/client/state/boards-store.d.ts +81 -9
- package/dist/types/client/state/canvas-store.d.ts +14 -1
- package/dist/types/client/state/context-chip-store.d.ts +22 -0
- package/dist/types/client/state/context-status-store.d.ts +35 -0
- package/dist/types/client/state/intent-bridge.d.ts +11 -8
- package/dist/types/client/state/knowledge-store.d.ts +22 -0
- package/dist/types/client/state/near-pin-store.d.ts +44 -1
- package/dist/types/client/state/presence-store.d.ts +4 -4
- package/dist/types/client/state/presentation.d.ts +28 -0
- package/dist/types/client/state/relation-store.d.ts +10 -0
- package/dist/types/client/state/session-store.d.ts +41 -2
- package/dist/types/client/state/workspace-settings.d.ts +7 -0
- package/dist/types/client/types.d.ts +13 -1
- package/dist/types/client/utils/keyboard.d.ts +2 -0
- package/dist/types/client/utils/time-ago.d.ts +4 -0
- package/dist/types/mcp/context-uri-template.d.ts +3 -1
- package/dist/types/server/agent-presence.d.ts +10 -3
- package/dist/types/server/ax-context.d.ts +1 -1
- package/dist/types/server/canvas-db.d.ts +30 -7
- package/dist/types/server/canvas-operations.d.ts +24 -2
- package/dist/types/server/canvas-provenance.d.ts +22 -2
- package/dist/types/server/canvas-serialization.d.ts +2 -0
- package/dist/types/server/canvas-state.d.ts +93 -15
- package/dist/types/server/canvas-validation.d.ts +1 -1
- package/dist/types/server/context-brief.d.ts +94 -6
- package/dist/types/server/context-reads.d.ts +33 -7
- package/dist/types/server/edit-summary.d.ts +20 -0
- package/dist/types/server/index.d.ts +71 -10
- package/dist/types/server/knowledge-lifecycle.d.ts +221 -0
- package/dist/types/server/lifecycle-status.d.ts +10 -0
- package/dist/types/server/memory-graph.d.ts +9 -0
- package/dist/types/server/mutation-history.d.ts +2 -0
- package/dist/types/server/operations/ops/ax-shared.d.ts +1 -1
- package/dist/types/server/operations/ops/boards.d.ts +2 -1
- package/dist/types/server/operations/ops/lifecycle.d.ts +2 -0
- package/dist/types/server/operations/ops/memory-graph.d.ts +2 -0
- package/dist/types/server/operations/ops/nodes.d.ts +5 -0
- package/dist/types/server/operations/ops/query.d.ts +23 -0
- package/dist/types/server/operations/registry.d.ts +1 -0
- package/dist/types/server/placement.d.ts +7 -0
- package/dist/types/server/scope-fence.d.ts +2 -1
- package/dist/types/server/spatial-analysis.d.ts +6 -3
- package/dist/types/server/tour-control.d.ts +32 -0
- package/dist/types/server/wiki-links.d.ts +14 -0
- package/dist/types/server/workbench-auth.d.ts +2 -0
- package/dist/types/shared/agent-context.d.ts +2 -0
- package/dist/types/shared/agent-presence.d.ts +15 -12
- package/dist/types/shared/auto-arrange.d.ts +1 -0
- package/dist/types/shared/boards.d.ts +4 -4
- package/dist/types/shared/knowledge-lifecycle.d.ts +41 -0
- package/dist/types/shared/knowledge-presets.d.ts +6 -0
- package/dist/types/shared/lifecycle-status.d.ts +24 -0
- package/dist/types/shared/memory-graph.d.ts +53 -0
- package/dist/types/shared/relations.d.ts +68 -0
- package/dist/types/shared/semantic-attention.d.ts +2 -0
- package/dist/types/shared/tour.d.ts +38 -0
- package/dist/types/shared/workspace-settings.d.ts +11 -0
- package/docs/RELEASE.md +21 -3
- package/docs/adr-001-bun-only-runtime.md +7 -1
- package/docs/adr-002-shared-product-separate-runtimes.md +93 -0
- package/docs/api-reference.md +109 -0
- package/docs/ax-host-adapter-contract.md +1 -1
- package/docs/ax-state-contract.md +5 -4
- package/docs/cli.md +153 -15
- package/docs/demos/pmx-canvas-demo.mp4 +0 -0
- package/docs/design/AgentContext.dc.html +3 -3
- package/docs/design/BoardPins.dc.html +37 -22
- package/docs/design/Categories.dc.html +208 -0
- package/docs/design/CategoryEditor.dc.html +33 -0
- package/docs/design/Chrome.dc.html +55 -9
- package/docs/design/ContextChip.dc.html +224 -0
- package/docs/design/ContextChip600.dc.html +136 -0
- package/docs/design/EmptyState.dc.html +45 -0
- package/docs/design/Flows.dc.html +23 -1
- package/docs/design/HeaderMarks.dc.html +183 -0
- package/docs/design/Home.dc.html +19 -1
- package/docs/design/HomeGraph.dc.html +86 -202
- package/docs/design/HomeMap.dc.html +23 -1
- package/docs/design/HomeTeam.dc.html +32 -14
- package/docs/design/Lifecycle.dc.html +22 -0
- package/docs/design/Lifecycle600.dc.html +18 -0
- package/docs/design/LifecycleVariants.dc.html +157 -0
- package/docs/design/LinkAuthorship.dc.html +139 -0
- package/docs/design/LinksChanged.dc.html +203 -0
- package/docs/design/LinksOptions.dc.html +137 -0
- package/docs/design/LinksOptions600.dc.html +134 -0
- package/docs/design/NearPin.dc.html +9 -10
- package/docs/design/Pane600.dc.html +4 -3
- package/docs/design/Relations.dc.html +3 -2
- package/docs/design/Restore.dc.html +152 -0
- package/docs/design/SeeChange.dc.html +267 -0
- package/docs/design/Uses.dc.html +12 -6
- package/docs/design/canvas.json +146 -19
- package/docs/design.md +454 -18
- package/docs/environment.md +0 -1
- package/docs/evals/curation-effect.md +128 -0
- package/docs/http-api.md +465 -38
- package/docs/mcp.md +150 -19
- package/docs/node-types.md +58 -3
- package/docs/plans/design-gaps-2026-10-08.md +53 -0
- package/docs/plans/plan-009-tech-debt-backlog.md +379 -0
- package/docs/plans/plan-016-context-made-visible-wave-1.md +150 -5
- package/docs/plans/plan-017-knowledge-categories-and-lifecycle.md +175 -0
- package/docs/plans/plan-018-connected-memory-wave-2.md +594 -0
- package/docs/plans/plan-019-post-0.9-roadmap.md +198 -0
- package/docs/product-context-vision-2026-09.md +17 -1
- package/docs/product-vision-2026-09.md +1082 -43
- package/docs/product-vision-review-2026-09.md +13 -1
- package/docs/screenshots/workbench-live-dark.png +0 -0
- package/docs/screenshots/workbench-live-light.png +0 -0
- package/docs/sdk.md +62 -2
- package/package.json +1 -1
- package/plugins/pmx-canvas/com.github.copilot/extensions/pmx-canvas/runtime.json +1 -1
- package/plugins/pmx-canvas/plugin.json +1 -1
- package/plugins/pmx-canvas/runtime.json +1 -1
- package/plugins/pmx-canvas/tools.json +601 -22
- package/skills/pmx-canvas/SKILL.md +234 -43
- package/skills/pmx-canvas/evals/evals.json +62 -0
- package/skills/pmx-canvas/references/ax-html-control-surface.md +6 -0
- package/skills/pmx-canvas/references/full-reference.md +120 -21
- package/skills/pmx-canvas/references/github-copilot-app-adapter.md +2 -2
- package/skills/pmx-canvas/references/importing-context.md +132 -0
- package/skills/pmx-canvas/references/installing-pmx-canvas.md +6 -6
- package/skills/pmx-canvas/references/tours-and-recording.md +16 -1
- package/skills/pmx-canvas-testing/SKILL.md +20 -0
- package/src/cli/agent.ts +2 -0
- package/src/cli/commands/ax.ts +12 -0
- package/src/cli/commands/boards.ts +87 -11
- package/src/cli/commands/edges.ts +28 -0
- package/src/cli/commands/groups.ts +7 -0
- package/src/cli/commands/nodes.ts +4 -2
- package/src/cli/commands/query.ts +34 -2
- package/src/cli/commands/record.ts +199 -48
- package/src/cli/index.ts +7 -1
- package/src/client/App.tsx +177 -70
- package/src/client/canvas/AttentionHistory.tsx +0 -2
- package/src/client/canvas/BarHint.tsx +40 -2
- package/src/client/canvas/BoardCopyDialog.tsx +1 -1
- package/src/client/canvas/BoardFolderDialog.tsx +7 -7
- package/src/client/canvas/BoardLinkDialog.tsx +138 -33
- package/src/client/canvas/BoardPinButton.tsx +33 -0
- package/src/client/canvas/BoardSwitcher.tsx +26 -40
- package/src/client/canvas/CanvasNode.tsx +360 -237
- package/src/client/canvas/CanvasViewport.tsx +45 -7
- package/src/client/canvas/CommandBar.tsx +29 -23
- package/src/client/canvas/CommandPalette.tsx +5 -12
- package/src/client/canvas/ConnectionBanner.tsx +3 -3
- package/src/client/canvas/ContextChip.tsx +296 -0
- package/src/client/canvas/ContextMenu.tsx +63 -5
- package/src/client/canvas/CrossBoardReferences.tsx +60 -0
- package/src/client/canvas/EdgeLayer.tsx +339 -76
- package/src/client/canvas/EmptyState.tsx +33 -18
- package/src/client/canvas/ExpandedNodeOverlay.tsx +72 -40
- package/src/client/canvas/ExternalWriters.tsx +57 -42
- package/src/client/canvas/HomeGraphView.tsx +942 -0
- package/src/client/canvas/HomeMapView.tsx +641 -0
- package/src/client/canvas/HomeReviewView.tsx +167 -0
- package/src/client/canvas/HomeView.tsx +687 -160
- package/src/client/canvas/IntentLayer.tsx +19 -12
- package/src/client/canvas/KnowledgeDialog.tsx +488 -0
- package/src/client/canvas/LifecycleChrome.tsx +133 -0
- package/src/client/canvas/LifecycleFields.tsx +91 -0
- package/src/client/canvas/LifecyclePanel.tsx +533 -0
- package/src/client/canvas/MemoryInspector.tsx +104 -0
- package/src/client/canvas/Minimap.tsx +3 -3
- package/src/client/canvas/NearPinLayer.tsx +187 -0
- package/src/client/canvas/NodeContextMark.tsx +175 -97
- package/src/client/canvas/Presentation.tsx +23 -57
- package/src/client/canvas/RelationPresetsDialog.tsx +413 -0
- package/src/client/canvas/RelationsPanel.tsx +82 -0
- package/src/client/canvas/SelectionBar.tsx +3 -6
- package/src/client/canvas/SessionPanel.tsx +90 -50
- package/src/client/canvas/SessionReceipt.tsx +311 -39
- package/src/client/canvas/ShortcutOverlay.tsx +1 -1
- package/src/client/canvas/SnapshotPanel.tsx +27 -36
- package/src/client/canvas/ToolRail.tsx +367 -192
- package/src/client/canvas/TopBar.tsx +354 -124
- package/src/client/canvas/canvas-area.ts +10 -3
- package/src/client/canvas/graph-geometry.ts +195 -0
- package/src/client/canvas/graph-model.ts +254 -0
- package/src/client/canvas/memory-layout.ts +106 -0
- package/src/client/canvas/use-chrome-height.ts +20 -0
- package/src/client/canvas/use-focus-trap.ts +31 -5
- package/src/client/canvas/use-memory-graph.ts +58 -0
- package/src/client/canvas/use-node-drag.ts +2 -1
- package/src/client/canvas/use-pan-zoom.ts +64 -7
- package/src/client/icons.tsx +0 -63
- package/src/client/mcp-app/style.css +0 -6
- package/src/client/nodes/AxStepControls.tsx +74 -50
- package/src/client/nodes/BoardNode.tsx +5 -1
- package/src/client/nodes/ContextNode.tsx +18 -11
- package/src/client/nodes/ExtAppFrame.tsx +0 -1
- package/src/client/nodes/FileNode.tsx +46 -42
- package/src/client/nodes/HtmlNode.tsx +44 -2
- package/src/client/nodes/ImageNode.tsx +1 -1
- package/src/client/nodes/InlineFormatBar.tsx +6 -9
- package/src/client/nodes/InlineMarkdownEditor.tsx +56 -17
- package/src/client/nodes/MarkdownNode.tsx +377 -109
- package/src/client/nodes/McpAppNode.tsx +50 -20
- package/src/client/nodes/MdFormatBar.tsx +21 -18
- package/src/client/nodes/PromptNode.tsx +1 -1
- package/src/client/nodes/ResponseNode.tsx +1 -1
- package/src/client/nodes/viewer-runtime-state.ts +54 -22
- package/src/client/state/attention-bridge.ts +64 -15
- package/src/client/state/boards-store.ts +193 -39
- package/src/client/state/canvas-store.ts +99 -12
- package/src/client/state/context-chip-store.ts +70 -0
- package/src/client/state/context-status-store.ts +53 -0
- package/src/client/state/intent-bridge.ts +51 -30
- package/src/client/state/knowledge-store.ts +43 -0
- package/src/client/state/near-pin-store.ts +115 -6
- package/src/client/state/presence-store.ts +7 -10
- package/src/client/state/presentation.ts +91 -0
- package/src/client/state/relation-store.ts +81 -0
- package/src/client/state/session-store.ts +144 -18
- package/src/client/state/sse-bridge.ts +206 -29
- package/src/client/state/workspace-settings.ts +11 -0
- package/src/client/theme/global.css +2759 -510
- package/src/client/types.ts +12 -0
- package/src/client/utils/keyboard.ts +10 -0
- package/src/client/utils/time-ago.ts +14 -0
- package/src/json-render/renderer/index.css +6 -1
- package/src/json-render/renderer/index.tsx +31 -1
- package/src/mcp/canvas-app.ts +12 -2
- package/src/mcp/context-uri-template.ts +7 -4
- package/src/mcp/server.ts +63 -41
- package/src/mcp/workbench-app.ts +39 -6
- package/src/server/agent-presence.ts +128 -28
- package/src/server/ax-context.ts +27 -13
- package/src/server/board-export.ts +12 -1
- package/src/server/canvas-db.ts +331 -42
- package/src/server/canvas-operations.ts +196 -84
- package/src/server/canvas-provenance.ts +53 -22
- package/src/server/canvas-serialization.ts +2 -0
- package/src/server/canvas-state.ts +950 -122
- package/src/server/canvas-validation.ts +9 -2
- package/src/server/context-brief.ts +345 -38
- package/src/server/context-reads.ts +179 -30
- package/src/server/demo-state.json +355 -24
- package/src/server/edit-summary.ts +74 -0
- package/src/server/html-surface.ts +8 -1
- package/src/server/index.ts +203 -13
- package/src/server/knowledge-lifecycle.ts +304 -0
- package/src/server/lifecycle-status.ts +232 -0
- package/src/server/memory-graph.ts +166 -0
- package/src/server/mutation-history.ts +18 -6
- package/src/server/operations/composites.ts +32 -11
- package/src/server/operations/http.ts +7 -2
- package/src/server/operations/index.ts +4 -0
- package/src/server/operations/mcp.ts +32 -1
- package/src/server/operations/ops/ax-presence.ts +1 -1
- package/src/server/operations/ops/ax-read.ts +57 -6
- package/src/server/operations/ops/ax-timeline.ts +28 -2
- package/src/server/operations/ops/backup.ts +5 -3
- package/src/server/operations/ops/batch.ts +35 -4
- package/src/server/operations/ops/boards.ts +188 -47
- package/src/server/operations/ops/canvas-wire.ts +31 -1
- package/src/server/operations/ops/edges.ts +36 -2
- package/src/server/operations/ops/groups.ts +6 -1
- package/src/server/operations/ops/json-render.ts +5 -1
- package/src/server/operations/ops/lifecycle.ts +262 -0
- package/src/server/operations/ops/memory-graph.ts +45 -0
- package/src/server/operations/ops/nodes.ts +107 -24
- package/src/server/operations/ops/query.ts +281 -68
- package/src/server/operations/ops/snapshots.ts +73 -1
- package/src/server/operations/ops/validate.ts +5 -1
- package/src/server/operations/ops/viewport.ts +97 -3
- package/src/server/operations/registry.ts +77 -26
- package/src/server/placement.ts +29 -0
- package/src/server/scope-fence.ts +78 -6
- package/src/server/server.ts +115 -16
- package/src/server/spatial-analysis.ts +48 -23
- package/src/server/tour-control.ts +82 -0
- package/src/server/wiki-links.ts +137 -0
- package/src/server/workbench-auth.ts +11 -0
- package/src/shared/agent-context.ts +3 -0
- package/src/shared/agent-presence.ts +15 -15
- package/src/shared/auto-arrange.ts +2 -0
- package/src/shared/boards.ts +4 -4
- package/src/shared/knowledge-lifecycle.ts +22 -0
- package/src/shared/knowledge-presets.ts +80 -0
- package/src/shared/lifecycle-status.ts +26 -0
- package/src/shared/memory-graph.ts +74 -0
- package/src/shared/relations.ts +98 -0
- package/src/shared/semantic-attention.ts +15 -1
- package/src/shared/tour.ts +23 -5
- package/src/shared/workspace-settings.ts +13 -0
- package/dist/types/client/canvas/ContextPinBar.d.ts +0 -1
- package/dist/types/client/canvas/FocusFieldLayer.d.ts +0 -1
- package/dist/types/client/canvas/kind-colors.d.ts +0 -3
- package/dist/types/server/agent-context.d.ts +0 -22
- package/src/client/canvas/ContextPinBar.tsx +0 -25
|
@@ -45,18 +45,26 @@ export interface AgentPresence {
|
|
|
45
45
|
opCount: number;
|
|
46
46
|
/**
|
|
47
47
|
* The agent's REAL context window, when its host reports it (tokens used /
|
|
48
|
-
* window size). Null when no adapter reports — the
|
|
49
|
-
* the
|
|
50
|
-
* says so.
|
|
48
|
+
* window size). Null when no adapter reports — the context chip then shows
|
|
49
|
+
* the brief's size against its budget instead.
|
|
51
50
|
*/
|
|
52
51
|
contextUsage: { used: number; total: number } | null;
|
|
53
52
|
lastSeenAt: string;
|
|
53
|
+
/**
|
|
54
|
+
* What this session has done since it attached (AgentContext.dc.html lens:
|
|
55
|
+
* "Claude · this session"): ids of the cards read, created, edited and
|
|
56
|
+
* pinned on the open board. Only on attached presences; counts every agent
|
|
57
|
+
* on the board, like the receipt.
|
|
58
|
+
*/
|
|
59
|
+
session?: SessionTouches;
|
|
54
60
|
}
|
|
55
61
|
|
|
56
|
-
export interface
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
62
|
+
export interface SessionTouches {
|
|
63
|
+
startedAt: string;
|
|
64
|
+
read: string[];
|
|
65
|
+
created: string[];
|
|
66
|
+
edited: string[];
|
|
67
|
+
pinned: string[];
|
|
60
68
|
}
|
|
61
69
|
|
|
62
70
|
/**
|
|
@@ -79,7 +87,6 @@ export interface AgentActivityEntry {
|
|
|
79
87
|
|
|
80
88
|
export interface AgentPresenceSnapshot {
|
|
81
89
|
presences: AgentPresence[];
|
|
82
|
-
budget: ContextBudget;
|
|
83
90
|
/** True when any presence is attached — the master gate for agent chrome. */
|
|
84
91
|
sessionActive: boolean;
|
|
85
92
|
/** Most recent agent writes, newest first (bounded by MAX_ACTIVITY_ENTRIES). */
|
|
@@ -102,8 +109,6 @@ export const PRESENCE_TOOLING_SETTLE_MS = 4_000;
|
|
|
102
109
|
* "Thinking" chips on a silent board. */
|
|
103
110
|
export const PRESENCE_THINKING_SETTLE_MS = 3 * 60_000;
|
|
104
111
|
export const MAX_PRESENCES = 16;
|
|
105
|
-
/** Default `budget.total` when `PMX_CANVAS_CONTEXT_BUDGET_TOKENS` is unset. */
|
|
106
|
-
export const CONTEXT_BUDGET_DEFAULT_TOKENS = 32_000;
|
|
107
112
|
|
|
108
113
|
/**
|
|
109
114
|
* Source labels that name a TRANSPORT, not an agent. A write arriving under
|
|
@@ -130,11 +135,6 @@ export function externalWriters(presences: readonly AgentPresence[]): AgentPrese
|
|
|
130
135
|
return presences.filter((presence) => !presence.attached);
|
|
131
136
|
}
|
|
132
137
|
|
|
133
|
-
/** Rough token estimate for a JSON payload (chars / 4) — good enough for a meter. */
|
|
134
|
-
export function estimateTokens(text: string): number {
|
|
135
|
-
return Math.ceil(text.length / 4);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
138
|
/** Chip label per phase — shared by the top-bar chip and the on-canvas cursor chip. */
|
|
139
139
|
export function agentPhaseLabel(presence: Pick<AgentPresence, 'phase' | 'detail'>): string {
|
|
140
140
|
switch (presence.phase) {
|
|
@@ -21,6 +21,7 @@ export interface ArrangeEdge {
|
|
|
21
21
|
id: string;
|
|
22
22
|
from: string;
|
|
23
23
|
to: string;
|
|
24
|
+
toBoardId?: string;
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
export interface AutoArrangeResult {
|
|
@@ -184,6 +185,7 @@ function buildUnitGraphs(
|
|
|
184
185
|
}
|
|
185
186
|
|
|
186
187
|
for (const edge of edges) {
|
|
188
|
+
if (edge.toBoardId !== undefined) continue;
|
|
187
189
|
const fromUnit = nodeToUnit.get(edge.from);
|
|
188
190
|
const toUnit = nodeToUnit.get(edge.to);
|
|
189
191
|
if (!fromUnit || !toUnit || fromUnit === toUnit) continue;
|
package/src/shared/boards.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
/** The Home
|
|
2
|
-
export const
|
|
1
|
+
/** The Home folder migrated 0.6 snapshots land on, so they do not bury the boards in use. */
|
|
2
|
+
export const MIGRATED_SNAPSHOT_FOLDER = 'From old snapshots';
|
|
3
3
|
|
|
4
4
|
/** Slash-separated folder paths shared by the UI, HTTP/MCP and SDK. */
|
|
5
|
-
export function
|
|
5
|
+
export function normalizeBoardFolder(value: string | null): string | null {
|
|
6
6
|
if (!value?.trim()) return null;
|
|
7
7
|
const parts = value.split('/').map((part) => part.trim());
|
|
8
8
|
if (parts.length > 8) throw new Error('Folders can be nested up to 8 levels.');
|
|
@@ -13,6 +13,6 @@ export function normalizeBoardCategory(value: string | null): string | null {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
/** Includes implicit parents, so a board in A/B can also be moved into A. */
|
|
16
|
-
export function
|
|
16
|
+
export function folderAncestors(path: string): string[] {
|
|
17
17
|
return path.split('/').map((_, index, parts) => parts.slice(0, index + 1).join('/'));
|
|
18
18
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
/** The same policy contract validates workspace writes and browser drafts. */
|
|
4
|
+
export const lifecycleSchema = z
|
|
5
|
+
.strictObject({
|
|
6
|
+
decayType: z.enum(['reality', 'decision', 'dependency', 'relevance']),
|
|
7
|
+
rate: z.enum(['fast', 'medium', 'slow', 'durable']),
|
|
8
|
+
triggers: z.array(z.string().trim().min(1)),
|
|
9
|
+
revalidationMethod: z.string().trim().min(1),
|
|
10
|
+
cadenceDays: z.number().int().min(1).max(36500).optional(),
|
|
11
|
+
})
|
|
12
|
+
.refine((value) => value.rate !== 'medium' || value.cadenceDays !== undefined, {
|
|
13
|
+
path: ['cadenceDays'],
|
|
14
|
+
message: 'Medium lifecycle requires a cadence in days.',
|
|
15
|
+
});
|
|
16
|
+
export const categorySchema = lifecycleSchema.safeExtend({
|
|
17
|
+
id: z.string().trim().min(1),
|
|
18
|
+
name: z.string().trim().min(1),
|
|
19
|
+
glyph: z.string().trim().min(1),
|
|
20
|
+
});
|
|
21
|
+
export type Lifecycle = z.infer<typeof lifecycleSchema>;
|
|
22
|
+
export type KnowledgeCategory = z.infer<typeof categorySchema>;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { KnowledgeCategory } from '../server/knowledge-lifecycle.js';
|
|
2
|
+
|
|
3
|
+
const category = (
|
|
4
|
+
id: string,
|
|
5
|
+
name: string,
|
|
6
|
+
glyph: string,
|
|
7
|
+
decayType: KnowledgeCategory['decayType'],
|
|
8
|
+
rate: KnowledgeCategory['rate'],
|
|
9
|
+
revalidationMethod: string,
|
|
10
|
+
): KnowledgeCategory => ({
|
|
11
|
+
id,
|
|
12
|
+
name,
|
|
13
|
+
glyph,
|
|
14
|
+
decayType,
|
|
15
|
+
rate,
|
|
16
|
+
revalidationMethod,
|
|
17
|
+
triggers: [],
|
|
18
|
+
...(rate === 'medium' ? { cadenceDays: 90 } : {}),
|
|
19
|
+
});
|
|
20
|
+
const research = category(
|
|
21
|
+
'research',
|
|
22
|
+
'Research',
|
|
23
|
+
'⌕',
|
|
24
|
+
'reality',
|
|
25
|
+
'medium',
|
|
26
|
+
'Check the sources and conflicting evidence.',
|
|
27
|
+
);
|
|
28
|
+
const metric = category('metric', 'Metric', '▥', 'reality', 'fast', 'Re-read the source dashboard and compare.');
|
|
29
|
+
const decision = category(
|
|
30
|
+
'decision',
|
|
31
|
+
'Decision',
|
|
32
|
+
'⚑',
|
|
33
|
+
'decision',
|
|
34
|
+
'durable',
|
|
35
|
+
'Check for a superseding decision and changed dependencies.',
|
|
36
|
+
);
|
|
37
|
+
const notes = category('notes', 'Notes', '✎', 'relevance', 'slow', 'Check relevance to the resumed task.');
|
|
38
|
+
|
|
39
|
+
/** Editable starter data. No runtime behavior depends on these names or ids. */
|
|
40
|
+
export const KNOWLEDGE_PRESETS: Record<string, { categories: KnowledgeCategory[]; folders: Record<string, string> }> = {
|
|
41
|
+
'Org · team · personal': {
|
|
42
|
+
categories: [
|
|
43
|
+
category('strategy', 'Strategy', '◎', 'relevance', 'slow', 'Check the current goals and decisions.'),
|
|
44
|
+
category('policy', 'Policy', '◇', 'decision', 'slow', 'Check with the policy owner.'),
|
|
45
|
+
decision,
|
|
46
|
+
research,
|
|
47
|
+
metric,
|
|
48
|
+
notes,
|
|
49
|
+
],
|
|
50
|
+
folders: {
|
|
51
|
+
Org: 'strategy',
|
|
52
|
+
'Org/Policies': 'policy',
|
|
53
|
+
Team: 'research',
|
|
54
|
+
'Team/Decisions': 'decision',
|
|
55
|
+
'Team/Metrics': 'metric',
|
|
56
|
+
Personal: 'notes',
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
'Solo research': {
|
|
60
|
+
categories: [
|
|
61
|
+
category('question', 'Question', '?', 'relevance', 'slow', 'Check whether this question still matters.'),
|
|
62
|
+
category('source', 'Source', '▤', 'reality', 'medium', 'Re-read the original source.'),
|
|
63
|
+
category(
|
|
64
|
+
'finding',
|
|
65
|
+
'Finding',
|
|
66
|
+
'◉',
|
|
67
|
+
'dependency',
|
|
68
|
+
'durable',
|
|
69
|
+
'Compare the supporting and contradicting evidence.',
|
|
70
|
+
),
|
|
71
|
+
category('note', 'Note', '✎', 'relevance', 'slow', 'Check relevance to the resumed task.'),
|
|
72
|
+
],
|
|
73
|
+
folders: { Projects: 'question', 'Projects/Findings': 'finding', Sources: 'source', Notes: 'note' },
|
|
74
|
+
},
|
|
75
|
+
'Product team': {
|
|
76
|
+
categories: [research, metric, decision, notes],
|
|
77
|
+
folders: { Discovery: 'research', 'Discovery/Metrics': 'metric', Delivery: 'notes', Decisions: 'decision' },
|
|
78
|
+
},
|
|
79
|
+
Empty: { categories: [], folders: {} },
|
|
80
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { MemoryTarget } from './memory-graph.js';
|
|
2
|
+
|
|
3
|
+
export interface SourceQualification extends MemoryTarget {
|
|
4
|
+
title: string;
|
|
5
|
+
reasons: string[];
|
|
6
|
+
unavailable?: true;
|
|
7
|
+
contentRevision?: number;
|
|
8
|
+
observedRevision?: number;
|
|
9
|
+
observedAt?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface LifecycleQualification {
|
|
13
|
+
retired: boolean;
|
|
14
|
+
unknown: boolean;
|
|
15
|
+
due: boolean;
|
|
16
|
+
reasons: string[];
|
|
17
|
+
changedSinceRead: boolean;
|
|
18
|
+
lastReadAt: string | null;
|
|
19
|
+
lastValidatedAt: string | null;
|
|
20
|
+
contentRevision: number;
|
|
21
|
+
contentChangedAt: string | null;
|
|
22
|
+
/** The revisions a validating reviewer must have inspected, qualified by source relation. */
|
|
23
|
+
observations: Record<string, number | null>;
|
|
24
|
+
sources: SourceQualification[];
|
|
25
|
+
relevance: 'card-pinned' | 'board-pinned' | 'not-selected';
|
|
26
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/** Board-qualified identities: card IDs alone are not unique across a library. */
|
|
2
|
+
export interface MemoryTarget {
|
|
3
|
+
boardId: string;
|
|
4
|
+
cardId?: string;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface WikiLink {
|
|
8
|
+
ref: string;
|
|
9
|
+
target?: MemoryTarget;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function wikiLinksFromData(data: Record<string, unknown>): WikiLink[] {
|
|
13
|
+
if (!Array.isArray(data.wikiLinks)) return [];
|
|
14
|
+
return data.wikiLinks.flatMap((value: unknown) => {
|
|
15
|
+
if (!value || typeof value !== 'object') return [];
|
|
16
|
+
const link = value as Record<string, unknown>;
|
|
17
|
+
if (typeof link.ref !== 'string') return [];
|
|
18
|
+
const target = link.target as Record<string, unknown> | undefined;
|
|
19
|
+
return [
|
|
20
|
+
{
|
|
21
|
+
ref: link.ref,
|
|
22
|
+
...(target && typeof target.boardId === 'string'
|
|
23
|
+
? {
|
|
24
|
+
target: {
|
|
25
|
+
boardId: target.boardId,
|
|
26
|
+
...(typeof target.cardId === 'string' ? { cardId: target.cardId } : {}),
|
|
27
|
+
},
|
|
28
|
+
}
|
|
29
|
+
: {}),
|
|
30
|
+
},
|
|
31
|
+
];
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export const memoryKey = (target: MemoryTarget): string => JSON.stringify([target.boardId, target.cardId ?? null]);
|
|
36
|
+
|
|
37
|
+
export interface MemoryGraphNode extends MemoryTarget {
|
|
38
|
+
key: string;
|
|
39
|
+
kind: 'board' | 'card';
|
|
40
|
+
title: string;
|
|
41
|
+
summary: string;
|
|
42
|
+
folder: string | null;
|
|
43
|
+
inContext: boolean;
|
|
44
|
+
summaryOnly: true;
|
|
45
|
+
/** False when the focused view omits incident relations; cannot acknowledge all links. */
|
|
46
|
+
linksComplete?: boolean;
|
|
47
|
+
/** Card link revision captured with this projection. */
|
|
48
|
+
linksRevision?: number;
|
|
49
|
+
type?: string;
|
|
50
|
+
nodeCount?: number;
|
|
51
|
+
position?: { x: number; y: number };
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface MemoryGraphEdge {
|
|
55
|
+
id: string;
|
|
56
|
+
from: string;
|
|
57
|
+
to: string;
|
|
58
|
+
kind: 'member' | 'portal' | 'wiki' | 'card' | 'previous';
|
|
59
|
+
relationKind?: string;
|
|
60
|
+
reason?: string;
|
|
61
|
+
label?: string;
|
|
62
|
+
type?: string;
|
|
63
|
+
source: MemoryTarget;
|
|
64
|
+
target: MemoryTarget;
|
|
65
|
+
missing: boolean;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface MemoryGraph {
|
|
69
|
+
nodes: MemoryGraphNode[];
|
|
70
|
+
edges: MemoryGraphEdge[];
|
|
71
|
+
unresolvedLinks: Array<{ source: MemoryTarget; ref: string }>;
|
|
72
|
+
focus: string | null;
|
|
73
|
+
depth: number;
|
|
74
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
export const relationKindSchema = z.string().trim().min(1).max(80);
|
|
4
|
+
export const relationReasonSchema = z.string().trim().max(4000);
|
|
5
|
+
export const relationDefinitionSchema = z.strictObject({
|
|
6
|
+
kind: relationKindSchema,
|
|
7
|
+
ink: z.enum(['supports', 'contradicts', 'cites', 'derived', 'informs', 'related']),
|
|
8
|
+
directed: z.boolean(),
|
|
9
|
+
});
|
|
10
|
+
export const relationVocabularySchema = z
|
|
11
|
+
.array(relationDefinitionSchema)
|
|
12
|
+
.max(64)
|
|
13
|
+
.refine(
|
|
14
|
+
(values) => new Set(values.map((value) => value.kind)).size === values.length,
|
|
15
|
+
'Relation kinds must be unique.',
|
|
16
|
+
);
|
|
17
|
+
export type RelationDefinition = z.infer<typeof relationDefinitionSchema>;
|
|
18
|
+
export const relationPresetSchema = z.strictObject({
|
|
19
|
+
id: z.string().trim().min(1),
|
|
20
|
+
name: z.string().trim().min(1).max(80),
|
|
21
|
+
vocabulary: relationVocabularySchema,
|
|
22
|
+
});
|
|
23
|
+
export type RelationPreset = z.infer<typeof relationPresetSchema>;
|
|
24
|
+
|
|
25
|
+
export const RELATION_KINDS: RelationDefinition[] = [
|
|
26
|
+
{ kind: 'supports', ink: 'supports', directed: true },
|
|
27
|
+
{ kind: 'contradicts', ink: 'contradicts', directed: true },
|
|
28
|
+
{ kind: 'cites', ink: 'cites', directed: true },
|
|
29
|
+
{ kind: 'derived-from', ink: 'derived', directed: true },
|
|
30
|
+
{ kind: 'answers', ink: 'informs', directed: true },
|
|
31
|
+
{ kind: 'depends-on', ink: 'informs', directed: true },
|
|
32
|
+
{ kind: 'supersedes', ink: 'informs', directed: true },
|
|
33
|
+
{ kind: 'flow', ink: 'derived', directed: true },
|
|
34
|
+
{ kind: 'related', ink: 'related', directed: false },
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
export const RELATION_PRESETS: Record<string, RelationDefinition[]> = {
|
|
38
|
+
Research: RELATION_KINDS.filter((item) =>
|
|
39
|
+
['supports', 'contradicts', 'cites', 'derived-from', 'related'].includes(item.kind),
|
|
40
|
+
),
|
|
41
|
+
Dependencies: RELATION_KINDS.filter((item) => ['depends-on', 'related'].includes(item.kind)),
|
|
42
|
+
Decision: [
|
|
43
|
+
{ kind: 'option', ink: 'derived', directed: true },
|
|
44
|
+
{ kind: 'if', ink: 'cites', directed: true },
|
|
45
|
+
{ kind: 'rejected', ink: 'related', directed: true },
|
|
46
|
+
{ kind: 'supersedes', ink: 'informs', directed: true },
|
|
47
|
+
],
|
|
48
|
+
Flow: [
|
|
49
|
+
{ kind: 'next', ink: 'derived', directed: true },
|
|
50
|
+
{ kind: 'if-fails', ink: 'contradicts', directed: true },
|
|
51
|
+
{ kind: 'loop', ink: 'related', directed: true },
|
|
52
|
+
],
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export function relationPreset(vocabulary: RelationDefinition[] = []): string | null {
|
|
56
|
+
return (
|
|
57
|
+
Object.entries(RELATION_PRESETS).find(
|
|
58
|
+
([, preset]) =>
|
|
59
|
+
preset.length === vocabulary.length &&
|
|
60
|
+
preset.every((item) =>
|
|
61
|
+
vocabulary.some(
|
|
62
|
+
(entry) => entry.kind === item.kind && entry.ink === item.ink && entry.directed === item.directed,
|
|
63
|
+
),
|
|
64
|
+
),
|
|
65
|
+
)?.[0] ?? null
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function relationKind(edge: { kind?: string; type?: string }): string {
|
|
70
|
+
return (
|
|
71
|
+
edge.kind ??
|
|
72
|
+
(edge.type === 'relation' ? 'related' : edge.type === 'references' ? 'cites' : (edge.type ?? 'related'))
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Direction is semantic, not inferred from ink or arrow decoration. */
|
|
77
|
+
export function relationSourceEnd(edge: { kind?: string; type?: string }): 'from' | 'to' | null {
|
|
78
|
+
const kind = relationKind(edge);
|
|
79
|
+
if (kind === 'depends-on') return 'to';
|
|
80
|
+
if (['derived-from', 'contradicts', 'supersedes'].includes(kind)) return 'from';
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function relationDefinition(
|
|
85
|
+
edge: { kind?: string; type?: string },
|
|
86
|
+
vocabulary: RelationDefinition[] = [],
|
|
87
|
+
): RelationDefinition {
|
|
88
|
+
const kind = relationKind(edge);
|
|
89
|
+
return (
|
|
90
|
+
vocabulary.find((item) => item.kind === kind) ??
|
|
91
|
+
RELATION_KINDS.find((item) => item.kind === kind) ?? { kind, ink: 'related', directed: true }
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** Keep the authored label and the explanation, rather than treating a label as a kind. */
|
|
96
|
+
export function relationText(edge: { kind?: string; type?: string; label?: string | null; reason?: string }): string {
|
|
97
|
+
return `${edge.kind ?? edge.type ?? 'related'}${edge.label ? ` "${edge.label}"` : ''}${edge.reason ? ` (why: ${edge.reason})` : ''}`;
|
|
98
|
+
}
|
|
@@ -22,6 +22,7 @@ export interface SemanticWatchEdgeSummary {
|
|
|
22
22
|
edgeType: CanvasEdge['type'];
|
|
23
23
|
fromId: string;
|
|
24
24
|
toId: string;
|
|
25
|
+
toBoardId?: string;
|
|
25
26
|
fromTitle: string | null;
|
|
26
27
|
toTitle: string | null;
|
|
27
28
|
}
|
|
@@ -135,8 +136,9 @@ function summarizeEdge(edge: CanvasEdge, nodeMap: Map<string, CanvasNodeState>):
|
|
|
135
136
|
edgeType: edge.type,
|
|
136
137
|
fromId: edge.from,
|
|
137
138
|
toId: edge.to,
|
|
139
|
+
...(edge.toBoardId !== undefined ? { toBoardId: edge.toBoardId } : {}),
|
|
138
140
|
fromTitle: getNodeTitle(nodeMap.get(edge.from)),
|
|
139
|
-
toTitle: getNodeTitle(nodeMap.get(edge.to)),
|
|
141
|
+
toTitle: edge.toBoardId === undefined ? getNodeTitle(nodeMap.get(edge.to)) : null,
|
|
140
142
|
};
|
|
141
143
|
}
|
|
142
144
|
|
|
@@ -326,6 +328,7 @@ export function formatCompactWatchEvent(event: SemanticWatchEvent): string {
|
|
|
326
328
|
}
|
|
327
329
|
|
|
328
330
|
export class SemanticWatchReducer {
|
|
331
|
+
private currentBoardId: string | null | undefined;
|
|
329
332
|
private currentLayout: CanvasLayout | null = null;
|
|
330
333
|
private currentPins = new Set<string>();
|
|
331
334
|
private previousSpatial: SpatialContext | null = null;
|
|
@@ -339,6 +342,17 @@ export class SemanticWatchReducer {
|
|
|
339
342
|
}
|
|
340
343
|
|
|
341
344
|
handleMessage(message: SseMessage): SemanticWatchEvent[] {
|
|
345
|
+
if (message.event === 'context-pins-changed' || message.event === 'canvas-layout-update') {
|
|
346
|
+
const record = message.data && typeof message.data === 'object' ? (message.data as Record<string, unknown>) : {};
|
|
347
|
+
if (typeof record.boardId === 'string' || record.boardId === null) {
|
|
348
|
+
if (this.currentBoardId !== undefined && record.boardId !== this.currentBoardId) {
|
|
349
|
+
this.currentLayout = null;
|
|
350
|
+
this.currentPins.clear();
|
|
351
|
+
this.previousSpatial = null;
|
|
352
|
+
}
|
|
353
|
+
this.currentBoardId = record.boardId;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
342
356
|
if (message.event === 'context-pins-changed') {
|
|
343
357
|
return this.handleContextPinsChanged(message.data);
|
|
344
358
|
}
|
package/src/shared/tour.ts
CHANGED
|
@@ -1,8 +1,20 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
|
|
3
3
|
export const cameraSchema = z.object({ x: z.number(), y: z.number(), scale: z.number().positive() });
|
|
4
|
+
/** A world-space box: `{ x, y }` is its top-left corner. */
|
|
5
|
+
export const rectSchema = z.object({
|
|
6
|
+
x: z.number(),
|
|
7
|
+
y: z.number(),
|
|
8
|
+
width: z.number().positive(),
|
|
9
|
+
height: z.number().positive(),
|
|
10
|
+
});
|
|
11
|
+
export const tourTargetSchema = z.union([
|
|
12
|
+
z.strictObject({ nodeId: z.string().min(1) }),
|
|
13
|
+
z.strictObject({ rect: rectSchema }),
|
|
14
|
+
z.strictObject({ viewport: cameraSchema }),
|
|
15
|
+
]);
|
|
4
16
|
export const tourStopSchema = z.object({
|
|
5
|
-
target:
|
|
17
|
+
target: tourTargetSchema,
|
|
6
18
|
duration: z.number().nonnegative().max(3600).optional(),
|
|
7
19
|
easing: z.enum(['linear', 'ease-in-out', 'ease-out']).optional(),
|
|
8
20
|
padding: z.number().nonnegative().optional(),
|
|
@@ -12,6 +24,7 @@ export const tourSchema = z.object({ stops: z.array(tourStopSchema).max(1000) })
|
|
|
12
24
|
export type Tour = z.infer<typeof tourSchema>;
|
|
13
25
|
export type TourStop = z.infer<typeof tourStopSchema>;
|
|
14
26
|
export type Camera = z.infer<typeof cameraSchema>;
|
|
27
|
+
export type Rect = z.infer<typeof rectSchema>;
|
|
15
28
|
export interface TourNode {
|
|
16
29
|
id: string;
|
|
17
30
|
type: string;
|
|
@@ -30,15 +43,20 @@ export function derivedTour(nodes: TourNode[]): Tour {
|
|
|
30
43
|
|
|
31
44
|
export function resolveStop(stop: TourStop, nodes: TourNode[], width: number, height: number): Camera {
|
|
32
45
|
if ('viewport' in stop.target) return stop.target.viewport;
|
|
46
|
+
if ('rect' in stop.target) return fitRect(stop.target.rect, stop.padding, width, height);
|
|
33
47
|
const id = stop.target.nodeId;
|
|
34
48
|
const node = nodes.find((n) => n.id === id);
|
|
35
49
|
if (!node) throw new Error(`Tour target not found: ${id}`);
|
|
36
|
-
|
|
50
|
+
return fitRect({ ...node.position, ...node.size }, stop.padding, width, height);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Centre a world-space rect in a width×height area with screen-space padding. */
|
|
54
|
+
function fitRect(rect: Rect, padding = 40, width: number, height: number): Camera {
|
|
37
55
|
if (padding * 2 >= Math.min(width, height)) throw new Error('Tour padding exceeds viewport');
|
|
38
|
-
const scale = Math.min((width - padding * 2) /
|
|
56
|
+
const scale = Math.min((width - padding * 2) / rect.width, (height - padding * 2) / rect.height);
|
|
39
57
|
return {
|
|
40
|
-
x: width / 2 - (
|
|
41
|
-
y: height / 2 - (
|
|
58
|
+
x: width / 2 - (rect.x + rect.width / 2) * scale,
|
|
59
|
+
y: height / 2 - (rect.y + rect.height / 2) * scale,
|
|
42
60
|
scale,
|
|
43
61
|
};
|
|
44
62
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
export const workspaceSettingsSchema = z.strictObject({
|
|
4
|
+
agentSessions: z.boolean(),
|
|
5
|
+
knowledgeLifecycle: z.boolean(),
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
export type WorkspaceSettings = z.infer<typeof workspaceSettingsSchema>;
|
|
9
|
+
export const workspaceSettingsPatchSchema = workspaceSettingsSchema.partial();
|
|
10
|
+
export const DEFAULT_WORKSPACE_SETTINGS: WorkspaceSettings = {
|
|
11
|
+
agentSessions: false,
|
|
12
|
+
knowledgeLifecycle: false,
|
|
13
|
+
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function ContextPinBar(): import("preact/src").JSX.Element | null;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function FocusFieldLayer(): import("preact/src").JSX.Element | null;
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import type { CanvasNodeState } from './canvas-state.js';
|
|
2
|
-
export interface AgentContextNode {
|
|
3
|
-
id: string;
|
|
4
|
-
type: CanvasNodeState['type'];
|
|
5
|
-
kind: string;
|
|
6
|
-
title: string | null;
|
|
7
|
-
content: string | null;
|
|
8
|
-
metadata?: Record<string, unknown>;
|
|
9
|
-
position?: {
|
|
10
|
-
x: number;
|
|
11
|
-
y: number;
|
|
12
|
-
};
|
|
13
|
-
}
|
|
14
|
-
interface AgentContextOptions {
|
|
15
|
-
defaultTextLength?: number;
|
|
16
|
-
webpageTextLength?: number;
|
|
17
|
-
includePosition?: boolean;
|
|
18
|
-
}
|
|
19
|
-
export declare function summarizeNodeForAgentContext(node: CanvasNodeState, options?: AgentContextOptions): string;
|
|
20
|
-
export declare function serializeNodeForAgentContext(node: CanvasNodeState, options?: AgentContextOptions): AgentContextNode;
|
|
21
|
-
export declare function buildAgentContextPreamble(nodes: CanvasNodeState[], options?: AgentContextOptions): string;
|
|
22
|
-
export {};
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { clearContextPins, contextPinnedNodeIds } from '../state/canvas-store';
|
|
2
|
-
import { attentionHistoryOpen } from '../state/attention-store';
|
|
3
|
-
import { IconClose } from '../icons';
|
|
4
|
-
|
|
5
|
-
export function ContextPinBar() {
|
|
6
|
-
const count = contextPinnedNodeIds.value.size;
|
|
7
|
-
if (count === 0 || attentionHistoryOpen.value) return null;
|
|
8
|
-
|
|
9
|
-
return (
|
|
10
|
-
<div class="context-pin-bar">
|
|
11
|
-
<span class="context-pin-bar-count">
|
|
12
|
-
{'\u2726'} {count} node{count !== 1 ? 's' : ''} in context
|
|
13
|
-
</span>
|
|
14
|
-
<button
|
|
15
|
-
type="button"
|
|
16
|
-
class="context-pin-bar-btn context-pin-bar-clear"
|
|
17
|
-
onClick={clearContextPins}
|
|
18
|
-
title="Clear all context pins"
|
|
19
|
-
aria-label="Clear all context pins"
|
|
20
|
-
>
|
|
21
|
-
<IconClose size={14} />
|
|
22
|
-
</button>
|
|
23
|
-
</div>
|
|
24
|
-
);
|
|
25
|
-
}
|