@peasant-labs/fairtrade 0.0.7 → 0.0.10

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.
@@ -20,6 +20,10 @@
20
20
  --ic-lg: 18px;
21
21
  --bd: 1px solid var(--rule);
22
22
  --bd-strong: 1px solid var(--rule-strong);
23
+ --stroke-hairline: 1px;
24
+ --stroke-emphasis: 2px;
25
+ --focus-ring-width: 3px;
26
+ --ghost-node-size: 9px;
23
27
  --control-h: 36px;
24
28
  --control-h-sm: 28px;
25
29
  --nav-h: 56px;
@@ -570,6 +570,22 @@
570
570
  "$type": "other",
571
571
  "$value": "1px solid var(--rule-strong)"
572
572
  },
573
+ "stroke-hairline": {
574
+ "$type": "other",
575
+ "$value": "1px"
576
+ },
577
+ "stroke-emphasis": {
578
+ "$type": "other",
579
+ "$value": "2px"
580
+ },
581
+ "focus-ring-width": {
582
+ "$type": "other",
583
+ "$value": "3px"
584
+ },
585
+ "ghost-node-size": {
586
+ "$type": "other",
587
+ "$value": "9px"
588
+ },
573
589
  "dialog-w": {
574
590
  "$type": "other",
575
591
  "$value": "420px"
@@ -71,7 +71,7 @@ export function KbdChord({ label, children, className, ...rest }: {
71
71
  *
72
72
  * @param {object} props
73
73
  * @param {React.ReactNode} props.children - the tag label (sentence/case passed in is preserved; chrome is lowercased by CSS).
74
- * @param {string} [props.brand] - a provider/company name (claude, gemini, openai, cursor, opencode, or an alias).
74
+ * @param {string} [props.brand] - a provider/company name (claude, gemini, openai, cursor, opencode, strike, or an alias).
75
75
  * When the tag names a company, pass this instead of `icon`: it leads with the real brand mark, never a generic glyph.
76
76
  * @param {React.ComponentType} [props.icon] - a lucide icon component reference rendered before the label (ignored when `brand` is set).
77
77
  * @param {string} [props.dot] - a color value for the leading swatch dot (set as --tag-c).
@@ -1,14 +1,14 @@
1
1
  /**
2
2
  * resolve any accepted name/alias to a canonical mark key, or null when unknown.
3
3
  * @param {string} name
4
- * @returns {('claude'|'gemini'|'openai'|'cursor'|'opencode')|null}
4
+ * @returns {('claude'|'gemini'|'openai'|'cursor'|'opencode'|'strike')|null}
5
5
  */
6
- export function resolveBrand(name: string): ("claude" | "gemini" | "openai" | "cursor" | "opencode") | null;
6
+ export function resolveBrand(name: string): ("claude" | "gemini" | "openai" | "cursor" | "opencode" | "strike") | null;
7
7
  /**
8
8
  * BrandMark - a single-color, currentColor-tinted company/provider logo.
9
9
  *
10
10
  * @param {object} props
11
- * @param {'claude'|'gemini'|'openai'|'cursor'|'opencode'|'anthropic'|'google'|'codex'|string} props.name
11
+ * @param {'claude'|'gemini'|'openai'|'cursor'|'opencode'|'strike'|'anthropic'|'google'|'codex'|string} props.name
12
12
  * the company/product; aliases resolve (anthropic->claude, google->gemini, codex->openai).
13
13
  * @param {number} [props.size] explicit px size; omit to inherit the contextual icon-token size
14
14
  * from the `.brand` rules in src/index.css (so a mark in a chip/tag/button matches its neighbours).
@@ -18,7 +18,7 @@ export function resolveBrand(name: string): ("claude" | "gemini" | "openai" | "c
18
18
  * @returns {JSX.Element|null} null when `name` does not resolve to a known mark.
19
19
  */
20
20
  export default function BrandMark({ name, size, label, className, ...rest }: {
21
- name: "claude" | "gemini" | "openai" | "cursor" | "opencode" | "anthropic" | "google" | "codex" | string;
21
+ name: "claude" | "gemini" | "openai" | "cursor" | "opencode" | "strike" | "anthropic" | "google" | "codex" | string;
22
22
  size?: number;
23
23
  label?: string;
24
24
  className?: string;
@@ -8,7 +8,7 @@
8
8
  * @param {object} props
9
9
  * @param {ChipTone} [props.tone] - semantic tone -> .chip-ok / .chip-warn / .chip-err (default: none)
10
10
  * @param {ChipSize} [props.size] - 'sm' -> .chip-sm dense box (default: none)
11
- * @param {string} [props.brand] - a provider/company name (claude, gemini, openai, cursor, opencode, or an alias).
11
+ * @param {string} [props.brand] - a provider/company name (claude, gemini, openai, cursor, opencode, strike, or an alias).
12
12
  * When the chip names a company, pass this instead of `icon`: it leads with the real brand mark, never a generic glyph. (ignored when not resolvable)
13
13
  * @param {React.ElementType} [props.icon] - leading lucide icon component ref (e.g. icon={Hash}) (ignored when `brand` is set)
14
14
  * @param {boolean} [props.chrome=false] - mark this as a ui-chrome chip -> lowercases the label. Leave off for user content (ids, names, data values).
@@ -24,8 +24,22 @@
24
24
  * @param {() => void} [props.onShowOlder] - deprecated legacy pagination callback; use onNavigate.
25
25
  * @param {string} [props.label='commit history'] - accessible name for the list (lowercase chrome).
26
26
  * @param {string} [props.className] - extra classes appended to the root.
27
+ * @param {Array<{sessionId:string, title:string, harness?:import('@peasant-labs/schema').Harness}>} [props.sessionLanes] - the timeline's session spine gutter (the session spine gutter). Omit to keep the pre-timeline layout unchanged.
28
+ * @param {string|null} [props.hoveredSessionId] - drives the SessionLane hover state + secondary highlight weight.
29
+ * @param {string|null} [props.selectedSessionId] - drives the SessionLane selected state + primary highlight weight.
30
+ * @param {(sessionId: string|null) => void} [props.onHoverSession]
31
+ * @param {(sessionId: string) => void} [props.onSelectSession]
32
+ * @param {import('./graph/codeMapState.js').TimelineHighlight} [props.highlightSelected] - `deriveTimelineHighlight(...).selected` commit ids to render at primary (amber) weight.
33
+ * @param {import('./graph/codeMapState.js').TimelineHighlight} [props.highlightHovered] - `deriveTimelineHighlight(...).hovered` commit ids to render at secondary weight.
34
+ * @param {Record<string, Array<{ghostHash:string, subject?:string, resolution:string, method:string, confidence:string}>>} [props.ghostGroupsByCommit] - keyed by the successor commit id; each renders a `GhostGroup` row directly beneath it.
35
+ * @param {string[]|Set<string>} [props.expandedGhostGroups] - successor hashes with their ghost group open; controlled by the caller's `toggle-ghost-group` reducer state.
36
+ * @param {(successorHash: string) => void} [props.onToggleGhostGroup]
37
+ * @param {string[]|Set<string>} [props.expandedCommitSessions] - commit hashes with the `+N more` session disclosure open; controlled by the caller's `toggle-commit-sessions` reducer state.
38
+ * @param {(commitHash: string) => void} [props.onToggleCommitSessions]
39
+ * @param {Record<string, string[]>} [props.touchedFilesByCommit] - deterministically ordered file paths keyed by commit id.
40
+ * @param {(file: string) => void} [props.onOpenTouchedFile]
27
41
  */
28
- export default function CommitGraph({ commits, selectedId, onNavigate, onSelect, onOpenSession, hasMore, onShowOlder, label, className, ...rest }: {
42
+ export default function CommitGraph({ commits, selectedId, onNavigate, onSelect, onOpenSession, hasMore, onShowOlder, label, className, sessionLanes, hoveredSessionId, selectedSessionId, onHoverSession, onSelectSession, highlightSelected, highlightHovered, ghostGroupsByCommit, expandedGhostGroups, onToggleGhostGroup, expandedCommitSessions, onToggleCommitSessions, touchedFilesByCommit, onOpenTouchedFile, ...rest }: {
29
43
  commits: Commit[];
30
44
  selectedId?: string;
31
45
  onNavigate?: (action: import("./graph/timelineNavigation.js").TimelineNavigationAction) => void;
@@ -35,6 +49,30 @@ export default function CommitGraph({ commits, selectedId, onNavigate, onSelect,
35
49
  onShowOlder?: () => void;
36
50
  label?: string;
37
51
  className?: string;
52
+ sessionLanes?: Array<{
53
+ sessionId: string;
54
+ title: string;
55
+ harness?: import("@peasant-labs/schema").Harness;
56
+ }>;
57
+ hoveredSessionId?: string | null;
58
+ selectedSessionId?: string | null;
59
+ onHoverSession?: (sessionId: string | null) => void;
60
+ onSelectSession?: (sessionId: string) => void;
61
+ highlightSelected?: import("./graph/codeMapState.js").TimelineHighlight;
62
+ highlightHovered?: import("./graph/codeMapState.js").TimelineHighlight;
63
+ ghostGroupsByCommit?: Record<string, Array<{
64
+ ghostHash: string;
65
+ subject?: string;
66
+ resolution: string;
67
+ method: string;
68
+ confidence: string;
69
+ }>>;
70
+ expandedGhostGroups?: string[] | Set<string>;
71
+ onToggleGhostGroup?: (successorHash: string) => void;
72
+ expandedCommitSessions?: string[] | Set<string>;
73
+ onToggleCommitSessions?: (commitHash: string) => void;
74
+ touchedFilesByCommit?: Record<string, string[]>;
75
+ onOpenTouchedFile?: (file: string) => void;
38
76
  }): any;
39
77
  export type Commit = {
40
78
  /**
@@ -4,4 +4,4 @@
4
4
  export function formatProvider(provider: unknown): string;
5
5
  /** @param {import('@peasant-labs/schema').Harness} provider */
6
6
  export function providerLabel(provider: import("@peasant-labs/schema").Harness): string;
7
- export const PROVIDER_LABEL: Readonly<Record<"cursor" | "claude-code" | "gemini-cli" | "codex" | "opencode" | "antigravity", string>>;
7
+ export const PROVIDER_LABEL: Readonly<Record<"strike" | "cursor" | "claude-code" | "gemini-cli" | "codex" | "opencode" | "antigravity", string>>;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * @param {object} props
3
+ * @param {string} props.ghostHash
4
+ * @param {string} [props.subject] - '' when unrecorded.
5
+ * @param {RewriteResolution} props.resolution
6
+ * @param {RewriteMethod} props.method
7
+ * @param {Confidence} props.confidence
8
+ * @param {string} [props.className]
9
+ */
10
+ export default function GhostCommitNode({ ghostHash, subject, resolution, method, confidence, className, ...rest }: {
11
+ ghostHash: string;
12
+ subject?: string;
13
+ resolution: RewriteResolution;
14
+ method: RewriteMethod;
15
+ confidence: Confidence;
16
+ className?: string;
17
+ }): any;
18
+ export type RewriteResolution = "live" | "rewritten" | "unresolved";
19
+ export type RewriteMethod = "hash" | "patch_id" | "author_identity" | "message_embedded" | "temporal" | "none";
20
+ export type Confidence = "high" | "medium" | "low";
@@ -0,0 +1,21 @@
1
+ /**
2
+ * @param {object} props
3
+ * @param {string} props.successorHash
4
+ * @param {Array<{ghostHash:string, subject?:string, resolution:string, method:string, confidence:string}>} props.ghosts
5
+ * @param {boolean} props.expanded
6
+ * @param {(successorHash: string) => void} props.onToggle
7
+ * @param {string} [props.className]
8
+ */
9
+ export default function GhostGroup({ successorHash, ghosts, expanded, onToggle, className, ...rest }: {
10
+ successorHash: string;
11
+ ghosts: Array<{
12
+ ghostHash: string;
13
+ subject?: string;
14
+ resolution: string;
15
+ method: string;
16
+ confidence: string;
17
+ }>;
18
+ expanded: boolean;
19
+ onToggle: (successorHash: string) => void;
20
+ className?: string;
21
+ }): any;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @param {object} props
3
+ * @param {'primary'|'secondary'} props.weight - selection (primary) vs hover (secondary, subordinate to a lingering selection).
4
+ * @param {{x1:number, y1:number, x2:number, y2:number}} props.geometry
5
+ * @param {string} [props.className]
6
+ */
7
+ export default function HighlightEdge({ weight, geometry, className, ...rest }: {
8
+ weight: "primary" | "secondary";
9
+ geometry: {
10
+ x1: number;
11
+ y1: number;
12
+ x2: number;
13
+ y2: number;
14
+ };
15
+ className?: string;
16
+ }): any;
@@ -0,0 +1,25 @@
1
+ /** @typedef {import('@peasant-labs/schema').InsightKind} InsightKind */
2
+ /** @typedef {import('@peasant-labs/schema').InsightProvenance} InsightProvenance */
3
+ /**
4
+ * @param {object} props
5
+ * @param {Array<{kind:InsightKind, provenance:InsightProvenance, title:string, summary?:string, evidence:Array<{sessionId:string, file?:string}>, onOpenEvidence?: Function}>} props.insights
6
+ * @param {(sessionId: string) => void} [props.onOpenEvidence]
7
+ * @param {string} [props.className]
8
+ */
9
+ export default function InsightPanel({ insights, onOpenEvidence, className, ...rest }: {
10
+ insights: Array<{
11
+ kind: InsightKind;
12
+ provenance: InsightProvenance;
13
+ title: string;
14
+ summary?: string;
15
+ evidence: Array<{
16
+ sessionId: string;
17
+ file?: string;
18
+ }>;
19
+ onOpenEvidence?: Function;
20
+ }>;
21
+ onOpenEvidence?: (sessionId: string) => void;
22
+ className?: string;
23
+ }): any;
24
+ export type InsightKind = import("@peasant-labs/schema").InsightKind;
25
+ export type InsightProvenance = import("@peasant-labs/schema").InsightProvenance;
@@ -0,0 +1,13 @@
1
+ /**
2
+ * @param {object} props
3
+ * @param {'relevance'|'debt'|'churn'} props.rankMode
4
+ * @param {(rankMode: 'relevance'|'debt'|'churn') => void} props.onChange
5
+ * @param {string} [props.className]
6
+ */
7
+ export default function RankModeControl({ rankMode, onChange, className, ...rest }: {
8
+ rankMode: "relevance" | "debt" | "churn";
9
+ onChange: (rankMode: "relevance" | "debt" | "churn") => void;
10
+ className?: string;
11
+ }): any;
12
+ export { MODES as RANK_MODE_CONTROL_MODES };
13
+ declare const MODES: readonly ["relevance", "debt", "churn"];
@@ -0,0 +1,15 @@
1
+ /**
2
+ * @param {object} props
3
+ * @param {import('./ranking.js').RankedRow} props.row
4
+ * @param {number} props.loc - lines of code, feeds the reused `MapNode` size class.
5
+ * @param {boolean} [props.selected]
6
+ * @param {(id: string) => void} [props.onSelect]
7
+ * @param {string} [props.className]
8
+ */
9
+ export default function RankedRow({ row, loc, selected, onSelect, className, ...rest }: {
10
+ row: import("./ranking.js").RankedRow;
11
+ loc: number;
12
+ selected?: boolean;
13
+ onSelect?: (id: string) => void;
14
+ className?: string;
15
+ }): any;
@@ -0,0 +1,15 @@
1
+ /**
2
+ * @param {object} props
3
+ * @param {string} props.tag - a `SCENT_TAGS` member.
4
+ * @param {string} [props.hoverText] - the path-conditioned hover copy for `partial-read` rows.
5
+ * @param {boolean} [props.active] - when interactive, whether this tag is the active filter.
6
+ * @param {(tag: string|null) => void} [props.onToggle] - present -> renders as an interactive filter toggle; absent -> a plain decorative label.
7
+ * @param {string} [props.className]
8
+ */
9
+ export default function ScentTag({ tag, hoverText, active, onToggle, className, ...rest }: {
10
+ tag: string;
11
+ hoverText?: string;
12
+ active?: boolean;
13
+ onToggle?: (tag: string | null) => void;
14
+ className?: string;
15
+ }): any;
@@ -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;
@@ -15,6 +15,40 @@ export function codeMapStatesEqual(left: CodeMapState, right: CodeMapState): boo
15
15
  * @returns {CodeMapState}
16
16
  */
17
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;
18
52
  /**
19
53
  * Derives the complete navigator and canvas inputs from payload plus canonical state.
20
54
  * Returned nodes are plain public payload data; no private indexes or depths are attached.
@@ -24,7 +58,11 @@ export function reduceCodeMapState(state: CodeMapState, action: CodeMapAction):
24
58
  */
25
59
  export function deriveCodeMapView(payload: import("./types.js").CodeMapPayload | undefined | null, state: CodeMapState): CodeMapView;
26
60
  /** @typedef {import('./types.js').MapNodePayload} MapNodePayload */
27
- /** @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>}} CodeMapAction */
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
+ */
28
66
  /**
29
67
  * @typedef {object} CodeMapState
30
68
  * @property {1} version
@@ -35,6 +73,12 @@ export function deriveCodeMapView(payload: import("./types.js").CodeMapPayload |
35
73
  * @property {string} navigatorFilter
36
74
  * @property {string|null} navigatorFocusedId
37
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.
38
82
  */
39
83
  /** @typedef {{node:import('./types.js').MapNodePayload, depth:number, parentId:string|null, childIds:string[], hasChildren:boolean, canExpand:boolean, forcedOpen:boolean, expanded:boolean}} CodeMapNavigatorRow */
40
84
  /** @typedef {{orderedIds:string[], rootIds:string[], childIdsByParent:Record<string,string[]>, depthById:Record<string,number>}} CodeMapHierarchy */
@@ -50,6 +94,16 @@ export const CODE_MAP_GRAIN_DEPTH: Readonly<{
50
94
  package: 1;
51
95
  file: 1;
52
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
+ };
53
107
  export type CodeMapPresentation = "navigator" | "canvas";
54
108
  export type CodeMapGrain = "project" | "package" | "file";
55
109
  export type CodeMapViewport = {
@@ -57,7 +111,12 @@ export type CodeMapViewport = {
57
111
  panX: number;
58
112
  panY: number;
59
113
  };
114
+ export type CodeMapRankMode = "relevance" | "debt" | "churn";
60
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
+ */
61
120
  export type CodeMapAction = {
62
121
  type: "replace" | "hydrate";
63
122
  state: Partial<CodeMapState>;
@@ -89,6 +148,27 @@ export type CodeMapAction = {
89
148
  id: string;
90
149
  grain: CodeMapGrain;
91
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;
92
172
  };
93
173
  export type CodeMapState = {
94
174
  version: 1;
@@ -99,6 +179,30 @@ export type CodeMapState = {
99
179
  navigatorFilter: string;
100
180
  navigatorFocusedId: string | null;
101
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;
102
206
  };
103
207
  export type CodeMapNavigatorRow = {
104
208
  node: import("./types.js").MapNodePayload;
@@ -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
+ };
@@ -2,11 +2,25 @@ export { default as Changes } from "./Changes.jsx";
2
2
  export { default as ChangeDetail } from "./ChangeDetail.jsx";
3
3
  export { default as CodeMapNavigator } from "./CodeMapNavigator.jsx";
4
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";
5
15
  export type MapNodeKind = import("./types.js").MapNodeKind;
6
16
  export type ChangeBinding = import("./types.js").ChangeBinding;
7
17
  export type EdgeViolationKind = import("./types.js").EdgeViolationKind;
8
18
  export type FileChangeStatus = import("./types.js").FileChangeStatus;
9
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;
10
24
  export type CommitRefPayload = import("./types.js").CommitRefPayload;
11
25
  export type TimelineSessionPayload = import("./types.js").TimelineSessionPayload;
12
26
  export type MapEdgePayload = import("./types.js").MapEdgePayload;
@@ -35,10 +49,16 @@ export type CodeMapNavigatorRow = import("./codeMapState.js").CodeMapNavigatorRo
35
49
  export type CodeMapCanvasView = import("./codeMapState.js").CodeMapCanvasView;
36
50
  export type CodeMapView = import("./codeMapState.js").CodeMapView;
37
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;
38
57
  export { default as CodeMap, codeMapPayloadToMapData } from "./CodeMap.jsx";
39
58
  export { default as CodeMapComposition, DefaultMapLegend } from "./CodeMapComposition.jsx";
40
- export { CODE_MAP_STATE_VERSION, CODE_MAP_VIEWPORT_SCALE, isCodeMapViewportScale, codeMapStatesEqual, createCodeMapState, reduceCodeMapState, deriveCodeMapView } from "./codeMapState.js";
59
+ export { CODE_MAP_STATE_VERSION, CODE_MAP_VIEWPORT_SCALE, isCodeMapViewportScale, codeMapStatesEqual, createCodeMapState, reduceCodeMapState, deriveCodeMapView, deriveTimelineHighlight, resolveEscapeAction } from "./codeMapState.js";
41
60
  export { GraphAppShell, GraphSectionNav, GRAPH_APP_SECTIONS } from "../inuse/InUseShell.jsx";
42
61
  export { buildChangesGraph, humanizeAge } from "./changeGraph.js";
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";
43
63
  export { assertChangeDetailPayloadEnums, assertChangeDiffPayloadEnums, assertCodeMapPayloadEnums, MAP_NODE_KINDS, CHANGE_BINDINGS, EDGE_VIOLATION_KINDS, FILE_CHANGE_STATUSES, DIFF_LINE_KINDS } from "./types.js";
44
- export { MapNodeKind, AllMapNodeKinds, isMapNodeKind, ChangeBinding, AllChangeBindings, isChangeBinding, EdgeViolationKind, AllEdgeViolationKinds, isEdgeViolationKind, FileChangeStatus, AllFileChangeStatuses, isFileChangeStatus, DiffLineKind, AllDiffLineKinds, isDiffLineKind } from "@peasant-labs/schema";
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";