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
|
@@ -3,9 +3,14 @@ import { showToast } from './attention-bridge';
|
|
|
3
3
|
import { computed, signal } from '@preact/signals';
|
|
4
4
|
import type { AxApprovalStatus, AxEventKind, AxWorkItemStatus } from '../../shared/ax-kinds.js';
|
|
5
5
|
import { HUMAN_STARTED_SESSION_LABEL } from '../../shared/agent-presence.js';
|
|
6
|
-
import { axSurfaceState } from './canvas-store';
|
|
6
|
+
import { axSurfaceState, nodes } from './canvas-store';
|
|
7
7
|
import { requestBestEffort, requestJson, requestOk } from './intent-bridge';
|
|
8
|
-
import { agentActivity } from './presence-store';
|
|
8
|
+
import { agentActivity, agentPresences } from './presence-store';
|
|
9
|
+
import { activeBoardId } from './boards-store';
|
|
10
|
+
import { agentSessionsEnabled } from './workspace-settings';
|
|
11
|
+
|
|
12
|
+
/** Explicit panel expansion, shared by the panel handle and the agent popover. */
|
|
13
|
+
export const sessionPanelOpened = signal(false);
|
|
9
14
|
|
|
10
15
|
// Structural views of the AX wire shapes (the client never imports server
|
|
11
16
|
// modules; the status/kind unions come from shared/). Only the fields the
|
|
@@ -358,6 +363,7 @@ export async function sendSteering(message: string, target?: string | null): Pro
|
|
|
358
363
|
|
|
359
364
|
/** Attach a human-started session; the agent's writes are attributed to it. */
|
|
360
365
|
export async function startSession(): Promise<boolean> {
|
|
366
|
+
if (!agentSessionsEnabled.value) return false;
|
|
361
367
|
const result = await requestOk('startSession', '/api/canvas/ax/presence', {
|
|
362
368
|
method: 'POST',
|
|
363
369
|
headers: { 'Content-Type': 'application/json' },
|
|
@@ -381,6 +387,8 @@ export interface SessionReceipt {
|
|
|
381
387
|
labels: string[];
|
|
382
388
|
/** Endings folded into this card (see applySessionReceipt). */
|
|
383
389
|
sessions: number;
|
|
390
|
+
/** When the session attached (the receipt's "This session · start–end"); null if unknown. */
|
|
391
|
+
startedAt: string | null;
|
|
384
392
|
endedAt: string;
|
|
385
393
|
/** Why it ended — the receipt should answer this, not leave the human asking. */
|
|
386
394
|
endedBy?: 'human' | 'agent' | 'idle-timeout';
|
|
@@ -390,7 +398,7 @@ export interface SessionReceipt {
|
|
|
390
398
|
counts: { items: number; done: number; cancelled: number; rejected: number; held: number };
|
|
391
399
|
/** The pre-session snapshot; null when the board was empty at attach, or on a
|
|
392
400
|
* merged receipt (each session's snapshot is in History). */
|
|
393
|
-
snapshot: { id: string; name: string } | null;
|
|
401
|
+
snapshot: { id: string; name: string; boardId: string | null } | null;
|
|
394
402
|
/** What the session did with context (docs/design/AgentContext.dc.html receipt). */
|
|
395
403
|
context: SessionContextActivity;
|
|
396
404
|
}
|
|
@@ -398,9 +406,19 @@ export interface SessionReceipt {
|
|
|
398
406
|
export interface ReceiptNode {
|
|
399
407
|
id: string;
|
|
400
408
|
title: string;
|
|
409
|
+
/** The board where this touch was recorded, for reopening a change's card. */
|
|
410
|
+
boardId?: string;
|
|
401
411
|
reason?: string;
|
|
412
|
+
/** Edited cards: what the edit did ("rewrote the second paragraph"). */
|
|
413
|
+
change?: string;
|
|
414
|
+
/** Edited cards: the text before and at the session's end, cut around the first difference. */
|
|
415
|
+
before?: string;
|
|
416
|
+
after?: string;
|
|
402
417
|
}
|
|
403
418
|
|
|
419
|
+
/** Card ids are local to a board; receipts can remain open across board switches. */
|
|
420
|
+
export const receiptNodeKey = (node: ReceiptNode): string => JSON.stringify([node.boardId, node.id]);
|
|
421
|
+
|
|
404
422
|
export interface SessionContextActivity {
|
|
405
423
|
read: ReceiptNode[];
|
|
406
424
|
pinned: ReceiptNode[];
|
|
@@ -416,7 +434,15 @@ function receiptNodes(value: unknown): ReceiptNode[] {
|
|
|
416
434
|
const record = entry as Record<string, unknown>;
|
|
417
435
|
if (typeof record.id !== 'string' || typeof record.title !== 'string') return [];
|
|
418
436
|
return [
|
|
419
|
-
{
|
|
437
|
+
{
|
|
438
|
+
id: record.id,
|
|
439
|
+
title: record.title,
|
|
440
|
+
...(typeof record.boardId === 'string' ? { boardId: record.boardId } : {}),
|
|
441
|
+
...(typeof record.reason === 'string' ? { reason: record.reason } : {}),
|
|
442
|
+
...(typeof record.change === 'string' ? { change: record.change } : {}),
|
|
443
|
+
...(typeof record.before === 'string' ? { before: record.before } : {}),
|
|
444
|
+
...(typeof record.after === 'string' ? { after: record.after } : {}),
|
|
445
|
+
},
|
|
420
446
|
];
|
|
421
447
|
});
|
|
422
448
|
}
|
|
@@ -425,22 +451,74 @@ function receiptNodes(value: unknown): ReceiptNode[] {
|
|
|
425
451
|
* The agent-activity lens: while on, nodes the last session did not touch
|
|
426
452
|
* (read, pin, create, edit) are dimmed. Null when off.
|
|
427
453
|
*/
|
|
428
|
-
|
|
454
|
+
/**
|
|
455
|
+
* The activity lens ("Dim untouched nodes"): off, one live session's touches
|
|
456
|
+
* (the chip that was pressed), or the receipt's. A live lens hands over to the
|
|
457
|
+
* receipt when that session ends, and switches off if its ending has none.
|
|
458
|
+
*/
|
|
459
|
+
export type ActivityLens = { kind: 'live'; sessionId: string } | { kind: 'receipt' } | null;
|
|
460
|
+
export const activityLens = signal<ActivityLens>(null);
|
|
461
|
+
|
|
462
|
+
const touchedIds = (lists: Array<Array<{ id: string } | string>>): Set<string> =>
|
|
463
|
+
new Set(lists.flat().map((entry) => (typeof entry === 'string' ? entry : entry.id)));
|
|
464
|
+
|
|
465
|
+
export const activityLensNodeIds = computed<Set<string> | null>(() => {
|
|
466
|
+
if (!agentSessionsEnabled.value) return null;
|
|
467
|
+
const lens = activityLens.value;
|
|
468
|
+
if (lens?.kind === 'live') {
|
|
469
|
+
const touches = agentPresences.value.find(
|
|
470
|
+
(presence) => presence.attached && presence.sessionId === lens.sessionId,
|
|
471
|
+
)?.session;
|
|
472
|
+
return touches ? touchedIds([touches.read, touches.pinned, touches.created, touches.edited]) : null;
|
|
473
|
+
}
|
|
474
|
+
const context = lens?.kind === 'receipt' ? sessionReceipt.value?.context : undefined;
|
|
475
|
+
return context
|
|
476
|
+
? touchedIds(
|
|
477
|
+
[context.read, context.pinned, context.created, context.edited].map((list) =>
|
|
478
|
+
list.filter((node) => !node.boardId || node.boardId === activeBoardId.value),
|
|
479
|
+
),
|
|
480
|
+
)
|
|
481
|
+
: null;
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
/** Cards an agent edited in a live session or in the receipt's session: they carry the violet bar. */
|
|
485
|
+
export const sessionEditedIds = computed<Set<string>>(
|
|
486
|
+
() =>
|
|
487
|
+
new Set([
|
|
488
|
+
...agentPresences.value.flatMap((presence) => (presence.attached ? (presence.session?.edited ?? []) : [])),
|
|
489
|
+
...(sessionReceipt.value?.context.edited
|
|
490
|
+
.filter((node) => !node.boardId || node.boardId === activeBoardId.value)
|
|
491
|
+
.map((node) => node.id) ?? []),
|
|
492
|
+
]),
|
|
493
|
+
);
|
|
429
494
|
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
on && context
|
|
434
|
-
? new Set([...context.read, ...context.pinned, ...context.created, ...context.edited].map((node) => node.id))
|
|
435
|
-
: null;
|
|
495
|
+
/** Turn the lens on for a live session (from its chip) or the receipt, or off. */
|
|
496
|
+
export function setActivityLens(on: boolean, live?: { sessionId: string }): void {
|
|
497
|
+
activityLens.value = on ? (live ? { kind: 'live', ...live } : { kind: 'receipt' }) : null;
|
|
436
498
|
}
|
|
437
499
|
|
|
438
500
|
/** The last ended session's receipt (design item 2); client-side, cleared on dismiss. */
|
|
439
501
|
export const sessionReceipt = signal<SessionReceipt | null>(null);
|
|
440
502
|
|
|
503
|
+
/** A card both sessions edited: the first Before, the last After, both changes. */
|
|
504
|
+
function mergeEdits(open: ReceiptNode[], next: ReceiptNode[]): ReceiptNode[] {
|
|
505
|
+
const later = new Map(next.map((node) => [receiptNodeKey(node), node]));
|
|
506
|
+
const merged = open.map((node) => {
|
|
507
|
+
const again = later.get(receiptNodeKey(node));
|
|
508
|
+
if (!again) return node;
|
|
509
|
+
later.delete(receiptNodeKey(node));
|
|
510
|
+
return {
|
|
511
|
+
...again,
|
|
512
|
+
change: [node.change, again.change].filter(Boolean).join('; then '),
|
|
513
|
+
before: node.before ?? again.before,
|
|
514
|
+
};
|
|
515
|
+
});
|
|
516
|
+
return [...merged, ...later.values()];
|
|
517
|
+
}
|
|
518
|
+
|
|
441
519
|
function unionNodes(a: ReceiptNode[], b: ReceiptNode[]): ReceiptNode[] {
|
|
442
|
-
const seen = new Set(a.map(
|
|
443
|
-
return [...a, ...b.filter((node) => !seen.has(node
|
|
520
|
+
const seen = new Set(a.map(receiptNodeKey));
|
|
521
|
+
return [...a, ...b.filter((node) => !seen.has(receiptNodeKey(node)))];
|
|
444
522
|
}
|
|
445
523
|
|
|
446
524
|
/**
|
|
@@ -452,6 +530,7 @@ function mergeReceipts(open: SessionReceipt, next: SessionReceipt): SessionRecei
|
|
|
452
530
|
return {
|
|
453
531
|
labels: [...new Set([...open.labels, ...next.labels])],
|
|
454
532
|
sessions: open.sessions + 1,
|
|
533
|
+
startedAt: open.startedAt && next.startedAt && next.startedAt < open.startedAt ? next.startedAt : open.startedAt,
|
|
455
534
|
endedAt: next.endedAt,
|
|
456
535
|
endedBy: open.endedBy === next.endedBy ? next.endedBy : undefined,
|
|
457
536
|
// Board-wide counts: the latest frame is the current board.
|
|
@@ -461,7 +540,7 @@ function mergeReceipts(open: SessionReceipt, next: SessionReceipt): SessionRecei
|
|
|
461
540
|
read: unionNodes(open.context.read, next.context.read),
|
|
462
541
|
pinned: unionNodes(open.context.pinned, next.context.pinned),
|
|
463
542
|
created: unionNodes(open.context.created, next.context.created),
|
|
464
|
-
edited:
|
|
543
|
+
edited: mergeEdits(open.context.edited, next.context.edited),
|
|
465
544
|
changedSinceRead: unionNodes(open.context.changedSinceRead, next.context.changedSinceRead),
|
|
466
545
|
},
|
|
467
546
|
};
|
|
@@ -479,10 +558,17 @@ export function applySessionReceipt(data: Record<string, unknown>): void {
|
|
|
479
558
|
const snapshot = data.snapshot as SessionReceipt['snapshot'] | undefined;
|
|
480
559
|
const context = data.context as Record<string, unknown> | undefined;
|
|
481
560
|
if (typeof data.label !== 'string' || typeof data.endedAt !== 'string') return;
|
|
482
|
-
|
|
561
|
+
const lens = activityLens.value;
|
|
562
|
+
const endsLiveLens = lens?.kind === 'live' && lens.sessionId === data.writer;
|
|
563
|
+
if (data.unchanged === true || typeof data.parentAgentId === 'string') {
|
|
564
|
+
// The session the lens followed ended with nothing to show: the lens goes off.
|
|
565
|
+
if (endsLiveLens) activityLens.value = null;
|
|
566
|
+
return;
|
|
567
|
+
}
|
|
483
568
|
const next: SessionReceipt = {
|
|
484
569
|
labels: [data.label],
|
|
485
570
|
sessions: 1,
|
|
571
|
+
startedAt: typeof data.startedAt === 'string' ? data.startedAt : null,
|
|
486
572
|
endedAt: data.endedAt,
|
|
487
573
|
endedBy:
|
|
488
574
|
data.endedBy === 'human' || data.endedBy === 'agent' || data.endedBy === 'idle-timeout'
|
|
@@ -496,7 +582,13 @@ export function applySessionReceipt(data: Record<string, unknown>): void {
|
|
|
496
582
|
held: Number(counts?.held ?? 0) || 0,
|
|
497
583
|
},
|
|
498
584
|
snapshot:
|
|
499
|
-
snapshot && typeof snapshot.id === 'string'
|
|
585
|
+
snapshot && typeof snapshot.id === 'string'
|
|
586
|
+
? {
|
|
587
|
+
id: snapshot.id,
|
|
588
|
+
name: String(snapshot.name ?? ''),
|
|
589
|
+
boardId: typeof snapshot.boardId === 'string' ? snapshot.boardId : null,
|
|
590
|
+
}
|
|
591
|
+
: null,
|
|
500
592
|
context: {
|
|
501
593
|
read: receiptNodes(context?.read),
|
|
502
594
|
pinned: receiptNodes(context?.pinned),
|
|
@@ -507,17 +599,51 @@ export function applySessionReceipt(data: Record<string, unknown>): void {
|
|
|
507
599
|
};
|
|
508
600
|
const open = sessionReceipt.value;
|
|
509
601
|
sessionReceipt.value = open ? mergeReceipts(open, next) : next;
|
|
510
|
-
|
|
602
|
+
// A live lens carries on as the receipt's once its session ends.
|
|
603
|
+
if (endsLiveLens) activityLens.value = { kind: 'receipt' };
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
/**
|
|
607
|
+
* Undo on the receipt's Edited row (AgentContext.dc.html): each card back to
|
|
608
|
+
* its content in the pre-session snapshot — the rest of the board stays.
|
|
609
|
+
*/
|
|
610
|
+
export async function undoSessionEdits(
|
|
611
|
+
snapshotId: string,
|
|
612
|
+
edits: ReceiptNode[],
|
|
613
|
+
): Promise<{ ok: boolean; restored: string[] }> {
|
|
614
|
+
let ok = true;
|
|
615
|
+
const restored: string[] = [];
|
|
616
|
+
for (const edit of edits) {
|
|
617
|
+
if (edit.boardId && edit.boardId !== activeBoardId.value) continue;
|
|
618
|
+
const nodeId = edit.id;
|
|
619
|
+
// A card you edited after the session keeps your edit.
|
|
620
|
+
const node = nodes.value.get(nodeId);
|
|
621
|
+
if (!node || node.lastEditedBy?.actor === 'human') continue;
|
|
622
|
+
const result = await requestJson<{ ok: boolean; restored: boolean }>(
|
|
623
|
+
'undoSessionEdit',
|
|
624
|
+
`/api/canvas/snapshots/${encodeURIComponent(snapshotId)}/restore-node`,
|
|
625
|
+
{ ok: false, restored: false },
|
|
626
|
+
{
|
|
627
|
+
method: 'POST',
|
|
628
|
+
headers: { 'Content-Type': 'application/json' },
|
|
629
|
+
body: JSON.stringify({ nodeId, preserveHumanEdits: true }),
|
|
630
|
+
},
|
|
631
|
+
);
|
|
632
|
+
ok = ok && result.ok;
|
|
633
|
+
if (result.ok && result.restored) restored.push(nodeId);
|
|
634
|
+
}
|
|
635
|
+
return { ok, restored };
|
|
511
636
|
}
|
|
512
637
|
|
|
513
638
|
export function dismissSessionReceipt(): void {
|
|
514
639
|
sessionReceipt.value = null;
|
|
515
|
-
|
|
640
|
+
if (activityLens.value?.kind === 'receipt') activityLens.value = null;
|
|
516
641
|
}
|
|
517
642
|
|
|
518
643
|
export function resetSessionStore(): void {
|
|
519
644
|
historyTop.value = null;
|
|
520
645
|
undoneActivityIds.value = new Set();
|
|
646
|
+
sessionPanelOpened.value = false;
|
|
521
647
|
sessionReceipt.value = null;
|
|
522
648
|
axTimeline.value = { events: [], evidence: [], steering: [] };
|
|
523
649
|
timelineFilter.value = 'all';
|