@peasant-labs/fairtrade 0.0.6 → 0.0.9
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/LICENSE +202 -21
- package/dist/lib/InUseShell-ClWg74-v.js +3388 -0
- package/dist/lib/commons.js +803 -838
- package/dist/lib/components.css +1 -1
- package/dist/lib/graph.css +1 -1
- package/dist/lib/graph.js +871 -276
- package/dist/lib/tokens.css +4 -0
- package/dist/lib/tokens.json +16 -0
- package/dist/lib/types/CommitGraph.d.ts +50 -3
- package/dist/lib/types/MapCanvas.d.ts +45 -2
- package/dist/lib/types/ProviderIcon.d.ts +23 -20
- package/dist/lib/types/commons/providers.d.ts +7 -8
- package/dist/lib/types/commons/types.d.ts +3 -6
- package/dist/lib/types/graph/Changes.d.ts +8 -4
- package/dist/lib/types/graph/CodeMap.d.ts +17 -1
- package/dist/lib/types/graph/CodeMapComposition.d.ts +25 -1
- package/dist/lib/types/graph/CodeMapNavigator.d.ts +35 -0
- package/dist/lib/types/graph/GhostCommitNode.d.ts +20 -0
- package/dist/lib/types/graph/GhostGroup.d.ts +21 -0
- package/dist/lib/types/graph/HighlightEdge.d.ts +16 -0
- package/dist/lib/types/graph/InsightPanel.d.ts +25 -0
- package/dist/lib/types/graph/RankModeControl.d.ts +13 -0
- package/dist/lib/types/graph/RankedRow.d.ts +15 -0
- package/dist/lib/types/graph/ScentTag.d.ts +15 -0
- package/dist/lib/types/graph/SessionLane.d.ts +29 -0
- package/dist/lib/types/graph/SessionOverflowDisclosure.d.ts +23 -0
- package/dist/lib/types/graph/TouchedFileCluster.d.ts +17 -0
- package/dist/lib/types/graph/changeGraph.d.ts +12 -0
- package/dist/lib/types/graph/codeMapState.d.ts +240 -0
- package/dist/lib/types/graph/graphContractPolicy.d.ts +24 -0
- package/dist/lib/types/graph/index.d.ts +35 -1
- package/dist/lib/types/graph/ranking.d.ts +222 -0
- package/dist/lib/types/graph/timelineNavigation.d.ts +33 -0
- package/dist/lib/types/graph/types.d.ts +67 -440
- package/dist/lib/types/index.d.ts +2 -0
- package/dist/lib/types/provider-policy.d.ts +27 -0
- package/dist/lib/types/transcript/TranscriptViewer.d.ts +1 -1
- package/dist/lib/types/transcript/adapter.d.ts +5 -40
- package/dist/lib/types/transcript/graph/GraphLegend.d.ts +3 -3
- package/dist/lib/types/transcript/graph/GraphTurnNode.d.ts +2 -2
- package/dist/lib/types/transcript/index.d.ts +3 -1
- package/dist/lib/types/transcript/initial-position.d.ts +80 -0
- package/dist/lib/types/transcript/state-capabilities.d.ts +22 -1
- package/dist/lib/types/transcript/useTranscriptInitialPosition.d.ts +26 -0
- package/dist/lib/types/transcript/view-model.d.ts +16 -16
- package/dist/lib/types/transcript/wire-types.d.ts +46 -308
- package/dist/lib/{ui-TG4XLhWL.js → ui-FKKOy92_.js} +3295 -3455
- package/dist/lib/ui.js +4 -4
- package/package.json +66 -26
- package/dist/lib/InUseShell-CjtqHauP.js +0 -1532
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param {object} props
|
|
3
|
+
* @param {string} props.sessionId
|
|
4
|
+
* @param {string} props.title
|
|
5
|
+
* @param {import('@peasant-labs/schema').Harness} [props.harness]
|
|
6
|
+
* @param {boolean} [props.hovered]
|
|
7
|
+
* @param {boolean} [props.selected]
|
|
8
|
+
* @param {(sessionId: string|null) => void} props.onHover
|
|
9
|
+
* @param {(sessionId: string) => void} props.onSelect
|
|
10
|
+
* @param {Array<{ghostHash:string, subject?:string, resolution:string, method:string, confidence:string}>} [props.unresolvedGhosts]
|
|
11
|
+
* @param {string} [props.className]
|
|
12
|
+
*/
|
|
13
|
+
export default function SessionLane({ sessionId, title, harness, hovered, selected, onHover, onSelect, unresolvedGhosts, className, ...rest }: {
|
|
14
|
+
sessionId: string;
|
|
15
|
+
title: string;
|
|
16
|
+
harness?: import("@peasant-labs/schema").Harness;
|
|
17
|
+
hovered?: boolean;
|
|
18
|
+
selected?: boolean;
|
|
19
|
+
onHover: (sessionId: string | null) => void;
|
|
20
|
+
onSelect: (sessionId: string) => void;
|
|
21
|
+
unresolvedGhosts?: Array<{
|
|
22
|
+
ghostHash: string;
|
|
23
|
+
subject?: string;
|
|
24
|
+
resolution: string;
|
|
25
|
+
method: string;
|
|
26
|
+
confidence: string;
|
|
27
|
+
}>;
|
|
28
|
+
className?: string;
|
|
29
|
+
}): any;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param {object} props
|
|
3
|
+
* @param {string} props.commitHash - or any owning-row id; used to key the reducer's `toggle-commit-sessions`.
|
|
4
|
+
* @param {Array<{sessionId:string, title:string, harness?:import('@peasant-labs/schema').Harness}>} props.overflow - the sessions beyond the inline-2.
|
|
5
|
+
* @param {boolean} props.expanded
|
|
6
|
+
* @param {(id: string) => void} props.onToggle
|
|
7
|
+
* @param {(sessionId: string) => void} [props.onSelect]
|
|
8
|
+
* @param {string} [props.itemLabel='sessions']
|
|
9
|
+
* @param {string} [props.className]
|
|
10
|
+
*/
|
|
11
|
+
export default function SessionOverflowDisclosure({ commitHash, overflow, expanded, onToggle, onSelect, itemLabel, className, ...rest }: {
|
|
12
|
+
commitHash: string;
|
|
13
|
+
overflow: Array<{
|
|
14
|
+
sessionId: string;
|
|
15
|
+
title: string;
|
|
16
|
+
harness?: import("@peasant-labs/schema").Harness;
|
|
17
|
+
}>;
|
|
18
|
+
expanded: boolean;
|
|
19
|
+
onToggle: (id: string) => void;
|
|
20
|
+
onSelect?: (sessionId: string) => void;
|
|
21
|
+
itemLabel?: string;
|
|
22
|
+
className?: string;
|
|
23
|
+
}): any;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param {object} props
|
|
3
|
+
* @param {string} props.commitHash
|
|
4
|
+
* @param {string[]} props.files - already ordered by the caller (DOI intrinsic, or visit order when a session is selected).
|
|
5
|
+
* @param {boolean} props.expanded
|
|
6
|
+
* @param {(id: string) => void} props.onToggle
|
|
7
|
+
* @param {(file: string) => void} [props.onOpenDiff]
|
|
8
|
+
* @param {string} [props.className]
|
|
9
|
+
*/
|
|
10
|
+
export default function TouchedFileCluster({ commitHash, files, expanded, onToggle, onOpenDiff, className, ...rest }: {
|
|
11
|
+
commitHash: string;
|
|
12
|
+
files: string[];
|
|
13
|
+
expanded: boolean;
|
|
14
|
+
onToggle: (id: string) => void;
|
|
15
|
+
onOpenDiff?: (file: string) => void;
|
|
16
|
+
className?: string;
|
|
17
|
+
}): any;
|
|
@@ -58,6 +58,10 @@ export type CommitGraphRow = {
|
|
|
58
58
|
* a recorded session sits behind this commit (→ filled dot + sparkle)
|
|
59
59
|
*/
|
|
60
60
|
session?: boolean;
|
|
61
|
+
/**
|
|
62
|
+
* named sessions bound to this commit
|
|
63
|
+
*/
|
|
64
|
+
sessionRefs?: import("./types.js").TimelineSessionPayload[];
|
|
61
65
|
/**
|
|
62
66
|
* this commit merged a branch back in (→ merged chip)
|
|
63
67
|
*/
|
|
@@ -103,4 +107,12 @@ export type ChangesGraph = {
|
|
|
103
107
|
* number of merged changes
|
|
104
108
|
*/
|
|
105
109
|
mergedCount: number;
|
|
110
|
+
/**
|
|
111
|
+
* sessions not linked to a commit in this timeline window
|
|
112
|
+
*/
|
|
113
|
+
unlinkedSessions: import("./types.js").TimelineSessionPayload[];
|
|
114
|
+
/**
|
|
115
|
+
* sessions linked to a commit outside the displayed default-branch window
|
|
116
|
+
*/
|
|
117
|
+
outsideWindowSessions: import("./types.js").TimelineSessionPayload[];
|
|
106
118
|
};
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
/** @param {unknown} value @returns {value is number} */
|
|
2
|
+
export function isCodeMapViewportScale(value: unknown): value is number;
|
|
3
|
+
/**
|
|
4
|
+
* Creates a canonical, JSON-safe code-map interaction state.
|
|
5
|
+
* @param {Partial<CodeMapState>|null} [seed]
|
|
6
|
+
* @returns {CodeMapState}
|
|
7
|
+
*/
|
|
8
|
+
export function createCodeMapState(seed?: Partial<CodeMapState> | null): CodeMapState;
|
|
9
|
+
/** @param {CodeMapState} left @param {CodeMapState} right */
|
|
10
|
+
export function codeMapStatesEqual(left: CodeMapState, right: CodeMapState): boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Applies one semantic interaction and returns a fresh canonical state.
|
|
13
|
+
* @param {CodeMapState} state
|
|
14
|
+
* @param {CodeMapAction} action
|
|
15
|
+
* @returns {CodeMapState}
|
|
16
|
+
*/
|
|
17
|
+
export function reduceCodeMapState(state: CodeMapState, action: CodeMapAction): CodeMapState;
|
|
18
|
+
/**
|
|
19
|
+
* Pure derivation of the timeline's highlight state. Hover is
|
|
20
|
+
* subordinate to selection: both are returned independently so a caller can render
|
|
21
|
+
* selection at primary weight (amber fill) and hover as a secondary/additive
|
|
22
|
+
* layer (stroke width-step + glow) without one clearing the other. Escape
|
|
23
|
+
* clears hover, then selection; see `resolveEscapeAction`.
|
|
24
|
+
* @param {{edges: Array<{sessionId:string, commitHash:string, ghost?:boolean}>}|undefined|null} payload
|
|
25
|
+
* @param {CodeMapState} state
|
|
26
|
+
* @returns {{selected: TimelineHighlight, hovered: TimelineHighlight}}
|
|
27
|
+
*/
|
|
28
|
+
export function deriveTimelineHighlight(payload: {
|
|
29
|
+
edges: Array<{
|
|
30
|
+
sessionId: string;
|
|
31
|
+
commitHash: string;
|
|
32
|
+
ghost?: boolean;
|
|
33
|
+
}>;
|
|
34
|
+
} | undefined | null, state: CodeMapState): {
|
|
35
|
+
selected: TimelineHighlight;
|
|
36
|
+
hovered: TimelineHighlight;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* The Escape-key contract: "Escape clears hover then selection."
|
|
40
|
+
* Pure and reusable by every primitive that captures the key, so the two-step
|
|
41
|
+
* behavior lives in exactly one place. Returns null when there is nothing to clear.
|
|
42
|
+
* @param {CodeMapState} state
|
|
43
|
+
* @returns {{type:'hover-session', sessionId:null} | {type:'select-session', sessionId:null} | null}
|
|
44
|
+
*/
|
|
45
|
+
export function resolveEscapeAction(state: CodeMapState): {
|
|
46
|
+
type: "hover-session";
|
|
47
|
+
sessionId: null;
|
|
48
|
+
} | {
|
|
49
|
+
type: "select-session";
|
|
50
|
+
sessionId: null;
|
|
51
|
+
} | null;
|
|
52
|
+
/**
|
|
53
|
+
* Derives the complete navigator and canvas inputs from payload plus canonical state.
|
|
54
|
+
* Returned nodes are plain public payload data; no private indexes or depths are attached.
|
|
55
|
+
* @param {import('./types.js').CodeMapPayload|undefined|null} payload
|
|
56
|
+
* @param {CodeMapState} state
|
|
57
|
+
* @returns {CodeMapView}
|
|
58
|
+
*/
|
|
59
|
+
export function deriveCodeMapView(payload: import("./types.js").CodeMapPayload | undefined | null, state: CodeMapState): CodeMapView;
|
|
60
|
+
/** @typedef {import('./types.js').MapNodePayload} MapNodePayload */
|
|
61
|
+
/**
|
|
62
|
+
* The COMPLETE public timeline/ranking action surface. Frozen here: names are
|
|
63
|
+
* consumed downstream (the timeline surface, the ranked entry list) and are never renamed.
|
|
64
|
+
* @typedef {{type:'replace'|'hydrate', state:Partial<CodeMapState>} | {type:'set-presentation', presentation:CodeMapPresentation} | {type:'select'|'toggle-expanded'|'open-in-map', id:string} | {type:'focus', id:string|null} | {type:'clear-selection'} | {type:'set-filter', filter:string} | {type:'set-expanded', ids:Iterable<string>} | {type:'set-grain', grain:CodeMapGrain} | {type:'set-viewport', viewport:CodeMapViewport|null} | {type:'reveal', id:string, grain:CodeMapGrain, expandedIds:Iterable<string>} | {type:'hover-session', sessionId:string|null} | {type:'select-session', sessionId:string|null} | {type:'toggle-commit-sessions', commitHash:string} | {type:'toggle-ghost-group', successorHash:string} | {type:'set-rank-mode', rankMode:CodeMapRankMode} | {type:'set-scent-filter', scentFilter:string|null} | {type:'set-rank-expanded', expanded:boolean}} CodeMapAction
|
|
65
|
+
*/
|
|
66
|
+
/**
|
|
67
|
+
* @typedef {object} CodeMapState
|
|
68
|
+
* @property {1} version
|
|
69
|
+
* @property {CodeMapPresentation} presentation
|
|
70
|
+
* @property {string|null} selectedId
|
|
71
|
+
* @property {CodeMapGrain} grain
|
|
72
|
+
* @property {string[]} expandedIds
|
|
73
|
+
* @property {string} navigatorFilter
|
|
74
|
+
* @property {string|null} navigatorFocusedId
|
|
75
|
+
* @property {CodeMapViewport|null} viewport
|
|
76
|
+
* @property {string|null} hoveredSessionId - transient; set/cleared by `hover-session`, never persisted to the route.
|
|
77
|
+
* @property {string|null} selectedSessionId - lingers after the pointer leaves; route-persisted (shareable deep link).
|
|
78
|
+
* @property {string[]} expandedCommitSessions - disclosure keys: commit hashes for sessions, `files:<hash>` for touched files, and `ranked:all` for the ranked-list cap.
|
|
79
|
+
* @property {string[]} expandedGhostGroups - successor commit hashes with their ghost group expanded.
|
|
80
|
+
* @property {CodeMapRankMode} rankMode - ranked-entry-list scoring mode.
|
|
81
|
+
* @property {string|null} scentFilter - one `SCENT_TAGS` member, or null for no filter.
|
|
82
|
+
*/
|
|
83
|
+
/** @typedef {{node:import('./types.js').MapNodePayload, depth:number, parentId:string|null, childIds:string[], hasChildren:boolean, canExpand:boolean, forcedOpen:boolean, expanded:boolean}} CodeMapNavigatorRow */
|
|
84
|
+
/** @typedef {{orderedIds:string[], rootIds:string[], childIdsByParent:Record<string,string[]>, depthById:Record<string,number>}} CodeMapHierarchy */
|
|
85
|
+
/** @typedef {{allNodes:import('./types.js').MapNodePayload[], nodes:import('./types.js').MapNodePayload[], visibleIds:string[], selectedId:string|null, grain:CodeMapGrain, expandedIds:string[], viewport:CodeMapViewport|null, hierarchy:CodeMapHierarchy}} CodeMapCanvasView */
|
|
86
|
+
/** @typedef {{state:CodeMapState, rows:CodeMapNavigatorRow[], focusedId:string|null, selected:import('./types.js').MapNodePayload|null, staleSelectedId:string|null, canvas:CodeMapCanvasView}} CodeMapView */
|
|
87
|
+
export const CODE_MAP_STATE_VERSION: 1;
|
|
88
|
+
export const CODE_MAP_VIEWPORT_SCALE: Readonly<{
|
|
89
|
+
min: 0.35;
|
|
90
|
+
max: 2.4;
|
|
91
|
+
}>;
|
|
92
|
+
export const CODE_MAP_GRAIN_DEPTH: Readonly<{
|
|
93
|
+
project: 0;
|
|
94
|
+
package: 1;
|
|
95
|
+
file: 1;
|
|
96
|
+
}>;
|
|
97
|
+
export type TimelineHighlight = {
|
|
98
|
+
sessionId: string | null;
|
|
99
|
+
commitHashes: string[];
|
|
100
|
+
ghostHashes: string[];
|
|
101
|
+
edges: Array<{
|
|
102
|
+
sessionId: string;
|
|
103
|
+
commitHash: string;
|
|
104
|
+
ghost?: boolean;
|
|
105
|
+
}>;
|
|
106
|
+
};
|
|
107
|
+
export type CodeMapPresentation = "navigator" | "canvas";
|
|
108
|
+
export type CodeMapGrain = "project" | "package" | "file";
|
|
109
|
+
export type CodeMapViewport = {
|
|
110
|
+
scale: number;
|
|
111
|
+
panX: number;
|
|
112
|
+
panY: number;
|
|
113
|
+
};
|
|
114
|
+
export type CodeMapRankMode = "relevance" | "debt" | "churn";
|
|
115
|
+
export type MapNodePayload = import("./types.js").MapNodePayload;
|
|
116
|
+
/**
|
|
117
|
+
* The COMPLETE public timeline/ranking action surface. Frozen here: names are
|
|
118
|
+
* consumed downstream (the timeline surface, the ranked entry list) and are never renamed.
|
|
119
|
+
*/
|
|
120
|
+
export type CodeMapAction = {
|
|
121
|
+
type: "replace" | "hydrate";
|
|
122
|
+
state: Partial<CodeMapState>;
|
|
123
|
+
} | {
|
|
124
|
+
type: "set-presentation";
|
|
125
|
+
presentation: CodeMapPresentation;
|
|
126
|
+
} | {
|
|
127
|
+
type: "select" | "toggle-expanded" | "open-in-map";
|
|
128
|
+
id: string;
|
|
129
|
+
} | {
|
|
130
|
+
type: "focus";
|
|
131
|
+
id: string | null;
|
|
132
|
+
} | {
|
|
133
|
+
type: "clear-selection";
|
|
134
|
+
} | {
|
|
135
|
+
type: "set-filter";
|
|
136
|
+
filter: string;
|
|
137
|
+
} | {
|
|
138
|
+
type: "set-expanded";
|
|
139
|
+
ids: Iterable<string>;
|
|
140
|
+
} | {
|
|
141
|
+
type: "set-grain";
|
|
142
|
+
grain: CodeMapGrain;
|
|
143
|
+
} | {
|
|
144
|
+
type: "set-viewport";
|
|
145
|
+
viewport: CodeMapViewport | null;
|
|
146
|
+
} | {
|
|
147
|
+
type: "reveal";
|
|
148
|
+
id: string;
|
|
149
|
+
grain: CodeMapGrain;
|
|
150
|
+
expandedIds: Iterable<string>;
|
|
151
|
+
} | {
|
|
152
|
+
type: "hover-session";
|
|
153
|
+
sessionId: string | null;
|
|
154
|
+
} | {
|
|
155
|
+
type: "select-session";
|
|
156
|
+
sessionId: string | null;
|
|
157
|
+
} | {
|
|
158
|
+
type: "toggle-commit-sessions";
|
|
159
|
+
commitHash: string;
|
|
160
|
+
} | {
|
|
161
|
+
type: "toggle-ghost-group";
|
|
162
|
+
successorHash: string;
|
|
163
|
+
} | {
|
|
164
|
+
type: "set-rank-mode";
|
|
165
|
+
rankMode: CodeMapRankMode;
|
|
166
|
+
} | {
|
|
167
|
+
type: "set-scent-filter";
|
|
168
|
+
scentFilter: string | null;
|
|
169
|
+
} | {
|
|
170
|
+
type: "set-rank-expanded";
|
|
171
|
+
expanded: boolean;
|
|
172
|
+
};
|
|
173
|
+
export type CodeMapState = {
|
|
174
|
+
version: 1;
|
|
175
|
+
presentation: CodeMapPresentation;
|
|
176
|
+
selectedId: string | null;
|
|
177
|
+
grain: CodeMapGrain;
|
|
178
|
+
expandedIds: string[];
|
|
179
|
+
navigatorFilter: string;
|
|
180
|
+
navigatorFocusedId: string | null;
|
|
181
|
+
viewport: CodeMapViewport | null;
|
|
182
|
+
/**
|
|
183
|
+
* - transient; set/cleared by `hover-session`, never persisted to the route.
|
|
184
|
+
*/
|
|
185
|
+
hoveredSessionId: string | null;
|
|
186
|
+
/**
|
|
187
|
+
* - lingers after the pointer leaves; route-persisted (shareable deep link).
|
|
188
|
+
*/
|
|
189
|
+
selectedSessionId: string | null;
|
|
190
|
+
/**
|
|
191
|
+
* - disclosure keys: commit hashes for sessions, `files:<hash>` for touched files, and `ranked:all` for the ranked-list cap.
|
|
192
|
+
*/
|
|
193
|
+
expandedCommitSessions: string[];
|
|
194
|
+
/**
|
|
195
|
+
* - successor commit hashes with their ghost group expanded.
|
|
196
|
+
*/
|
|
197
|
+
expandedGhostGroups: string[];
|
|
198
|
+
/**
|
|
199
|
+
* - ranked-entry-list scoring mode.
|
|
200
|
+
*/
|
|
201
|
+
rankMode: CodeMapRankMode;
|
|
202
|
+
/**
|
|
203
|
+
* - one `SCENT_TAGS` member, or null for no filter.
|
|
204
|
+
*/
|
|
205
|
+
scentFilter: string | null;
|
|
206
|
+
};
|
|
207
|
+
export type CodeMapNavigatorRow = {
|
|
208
|
+
node: import("./types.js").MapNodePayload;
|
|
209
|
+
depth: number;
|
|
210
|
+
parentId: string | null;
|
|
211
|
+
childIds: string[];
|
|
212
|
+
hasChildren: boolean;
|
|
213
|
+
canExpand: boolean;
|
|
214
|
+
forcedOpen: boolean;
|
|
215
|
+
expanded: boolean;
|
|
216
|
+
};
|
|
217
|
+
export type CodeMapHierarchy = {
|
|
218
|
+
orderedIds: string[];
|
|
219
|
+
rootIds: string[];
|
|
220
|
+
childIdsByParent: Record<string, string[]>;
|
|
221
|
+
depthById: Record<string, number>;
|
|
222
|
+
};
|
|
223
|
+
export type CodeMapCanvasView = {
|
|
224
|
+
allNodes: import("./types.js").MapNodePayload[];
|
|
225
|
+
nodes: import("./types.js").MapNodePayload[];
|
|
226
|
+
visibleIds: string[];
|
|
227
|
+
selectedId: string | null;
|
|
228
|
+
grain: CodeMapGrain;
|
|
229
|
+
expandedIds: string[];
|
|
230
|
+
viewport: CodeMapViewport | null;
|
|
231
|
+
hierarchy: CodeMapHierarchy;
|
|
232
|
+
};
|
|
233
|
+
export type CodeMapView = {
|
|
234
|
+
state: CodeMapState;
|
|
235
|
+
rows: CodeMapNavigatorRow[];
|
|
236
|
+
focusedId: string | null;
|
|
237
|
+
selected: import("./types.js").MapNodePayload | null;
|
|
238
|
+
staleSelectedId: string | null;
|
|
239
|
+
canvas: CodeMapCanvasView;
|
|
240
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/** @param {Array<{kind:string, provenance:string}>} insights */
|
|
2
|
+
export function assertInsightContractValues(insights: Array<{
|
|
3
|
+
kind: string;
|
|
4
|
+
provenance: string;
|
|
5
|
+
}>): void;
|
|
6
|
+
/** @param {Array<{readAttribution:string, readState:string}>} nodes */
|
|
7
|
+
export function assertRankingContractValues(nodes: Array<{
|
|
8
|
+
readAttribution: string;
|
|
9
|
+
readState: string;
|
|
10
|
+
}>): void;
|
|
11
|
+
/** @typedef {import('@peasant-labs/schema').InsightKind} InsightKind */
|
|
12
|
+
/** @typedef {import('@peasant-labs/schema').InsightProvenance} InsightProvenance */
|
|
13
|
+
/** @typedef {import('@peasant-labs/schema').ReadAttributionState} ReadAttributionState */
|
|
14
|
+
/** @typedef {import('@peasant-labs/schema').ReadStateGrade} ReadStateGrade */
|
|
15
|
+
/** @typedef {{markerClass:string}} InsightProvenancePresentation */
|
|
16
|
+
export const INSIGHT_KIND_LABELS: Readonly<Readonly<Record<"unusual" | "decision" | "friction" | "retry_loop", string>>>;
|
|
17
|
+
export const INSIGHT_PROVENANCE_PRESENTATIONS: Readonly<Readonly<Record<"mechanical" | "mined", InsightProvenancePresentation>>>;
|
|
18
|
+
export type InsightKind = import("@peasant-labs/schema").InsightKind;
|
|
19
|
+
export type InsightProvenance = import("@peasant-labs/schema").InsightProvenance;
|
|
20
|
+
export type ReadAttributionState = import("@peasant-labs/schema").ReadAttributionState;
|
|
21
|
+
export type ReadStateGrade = import("@peasant-labs/schema").ReadStateGrade;
|
|
22
|
+
export type InsightProvenancePresentation = {
|
|
23
|
+
markerClass: string;
|
|
24
|
+
};
|
|
@@ -1,11 +1,28 @@
|
|
|
1
1
|
export { default as Changes } from "./Changes.jsx";
|
|
2
2
|
export { default as ChangeDetail } from "./ChangeDetail.jsx";
|
|
3
|
+
export { default as CodeMapNavigator } from "./CodeMapNavigator.jsx";
|
|
4
|
+
export { assertTimelineNavigationAction } from "./timelineNavigation.js";
|
|
5
|
+
export { default as SessionLane } from "./SessionLane.jsx";
|
|
6
|
+
export { default as GhostCommitNode } from "./GhostCommitNode.jsx";
|
|
7
|
+
export { default as GhostGroup } from "./GhostGroup.jsx";
|
|
8
|
+
export { default as HighlightEdge } from "./HighlightEdge.jsx";
|
|
9
|
+
export { default as SessionOverflowDisclosure } from "./SessionOverflowDisclosure.jsx";
|
|
10
|
+
export { default as RankedRow } from "./RankedRow.jsx";
|
|
11
|
+
export { default as ScentTag } from "./ScentTag.jsx";
|
|
12
|
+
export { default as RankModeControl } from "./RankModeControl.jsx";
|
|
13
|
+
export { default as InsightPanel } from "./InsightPanel.jsx";
|
|
14
|
+
export { default as TouchedFileCluster } from "./TouchedFileCluster.jsx";
|
|
3
15
|
export type MapNodeKind = import("./types.js").MapNodeKind;
|
|
4
16
|
export type ChangeBinding = import("./types.js").ChangeBinding;
|
|
5
17
|
export type EdgeViolationKind = import("./types.js").EdgeViolationKind;
|
|
6
18
|
export type FileChangeStatus = import("./types.js").FileChangeStatus;
|
|
7
19
|
export type DiffLineKind = import("./types.js").DiffLineKind;
|
|
20
|
+
export type InsightKind = import("@peasant-labs/schema").InsightKind;
|
|
21
|
+
export type InsightProvenance = import("@peasant-labs/schema").InsightProvenance;
|
|
22
|
+
export type ReadAttributionState = import("@peasant-labs/schema").ReadAttributionState;
|
|
23
|
+
export type ReadStateGrade = import("@peasant-labs/schema").ReadStateGrade;
|
|
8
24
|
export type CommitRefPayload = import("./types.js").CommitRefPayload;
|
|
25
|
+
export type TimelineSessionPayload = import("./types.js").TimelineSessionPayload;
|
|
9
26
|
export type MapEdgePayload = import("./types.js").MapEdgePayload;
|
|
10
27
|
export type ActivityEdgePayload = import("./types.js").ActivityEdgePayload;
|
|
11
28
|
export type EdgeViolationPayload = import("./types.js").EdgeViolationPayload;
|
|
@@ -23,8 +40,25 @@ export type DiffLinePayload = import("./types.js").DiffLinePayload;
|
|
|
23
40
|
export type DiffHunkPayload = import("./types.js").DiffHunkPayload;
|
|
24
41
|
export type ChangeDiffPayload = import("./types.js").ChangeDiffPayload;
|
|
25
42
|
export type CodeMapPayload = import("./types.js").CodeMapPayload;
|
|
43
|
+
export type CodeMapPresentation = import("./codeMapState.js").CodeMapPresentation;
|
|
44
|
+
export type CodeMapGrain = import("./codeMapState.js").CodeMapGrain;
|
|
45
|
+
export type CodeMapViewport = import("./codeMapState.js").CodeMapViewport;
|
|
46
|
+
export type CodeMapState = import("./codeMapState.js").CodeMapState;
|
|
47
|
+
export type CodeMapAction = import("./codeMapState.js").CodeMapAction;
|
|
48
|
+
export type CodeMapNavigatorRow = import("./codeMapState.js").CodeMapNavigatorRow;
|
|
49
|
+
export type CodeMapCanvasView = import("./codeMapState.js").CodeMapCanvasView;
|
|
50
|
+
export type CodeMapView = import("./codeMapState.js").CodeMapView;
|
|
51
|
+
export type TimelineNavigationAction = import("./timelineNavigation.js").TimelineNavigationAction;
|
|
52
|
+
export type CodeMapRankMode = import("./codeMapState.js").CodeMapRankMode;
|
|
53
|
+
export type TimelineHighlight = import("./codeMapState.js").TimelineHighlight;
|
|
54
|
+
export type RankInputNode = import("./ranking.js").RankInputNode;
|
|
55
|
+
export type RankedRowData = import("./ranking.js").RankedRow;
|
|
56
|
+
export type DebtState = import("./ranking.js").DebtState;
|
|
26
57
|
export { default as CodeMap, codeMapPayloadToMapData } from "./CodeMap.jsx";
|
|
27
58
|
export { default as CodeMapComposition, DefaultMapLegend } from "./CodeMapComposition.jsx";
|
|
59
|
+
export { CODE_MAP_STATE_VERSION, CODE_MAP_VIEWPORT_SCALE, isCodeMapViewportScale, codeMapStatesEqual, createCodeMapState, reduceCodeMapState, deriveCodeMapView, deriveTimelineHighlight, resolveEscapeAction } from "./codeMapState.js";
|
|
28
60
|
export { GraphAppShell, GraphSectionNav, GRAPH_APP_SECTIONS } from "../inuse/InUseShell.jsx";
|
|
29
61
|
export { buildChangesGraph, humanizeAge } from "./changeGraph.js";
|
|
30
|
-
export {
|
|
62
|
+
export { DOI_WEIGHTS, DEBT_VIEWED, COVERAGE_CAP, RECENCY_HALF_LIFE_DAYS, RANK_FLOOR, RANK_CAP, SCENT_TAGS, debtState, debt, coverage, hunkClears, partialReadHoverText, debtHoverText, scentTagsFor, rankMapNodesIntrinsic, deriveRankedRows, rankMapNodes, gateRankedRows } from "./ranking.js";
|
|
63
|
+
export { assertChangeDetailPayloadEnums, assertChangeDiffPayloadEnums, assertCodeMapPayloadEnums, MAP_NODE_KINDS, CHANGE_BINDINGS, EDGE_VIOLATION_KINDS, FILE_CHANGE_STATUSES, DIFF_LINE_KINDS } from "./types.js";
|
|
64
|
+
export { MapNodeKind, AllMapNodeKinds, isMapNodeKind, ChangeBinding, AllChangeBindings, isChangeBinding, EdgeViolationKind, AllEdgeViolationKinds, isEdgeViolationKind, FileChangeStatus, AllFileChangeStatuses, isFileChangeStatus, DiffLineKind, AllDiffLineKinds, isDiffLineKind, InsightKind, AllInsightKinds, isInsightKind, InsightProvenance, AllInsightProvenances, isInsightProvenance, ReadAttributionState, AllReadAttributionStates, isReadAttributionState, ReadStateGrade, AllReadStateGrades, isReadStateGrade } from "@peasant-labs/schema";
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Comprehension-debt state resolution over MapNode scalars only (no per-hunk
|
|
3
|
+
* wire data required; the formula is pure over ReadState plus the three
|
|
4
|
+
* region-coverage counts).
|
|
5
|
+
* @param {RankInputNode} node
|
|
6
|
+
* @returns {DebtState}
|
|
7
|
+
*/
|
|
8
|
+
export function debtState(node: RankInputNode): DebtState;
|
|
9
|
+
/**
|
|
10
|
+
* Comprehension-debt magnitude. `state` must be the value `debtState(node)` returned for
|
|
11
|
+
* the SAME node (kept as a parameter, not recomputed, so callers that already
|
|
12
|
+
* branched on `debtState` never pay for or risk re-deriving it differently).
|
|
13
|
+
* @param {RankInputNode} node @param {DebtState} state
|
|
14
|
+
* @returns {number}
|
|
15
|
+
*/
|
|
16
|
+
export function debt(node: RankInputNode, state: DebtState): number;
|
|
17
|
+
/** `coverage`: an unattributable hunk caps it strictly below 1 (COVERAGE_CAP). @param {RankInputNode} node */
|
|
18
|
+
export function coverage(node: RankInputNode): number;
|
|
19
|
+
/** `hunkClears`: the named state gate, never shadowed by a fallback. @param {RankInputNode} node */
|
|
20
|
+
export function hunkClears(node: RankInputNode): boolean;
|
|
21
|
+
/**
|
|
22
|
+
* The path-conditioned partial-read hover copy. Returns null
|
|
23
|
+
* for every non-`partial-read` state. Callers only call this after checking
|
|
24
|
+
* `debtState(node) === 'partial-read'`.
|
|
25
|
+
* @param {RankInputNode} node
|
|
26
|
+
* @returns {string|null}
|
|
27
|
+
*/
|
|
28
|
+
export function partialReadHoverText(node: RankInputNode): string | null;
|
|
29
|
+
/**
|
|
30
|
+
* State-specific honesty copy for every visible debt tag. The copy describes
|
|
31
|
+
* recorded evidence and always remains a prompt, never a claim about a person.
|
|
32
|
+
* @param {RankInputNode} node
|
|
33
|
+
* @param {DebtState} state
|
|
34
|
+
* @returns {string|null}
|
|
35
|
+
*/
|
|
36
|
+
export function debtHoverText(node: RankInputNode, state: DebtState): string | null;
|
|
37
|
+
/**
|
|
38
|
+
* Up to two scent tags per row, including the softened `viewed`
|
|
39
|
+
* treatment and the multi-state debt vocabulary. The `partial-read` state
|
|
40
|
+
* reuses the strong/softened tag with the path-conditioned hover. No new
|
|
41
|
+
* tag for the partial state.
|
|
42
|
+
* @param {RankInputNode} node @param {DebtState} state @param {{focusId?:string|null, parentOf?:Map<string,string|null>, distanceToFocus?:number|null, maxTouch?:number, hoveredOrSelectedSessionId?:string|null}} [context]
|
|
43
|
+
* @returns {string[]}
|
|
44
|
+
*/
|
|
45
|
+
export function scentTagsFor(node: RankInputNode, state: DebtState, context?: {
|
|
46
|
+
focusId?: string | null;
|
|
47
|
+
parentOf?: Map<string, string | null>;
|
|
48
|
+
distanceToFocus?: number | null;
|
|
49
|
+
maxTouch?: number;
|
|
50
|
+
hoveredOrSelectedSessionId?: string | null;
|
|
51
|
+
}): string[];
|
|
52
|
+
/**
|
|
53
|
+
* Computes only payload/rank-mode intrinsic terms. A caller can memoize this
|
|
54
|
+
* object by node-array identity and rank mode; focus, filter, hover and session
|
|
55
|
+
* selection belong exclusively to `deriveRankedRows` below.
|
|
56
|
+
* @param {RankInputNode[]} nodes
|
|
57
|
+
* @param {{rankMode?: RankMode, nowMs?: number}} [options]
|
|
58
|
+
* @returns {IntrinsicRanking}
|
|
59
|
+
*/
|
|
60
|
+
export function rankMapNodesIntrinsic(nodes: RankInputNode[], options?: {
|
|
61
|
+
rankMode?: RankMode;
|
|
62
|
+
nowMs?: number;
|
|
63
|
+
}): IntrinsicRanking;
|
|
64
|
+
/**
|
|
65
|
+
* Applies focus distance, active-session scent, sort, and filter to memoized
|
|
66
|
+
* intrinsic terms. Ties break by node id; all-equal intrinsic terms stay 0.
|
|
67
|
+
* @param {IntrinsicRanking} intrinsicRanking
|
|
68
|
+
* @param {{focusId?: string|null, scentFilter?: string|null, hoveredOrSelectedSessionId?: string|null}} [options]
|
|
69
|
+
* @returns {RankedRow[]}
|
|
70
|
+
*/
|
|
71
|
+
export function deriveRankedRows(intrinsicRanking: IntrinsicRanking, options?: {
|
|
72
|
+
focusId?: string | null;
|
|
73
|
+
scentFilter?: string | null;
|
|
74
|
+
hoveredOrSelectedSessionId?: string | null;
|
|
75
|
+
}): RankedRow[];
|
|
76
|
+
/** Compatibility composition of the public two-phase ranking API.
|
|
77
|
+
* @param {RankInputNode[]} nodes
|
|
78
|
+
* @param {{rankMode?: RankMode, focusId?: string|null, scentFilter?: string|null, hoveredOrSelectedSessionId?: string|null, nowMs?: number}} [options]
|
|
79
|
+
*/
|
|
80
|
+
export function rankMapNodes(nodes: RankInputNode[], options?: {
|
|
81
|
+
rankMode?: RankMode;
|
|
82
|
+
focusId?: string | null;
|
|
83
|
+
scentFilter?: string | null;
|
|
84
|
+
hoveredOrSelectedSessionId?: string | null;
|
|
85
|
+
nowMs?: number;
|
|
86
|
+
}): RankedRow[];
|
|
87
|
+
/**
|
|
88
|
+
* Threshold gating: show `DOI >= max(0.25, 0.5*maxDOI)`, floor 5, cap 25,
|
|
89
|
+
* then a single "show all N files" expander. Deterministic, fixture-pinnable.
|
|
90
|
+
* In debt mode, known debt is included before thresholded unknown/clear rows,
|
|
91
|
+
* so threshold and cap gating cannot hide actionable evidence behind unknowns.
|
|
92
|
+
* @param {RankedRow[]} rows @param {{expanded?: boolean, rankMode?:RankMode}} [options]
|
|
93
|
+
* @returns {{visible: RankedRow[], total: number, overflowCount: number}}
|
|
94
|
+
*/
|
|
95
|
+
export function gateRankedRows(rows: RankedRow[], options?: {
|
|
96
|
+
expanded?: boolean;
|
|
97
|
+
rankMode?: RankMode;
|
|
98
|
+
}): {
|
|
99
|
+
visible: RankedRow[];
|
|
100
|
+
total: number;
|
|
101
|
+
overflowCount: number;
|
|
102
|
+
};
|
|
103
|
+
/** @typedef {import('@peasant-labs/schema').ReadAttributionState} ReadAttributionState */
|
|
104
|
+
/** @typedef {import('@peasant-labs/schema').ReadStateGrade} ReadStateGrade */
|
|
105
|
+
/** @typedef {'relevance'|'debt'|'churn'} RankMode */
|
|
106
|
+
/** @typedef {'unknown'|'none'|'reviewed'|'partial-read'|'viewed'|'no-recorded-read'} DebtState */
|
|
107
|
+
/**
|
|
108
|
+
* One node's ranking-relevant scalars. Every field is read-only input; nothing
|
|
109
|
+
* here is mutated. `lastTouchMs` and `parent` are optional client-side hints
|
|
110
|
+
* hints. An absent value means "no recency/tree-focus
|
|
111
|
+
* signal", never a fabricated 0.
|
|
112
|
+
* @typedef {object} RankInputNode
|
|
113
|
+
* @property {string} id
|
|
114
|
+
* @property {string} name
|
|
115
|
+
* @property {number} touchCount
|
|
116
|
+
* @property {number} effortDensity - 0..1
|
|
117
|
+
* @property {number} agentEditedCount
|
|
118
|
+
* @property {number} readCount
|
|
119
|
+
* @property {ReadAttributionState} readAttribution
|
|
120
|
+
* @property {ReadStateGrade} readState - composed effective read-state grade for the CURRENT content version
|
|
121
|
+
* @property {number} changedRegionCount - total changed regions (Hall)
|
|
122
|
+
* @property {number} attributedRegionCount - attributed regions (H, M)
|
|
123
|
+
* @property {number} reviewedRegionCount - reviewed-of-attributed regions (N)
|
|
124
|
+
* @property {number} [lastTouchMs]
|
|
125
|
+
* @property {string|null} [parent]
|
|
126
|
+
* @property {string|null} [recentSessionId] - the session that most recently edited this node, if known
|
|
127
|
+
*/
|
|
128
|
+
/** @typedef {{id:string, name:string, doi:number, debtState:DebtState, debt:number, coverage:number, hunkClears:boolean, scentTags:string[], hoverText:string|null}} RankedRow */
|
|
129
|
+
/** @typedef {{node:RankInputNode, intrinsic:number, debtState:DebtState, debt:number, coverage:number, hunkClears:boolean, hoverText:string|null}} IntrinsicRankedNode */
|
|
130
|
+
/** @typedef {{rankMode:RankMode, rows:IntrinsicRankedNode[], parentOf:Map<string,string|null>, maxTouch:number}} IntrinsicRanking */
|
|
131
|
+
/** DOI (degree-of-interest) term weights. Sum to 1.0 and are fixture-pinned. */
|
|
132
|
+
export const DOI_WEIGHTS: Readonly<{
|
|
133
|
+
touch: 0.35;
|
|
134
|
+
effortDensity: 0.25;
|
|
135
|
+
debt: 0.25;
|
|
136
|
+
recency: 0.15;
|
|
137
|
+
}>;
|
|
138
|
+
/** Comprehension-debt constants, declared beside DOI_WEIGHTS per the frozen contract. */
|
|
139
|
+
export const DEBT_VIEWED: 0.5;
|
|
140
|
+
export const COVERAGE_CAP: 0.9;
|
|
141
|
+
/** Recency half-life, days. */
|
|
142
|
+
export const RECENCY_HALF_LIFE_DAYS: 14;
|
|
143
|
+
/** Threshold-gating constants. */
|
|
144
|
+
export const RANK_FLOOR: 5;
|
|
145
|
+
export const RANK_CAP: 25;
|
|
146
|
+
/**
|
|
147
|
+
* The seven-member scent-tag closed set. Exhaustiveness is enforced by
|
|
148
|
+
* `code-map-ranking.yaml`'s guard: every member must have at least one
|
|
149
|
+
* derivation case, so a future eighth tag without a case reddens.
|
|
150
|
+
* @type {readonly string[]}
|
|
151
|
+
*/
|
|
152
|
+
export const SCENT_TAGS: readonly string[];
|
|
153
|
+
export type ReadAttributionState = import("@peasant-labs/schema").ReadAttributionState;
|
|
154
|
+
export type ReadStateGrade = import("@peasant-labs/schema").ReadStateGrade;
|
|
155
|
+
export type RankMode = "relevance" | "debt" | "churn";
|
|
156
|
+
export type DebtState = "unknown" | "none" | "reviewed" | "partial-read" | "viewed" | "no-recorded-read";
|
|
157
|
+
/**
|
|
158
|
+
* One node's ranking-relevant scalars. Every field is read-only input; nothing
|
|
159
|
+
* here is mutated. `lastTouchMs` and `parent` are optional client-side hints
|
|
160
|
+
* hints. An absent value means "no recency/tree-focus
|
|
161
|
+
* signal", never a fabricated 0.
|
|
162
|
+
*/
|
|
163
|
+
export type RankInputNode = {
|
|
164
|
+
id: string;
|
|
165
|
+
name: string;
|
|
166
|
+
touchCount: number;
|
|
167
|
+
/**
|
|
168
|
+
* - 0..1
|
|
169
|
+
*/
|
|
170
|
+
effortDensity: number;
|
|
171
|
+
agentEditedCount: number;
|
|
172
|
+
readCount: number;
|
|
173
|
+
readAttribution: ReadAttributionState;
|
|
174
|
+
/**
|
|
175
|
+
* - composed effective read-state grade for the CURRENT content version
|
|
176
|
+
*/
|
|
177
|
+
readState: ReadStateGrade;
|
|
178
|
+
/**
|
|
179
|
+
* - total changed regions (Hall)
|
|
180
|
+
*/
|
|
181
|
+
changedRegionCount: number;
|
|
182
|
+
/**
|
|
183
|
+
* - attributed regions (H, M)
|
|
184
|
+
*/
|
|
185
|
+
attributedRegionCount: number;
|
|
186
|
+
/**
|
|
187
|
+
* - reviewed-of-attributed regions (N)
|
|
188
|
+
*/
|
|
189
|
+
reviewedRegionCount: number;
|
|
190
|
+
lastTouchMs?: number;
|
|
191
|
+
parent?: string | null;
|
|
192
|
+
/**
|
|
193
|
+
* - the session that most recently edited this node, if known
|
|
194
|
+
*/
|
|
195
|
+
recentSessionId?: string | null;
|
|
196
|
+
};
|
|
197
|
+
export type RankedRow = {
|
|
198
|
+
id: string;
|
|
199
|
+
name: string;
|
|
200
|
+
doi: number;
|
|
201
|
+
debtState: DebtState;
|
|
202
|
+
debt: number;
|
|
203
|
+
coverage: number;
|
|
204
|
+
hunkClears: boolean;
|
|
205
|
+
scentTags: string[];
|
|
206
|
+
hoverText: string | null;
|
|
207
|
+
};
|
|
208
|
+
export type IntrinsicRankedNode = {
|
|
209
|
+
node: RankInputNode;
|
|
210
|
+
intrinsic: number;
|
|
211
|
+
debtState: DebtState;
|
|
212
|
+
debt: number;
|
|
213
|
+
coverage: number;
|
|
214
|
+
hunkClears: boolean;
|
|
215
|
+
hoverText: string | null;
|
|
216
|
+
};
|
|
217
|
+
export type IntrinsicRanking = {
|
|
218
|
+
rankMode: RankMode;
|
|
219
|
+
rows: IntrinsicRankedNode[];
|
|
220
|
+
parentOf: Map<string, string | null>;
|
|
221
|
+
maxTouch: number;
|
|
222
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fail closed at untyped JavaScript boundaries before a host interprets a timeline gesture.
|
|
3
|
+
* The accepted object shapes are exact so additions require an explicit contract change.
|
|
4
|
+
*
|
|
5
|
+
* @param {unknown} value
|
|
6
|
+
* @returns {asserts value is TimelineNavigationAction}
|
|
7
|
+
*/
|
|
8
|
+
export function assertTimelineNavigationAction(value: unknown): asserts value is TimelineNavigationAction;
|
|
9
|
+
export type TimelineNavigationAction = {
|
|
10
|
+
type: "open-change";
|
|
11
|
+
change: {
|
|
12
|
+
id: string;
|
|
13
|
+
branch: string | null;
|
|
14
|
+
};
|
|
15
|
+
} | {
|
|
16
|
+
type: "open-session";
|
|
17
|
+
sessionId: string;
|
|
18
|
+
source: {
|
|
19
|
+
kind: "commit";
|
|
20
|
+
commit: {
|
|
21
|
+
id: string;
|
|
22
|
+
branch: string | null;
|
|
23
|
+
};
|
|
24
|
+
} | {
|
|
25
|
+
kind: "unlinked";
|
|
26
|
+
} | {
|
|
27
|
+
kind: "outside-window";
|
|
28
|
+
};
|
|
29
|
+
} | {
|
|
30
|
+
type: "open-map";
|
|
31
|
+
} | {
|
|
32
|
+
type: "show-older";
|
|
33
|
+
};
|