pmx-canvas 0.7.3 → 0.8.2
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/THIRD_PARTY_LICENSES.txt +331 -0
- package/.github/extensions/pmx-canvas/extension.mjs +25 -172
- package/.github/extensions/pmx-canvas/mcp-bootstrap.ts +198 -0
- package/.github/extensions/pmx-canvas/runtime.d.mts +41 -0
- package/.github/extensions/pmx-canvas/runtime.json +3 -0
- package/.github/extensions/pmx-canvas/runtime.mjs +194 -0
- package/.github/extensions/pmx-canvas/start-mcp.mjs +51 -0
- package/.github/extensions/pmx-canvas/tools.json +2560 -0
- package/CHANGELOG.md +64 -0
- package/Readme.md +21 -7
- package/dist/canvas/fonts/OFL.txt +93 -0
- package/dist/canvas/fonts/ibm-plex-mono-latin-400-normal.woff2 +0 -0
- package/dist/canvas/fonts/ibm-plex-mono-latin-500-normal.woff2 +0 -0
- package/dist/canvas/fonts/ibm-plex-mono-latin-ext-400-normal.woff2 +0 -0
- package/dist/canvas/fonts/ibm-plex-mono-latin-ext-500-normal.woff2 +0 -0
- package/dist/canvas/fonts/ibm-plex-sans-latin-400-normal.woff2 +0 -0
- package/dist/canvas/fonts/ibm-plex-sans-latin-500-normal.woff2 +0 -0
- package/dist/canvas/fonts/ibm-plex-sans-latin-600-normal.woff2 +0 -0
- package/dist/canvas/fonts/ibm-plex-sans-latin-ext-400-normal.woff2 +0 -0
- package/dist/canvas/fonts/ibm-plex-sans-latin-ext-500-normal.woff2 +0 -0
- package/dist/canvas/fonts/ibm-plex-sans-latin-ext-600-normal.woff2 +0 -0
- package/dist/canvas/global.css +726 -674
- package/dist/canvas/index.js +90 -88
- package/dist/canvas/mcp-app.html +7879 -0
- package/dist/canvas/mermaid-entry.js +1 -1
- package/dist/canvas/surface-theme.css +151 -46
- package/dist/json-render/index.css +81 -1
- package/dist/json-render/index.js +1 -1
- package/dist/types/cli/commands/record.d.ts +1 -1
- package/dist/types/client/canvas/NodeContextMark.d.ts +24 -0
- package/dist/types/client/canvas/SessionReceipt.d.ts +3 -1
- package/dist/types/client/icons.d.ts +1 -2
- package/dist/types/client/mcp-app/index.d.ts +1 -0
- package/dist/types/client/nodes/HtmlNode.d.ts +1 -0
- package/dist/types/client/nodes/ax-node-actions.d.ts +2 -2
- package/dist/types/client/nodes/markdown-sanitize.d.ts +2 -0
- package/dist/types/client/nodes/use-workbench-asset.d.ts +2 -0
- package/dist/types/client/state/attention-store.d.ts +0 -5
- package/dist/types/client/state/context-status-store.d.ts +53 -0
- package/dist/types/client/state/intent-bridge.d.ts +3 -0
- package/dist/types/client/state/near-pin-store.d.ts +16 -0
- package/dist/types/client/state/presence-store.d.ts +5 -0
- package/dist/types/client/state/session-store.d.ts +33 -3
- package/dist/types/client/state/workbench-transport.d.ts +16 -0
- package/dist/types/client/theme/tokens.d.ts +1 -3
- package/dist/types/client/types.d.ts +9 -0
- package/dist/types/json-render/server.d.ts +1 -1
- package/dist/types/mcp/app-server.d.ts +3 -0
- package/dist/types/mcp/canvas-access.d.ts +1 -1
- package/dist/types/mcp/canvas-app.d.ts +4 -0
- package/dist/types/mcp/workbench-app.d.ts +4 -0
- package/dist/types/server/agent-presence.d.ts +1 -1
- package/dist/types/server/ax-state.d.ts +1 -1
- package/dist/types/server/canvas-db.d.ts +8 -0
- package/dist/types/server/canvas-geometry.d.ts +25 -0
- package/dist/types/server/canvas-operations.d.ts +1 -11
- package/dist/types/server/canvas-state.d.ts +25 -3
- package/dist/types/server/context-brief.d.ts +8 -1
- package/dist/types/server/context-reads.d.ts +30 -7
- package/dist/types/server/index.d.ts +6 -1
- package/dist/types/server/mcp-app-runtime.d.ts +1 -0
- package/dist/types/server/operations/http.d.ts +2 -0
- package/dist/types/server/operations/invoker.d.ts +4 -2
- package/dist/types/server/operations/ops/nodes.d.ts +0 -6
- package/dist/types/server/server.d.ts +1 -0
- package/dist/types/server/spatial-analysis.d.ts +2 -0
- package/dist/types/shared/agent-context.d.ts +22 -0
- package/dist/types/shared/agent-presence.d.ts +3 -10
- package/dist/types/shared/canvas-app.d.ts +54 -0
- package/dist/types/shared/themes.d.ts +1 -1
- package/docs/RELEASE.md +7 -3
- package/docs/agent-plugin.md +123 -0
- package/docs/ax-state-contract.md +40 -0
- package/docs/cli.md +7 -2
- package/docs/design/AgentContext.dc.html +186 -0
- package/docs/design/Before.dc.html +208 -0
- package/docs/design/BoardPins.dc.html +151 -0
- package/docs/design/Chrome.dc.html +211 -0
- package/docs/design/Context.dc.html +239 -0
- package/docs/design/Flows.dc.html +181 -0
- package/docs/design/Home.dc.html +209 -0
- package/docs/design/HomeGraph.dc.html +211 -0
- package/docs/design/HomeMap.dc.html +117 -0
- package/docs/design/HomeTeam.dc.html +176 -0
- package/docs/design/Light.dc.html +28 -0
- package/docs/design/Main.dc.html +280 -0
- package/docs/design/NearPin.dc.html +260 -0
- package/docs/design/Pane600.dc.html +120 -0
- package/docs/design/Relations.dc.html +297 -0
- package/docs/design/Themes.dc.html +121 -0
- package/docs/design/TokenSystem.dc.html +136 -0
- package/docs/design/Tokens.dc.html +163 -0
- package/docs/design/Types1.dc.html +177 -0
- package/docs/design/Types2.dc.html +226 -0
- package/docs/design/Types3.dc.html +195 -0
- package/docs/design/Uses.dc.html +152 -0
- package/docs/design/Vision.dc.html +116 -0
- package/docs/design/Zoom.dc.html +82 -0
- package/docs/design/canvas.json +274 -0
- package/docs/design.md +217 -0
- package/docs/environment.md +1 -1
- package/docs/http-api.md +86 -16
- package/docs/mcp.md +202 -4
- package/docs/node-types.md +34 -10
- package/docs/plans/plan-009-tech-debt-backlog.md +1 -1
- package/docs/plans/plan-015-design-foundation-wave-0.md +177 -0
- package/docs/plans/plan-016-context-made-visible-wave-1.md +148 -0
- package/docs/product-vision-2026-09.md +47 -7
- package/docs/screenshot.png +0 -0
- package/docs/sdk.md +1 -0
- package/package.json +10 -4
- package/plugins/pmx-canvas/LICENSE +21 -0
- package/plugins/pmx-canvas/THIRD_PARTY_LICENSES.txt +331 -0
- package/plugins/pmx-canvas/assets/preview.png +0 -0
- package/plugins/pmx-canvas/com.github.copilot/extensions/pmx-canvas/extension.mjs +930 -0
- package/plugins/pmx-canvas/com.github.copilot/extensions/pmx-canvas/runtime.json +3 -0
- package/plugins/pmx-canvas/com.github.copilot/extensions/pmx-canvas/runtime.mjs +194 -0
- package/plugins/pmx-canvas/com.github.copilot/extensions/pmx-canvas/steering-delivery.mjs +79 -0
- package/plugins/pmx-canvas/mcp.json +12 -0
- package/plugins/pmx-canvas/plugin.json +24 -0
- package/plugins/pmx-canvas/runtime.json +3 -0
- package/plugins/pmx-canvas/runtime.mjs +194 -0
- package/plugins/pmx-canvas/start-mcp.mjs +51 -0
- package/plugins/pmx-canvas/tools.json +2560 -0
- package/skills/pmx-canvas/SKILL.md +29 -9
- 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 +11 -7
- package/skills/pmx-canvas/references/github-copilot-app-adapter.md +20 -8
- package/skills/pmx-canvas/references/installing-pmx-canvas.md +6 -6
- package/skills/pmx-canvas-testing/SKILL.md +5 -4
- package/src/cli/commands/copilot.ts +5 -0
- package/src/cli/commands/nodes.ts +3 -2
- package/src/cli/commands/view.ts +1 -1
- package/src/cli/index.ts +10 -4
- package/src/client/App.tsx +6 -1
- package/src/client/canvas/AgentPresenceLayer.tsx +3 -3
- package/src/client/canvas/AnnotationLayer.tsx +1 -1
- package/src/client/canvas/CanvasNode.tsx +32 -49
- package/src/client/canvas/CanvasViewport.tsx +0 -2
- package/src/client/canvas/CommandPalette.tsx +3 -2
- package/src/client/canvas/ContextMenu.tsx +11 -0
- package/src/client/canvas/EdgeLayer.tsx +1 -1
- package/src/client/canvas/ExportDialog.tsx +33 -6
- package/src/client/canvas/IntentLayer.tsx +2 -2
- package/src/client/canvas/Minimap.tsx +12 -7
- package/src/client/canvas/NodeContextMark.tsx +156 -0
- package/src/client/canvas/SessionPanel.tsx +4 -7
- package/src/client/canvas/SessionReceipt.tsx +114 -17
- package/src/client/canvas/ShortcutOverlay.tsx +6 -1
- package/src/client/canvas/SnapshotPanel.tsx +11 -2
- package/src/client/canvas/ToolRail.tsx +12 -9
- package/src/client/canvas/TopBar.tsx +16 -11
- package/src/client/icons.tsx +2 -12
- package/src/client/mcp-app/index.tsx +137 -0
- package/src/client/mcp-app/style.css +10 -0
- package/src/client/nodes/AttachmentNode.tsx +8 -1
- package/src/client/nodes/AxStepControls.tsx +1 -1
- package/src/client/nodes/ContextNode.tsx +9 -9
- package/src/client/nodes/ExtAppFrame.tsx +13 -8
- package/src/client/nodes/FileNode.tsx +8 -5
- package/src/client/nodes/HtmlNode.tsx +12 -2
- package/src/client/nodes/ImageNode.tsx +4 -2
- package/src/client/nodes/InlineMarkdownEditor.tsx +2 -1
- package/src/client/nodes/LedgerNode.tsx +2 -2
- package/src/client/nodes/MarkdownNode.tsx +44 -9
- package/src/client/nodes/McpAppNode.tsx +6 -4
- package/src/client/nodes/PromptNode.tsx +5 -17
- package/src/client/nodes/ResponseNode.tsx +3 -15
- package/src/client/nodes/StatusNode.tsx +2 -2
- package/src/client/nodes/StatusSummary.tsx +3 -1
- package/src/client/nodes/TraceNode.tsx +6 -4
- package/src/client/nodes/WebpageNode.tsx +1 -1
- package/src/client/nodes/ax-node-actions.ts +2 -2
- package/src/client/nodes/iframe-document-url.ts +3 -2
- package/src/client/nodes/markdown-sanitize.ts +10 -0
- package/src/client/nodes/surface-url.ts +10 -0
- package/src/client/nodes/use-surface-frame.ts +3 -1
- package/src/client/nodes/use-workbench-asset.ts +26 -0
- package/src/client/state/attention-bridge.ts +0 -8
- package/src/client/state/attention-store.ts +0 -17
- package/src/client/state/canvas-store.ts +4 -2
- package/src/client/state/context-status-store.ts +66 -0
- package/src/client/state/human-store.ts +2 -0
- package/src/client/state/iframe-mode.ts +5 -0
- package/src/client/state/intent-bridge.ts +10 -4
- package/src/client/state/near-pin-store.ts +53 -0
- package/src/client/state/presence-store.ts +5 -10
- package/src/client/state/session-store.ts +106 -9
- package/src/client/state/sse-bridge.ts +26 -7
- package/src/client/state/theme-override.ts +1 -1
- package/src/client/state/workbench-transport.ts +36 -0
- package/src/client/theme/global.css +726 -674
- package/src/client/theme/surface-theme.css +151 -46
- package/src/client/theme/tokens.ts +7 -11
- package/src/client/types.ts +10 -0
- package/src/json-render/renderer/index.css +6 -1
- package/src/json-render/renderer/index.tsx +0 -1
- package/src/json-render/server.ts +71 -14
- package/src/mcp/app-server.ts +64 -0
- package/src/mcp/canvas-access.ts +14 -11
- package/src/mcp/canvas-app.ts +318 -0
- package/src/mcp/server.ts +1 -1
- package/src/mcp/workbench-app.ts +211 -0
- package/src/server/agent-presence.ts +45 -6
- package/src/server/ax-context.ts +1 -1
- package/src/server/ax-state.ts +1 -1
- package/src/server/board-export.ts +5 -2
- package/src/server/canvas-db.ts +46 -12
- package/src/server/canvas-geometry.ts +64 -0
- package/src/server/canvas-operations.ts +7 -25
- package/src/server/canvas-state.ts +105 -15
- package/src/server/canvas-validation.ts +19 -4
- package/src/server/context-brief.ts +39 -2
- package/src/server/context-reads.ts +87 -15
- package/src/server/demo-state.json +31 -31
- package/src/server/html-surface.ts +4 -5
- package/src/server/index.ts +41 -5
- package/src/server/mcp-app-runtime.ts +11 -0
- package/src/server/operations/composites.ts +4 -3
- package/src/server/operations/http.ts +4 -4
- package/src/server/operations/invoker.ts +13 -4
- package/src/server/operations/mcp.ts +6 -0
- package/src/server/operations/ops/ax-read.ts +1 -1
- package/src/server/operations/ops/ax-timeline.ts +37 -0
- package/src/server/operations/ops/boards.ts +1 -1
- package/src/server/operations/ops/canvas-wire.ts +3 -6
- package/src/server/operations/ops/intent.ts +31 -2
- package/src/server/operations/ops/json-render.ts +6 -2
- package/src/server/operations/ops/nodes.ts +8 -76
- package/src/server/operations/ops/query.ts +8 -2
- package/src/server/operations/ops/snapshots.ts +4 -1
- package/src/server/operations/ops/viewport.ts +29 -5
- package/src/server/operations/registry.ts +41 -5
- package/src/server/scope-fence.ts +55 -10
- package/src/server/server.ts +83 -5
- package/src/server/spatial-analysis.ts +2 -2
- package/src/server/workboard.ts +6 -1
- package/src/{server → shared}/agent-context.ts +2 -2
- package/src/shared/agent-presence.ts +3 -15
- package/src/shared/canvas-app.ts +62 -0
- package/src/shared/themes.ts +5 -5
- package/src/client/canvas/FocusFieldLayer.tsx +0 -116
- package/src/client/canvas/kind-colors.ts +0 -23
|
@@ -1,13 +1,25 @@
|
|
|
1
|
-
import { useState } from 'preact/hooks';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { useEffect, useState } from 'preact/hooks';
|
|
2
|
+
import { toggleContextPin } from '../state/canvas-store';
|
|
3
|
+
import {
|
|
4
|
+
activityLensNodeIds,
|
|
5
|
+
dismissSessionReceipt,
|
|
6
|
+
type ReceiptNode,
|
|
7
|
+
type SessionContextActivity,
|
|
8
|
+
sessionReceipt,
|
|
9
|
+
setActivityLens,
|
|
10
|
+
} from '../state/session-store';
|
|
11
|
+
import { IconClose, IconPin } from '../icons';
|
|
12
|
+
import { GLYPHS } from './NodeContextMark';
|
|
13
|
+
import { workbenchFetch } from '../state/workbench-transport';
|
|
4
14
|
|
|
5
15
|
/**
|
|
6
16
|
* Session receipt (rail-chrome-v2 phase 5, design item 2): a dismissible card
|
|
7
17
|
* at the canvas region's top-right after a session ends — what the session did
|
|
8
18
|
* (items / done / vetoed), the pre-session snapshot (taken at attach, so View
|
|
9
19
|
* diff shows the session's changes and a restore undoes them), and History
|
|
10
|
-
* (the snapshots panel). Client-side state, cleared on dismiss
|
|
20
|
+
* (the snapshots panel). Client-side state, cleared on dismiss (see
|
|
21
|
+
* applySessionReceipt for which endings show at all and how a burst merges
|
|
22
|
+
* into one card).
|
|
11
23
|
*/
|
|
12
24
|
|
|
13
25
|
export interface DiffSummary {
|
|
@@ -28,17 +40,96 @@ export function summarizeDiff(diff: unknown): DiffSummary | null {
|
|
|
28
40
|
};
|
|
29
41
|
}
|
|
30
42
|
|
|
43
|
+
const titles = (nodes: ReceiptNode[]) => nodes.map((node) => node.title).join(', ');
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* What the session did with context (docs/design/AgentContext.dc.html): an
|
|
47
|
+
* amber line for pins it read that changed since, one row per kind of touch,
|
|
48
|
+
* and the lens switch that dims every node the session did not touch.
|
|
49
|
+
*/
|
|
50
|
+
function ReceiptContext({ context, label }: { context: SessionContextActivity; label: string }) {
|
|
51
|
+
const rows: Array<{ key: keyof SessionContextActivity; name: string; glyph: keyof typeof GLYPHS | 'pin' }> = [
|
|
52
|
+
{ key: 'read', name: 'Read', glyph: 'eye' },
|
|
53
|
+
{ key: 'pinned', name: 'Pinned', glyph: 'pin' },
|
|
54
|
+
{ key: 'created', name: 'Created', glyph: 'spark' },
|
|
55
|
+
{ key: 'edited', name: 'Edited', glyph: 'pen' },
|
|
56
|
+
];
|
|
57
|
+
const present = rows.filter((row) => context[row.key].length > 0);
|
|
58
|
+
if (present.length === 0 && context.changedSinceRead.length === 0) return null;
|
|
59
|
+
const lensOn = activityLensNodeIds.value !== null;
|
|
60
|
+
return (
|
|
61
|
+
<div class="session-receipt-context" data-testid="session-receipt-context">
|
|
62
|
+
{context.changedSinceRead.length > 0 && (
|
|
63
|
+
<div class="session-receipt-warn">
|
|
64
|
+
<svg viewBox="0 0 24 24" aria-hidden="true">
|
|
65
|
+
<path d={GLYPHS.warn} />
|
|
66
|
+
</svg>
|
|
67
|
+
<span>
|
|
68
|
+
{titles(context.changedSinceRead)} changed after {label} read{' '}
|
|
69
|
+
{context.changedSinceRead.length === 1 ? 'it' : 'them'}.
|
|
70
|
+
</span>
|
|
71
|
+
</div>
|
|
72
|
+
)}
|
|
73
|
+
{present.map((row) => (
|
|
74
|
+
<div key={row.key} class="session-receipt-context-row" data-row={row.key}>
|
|
75
|
+
<div class="session-receipt-context-head">
|
|
76
|
+
{row.glyph === 'pin' ? (
|
|
77
|
+
<IconPin />
|
|
78
|
+
) : (
|
|
79
|
+
<svg viewBox="0 0 24 24" aria-hidden="true">
|
|
80
|
+
<path d={GLYPHS[row.glyph]} />
|
|
81
|
+
</svg>
|
|
82
|
+
)}
|
|
83
|
+
<span class="session-receipt-context-name">{row.name}</span>
|
|
84
|
+
<span class="session-receipt-context-count">{context[row.key].length}</span>
|
|
85
|
+
{row.key === 'pinned' && (
|
|
86
|
+
<button
|
|
87
|
+
type="button"
|
|
88
|
+
class="session-receipt-mini"
|
|
89
|
+
onClick={() => {
|
|
90
|
+
for (const node of context.pinned) toggleContextPin(node.id);
|
|
91
|
+
}}
|
|
92
|
+
>
|
|
93
|
+
Unpin
|
|
94
|
+
</button>
|
|
95
|
+
)}
|
|
96
|
+
</div>
|
|
97
|
+
<div class="session-receipt-context-items">
|
|
98
|
+
{row.key === 'pinned'
|
|
99
|
+
? context.pinned.map((node) => (node.reason ? `${node.title} — “${node.reason}”` : node.title)).join('; ')
|
|
100
|
+
: titles(context[row.key])}
|
|
101
|
+
</div>
|
|
102
|
+
</div>
|
|
103
|
+
))}
|
|
104
|
+
<button
|
|
105
|
+
type="button"
|
|
106
|
+
role="switch"
|
|
107
|
+
aria-checked={lensOn}
|
|
108
|
+
class={`session-receipt-lens${lensOn ? ' is-on' : ''}`}
|
|
109
|
+
onClick={() => setActivityLens(!lensOn)}
|
|
110
|
+
>
|
|
111
|
+
<span class="session-receipt-lens-track" aria-hidden="true">
|
|
112
|
+
<span class="session-receipt-lens-knob" />
|
|
113
|
+
</span>
|
|
114
|
+
Dim untouched nodes
|
|
115
|
+
</button>
|
|
116
|
+
</div>
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
|
|
31
120
|
export function SessionReceipt({ onOpenSnapshots }: { onOpenSnapshots: () => void }) {
|
|
32
121
|
const receipt = sessionReceipt.value;
|
|
33
122
|
const [diff, setDiff] = useState<DiffSummary | null>(null);
|
|
34
123
|
const [loadingDiff, setLoadingDiff] = useState(false);
|
|
124
|
+
// A new or merged receipt: the old diff no longer describes it.
|
|
125
|
+
useEffect(() => setDiff(null), [receipt]);
|
|
35
126
|
if (!receipt) return null;
|
|
36
127
|
|
|
37
128
|
const viewDiff = async () => {
|
|
38
129
|
if (!receipt.snapshot) return;
|
|
39
130
|
setLoadingDiff(true);
|
|
40
131
|
try {
|
|
41
|
-
const response = await
|
|
132
|
+
const response = await workbenchFetch(`/api/canvas/snapshots/${encodeURIComponent(receipt.snapshot.id)}/diff`, {
|
|
42
133
|
headers: { 'x-pmx-workbench': '1' },
|
|
43
134
|
});
|
|
44
135
|
if (response.ok) {
|
|
@@ -60,13 +151,15 @@ export function SessionReceipt({ onOpenSnapshots }: { onOpenSnapshots: () => voi
|
|
|
60
151
|
<div class="session-receipt-head">
|
|
61
152
|
<span class="session-receipt-dot" aria-hidden="true" />
|
|
62
153
|
<span class="session-receipt-title">
|
|
63
|
-
{receipt.
|
|
64
|
-
?
|
|
65
|
-
: receipt.endedBy === '
|
|
66
|
-
? 'Session ended
|
|
67
|
-
: receipt.endedBy === '
|
|
68
|
-
? 'Session ended
|
|
69
|
-
:
|
|
154
|
+
{receipt.sessions > 1
|
|
155
|
+
? `${receipt.sessions} sessions ended`
|
|
156
|
+
: receipt.endedBy === 'human'
|
|
157
|
+
? 'Session ended by you'
|
|
158
|
+
: receipt.endedBy === 'idle-timeout'
|
|
159
|
+
? 'Session ended — idle timeout'
|
|
160
|
+
: receipt.endedBy === 'agent'
|
|
161
|
+
? 'Session ended by the agent'
|
|
162
|
+
: 'Session ended'}
|
|
70
163
|
{endedLabel ? ` · ${endedLabel}` : ''}
|
|
71
164
|
</span>
|
|
72
165
|
<button
|
|
@@ -78,6 +171,7 @@ export function SessionReceipt({ onOpenSnapshots }: { onOpenSnapshots: () => voi
|
|
|
78
171
|
<IconClose />
|
|
79
172
|
</button>
|
|
80
173
|
</div>
|
|
174
|
+
{receipt.sessions > 1 && <div class="session-receipt-who">{receipt.labels.join(', ')}</div>}
|
|
81
175
|
<div class="session-receipt-tiles">
|
|
82
176
|
<div class="session-receipt-tile">
|
|
83
177
|
<span class="session-receipt-tile-label">Items</span>
|
|
@@ -108,12 +202,15 @@ export function SessionReceipt({ onOpenSnapshots }: { onOpenSnapshots: () => voi
|
|
|
108
202
|
</div>
|
|
109
203
|
)}
|
|
110
204
|
</div>
|
|
205
|
+
<ReceiptContext context={receipt.context} label={receipt.labels.join(', ')} />
|
|
111
206
|
<div class="session-receipt-note">
|
|
112
|
-
{receipt.
|
|
113
|
-
? '
|
|
114
|
-
: receipt.
|
|
115
|
-
? '
|
|
116
|
-
:
|
|
207
|
+
{receipt.sessions > 1
|
|
208
|
+
? 'History has each session’s diff and the snapshot from before it.'
|
|
209
|
+
: receipt.snapshot
|
|
210
|
+
? 'A snapshot of the board from before this session is saved — restore it to undo the session.'
|
|
211
|
+
: receipt.context.created.length === 0 && receipt.context.edited.length === 0
|
|
212
|
+
? 'The board itself did not change — nothing to restore.'
|
|
213
|
+
: 'The board was empty when the session started — nothing to restore.'}
|
|
117
214
|
</div>
|
|
118
215
|
{diff && (
|
|
119
216
|
<div class="session-receipt-diff" data-testid="session-receipt-diff">
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isHostedWorkbench } from '../state/workbench-transport';
|
|
1
2
|
import { isMac, modChord } from '../utils/platform';
|
|
2
3
|
|
|
3
4
|
interface ShortcutGroup {
|
|
@@ -74,7 +75,11 @@ export function ShortcutOverlay({ onClose }: { onClose: () => void }) {
|
|
|
74
75
|
{group.shortcuts.map((s) => (
|
|
75
76
|
<div key={s.keys} class="shortcut-row">
|
|
76
77
|
<kbd class="shortcut-keys">{s.keys}</kbd>
|
|
77
|
-
<span class="shortcut-desc">
|
|
78
|
+
<span class="shortcut-desc">
|
|
79
|
+
{isHostedWorkbench() && s.desc.startsWith('Undo / redo')
|
|
80
|
+
? 'Undo / redo — available in the local workbench only'
|
|
81
|
+
: s.desc}
|
|
82
|
+
</span>
|
|
78
83
|
</div>
|
|
79
84
|
))}
|
|
80
85
|
</div>
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isHostedWorkbench } from '../state/workbench-transport';
|
|
1
2
|
import { useCallback, useEffect, useRef, useState } from 'preact/hooks';
|
|
2
3
|
import { IconClose } from '../icons';
|
|
3
4
|
import {
|
|
@@ -171,7 +172,11 @@ export function SnapshotPanel({
|
|
|
171
172
|
type="button"
|
|
172
173
|
class="snapshot-action-btn snapshot-action-restore"
|
|
173
174
|
onClick={() => setConfirming({ id: snap.id, action: 'restore' })}
|
|
174
|
-
title=
|
|
175
|
+
title={
|
|
176
|
+
isHostedWorkbench()
|
|
177
|
+
? 'Restore this snapshot — replaces the current canvas'
|
|
178
|
+
: 'Restore this snapshot — replaces the current canvas (undoable)'
|
|
179
|
+
}
|
|
175
180
|
disabled={restoringId !== null}
|
|
176
181
|
>
|
|
177
182
|
{restoringId === snap.id ? 'Restoring…' : restoreLabel}
|
|
@@ -219,7 +224,11 @@ export function SnapshotPanel({
|
|
|
219
224
|
{saving ? '…' : 'Save'}
|
|
220
225
|
</button>
|
|
221
226
|
</div>
|
|
222
|
-
<div class="snapshot-restore-note">
|
|
227
|
+
<div class="snapshot-restore-note">
|
|
228
|
+
{isHostedWorkbench()
|
|
229
|
+
? 'Restoring replaces the current canvas. Save a snapshot first to keep your current state.'
|
|
230
|
+
: 'Restoring replaces the current canvas. You can undo it if needed.'}
|
|
231
|
+
</div>
|
|
223
232
|
|
|
224
233
|
<div class="snapshot-list">
|
|
225
234
|
{loading && <div class="snapshot-empty">Loading…</div>}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useEffect, useRef, useState } from 'preact/hooks';
|
|
2
|
+
import { isHostedWorkbench, workbenchFetch } from '../state/workbench-transport';
|
|
2
3
|
import {
|
|
3
4
|
IconArrange,
|
|
4
5
|
IconClearTrace,
|
|
@@ -229,7 +230,7 @@ export function ToolRail({
|
|
|
229
230
|
const activeTheme = normalizeCanvasThemeName(canvasTheme.value);
|
|
230
231
|
|
|
231
232
|
const sendIntent = (type: string, payload: Record<string, unknown> = {}) => {
|
|
232
|
-
|
|
233
|
+
workbenchFetch(`/api/workbench/intent?_ts=${Date.now()}`, {
|
|
233
234
|
method: 'POST',
|
|
234
235
|
headers: { 'Content-Type': 'application/json' },
|
|
235
236
|
body: JSON.stringify({ type, payload }),
|
|
@@ -398,14 +399,16 @@ export function ToolRail({
|
|
|
398
399
|
>
|
|
399
400
|
<IconArrange />
|
|
400
401
|
</RailButton>
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
402
|
+
{!isHostedWorkbench() && (
|
|
403
|
+
<RailButton
|
|
404
|
+
label={isTraceOn ? 'Disable trace' : 'Enable trace'}
|
|
405
|
+
active={isTraceOn}
|
|
406
|
+
onClick={() => sendIntent('trace-toggle', { enabled: !isTraceOn })}
|
|
407
|
+
>
|
|
408
|
+
<IconTrace />
|
|
409
|
+
</RailButton>
|
|
410
|
+
)}
|
|
411
|
+
{!isHostedWorkbench() && (isTraceOn || traceNodeCount > 0) && (
|
|
409
412
|
<RailButton label="Clear trace" onClick={() => sendIntent('trace-clear')}>
|
|
410
413
|
<IconClearTrace />
|
|
411
414
|
</RailButton>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { exportDialogOpen } from './ExportDialog';
|
|
2
2
|
import { activeBoardId } from '../state/boards-store';
|
|
3
3
|
import { BoardSwitcher } from './BoardSwitcher';
|
|
4
|
+
import { isHostedWorkbench, workbenchFetch } from '../state/workbench-transport';
|
|
4
5
|
import type { ComponentChildren } from 'preact';
|
|
5
6
|
import { presenting } from '../state/presentation';
|
|
6
7
|
import { useEffect, useState } from 'preact/hooks';
|
|
@@ -24,8 +25,7 @@ import { degradedState } from './ConnectionBanner';
|
|
|
24
25
|
import { ExternalWriterIndicator } from './ExternalWriters';
|
|
25
26
|
import { useNow } from './use-now';
|
|
26
27
|
import { agentPhaseLabel } from '../../shared/agent-presence.js';
|
|
27
|
-
import {
|
|
28
|
-
import { activeSession, agentPresences, attachedSessions, contextBudget } from '../state/presence-store';
|
|
28
|
+
import { activeSession, agentPresences, attachedSessions, contextBudget, writerColor } from '../state/presence-store';
|
|
29
29
|
import { endSession, pendingGates, startSession } from '../state/session-store';
|
|
30
30
|
import { formatCountdown, gateRemainingMs } from '../../shared/approval-gates.js';
|
|
31
31
|
|
|
@@ -56,6 +56,7 @@ function AgentChip() {
|
|
|
56
56
|
!allSessions.some(
|
|
57
57
|
(candidate) =>
|
|
58
58
|
candidate.sessionId !== session.sessionId &&
|
|
59
|
+
!candidate.parentAgentId &&
|
|
59
60
|
(candidate.sessionId === session.parentAgentId || candidate.source === session.parentAgentId),
|
|
60
61
|
),
|
|
61
62
|
);
|
|
@@ -83,12 +84,16 @@ function AgentChip() {
|
|
|
83
84
|
<span class="agent-chips">
|
|
84
85
|
{visible.map((session) => {
|
|
85
86
|
// Fleet roll-up: workers declaring this session as their parent count
|
|
86
|
-
// into its chip instead of growing the bar one chip per worker.
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
87
|
+
// into its chip instead of growing the bar one chip per worker. A
|
|
88
|
+
// worker's own chip carries no roll-up: same-source siblings would
|
|
89
|
+
// otherwise match it through `session.source`.
|
|
90
|
+
const workers = session.parentAgentId
|
|
91
|
+
? 0
|
|
92
|
+
: agentPresences.value.filter(
|
|
93
|
+
(presence) =>
|
|
94
|
+
presence.parentAgentId != null &&
|
|
95
|
+
(presence.parentAgentId === session.sessionId || presence.parentAgentId === session.source),
|
|
96
|
+
).length;
|
|
92
97
|
return (
|
|
93
98
|
<BarHint
|
|
94
99
|
key={session.sessionId}
|
|
@@ -99,7 +104,7 @@ function AgentChip() {
|
|
|
99
104
|
<span
|
|
100
105
|
class={`agent-chip phase-${session.phase}`}
|
|
101
106
|
data-phase={session.phase}
|
|
102
|
-
style={{ '--identity-color':
|
|
107
|
+
style={{ '--identity-color': writerColor(session.sessionId) }}
|
|
103
108
|
>
|
|
104
109
|
<span class="agent-chip-dot" aria-hidden="true" />
|
|
105
110
|
<span class="agent-chip-label">{agentPhaseLabel(session)}</span>
|
|
@@ -272,7 +277,7 @@ export function TopBar() {
|
|
|
272
277
|
const [workspaceName, setWorkspaceName] = useState<string>('');
|
|
273
278
|
useEffect(() => {
|
|
274
279
|
let cancelled = false;
|
|
275
|
-
|
|
280
|
+
workbenchFetch('/health')
|
|
276
281
|
.then((r) => (r.ok ? r.json() : null))
|
|
277
282
|
.then((data: { workspace?: string } | null) => {
|
|
278
283
|
if (cancelled || typeof data?.workspace !== 'string' || !data.workspace) return;
|
|
@@ -327,7 +332,7 @@ export function TopBar() {
|
|
|
327
332
|
<GateBadge />
|
|
328
333
|
<ContextBudget />
|
|
329
334
|
<ExternalWriterIndicator />
|
|
330
|
-
<StartSessionButton />
|
|
335
|
+
{!isHostedWorkbench() && <StartSessionButton />}
|
|
331
336
|
|
|
332
337
|
<div class="top-bar-sep" />
|
|
333
338
|
|
package/src/client/icons.tsx
CHANGED
|
@@ -112,14 +112,6 @@ export function IconUndo(p: IconProps): JSX.Element {
|
|
|
112
112
|
);
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
-
export function IconSparkle(p: IconProps): JSX.Element {
|
|
116
|
-
return (
|
|
117
|
-
<Icon {...p}>
|
|
118
|
-
<path d="m8 1 2 5 5 2-5 2-2 5-2-5-5-2 5-2Z" />
|
|
119
|
-
</Icon>
|
|
120
|
-
);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
115
|
/** Upload into a tray — attach a document. */
|
|
124
116
|
export function IconUpload(p: IconProps): JSX.Element {
|
|
125
117
|
return (
|
|
@@ -326,13 +318,11 @@ export function IconSteer(p: IconProps): JSX.Element {
|
|
|
326
318
|
);
|
|
327
319
|
}
|
|
328
320
|
|
|
329
|
-
/**
|
|
321
|
+
/** Push pin — context pinning (docs/design/Chrome.dc.html). */
|
|
330
322
|
export function IconPin(p: IconProps): JSX.Element {
|
|
331
323
|
return (
|
|
332
324
|
<Icon {...p}>
|
|
333
|
-
<
|
|
334
|
-
<line x1="11" y1="1.5" x2="11" y2="5" />
|
|
335
|
-
<circle cx="11" cy="4.5" r="1.6" fill="currentColor" stroke="none" />
|
|
325
|
+
<path d="M6 2.67h4l-.53 3.66 1.86 2H4.67l1.86-2zM8 8.33v5" />
|
|
336
326
|
</Icon>
|
|
337
327
|
);
|
|
338
328
|
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import '../uuid-polyfill';
|
|
2
|
+
import { App as McpApp } from '@modelcontextprotocol/ext-apps';
|
|
3
|
+
import { render } from 'preact';
|
|
4
|
+
import { useEffect, useRef, useState } from 'preact/hooks';
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import { App as Workbench } from '../App';
|
|
7
|
+
import { activeBoardId, boardList, boardsLoaded } from '../state/boards-store';
|
|
8
|
+
import { axSurfaceState, contextPinnedNodeIds, nodes, selectedNodeIds } from '../state/canvas-store';
|
|
9
|
+
import { installWorkbenchDownload, installWorkbenchTransport } from '../state/workbench-transport';
|
|
10
|
+
import { resolveIframeMode } from '../state/iframe-mode';
|
|
11
|
+
import { summarizeNodeForAgentContext } from '../../shared/agent-context';
|
|
12
|
+
import { canvasAppContext } from '../../shared/canvas-app';
|
|
13
|
+
|
|
14
|
+
const bridge = new McpApp(
|
|
15
|
+
{ name: 'PMX Canvas', version: '1.0.0' },
|
|
16
|
+
{ availableDisplayModes: ['inline', 'fullscreen'] },
|
|
17
|
+
);
|
|
18
|
+
const responseSchema = z.object({
|
|
19
|
+
status: z.number(),
|
|
20
|
+
body: z.string(),
|
|
21
|
+
contentType: z.string(),
|
|
22
|
+
encoding: z.enum(['text', 'base64']),
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
// Preserve the workbench's fetch/Response contracts, without passing its human
|
|
26
|
+
// headers or exposing the daemon URL to the embedded browser.
|
|
27
|
+
installWorkbenchTransport(async (input, init) => {
|
|
28
|
+
const path = typeof input === 'string' ? input : input instanceof URL ? input.toString() : input.url;
|
|
29
|
+
const method = (init?.method ?? (input instanceof Request ? input.method : 'GET')).toUpperCase();
|
|
30
|
+
if (init?.body !== undefined && typeof init.body !== 'string')
|
|
31
|
+
return Response.json({ ok: false, error: 'Document uploads require the local PMX workbench.' }, { status: 403 });
|
|
32
|
+
init?.signal?.throwIfAborted();
|
|
33
|
+
const result = await bridge.callServerTool({
|
|
34
|
+
name: 'pmx_workbench_request',
|
|
35
|
+
arguments: {
|
|
36
|
+
path,
|
|
37
|
+
method,
|
|
38
|
+
...(init?.body === undefined ? {} : { body: init.body }),
|
|
39
|
+
expectedBoardId: activeBoardId.value,
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
init?.signal?.throwIfAborted();
|
|
43
|
+
const response = responseSchema.parse(result._meta?.response);
|
|
44
|
+
const body =
|
|
45
|
+
response.encoding === 'base64' ? Uint8Array.from(atob(response.body), (char) => char.charCodeAt(0)) : response.body;
|
|
46
|
+
return new Response(method === 'HEAD' || response.status === 204 ? null : body, {
|
|
47
|
+
status: response.status,
|
|
48
|
+
headers: { 'Content-Type': response.contentType },
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const focusSchema = z.object({ focus: z.array(z.string()) });
|
|
53
|
+
|
|
54
|
+
function selectionContext() {
|
|
55
|
+
const focus = focusSchema.safeParse(axSurfaceState.value);
|
|
56
|
+
return canvasAppContext(
|
|
57
|
+
{
|
|
58
|
+
boardId: activeBoardId.value,
|
|
59
|
+
boardName: boardList.value.find((board) => board.id === activeBoardId.value)?.name ?? 'Home',
|
|
60
|
+
pinnedNodeIds: [...contextPinnedNodeIds.value],
|
|
61
|
+
nodes: [...nodes.value.values()].map((node) => ({
|
|
62
|
+
id: node.id,
|
|
63
|
+
type: node.type,
|
|
64
|
+
title: typeof node.data.title === 'string' ? node.data.title : node.type,
|
|
65
|
+
contentRevision: node.contentRevision ?? 0,
|
|
66
|
+
text: summarizeNodeForAgentContext(node),
|
|
67
|
+
})),
|
|
68
|
+
},
|
|
69
|
+
[...selectedNodeIds.value],
|
|
70
|
+
focus.success ? focus.data.focus : [],
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function HostedWorkbench() {
|
|
75
|
+
const [acknowledged, setAcknowledged] = useState('');
|
|
76
|
+
const [retry, setRetry] = useState(0);
|
|
77
|
+
const queue = useRef(Promise.resolve());
|
|
78
|
+
const context = selectionContext();
|
|
79
|
+
const key = JSON.stringify(context);
|
|
80
|
+
const desired = useRef(key);
|
|
81
|
+
desired.current = key;
|
|
82
|
+
const caps = bridge.getHostCapabilities();
|
|
83
|
+
const ready = boardsLoaded.value;
|
|
84
|
+
useEffect(() => {
|
|
85
|
+
if (!ready || !caps?.updateModelContext || acknowledged === key) return;
|
|
86
|
+
let cancelled = false;
|
|
87
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
88
|
+
queue.current = queue.current
|
|
89
|
+
.then(async () => {
|
|
90
|
+
if (cancelled || desired.current !== key) return;
|
|
91
|
+
setAcknowledged('');
|
|
92
|
+
await bridge.updateModelContext({ structuredContent: context });
|
|
93
|
+
if (cancelled || desired.current !== key) return;
|
|
94
|
+
setAcknowledged(key);
|
|
95
|
+
})
|
|
96
|
+
.catch(() => {
|
|
97
|
+
// Context is background synchronization, not extra workbench chrome.
|
|
98
|
+
// Retry unchanged context too, and only consider a host ACK successful.
|
|
99
|
+
if (!cancelled && desired.current === key) timer = setTimeout(() => setRetry((value) => value + 1), 2000);
|
|
100
|
+
});
|
|
101
|
+
return () => {
|
|
102
|
+
cancelled = true;
|
|
103
|
+
clearTimeout(timer);
|
|
104
|
+
};
|
|
105
|
+
}, [key, ready, retry]);
|
|
106
|
+
return (
|
|
107
|
+
<div class="pmx-host-app">
|
|
108
|
+
<Workbench />
|
|
109
|
+
</div>
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Polling is the sole state owner. Launcher tool results never rehydrate the
|
|
114
|
+
// workbench, so delayed initial notifications cannot roll back its live state.
|
|
115
|
+
bridge.ontoolresult = () => {};
|
|
116
|
+
void bridge
|
|
117
|
+
.connect()
|
|
118
|
+
.then(async () => {
|
|
119
|
+
if (!bridge.getHostCapabilities()?.serverTools) throw new Error('This host does not support app tool calls.');
|
|
120
|
+
if (bridge.getHostCapabilities()?.downloadFile) {
|
|
121
|
+
installWorkbenchDownload((file) =>
|
|
122
|
+
bridge.downloadFile({
|
|
123
|
+
contents: [
|
|
124
|
+
{
|
|
125
|
+
type: 'resource',
|
|
126
|
+
resource: { uri: `file:///${encodeURIComponent(file.name)}`, mimeType: file.mimeType, text: file.text },
|
|
127
|
+
},
|
|
128
|
+
],
|
|
129
|
+
}),
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
await resolveIframeMode();
|
|
133
|
+
render(<HostedWorkbench />, document.getElementById('app')!);
|
|
134
|
+
})
|
|
135
|
+
.catch((error: unknown) => {
|
|
136
|
+
document.getElementById('app')!.textContent = `Could not connect PMX: ${String(error)}`;
|
|
137
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
.pmx-host-app { height: 100%; display: flex; flex-direction: column; }
|
|
2
|
+
.pmx-host-app > .app-shell { flex: 1; min-height: 0; height: auto; }
|
|
3
|
+
/* Keep context controls clear of the host's floating chat composer. */
|
|
4
|
+
.pmx-host-app .context-pin-bar {
|
|
5
|
+
bottom: 16px;
|
|
6
|
+
left: 16px;
|
|
7
|
+
transform: none;
|
|
8
|
+
}
|
|
9
|
+
/* Guard refusals must remain readable while the full source editor is open. */
|
|
10
|
+
.pmx-host-app .attention-toast.attention-tone-remove { z-index: 100100; }
|
|
@@ -4,10 +4,12 @@ import type { CanvasNodeState } from '../types';
|
|
|
4
4
|
import { activeBoardId } from '../state/boards-store';
|
|
5
5
|
import { requestJson } from '../state/intent-bridge';
|
|
6
6
|
import { expandNode, collapseExpandedNode } from '../state/canvas-store';
|
|
7
|
+
import { useWorkbenchAsset } from './use-workbench-asset';
|
|
7
8
|
|
|
8
9
|
/** Originals stay useful even when the connected host cannot extract them. */
|
|
9
10
|
export function AttachmentNode({ node, expanded = false }: { node: CanvasNodeState; expanded?: boolean }) {
|
|
10
11
|
const attachmentId = String(node.data.attachmentId);
|
|
12
|
+
const downloadUrl = useWorkbenchAsset(`/api/canvas/attachments/${encodeURIComponent(attachmentId)}/bytes`);
|
|
11
13
|
const boardId = activeBoardId.value;
|
|
12
14
|
const [job, setJob] = useState<DocumentImport | null>(null);
|
|
13
15
|
const [review, setReview] = useState(expanded);
|
|
@@ -68,7 +70,12 @@ export function AttachmentNode({ node, expanded = false }: { node: CanvasNodeSta
|
|
|
68
70
|
? 'Markdown added'
|
|
69
71
|
: 'Original attached'}
|
|
70
72
|
</div>
|
|
71
|
-
<a
|
|
73
|
+
<a
|
|
74
|
+
href={downloadUrl}
|
|
75
|
+
download={String(node.data.title ?? 'attachment')}
|
|
76
|
+
target="_blank"
|
|
77
|
+
rel="noopener noreferrer"
|
|
78
|
+
>
|
|
72
79
|
Download original · {Math.ceil(Number(node.data.size ?? 0) / 1024)} KB
|
|
73
80
|
</a>
|
|
74
81
|
{job?.reason && <p>{job.reason}</p>}
|
|
@@ -298,8 +298,8 @@ export function ContextNode({
|
|
|
298
298
|
style={{
|
|
299
299
|
padding: '4px 8px',
|
|
300
300
|
fontSize: '10px',
|
|
301
|
-
background: 'var(--c-accent
|
|
302
|
-
border: '1px solid var(--c-accent
|
|
301
|
+
background: 'color-mix(in srgb, var(--c-accent) 12%, transparent)',
|
|
302
|
+
border: '1px solid color-mix(in srgb, var(--c-accent) 25%, transparent)',
|
|
303
303
|
borderRadius: '4px',
|
|
304
304
|
color: 'var(--c-text-soft)',
|
|
305
305
|
cursor: 'pointer',
|
|
@@ -363,7 +363,7 @@ export function ContextNode({
|
|
|
363
363
|
style={{
|
|
364
364
|
fontSize: '9px',
|
|
365
365
|
padding: '1px 4px',
|
|
366
|
-
background: 'var(--c-accent
|
|
366
|
+
background: 'color-mix(in srgb, var(--c-accent) 10%, transparent)',
|
|
367
367
|
color: 'var(--c-accent)',
|
|
368
368
|
borderRadius: '3px',
|
|
369
369
|
display: 'inline-block',
|
|
@@ -402,8 +402,8 @@ export function ContextNode({
|
|
|
402
402
|
style={{
|
|
403
403
|
fontSize: '9px',
|
|
404
404
|
padding: '1px 4px',
|
|
405
|
-
background: 'var(--c-
|
|
406
|
-
color: 'var(--c-
|
|
405
|
+
background: 'color-mix(in srgb, var(--c-accent) 12%, transparent)',
|
|
406
|
+
color: 'var(--c-accent)',
|
|
407
407
|
borderRadius: '3px',
|
|
408
408
|
display: 'inline-block',
|
|
409
409
|
}}
|
|
@@ -420,8 +420,8 @@ export function ContextNode({
|
|
|
420
420
|
style={{
|
|
421
421
|
padding: '4px 8px',
|
|
422
422
|
fontSize: '10px',
|
|
423
|
-
background: 'var(--c-accent
|
|
424
|
-
border: '1px solid var(--c-accent
|
|
423
|
+
background: 'color-mix(in srgb, var(--c-accent) 12%, transparent)',
|
|
424
|
+
border: '1px solid color-mix(in srgb, var(--c-accent) 25%, transparent)',
|
|
425
425
|
borderRadius: '4px',
|
|
426
426
|
color: 'var(--c-text-soft)',
|
|
427
427
|
cursor: 'pointer',
|
|
@@ -518,8 +518,8 @@ export function ContextNode({
|
|
|
518
518
|
style={{
|
|
519
519
|
padding: '4px 8px',
|
|
520
520
|
fontSize: '10px',
|
|
521
|
-
background: 'var(--c-accent
|
|
522
|
-
border: '1px solid var(--c-accent
|
|
521
|
+
background: 'color-mix(in srgb, var(--c-accent) 12%, transparent)',
|
|
522
|
+
border: '1px solid color-mix(in srgb, var(--c-accent) 25%, transparent)',
|
|
523
523
|
borderRadius: '4px',
|
|
524
524
|
color: 'var(--c-text-soft)',
|
|
525
525
|
cursor: 'pointer',
|