@principal-ai/subsystems-react 0.55.3 → 0.56.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/dist/index.d.ts +12 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/pierre/PierreFileView.js +3 -3
- package/dist/pierre/PierreFileView.js.map +1 -1
- package/dist/pierre/PierreTrailCodeView.d.ts +1 -6
- package/dist/pierre/PierreTrailCodeView.d.ts.map +1 -1
- package/dist/pierre/PierreTrailCodeView.js +21 -18
- package/dist/pierre/PierreTrailCodeView.js.map +1 -1
- package/dist/pierre/fileAvailability.d.ts +4 -7
- package/dist/pierre/fileAvailability.d.ts.map +1 -1
- package/dist/pierre/fileAvailability.js +5 -10
- package/dist/pierre/fileAvailability.js.map +1 -1
- package/dist/subsystem/C4Graph.d.ts.map +1 -1
- package/dist/subsystem/C4Graph.js +1 -1
- package/dist/subsystem/C4Graph.js.map +1 -1
- package/dist/subsystem/DecorationPanel.d.ts +37 -0
- package/dist/subsystem/DecorationPanel.d.ts.map +1 -0
- package/dist/subsystem/DecorationPanel.js +147 -0
- package/dist/subsystem/DecorationPanel.js.map +1 -0
- package/dist/subsystem/FileDrawer.d.ts +3 -1
- package/dist/subsystem/FileDrawer.d.ts.map +1 -1
- package/dist/subsystem/FileDrawer.js +2 -2
- package/dist/subsystem/FileDrawer.js.map +1 -1
- package/dist/subsystem/IssueList.d.ts.map +1 -1
- package/dist/subsystem/IssueList.js +26 -0
- package/dist/subsystem/IssueList.js.map +1 -1
- package/dist/subsystem/SubsystemComponentGraph.d.ts +9 -5
- package/dist/subsystem/SubsystemComponentGraph.d.ts.map +1 -1
- package/dist/subsystem/SubsystemComponentGraph.js +37 -47
- package/dist/subsystem/SubsystemComponentGraph.js.map +1 -1
- package/dist/subsystem/TrailStackBreadcrumb.d.ts +21 -0
- package/dist/subsystem/TrailStackBreadcrumb.d.ts.map +1 -0
- package/dist/subsystem/TrailStackBreadcrumb.js +77 -0
- package/dist/subsystem/TrailStackBreadcrumb.js.map +1 -0
- package/dist/subsystem/TrailStepsNav.d.ts +4 -3
- package/dist/subsystem/TrailStepsNav.d.ts.map +1 -1
- package/dist/subsystem/TrailStepsNav.js +13 -16
- package/dist/subsystem/TrailStepsNav.js.map +1 -1
- package/dist/subsystem/TrailsPanel.d.ts +9 -7
- package/dist/subsystem/TrailsPanel.d.ts.map +1 -1
- package/dist/subsystem/TrailsPanel.js +126 -76
- package/dist/subsystem/TrailsPanel.js.map +1 -1
- package/dist/subsystem/decoration.d.ts +112 -0
- package/dist/subsystem/decoration.d.ts.map +1 -0
- package/dist/subsystem/decoration.js +54 -0
- package/dist/subsystem/decoration.js.map +1 -0
- package/dist/subsystem/model.d.ts +5 -18
- package/dist/subsystem/model.d.ts.map +1 -1
- package/dist/subsystem/model.js +3 -11
- package/dist/subsystem/model.js.map +1 -1
- package/dist/subsystem/nodes.d.ts.map +1 -1
- package/dist/subsystem/nodes.js +17 -24
- package/dist/subsystem/nodes.js.map +1 -1
- package/dist/subsystem/stepEmphasis.d.ts +78 -0
- package/dist/subsystem/stepEmphasis.d.ts.map +1 -0
- package/dist/subsystem/stepEmphasis.js +89 -0
- package/dist/subsystem/stepEmphasis.js.map +1 -0
- package/dist/subsystem/trailBrief.d.ts.map +1 -1
- package/dist/subsystem/trailBrief.js +20 -0
- package/dist/subsystem/trailBrief.js.map +1 -1
- package/dist/subsystem/trailStack.d.ts +53 -0
- package/dist/subsystem/trailStack.d.ts.map +1 -0
- package/dist/subsystem/trailStack.js +154 -0
- package/dist/subsystem/trailStack.js.map +1 -0
- package/dist/subsystem/trailStepDisplay.d.ts +38 -0
- package/dist/subsystem/trailStepDisplay.d.ts.map +1 -0
- package/dist/subsystem/trailStepDisplay.js +41 -0
- package/dist/subsystem/trailStepDisplay.js.map +1 -0
- package/package.json +3 -3
- package/src/index.ts +47 -1
- package/src/pierre/PierreFileView.tsx +3 -3
- package/src/pierre/PierreTrailCodeView.tsx +25 -28
- package/src/pierre/fileAvailability.test.ts +0 -6
- package/src/pierre/fileAvailability.ts +5 -13
- package/src/stories/Canvases/Subsystem/Deprecated.stories.tsx +3 -17
- package/src/stories/Canvases/Subsystem/NodeAnatomy.stories.tsx +3 -31
- package/src/stories/Canvases/Subsystem/StepEmphasis.stories.tsx +528 -0
- package/src/stories/Canvases/Subsystem/Trails.stories.tsx +0 -187
- package/src/stories/Components/DecorationPanel.stories.tsx +160 -0
- package/src/subsystem/C4Graph.tsx +0 -1
- package/src/subsystem/DecorationPanel.test.tsx +128 -0
- package/src/subsystem/DecorationPanel.tsx +334 -0
- package/src/subsystem/FileDrawer.tsx +6 -0
- package/src/subsystem/IssueList.tsx +26 -0
- package/src/subsystem/SubsystemComponentGraph.tsx +68 -65
- package/src/subsystem/TrailStackBreadcrumb.test.tsx +109 -0
- package/src/subsystem/TrailStackBreadcrumb.tsx +172 -0
- package/src/subsystem/TrailStepsNav.test.tsx +35 -0
- package/src/subsystem/TrailStepsNav.tsx +18 -19
- package/src/subsystem/TrailsPanel.test.tsx +149 -0
- package/src/subsystem/TrailsPanel.tsx +165 -39
- package/src/subsystem/decoration.test.ts +72 -0
- package/src/subsystem/decoration.ts +151 -0
- package/src/subsystem/model.test.ts +7 -22
- package/src/subsystem/model.ts +6 -20
- package/src/subsystem/nodes.tsx +19 -28
- package/src/subsystem/stepEmphasis.test.ts +110 -0
- package/src/subsystem/stepEmphasis.ts +151 -0
- package/src/subsystem/trailBrief.test.ts +29 -0
- package/src/subsystem/trailBrief.ts +20 -0
- package/src/subsystem/trailStack.test.ts +133 -0
- package/src/subsystem/trailStack.ts +229 -0
- package/src/subsystem/trailStepDisplay.ts +68 -0
- package/src/stories/Canvases/Subsystem/Proposed.stories.tsx +0 -256
- package/src/stories/Canvases/Subsystem/ProposedTrails.stories.tsx +0 -184
|
@@ -0,0 +1,528 @@
|
|
|
1
|
+
import React, { useCallback, useMemo, useState } from 'react';
|
|
2
|
+
import '@xyflow/react/dist/style.css';
|
|
3
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
4
|
+
import { ThemeProvider, defaultEditorTheme } from '@principal-ade/industry-theme';
|
|
5
|
+
import { Star } from 'lucide-react';
|
|
6
|
+
import { SubsystemComponentGraph } from '../../../subsystem/SubsystemComponentGraph';
|
|
7
|
+
import type { SubsystemComponent, SubsystemTrail } from '../../../subsystem/model';
|
|
8
|
+
import {
|
|
9
|
+
buildStepEmphasisMap,
|
|
10
|
+
orphanedEmphasis,
|
|
11
|
+
stepClaimKey,
|
|
12
|
+
type StepEmphasisDocument,
|
|
13
|
+
type StepEmphasisRecord,
|
|
14
|
+
} from '../../../subsystem/stepEmphasis';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* PROTOTYPE: step emphasis as a separate augmentation document.
|
|
18
|
+
*
|
|
19
|
+
* The point of the story is to make the *data model* concrete before the store
|
|
20
|
+
* lands. The marks below live in story state, keyed by trail + claim
|
|
21
|
+
* fingerprint — not on the portable `SubsystemTrail`. Reorder the steps or edit
|
|
22
|
+
* a claim and watch what the keys do.
|
|
23
|
+
*/
|
|
24
|
+
const meta = {
|
|
25
|
+
title: 'Canvases/Subsystem/Step emphasis',
|
|
26
|
+
component: SubsystemComponentGraph,
|
|
27
|
+
parameters: {
|
|
28
|
+
layout: 'fullscreen',
|
|
29
|
+
docs: {
|
|
30
|
+
description: {
|
|
31
|
+
component:
|
|
32
|
+
'Prototype for the focus-guidance augmentation: star a walkthrough step with a kind + optional note, stored separately from the model document.',
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
decorators: [
|
|
37
|
+
(Story) => (
|
|
38
|
+
<ThemeProvider theme={defaultEditorTheme}>
|
|
39
|
+
<Story />
|
|
40
|
+
</ThemeProvider>
|
|
41
|
+
),
|
|
42
|
+
],
|
|
43
|
+
} satisfies Meta<typeof SubsystemComponentGraph>;
|
|
44
|
+
|
|
45
|
+
export default meta;
|
|
46
|
+
type Story = StoryObj<typeof meta>;
|
|
47
|
+
|
|
48
|
+
const STORY_PURL = 'pkg:github/principal-ai/desktop-app';
|
|
49
|
+
const stepPurl = (file: string) => `${STORY_PURL}#${file}`;
|
|
50
|
+
|
|
51
|
+
const components: SubsystemComponent[] = [
|
|
52
|
+
{
|
|
53
|
+
alias: 'panel',
|
|
54
|
+
name: 'DrawingsLeftPanel',
|
|
55
|
+
construct: 'class',
|
|
56
|
+
file: 'src/panels/DrawingsLeftPanel.tsx',
|
|
57
|
+
purl: STORY_PURL,
|
|
58
|
+
purpose: 'lists drawings; emits open/delete intents',
|
|
59
|
+
symbol: 'DrawingsLeftPanel',
|
|
60
|
+
process: 'draw-list',
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
alias: 'host',
|
|
64
|
+
name: 'useDrawingsHost',
|
|
65
|
+
construct: 'function',
|
|
66
|
+
file: 'src/hooks/useDrawingsHost.ts',
|
|
67
|
+
purl: STORY_PURL,
|
|
68
|
+
purpose: 'hosts drawing CRUD; dispatches to storage and shell',
|
|
69
|
+
symbol: 'useDrawingsHost',
|
|
70
|
+
process: 'draw-host',
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
alias: 'storage',
|
|
74
|
+
name: 'DrawingsStorage',
|
|
75
|
+
construct: 'class',
|
|
76
|
+
file: 'src/storage/drawingsStorage.ts',
|
|
77
|
+
purl: STORY_PURL,
|
|
78
|
+
purpose: 'persists drawings as files',
|
|
79
|
+
symbol: 'DrawingsStorage',
|
|
80
|
+
process: 'draw-host',
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
alias: 'fs',
|
|
84
|
+
name: 'FileSystemService',
|
|
85
|
+
construct: 'external',
|
|
86
|
+
file: 'src/services/fileSystem.ts',
|
|
87
|
+
purl: STORY_PURL,
|
|
88
|
+
purpose: 'sandboxed host fd/fs access',
|
|
89
|
+
symbol: 'FileSystemService',
|
|
90
|
+
role: 'service',
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
alias: 'shell',
|
|
94
|
+
name: 'WorkspaceShell',
|
|
95
|
+
construct: 'class',
|
|
96
|
+
file: 'src/workspace/WorkspaceShell.tsx',
|
|
97
|
+
purl: STORY_PURL,
|
|
98
|
+
purpose: 'mounts tabs for opened drawings',
|
|
99
|
+
symbol: 'WorkspaceShell',
|
|
100
|
+
process: 'draw-host',
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
alias: 'tab',
|
|
104
|
+
name: 'DrawingTabContent',
|
|
105
|
+
construct: 'class',
|
|
106
|
+
file: 'src/components/DrawingTabContent.tsx',
|
|
107
|
+
purl: STORY_PURL,
|
|
108
|
+
purpose: 'loads/saves an open drawing',
|
|
109
|
+
symbol: 'DrawingTabContent',
|
|
110
|
+
process: 'draw-host',
|
|
111
|
+
},
|
|
112
|
+
];
|
|
113
|
+
|
|
114
|
+
const seedTrails: SubsystemTrail[] = [
|
|
115
|
+
{
|
|
116
|
+
id: 'tl-open-drawing',
|
|
117
|
+
title: 'Open drawing',
|
|
118
|
+
steps: [
|
|
119
|
+
{
|
|
120
|
+
from: 'panel',
|
|
121
|
+
to: 'storage',
|
|
122
|
+
mechanism: 'calls',
|
|
123
|
+
file: 'src/panels/DrawingsLeftPanel.tsx',
|
|
124
|
+
span: { startLine: 56, endLine: 56, contentHash: 'fixture' },
|
|
125
|
+
purl: stepPurl('src/panels/DrawingsLeftPanel.tsx'),
|
|
126
|
+
symbol: 'DrawingsLeftPanel.scan',
|
|
127
|
+
annotation: 'Lists the drawings directory; each row feeds an open intent.',
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
from: 'panel',
|
|
131
|
+
to: 'host',
|
|
132
|
+
mechanism: 'produces',
|
|
133
|
+
file: 'src/panels/DrawingsLeftPanel.tsx',
|
|
134
|
+
span: { startLine: 85, endLine: 85, contentHash: 'fixture' },
|
|
135
|
+
purl: stepPurl('src/panels/DrawingsLeftPanel.tsx'),
|
|
136
|
+
symbol: 'DrawingsLeftPanel.openDrawing',
|
|
137
|
+
annotation: 'Emits the open intent up to the host.',
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
from: 'host',
|
|
141
|
+
to: 'storage',
|
|
142
|
+
mechanism: 'calls',
|
|
143
|
+
file: 'src/hooks/useDrawingsHost.ts',
|
|
144
|
+
span: { startLine: 45, endLine: 45, contentHash: 'fixture' },
|
|
145
|
+
purl: stepPurl('src/hooks/useDrawingsHost.ts'),
|
|
146
|
+
symbol: 'useDrawingsHost.openDrawing',
|
|
147
|
+
annotation: 'Host resolves the path and delegates to storage.',
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
from: 'host',
|
|
151
|
+
to: 'shell',
|
|
152
|
+
mechanism: 'produces',
|
|
153
|
+
file: 'src/workspace/WorkspaceShell.tsx',
|
|
154
|
+
span: { startLine: 369, endLine: 369, contentHash: 'fixture' },
|
|
155
|
+
purl: stepPurl('src/workspace/WorkspaceShell.tsx'),
|
|
156
|
+
symbol: 'WorkspaceShell.openTab',
|
|
157
|
+
annotation: 'Asks the shell to surface the drawing as a tab.',
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
from: 'shell',
|
|
161
|
+
to: 'tab',
|
|
162
|
+
mechanism: 'feeds',
|
|
163
|
+
file: 'src/workspace/WorkspaceShell.tsx',
|
|
164
|
+
span: { startLine: 372, endLine: 372, contentHash: 'fixture' },
|
|
165
|
+
purl: stepPurl('src/workspace/WorkspaceShell.tsx'),
|
|
166
|
+
symbol: 'WorkspaceShell.mountTab',
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
from: 'storage',
|
|
170
|
+
to: 'fs',
|
|
171
|
+
mechanism: 'calls',
|
|
172
|
+
file: 'src/storage/drawingsStorage.ts',
|
|
173
|
+
span: { startLine: 90, endLine: 90, contentHash: 'fixture' },
|
|
174
|
+
purl: stepPurl('src/storage/drawingsStorage.ts'),
|
|
175
|
+
symbol: 'DrawingsStorage.read',
|
|
176
|
+
annotation: 'Reads the file through the sandboxed fs service.',
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
from: 'tab',
|
|
180
|
+
to: 'fs',
|
|
181
|
+
mechanism: 'calls',
|
|
182
|
+
file: 'src/components/DrawingTabContent.tsx',
|
|
183
|
+
span: { startLine: 83, endLine: 83, contentHash: 'fixture' },
|
|
184
|
+
purl: stepPurl('src/components/DrawingTabContent.tsx'),
|
|
185
|
+
symbol: 'DrawingTabContent.load',
|
|
186
|
+
},
|
|
187
|
+
],
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
id: 'tl-save-drawing',
|
|
191
|
+
title: 'Save drawing',
|
|
192
|
+
steps: [
|
|
193
|
+
{
|
|
194
|
+
from: 'tab',
|
|
195
|
+
to: 'fs',
|
|
196
|
+
mechanism: 'calls',
|
|
197
|
+
file: 'src/components/DrawingTabContent.tsx',
|
|
198
|
+
span: { startLine: 112, endLine: 112, contentHash: 'fixture' },
|
|
199
|
+
purl: stepPurl('src/components/DrawingTabContent.tsx'),
|
|
200
|
+
symbol: 'DrawingTabContent.save',
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
from: 'tab',
|
|
204
|
+
to: 'host',
|
|
205
|
+
mechanism: 'produces',
|
|
206
|
+
file: 'src/components/DrawingTabContent.tsx',
|
|
207
|
+
span: { startLine: 121, endLine: 121, contentHash: 'fixture' },
|
|
208
|
+
purl: stepPurl('src/components/DrawingTabContent.tsx'),
|
|
209
|
+
symbol: 'DrawingTabContent.emitSaved',
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
from: 'host',
|
|
213
|
+
to: 'panel',
|
|
214
|
+
mechanism: 'produces',
|
|
215
|
+
file: 'src/hooks/useDrawingsHost.ts',
|
|
216
|
+
span: { startLine: 64, endLine: 64, contentHash: 'fixture' },
|
|
217
|
+
purl: stepPurl('src/hooks/useDrawingsHost.ts'),
|
|
218
|
+
symbol: 'useDrawingsHost.onSaved',
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
from: 'panel',
|
|
222
|
+
to: 'storage',
|
|
223
|
+
mechanism: 'calls',
|
|
224
|
+
file: 'src/panels/DrawingsLeftPanel.tsx',
|
|
225
|
+
span: { startLine: 56, endLine: 56, contentHash: 'fixture' },
|
|
226
|
+
purl: stepPurl('src/panels/DrawingsLeftPanel.tsx'),
|
|
227
|
+
symbol: 'DrawingsLeftPanel.scan',
|
|
228
|
+
},
|
|
229
|
+
],
|
|
230
|
+
},
|
|
231
|
+
];
|
|
232
|
+
|
|
233
|
+
const SEEDED_AT = '2026-10-19T12:00:00.000Z';
|
|
234
|
+
|
|
235
|
+
function seedEmphasis(trails: SubsystemTrail[]): StepEmphasisRecord[] {
|
|
236
|
+
const trail = trails[0]!;
|
|
237
|
+
const at = (stepIndex: number, guidance: string): StepEmphasisRecord => ({
|
|
238
|
+
trailId: trail.id,
|
|
239
|
+
stepKey: stepClaimKey(trail.steps[stepIndex]!),
|
|
240
|
+
guidance,
|
|
241
|
+
provenance: { source: 'author', at: SEEDED_AT, author: 'you' },
|
|
242
|
+
});
|
|
243
|
+
return [
|
|
244
|
+
at(
|
|
245
|
+
0,
|
|
246
|
+
'The **scan** is where a drawing row becomes an open intent. Everything below depends on this hand-off.',
|
|
247
|
+
),
|
|
248
|
+
at(
|
|
249
|
+
3,
|
|
250
|
+
'The shell is the **hinge**: the tab only exists after this call, so this is where the flow becomes visible.',
|
|
251
|
+
),
|
|
252
|
+
at(
|
|
253
|
+
5,
|
|
254
|
+
'**Risky seam.** First filesystem touch — a sandbox denial lands here rather than in storage.',
|
|
255
|
+
),
|
|
256
|
+
];
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const muted = '#9aa4b2';
|
|
260
|
+
const border = '#2a2f3a';
|
|
261
|
+
const panelBg = '#0f1115';
|
|
262
|
+
|
|
263
|
+
function InspectorRow({
|
|
264
|
+
label,
|
|
265
|
+
value,
|
|
266
|
+
color,
|
|
267
|
+
}: {
|
|
268
|
+
label: string;
|
|
269
|
+
value: string;
|
|
270
|
+
color?: string;
|
|
271
|
+
}) {
|
|
272
|
+
return (
|
|
273
|
+
<div style={{ display: 'flex', gap: 8, fontSize: 11, lineHeight: 1.5 }}>
|
|
274
|
+
<span style={{ color: muted, minWidth: 74 }}>{label}</span>
|
|
275
|
+
<span style={{ color: color ?? '#e6edf3', overflowWrap: 'anywhere' }}>{value}</span>
|
|
276
|
+
</div>
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
function Prototype() {
|
|
281
|
+
const [trails, setTrails] = useState<SubsystemTrail[]>(seedTrails);
|
|
282
|
+
const [records, setRecords] = useState<StepEmphasisRecord[]>(() =>
|
|
283
|
+
seedEmphasis(seedTrails),
|
|
284
|
+
);
|
|
285
|
+
const emphasis = useMemo(() => buildStepEmphasisMap(records), [records]);
|
|
286
|
+
const orphans = useMemo(() => orphanedEmphasis(records, trails), [records, trails]);
|
|
287
|
+
|
|
288
|
+
const removeGuidance = useCallback(
|
|
289
|
+
(trail: SubsystemTrail, stepIndex: number) => {
|
|
290
|
+
const step = trail.steps[stepIndex];
|
|
291
|
+
if (!step) return;
|
|
292
|
+
const stepKey = stepClaimKey(step);
|
|
293
|
+
setRecords((prev) =>
|
|
294
|
+
prev.filter((r) => !(r.trailId === trail.id && r.stepKey === stepKey)),
|
|
295
|
+
);
|
|
296
|
+
},
|
|
297
|
+
[],
|
|
298
|
+
);
|
|
299
|
+
|
|
300
|
+
const swapFirstSteps = useCallback(() => {
|
|
301
|
+
setTrails((prev) =>
|
|
302
|
+
prev.map((trail, trailIndex) =>
|
|
303
|
+
trailIndex === 0 && trail.steps.length > 2
|
|
304
|
+
? {
|
|
305
|
+
...trail,
|
|
306
|
+
steps: [trail.steps[1]!, trail.steps[0]!, ...trail.steps.slice(2)],
|
|
307
|
+
}
|
|
308
|
+
: trail,
|
|
309
|
+
),
|
|
310
|
+
);
|
|
311
|
+
}, []);
|
|
312
|
+
|
|
313
|
+
const editStepClaim = useCallback(() => {
|
|
314
|
+
setTrails((prev) =>
|
|
315
|
+
prev.map((trail, trailIndex) =>
|
|
316
|
+
trailIndex === 0
|
|
317
|
+
? {
|
|
318
|
+
...trail,
|
|
319
|
+
steps: trail.steps.map((step, stepIndex) =>
|
|
320
|
+
stepIndex === 1
|
|
321
|
+
? {
|
|
322
|
+
...step,
|
|
323
|
+
span: step.span
|
|
324
|
+
? { ...step.span, startLine: step.span.startLine + 1, contentHash: 'edited' }
|
|
325
|
+
: { startLine: 1, endLine: 1, contentHash: 'edited' },
|
|
326
|
+
}
|
|
327
|
+
: step,
|
|
328
|
+
),
|
|
329
|
+
}
|
|
330
|
+
: trail,
|
|
331
|
+
),
|
|
332
|
+
);
|
|
333
|
+
}, []);
|
|
334
|
+
|
|
335
|
+
const addAgentMark = useCallback(() => {
|
|
336
|
+
const trail = trails[1];
|
|
337
|
+
const step = trail?.steps[3];
|
|
338
|
+
if (!trail || !step) return;
|
|
339
|
+
const stepKey = stepClaimKey(step);
|
|
340
|
+
setRecords((prev) =>
|
|
341
|
+
prev.some((r) => r.trailId === trail.id && r.stepKey === stepKey)
|
|
342
|
+
? prev
|
|
343
|
+
: [
|
|
344
|
+
...prev,
|
|
345
|
+
{
|
|
346
|
+
trailId: trail.id,
|
|
347
|
+
stepKey,
|
|
348
|
+
guidance:
|
|
349
|
+
'Marked by **opencode** while tracing the save path. The panel scan runs again after the write to refresh the list.',
|
|
350
|
+
provenance: {
|
|
351
|
+
source: 'agent',
|
|
352
|
+
at: new Date().toISOString(),
|
|
353
|
+
author: 'opencode',
|
|
354
|
+
},
|
|
355
|
+
},
|
|
356
|
+
],
|
|
357
|
+
);
|
|
358
|
+
}, [trails]);
|
|
359
|
+
|
|
360
|
+
const pruneOrphans = useCallback(() => {
|
|
361
|
+
setRecords((prev) => {
|
|
362
|
+
const dead = new Set(orphans.map((r) => `${r.trailId}:${r.stepKey}`));
|
|
363
|
+
return prev.filter((r) => !dead.has(`${r.trailId}:${r.stepKey}`));
|
|
364
|
+
});
|
|
365
|
+
}, [orphans]);
|
|
366
|
+
|
|
367
|
+
const documentModel: StepEmphasisDocument = {
|
|
368
|
+
version: 1,
|
|
369
|
+
modelId: 'sg-prototype',
|
|
370
|
+
emphasis: records,
|
|
371
|
+
};
|
|
372
|
+
|
|
373
|
+
const button = (label: string, onClick: () => void, disabled = false) => (
|
|
374
|
+
<button
|
|
375
|
+
type="button"
|
|
376
|
+
onClick={onClick}
|
|
377
|
+
disabled={disabled}
|
|
378
|
+
style={{
|
|
379
|
+
padding: '5px 9px',
|
|
380
|
+
borderRadius: 5,
|
|
381
|
+
border: `1px solid ${border}`,
|
|
382
|
+
background: '#171a21',
|
|
383
|
+
color: disabled ? '#5b636e' : '#e6edf3',
|
|
384
|
+
fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace',
|
|
385
|
+
fontSize: 11,
|
|
386
|
+
cursor: disabled ? 'default' : 'pointer',
|
|
387
|
+
}}
|
|
388
|
+
>
|
|
389
|
+
{label}
|
|
390
|
+
</button>
|
|
391
|
+
);
|
|
392
|
+
|
|
393
|
+
return (
|
|
394
|
+
<div style={{ display: 'flex', height: '100vh', background: panelBg }}>
|
|
395
|
+
<div style={{ flex: 1, minWidth: 0, position: 'relative' }}>
|
|
396
|
+
<SubsystemComponentGraph
|
|
397
|
+
components={components}
|
|
398
|
+
trails={trails}
|
|
399
|
+
initialTrailId="tl-open-drawing"
|
|
400
|
+
persistKey="step-emphasis-prototype"
|
|
401
|
+
stepEmphasis={emphasis}
|
|
402
|
+
onRemoveStepEmphasis={removeGuidance}
|
|
403
|
+
title="Step emphasis prototype"
|
|
404
|
+
description="Key steps carry a star and markdown guidance. The mark lives in a separate augmentation document, keyed by the step's claim."
|
|
405
|
+
/>
|
|
406
|
+
</div>
|
|
407
|
+
|
|
408
|
+
<aside
|
|
409
|
+
style={{
|
|
410
|
+
width: 380,
|
|
411
|
+
flexShrink: 0,
|
|
412
|
+
display: 'flex',
|
|
413
|
+
flexDirection: 'column',
|
|
414
|
+
borderLeft: `1px solid ${border}`,
|
|
415
|
+
background: '#0b0d11',
|
|
416
|
+
overflow: 'hidden',
|
|
417
|
+
}}
|
|
418
|
+
>
|
|
419
|
+
<header style={{ padding: '14px 16px 10px', borderBottom: `1px solid ${border}` }}>
|
|
420
|
+
<div
|
|
421
|
+
style={{
|
|
422
|
+
display: 'flex',
|
|
423
|
+
alignItems: 'center',
|
|
424
|
+
gap: 6,
|
|
425
|
+
fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace',
|
|
426
|
+
fontSize: 12,
|
|
427
|
+
color: '#e6edf3',
|
|
428
|
+
}}
|
|
429
|
+
>
|
|
430
|
+
<Star size={13} fill="#f5a524" color="#f5a524" />
|
|
431
|
+
Step emphasis · prototype
|
|
432
|
+
</div>
|
|
433
|
+
<p style={{ margin: '6px 0 0', fontSize: 11, lineHeight: 1.5, color: muted }}>
|
|
434
|
+
A separate augmentation document, not the portable model. Marks key on the
|
|
435
|
+
step's <em>claim</em>, so reorder keeps them and a claim edit orphans them.
|
|
436
|
+
</p>
|
|
437
|
+
</header>
|
|
438
|
+
|
|
439
|
+
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6, padding: '10px 16px' }}>
|
|
440
|
+
{button('Reorder steps', swapFirstSteps)}
|
|
441
|
+
{button('Edit step 2 claim', editStepClaim)}
|
|
442
|
+
{button('Add agent mark', addAgentMark)}
|
|
443
|
+
{button(
|
|
444
|
+
`Prune ${orphans.length} orphan${orphans.length === 1 ? '' : 's'}`,
|
|
445
|
+
pruneOrphans,
|
|
446
|
+
orphans.length === 0,
|
|
447
|
+
)}
|
|
448
|
+
</div>
|
|
449
|
+
|
|
450
|
+
<div style={{ padding: '0 16px 10px', display: 'grid', gap: 3 }}>
|
|
451
|
+
<InspectorRow label="store" value="~/.principal/subsystem-model-augmentations/" />
|
|
452
|
+
<InspectorRow label="modelId" value={documentModel.modelId} />
|
|
453
|
+
<InspectorRow
|
|
454
|
+
label="marks"
|
|
455
|
+
value={`${records.length} total · ${orphans.length} orphaned`}
|
|
456
|
+
color={orphans.length > 0 ? '#e5534b' : undefined}
|
|
457
|
+
/>
|
|
458
|
+
</div>
|
|
459
|
+
|
|
460
|
+
<div
|
|
461
|
+
style={{
|
|
462
|
+
display: 'flex',
|
|
463
|
+
alignItems: 'center',
|
|
464
|
+
gap: 6,
|
|
465
|
+
padding: '0 16px 10px',
|
|
466
|
+
fontSize: 10,
|
|
467
|
+
color: muted,
|
|
468
|
+
}}
|
|
469
|
+
>
|
|
470
|
+
<Star size={10} fill="#f5a524" color="#f5a524" />
|
|
471
|
+
A mark is a single star plus markdown guidance.
|
|
472
|
+
</div>
|
|
473
|
+
|
|
474
|
+
{orphans.length > 0 && (
|
|
475
|
+
<div style={{ padding: '0 16px 10px', display: 'grid', gap: 4 }}>
|
|
476
|
+
<span style={{ fontSize: 10, letterSpacing: '0.08em', color: '#e5534b' }}>
|
|
477
|
+
ORPHANED — the claim changed
|
|
478
|
+
</span>
|
|
479
|
+
{orphans.map((r) => (
|
|
480
|
+
<div
|
|
481
|
+
key={`${r.trailId}:${r.stepKey}`}
|
|
482
|
+
style={{ fontSize: 11, color: muted, fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace' }}
|
|
483
|
+
>
|
|
484
|
+
<span style={{ color: '#f5a524' }}>Key</span> {r.trailId} · {r.stepKey}
|
|
485
|
+
</div>
|
|
486
|
+
))}
|
|
487
|
+
</div>
|
|
488
|
+
)}
|
|
489
|
+
|
|
490
|
+
<div
|
|
491
|
+
style={{
|
|
492
|
+
flex: 1,
|
|
493
|
+
minHeight: 0,
|
|
494
|
+
overflow: 'auto',
|
|
495
|
+
borderTop: `1px solid ${border}`,
|
|
496
|
+
padding: '10px 16px 16px',
|
|
497
|
+
}}
|
|
498
|
+
>
|
|
499
|
+
<div
|
|
500
|
+
style={{
|
|
501
|
+
fontSize: 10,
|
|
502
|
+
letterSpacing: '0.08em',
|
|
503
|
+
color: muted,
|
|
504
|
+
marginBottom: 6,
|
|
505
|
+
}}
|
|
506
|
+
>
|
|
507
|
+
AUGMENTATION DOCUMENT
|
|
508
|
+
</div>
|
|
509
|
+
<pre
|
|
510
|
+
style={{
|
|
511
|
+
margin: 0,
|
|
512
|
+
fontSize: 10,
|
|
513
|
+
lineHeight: 1.45,
|
|
514
|
+
color: '#c9d1d9',
|
|
515
|
+
whiteSpace: 'pre-wrap',
|
|
516
|
+
}}
|
|
517
|
+
>
|
|
518
|
+
{JSON.stringify(documentModel, null, 2)}
|
|
519
|
+
</pre>
|
|
520
|
+
</div>
|
|
521
|
+
</aside>
|
|
522
|
+
</div>
|
|
523
|
+
);
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
export const Interactive: Story = {
|
|
527
|
+
render: () => <Prototype />,
|
|
528
|
+
};
|