@peasant-labs/fairtrade 0.0.18 → 0.0.20

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/lib/graph.js CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as e, A as t, B as n, C as r, D as i, E as a, F as o, G as s, H as c, I as l, J as u, K as d, L as f, M as p, N as m, O as h, P as g, Q as _, R as v, S as y, T as b, U as x, V as S, W as C, X as w, Y as T, Z as E, _ as D, a as O, at as k, b as A, c as j, et as M, f as ee, g as N, h as P, ht as F, i as I, it as te, j as ne, k as re, m as ie, n as ae, nt as oe, o as se, ot as ce, pt as le, q as ue, r as de, rt as fe, s as pe, t as me, tt as he, ut as ge, v as L, w as _e, x as ve, xt as ye, y as be, z as xe } from "./GraphLegend-D9bZVLfT.js";
1
+ import { $ as e, A as t, B as n, C as r, D as i, E as a, F as o, G as s, H as c, I as l, J as u, K as d, L as f, M as p, N as m, O as h, P as g, Q as _, R as v, S as y, T as b, U as x, V as S, W as C, X as w, Y as T, Z as E, _ as D, a as O, at as k, b as A, c as j, et as M, f as ee, g as N, h as P, ht as F, i as I, it as te, j as ne, k as re, m as ie, n as ae, nt as oe, o as se, ot as ce, pt as le, q as ue, r as de, rt as fe, s as pe, t as me, tt as he, ut as ge, v as L, w as _e, x as ve, xt as ye, y as be, z as xe } from "./GraphLegend-BB0V2w59.js";
2
2
  import { memo as Se, useCallback as R, useEffect as z, useMemo as B, useRef as V, useState as H } from "react";
3
3
  import { Fragment as Ce, jsx as U, jsxs as W } from "react/jsx-runtime";
4
4
  import { Box as we, Check as Te, ChevronDown as Ee, ChevronRight as G, Coins as De, CornerDownRight as Oe, FileCode as ke, FileDiff as Ae, FileText as je, Folder as Me, GitMerge as Ne, Hash as Pe, Map as Fe, Maximize2 as Ie, MessageSquare as Le, Minus as Re, Plus as ze, RotateCcw as Be, RotateCw as Ve, Search as He, Share2 as Ue, Tag as We, TriangleAlert as Ge, X as Ke } from "lucide-react";
@@ -1,9 +1,9 @@
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'|'strike')|null}
4
+ * @returns {('claude'|'gemini'|'openai'|'cursor'|'opencode'|'strike'|'pi')|null}
5
5
  */
6
- export function resolveBrand(name: string): ("claude" | "gemini" | "openai" | "cursor" | "opencode" | "strike") | null;
6
+ export function resolveBrand(name: string): ("claude" | "gemini" | "openai" | "cursor" | "opencode" | "strike" | "pi") | null;
7
7
  /**
8
8
  * BrandMark - a single-color, currentColor-tinted company/provider logo.
9
9
  *
@@ -1,16 +1,26 @@
1
1
  /**
2
+ * A single checkbox - checked, unchecked, or mixed (indeterminate).
3
+ *
2
4
  * @typedef {Object} CheckboxProps
3
5
  * @property {boolean} [checked] controlled checked state (pair with onChange)
4
6
  * @property {boolean} [defaultChecked] initial state for uncontrolled use (default false)
7
+ * @property {boolean} [indeterminate] mixed state: draws a dash and reports the mixed
8
+ * accessible state while `checked` stays false (default false)
5
9
  * @property {(checked: boolean, event: import('react').ChangeEvent<HTMLInputElement>) => void} [onChange]
6
10
  * @property {boolean} [disabled] native disabled attribute (default false)
7
11
  * @property {import('react').ReactNode} [children] label text (rendered as passed, not lowercased)
8
12
  */
9
13
  /**
10
14
  * A single checkbox: <label class="check"> wrapping the styled <input type="checkbox" class="check-box">.
15
+ *
16
+ * `indeterminate` is a mixed state, distinct from checked: it renders its own dash and is exposed to
17
+ * assistive technology as `aria-checked="mixed"`, so the state is never carried by the mark alone.
18
+ * The mixed flag is not a DOM attribute on a native checkbox; it is the input's `indeterminate` IDL
19
+ * property, which is why the component owns a ref. A click on a mixed checkbox reports `true`, exactly
20
+ * as a plain unchecked checkbox would.
11
21
  * @param {CheckboxProps & import('react').InputHTMLAttributes<HTMLInputElement>} props
12
22
  */
13
- export default function Checkbox({ checked, defaultChecked, onChange, disabled, children, ...rest }: CheckboxProps & import("react").InputHTMLAttributes<HTMLInputElement>): import("react").JSX.Element;
23
+ export default function Checkbox({ checked, defaultChecked, indeterminate, onChange, disabled, children, ...rest }: CheckboxProps & import("react").InputHTMLAttributes<HTMLInputElement>): import("react").JSX.Element;
14
24
  /**
15
25
  * @typedef {Object} RadioProps
16
26
  * @property {string} name shared group name; radios must come in groups of >=2 so any one
@@ -53,6 +63,9 @@ export function Radio({ name, value, checked, defaultChecked, onChange, disabled
53
63
  * @param {RadioGroupProps & import('react').HTMLAttributes<HTMLDivElement>} props
54
64
  */
55
65
  export function RadioGroup({ name, value, defaultValue, onChange, options, ariaLabel, ...rest }: RadioGroupProps & import("react").HTMLAttributes<HTMLDivElement>): import("react").JSX.Element;
66
+ /**
67
+ * A single checkbox - checked, unchecked, or mixed (indeterminate).
68
+ */
56
69
  export type CheckboxProps = {
57
70
  /**
58
71
  * controlled checked state (pair with onChange)
@@ -62,6 +75,11 @@ export type CheckboxProps = {
62
75
  * initial state for uncontrolled use (default false)
63
76
  */
64
77
  defaultChecked?: boolean;
78
+ /**
79
+ * mixed state: draws a dash and reports the mixed
80
+ * accessible state while `checked` stays false (default false)
81
+ */
82
+ indeterminate?: boolean;
65
83
  onChange?: (checked: boolean, event: import("react").ChangeEvent<HTMLInputElement>) => void;
66
84
  /**
67
85
  * native disabled attribute (default false)
@@ -0,0 +1,226 @@
1
+ /**
2
+ * HelperGroup - a count chip inside one owner-anchored tree of saved threads.
3
+ *
4
+ * Presentation only: the host passes the complete authorized member set for the
5
+ * exact scope. No wire decoding, membership inference, fetching, paging, or
6
+ * selection storage occurs here. renderMember receives the original row,
7
+ * including its route-specific data.
8
+ *
9
+ * A helper tree is the ordinary row a host retained (`HelperGroupListItem`'s
10
+ * `owner`), the immediate groups that hang off it (`HelperGroup`), and the
11
+ * member rows those groups hold. The count chip sits ONE indent step inside the
12
+ * tree, between the owner row and the members it discloses, and carries no
13
+ * checkbox of its own. Members render only while the chip is open, each as a
14
+ * row like the owner's: title, middot facts, an individual checkbox, and
15
+ * host-authorized navigation.
16
+ *
17
+ * One continuous connector traces the centre of every MOUNTED row checkbox:
18
+ * verticals run in the parent's column, one square step lands on the deeper
19
+ * row's line, and one column is kept per depth, so a row the host never mounted
20
+ * is never traced. The connector is measured, never authored: mount,
21
+ * expand/collapse, a row that gains or loses its checkbox, and a resize all
22
+ * re-measure it.
23
+ *
24
+ * @param {object} props
25
+ * @param {string} props.groupId
26
+ * @param {string} props.memberScope - exact scope token the members belong to;
27
+ * a changed scope resets uncontrolled disclosure, never inherits it
28
+ * @param {number} props.helperThreadCount - saved threads, never review/message totals
29
+ * @param {unknown[]} [props.members]
30
+ * @param {(row: any) => import('react').ReactNode} props.renderMember
31
+ * @param {(row: any) => string} props.getMemberKey - stable local/public transcript ID
32
+ * @param {boolean} [props.expanded] - controlled disclosure for host Back restoration
33
+ * @param {(expanded: boolean) => void} [props.onExpandedChange]
34
+ * @param {boolean} [props.scopeExpired] - fail-closed: hides members, offers only
35
+ * an originating-list refresh, never loads anything broader
36
+ * @param {() => void} [props.onRefreshList] - refresh the originating query,
37
+ * never an all-members fallback
38
+ * @param {(row: any) => boolean} [props.isMemberSelected] - host-owned selection
39
+ * predicate; supply it whenever renderMember draws per-member checkboxes, so
40
+ * the CLOSED control can state a selection the viewer cannot see
41
+ * @param {import('react').ReactNode} [props.memberFooter] - host-rendered slot
42
+ * placed immediately after the member rows (or the empty notice) inside the
43
+ * open body: THE canonical position for host paging controls ("page X of Y",
44
+ * previous/next). Paging fetch, page/limit state, and the server counts stay
45
+ * host-owned; the group never fetches, stores a page, or reads a scope token,
46
+ * and renders the slot only while it is open and not scope-expired.
47
+ */
48
+ export default function HelperGroup(props: {
49
+ groupId: string;
50
+ memberScope: string;
51
+ helperThreadCount: number;
52
+ members?: unknown[];
53
+ renderMember: (row: any) => import("react").ReactNode;
54
+ getMemberKey: (row: any) => string;
55
+ expanded?: boolean;
56
+ onExpandedChange?: (expanded: boolean) => void;
57
+ scopeExpired?: boolean;
58
+ onRefreshList?: () => void;
59
+ isMemberSelected?: (row: any) => boolean;
60
+ memberFooter?: import("react").ReactNode;
61
+ }): import("react").JSX.Element;
62
+ /**
63
+ * Roll one owner row and its helper members up into the owner checkbox state.
64
+ * The owner's own row is part of the rollup, so a tree whose owner is selected
65
+ * but whose members are not states `partial`, never a clean `checked`.
66
+ * @param {string|undefined|null} ownerId
67
+ * @param {Array<string|undefined|null>} memberIds
68
+ * @param {(id: string) => boolean} isSelected
69
+ * @returns {'checked'|'unchecked'|'partial'}
70
+ */
71
+ export function helperOwnerState(ownerId: string | undefined | null, memberIds: Array<string | undefined | null>, isSelected: (id: string) => boolean): "checked" | "unchecked" | "partial";
72
+ /**
73
+ * The selection state of one helper tree: the DISPLAYED selection is the whole
74
+ * tree while the select-all override is active, and the manual set otherwise.
75
+ * Selection STATE stays host-owned; this is the value useHelperSelection stores.
76
+ * @typedef {object} HelperSelectionState
77
+ * @property {boolean} allActive - true while the select-all override is engaged
78
+ * @property {Set<string>} manual - the configured and hand-picked selection
79
+ */
80
+ /**
81
+ * The ids a tree currently DISPLAYS, owner first then members, or the manual set
82
+ * while the override is off. Ids are de-duplicated, and a missing owner (a
83
+ * helper-only result) is dropped.
84
+ * @param {HelperSelectionState} state
85
+ * @param {string|undefined|null} ownerId
86
+ * @param {Array<string|undefined|null>} memberIds
87
+ * @returns {string[]}
88
+ */
89
+ export function helperSelectionIds(state: HelperSelectionState, ownerId: string | undefined | null, memberIds: Array<string | undefined | null>): string[];
90
+ /**
91
+ * Toggle the owner checkbox: engage the all-selection from the manual side, or
92
+ * restore the manual selection from the all side. The manual set is never touched,
93
+ * so a manual member pick survives the cycle.
94
+ * @param {HelperSelectionState} state
95
+ * @returns {HelperSelectionState}
96
+ */
97
+ export function helperOwnerToggle(state: HelperSelectionState): HelperSelectionState;
98
+ /**
99
+ * Toggle one member checkbox. The write lands on the manual side and ends any
100
+ * all-selection: while the override is active the base is the DISPLAYED
101
+ * all-selection, so unticking one member keeps every other row selected and the
102
+ * next owner press restores all-but-that-member.
103
+ * @param {HelperSelectionState} state
104
+ * @param {string|undefined|null} ownerId
105
+ * @param {Array<string|undefined|null>} memberIds
106
+ * @param {string} memberId
107
+ * @param {boolean} checked
108
+ * @returns {HelperSelectionState}
109
+ */
110
+ export function helperMemberToggle(state: HelperSelectionState, ownerId: string | undefined | null, memberIds: Array<string | undefined | null>, memberId: string, checked: boolean): HelperSelectionState;
111
+ /**
112
+ * Hold the canonical helper-tree selection for one owner. The selection lives in
113
+ * the calling host, never in the components.
114
+ *
115
+ * A changed owner or member set is a different tree, so the hook resets to that
116
+ * tree's configured selection instead of carrying a pick across a scenario switch.
117
+ * @param {object} [config]
118
+ * @param {string} [config.ownerId] the tree's owner row id; omit for a
119
+ * helper-only result, where every member selects on its own
120
+ * @param {string[]} [config.memberIds] every helper member under that owner
121
+ * @param {string[]} [config.initialSelectedIds] the configured manual selection
122
+ * @returns {{selectedIds: string[], isSelected: (id: string) => boolean,
123
+ * ownerState: 'checked'|'unchecked'|'partial',
124
+ * onSelect: (id: string, checked: boolean) => void}}
125
+ */
126
+ export function useHelperSelection({ ownerId, memberIds, initialSelectedIds }?: {
127
+ ownerId?: string;
128
+ memberIds?: string[];
129
+ initialSelectedIds?: string[];
130
+ }): {
131
+ selectedIds: string[];
132
+ isSelected: (id: string) => boolean;
133
+ ownerState: "checked" | "unchecked" | "partial";
134
+ onSelect: (id: string, checked: boolean) => void;
135
+ };
136
+ /**
137
+ * One owner-anchored helper tree: an ordinary row (or an explicit unavailable
138
+ * context) above its immediate helper groups, traced by ONE measured connector.
139
+ *
140
+ * The tree owns the connector, not the rows: every mounted row registers its
141
+ * element here, the tree measures the centre of each mounted row checkbox after
142
+ * each change and on resize, and the single path is drawn behind the rows. The
143
+ * connector is a selection aid only - it carries no meaning that the rows and
144
+ * their checkboxes do not already carry.
145
+ *
146
+ * For a helper-only result supply ownerStatus instead of owner; no fake title
147
+ * or owner action is rendered. Keep distinct unresolved containers keyed by
148
+ * backend group ID.
149
+ * @param {object} props
150
+ * @param {import('react').ReactNode} [props.owner]
151
+ * @param {string} [props.ownerStatus]
152
+ * @param {import('react').ReactNode} props.children - immediate HelperGroup children
153
+ */
154
+ export function HelperGroupListItem({ owner, ownerStatus, children }: {
155
+ owner?: import("react").ReactNode;
156
+ ownerStatus?: string;
157
+ children: import("react").ReactNode;
158
+ }): import("react").JSX.Element;
159
+ /**
160
+ * One helper member drawn as the ordinary list row it is: title, a facts line
161
+ * with middot separators, an optional individual checkbox, and host-authorized
162
+ * navigation. Display-only when selection and navigation are both absent. The
163
+ * two optional behaviors are individual-only: a per-thread checkbox and
164
+ * host-authorized open navigation. No aggregate selection, no self-built links,
165
+ * no per-row disclosure. Hosts map scalar display props from their typed row and
166
+ * preserve route-specific status/usage/ordinary-child exits in children. These
167
+ * are UI props, not another wire DTO.
168
+ *
169
+ * Inside a helper tree the row registers itself so the tree can trace its
170
+ * checkbox; outside one it renders exactly as before. Because a host can turn
171
+ * selection off after mount, every render schedules a re-measure - the checkbox
172
+ * may have appeared or gone.
173
+ *
174
+ * Facts that have no measured value state that honestly ("unknown input
175
+ * submissions"), and a count of one singularizes: a row never claims "1 input
176
+ * submissions" or "1 turns". The separator falls BETWEEN facts that survive, so
177
+ * a row cannot open or end its facts line with a stray middot.
178
+ * @param {object} props
179
+ * @param {string} props.id - individual transcript identity, never a group ID
180
+ * @param {string} props.title - verbatim user content
181
+ * @param {string} [props.provider]
182
+ * @param {number} [props.inputSubmissionCount]
183
+ * @param {number} [props.turnCount]
184
+ * @param {string} [props.href] - host-created authorized route
185
+ * @param {(id: string, event: import('react').MouseEvent) => void} [props.onOpen]
186
+ * @param {boolean} [props.selected]
187
+ * @param {boolean} [props.selectionDisabled]
188
+ * @param {boolean} [props.indeterminate] - mixed state for a row that rolls
189
+ * helper members up (the tree owner); ignored without `onSelect`
190
+ * @param {(id: string, selected: boolean) => void} [props.onSelect]
191
+ * @param {import('react').ReactNode} [props.children]
192
+ */
193
+ export function HelperThreadRow({ id, title, provider, inputSubmissionCount, turnCount, href, onOpen, selected, selectionDisabled, indeterminate, onSelect, children }: {
194
+ id: string;
195
+ title: string;
196
+ provider?: string;
197
+ inputSubmissionCount?: number;
198
+ turnCount?: number;
199
+ href?: string;
200
+ onOpen?: (id: string, event: import("react").MouseEvent) => void;
201
+ selected?: boolean;
202
+ selectionDisabled?: boolean;
203
+ indeterminate?: boolean;
204
+ onSelect?: (id: string, selected: boolean) => void;
205
+ children?: import("react").ReactNode;
206
+ }): import("react").JSX.Element;
207
+ export namespace HELPER_OWNER_STATE {
208
+ let CHECKED: string;
209
+ let UNCHECKED: string;
210
+ let PARTIAL: string;
211
+ }
212
+ /**
213
+ * The selection state of one helper tree: the DISPLAYED selection is the whole
214
+ * tree while the select-all override is active, and the manual set otherwise.
215
+ * Selection STATE stays host-owned; this is the value useHelperSelection stores.
216
+ */
217
+ export type HelperSelectionState = {
218
+ /**
219
+ * - true while the select-all override is engaged
220
+ */
221
+ allActive: boolean;
222
+ /**
223
+ * - the configured and hand-picked selection
224
+ */
225
+ manual: Set<string>;
226
+ };
@@ -0,0 +1,36 @@
1
+ /**
2
+ * PromptDigest — the prompts behind a pull request, rendered read-only from the schema type.
3
+ *
4
+ * @param {object} props
5
+ * @param {PromptDigestPayload} props.digest - the digest exactly as Village computed it. the
6
+ * component renders the items it is given: it never builds, fetches, budgets, or collapses
7
+ * a chain. a collapsed chain arrives as data, its session boundary items standing in for
8
+ * the runs of prompts they hold.
9
+ * @param {(item: PromptDigestItemPayload) => string} [props.itemHref] - resolves one chain item to
10
+ * its link target; the item's `kind` selects the destination (`session` -> the transcript on
11
+ * Village, `prompt` and `skill` -> that turn in the shared transcript viewer, `commit` -> the
12
+ * commit on GitHub). omit it and the chain renders as plain rows; the component owns no routes.
13
+ * @param {PromptAuthor} [props.author] - the writer of these prompts, supplied by the page (not
14
+ * wire data). when given, every prompt row's avatar renders the writer's GitHub profile
15
+ * photo via the existing `Avatar` family; when omitted, prompt rows keep today's generic
16
+ * glyph.
17
+ * @param {string} [props.className] - extra classes appended after `.pd`
18
+ */
19
+ export default function PromptDigest({ digest, itemHref, author, className, ...rest }: {
20
+ digest: PromptDigestPayload;
21
+ itemHref?: (item: PromptDigestItemPayload) => string;
22
+ author?: PromptAuthor;
23
+ className?: string;
24
+ }): import("react").JSX.Element;
25
+ export type PromptDigestPayload = import("@peasant-labs/schema").PromptDigest;
26
+ export type PromptDigestItemPayload = import("@peasant-labs/schema").PromptDigestItem;
27
+ export type PromptAuthor = {
28
+ /**
29
+ * - the GitHub login; also the avatar's accessible name.
30
+ */
31
+ login: string;
32
+ /**
33
+ * - the GitHub profile photo url.
34
+ */
35
+ avatarUrl: string;
36
+ };
@@ -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<"strike" | "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" | "pi", string>>;
@@ -18,6 +18,7 @@ export { default as PolicySelect } from "./PolicySelect.jsx";
18
18
  export { default as MapCanvas } from "./MapCanvas.jsx";
19
19
  export { default as StepsWaterfall } from "./StepsWaterfall.jsx";
20
20
  export { default as GroupedMultiSelect } from "./GroupedMultiSelect.jsx";
21
+ export { default as PromptDigest } from "./PromptDigest.jsx";
21
22
  export { default as ToolCallRenderer } from "./ToolRenderers.jsx";
22
23
  export { default as Tour } from "./Tour.jsx";
23
24
  export { default as FacetRail } from "./FacetRail.jsx";
@@ -35,6 +36,7 @@ export { Avatar, AvatarGroup, Kbd, KbdChord, Tag } from "./Avatar.jsx";
35
36
  export { default as BrandMark, resolveBrand } from "./BrandMark.jsx";
36
37
  export { providerAccent, providerDisplayName } from "./provider-policy.js";
37
38
  export { Skeleton, Progress, Spinner, Toast, FeedbackPanel } from "./Feedback.jsx";
39
+ export { default as HelperGroup, HelperGroupListItem, HelperThreadRow, useHelperSelection, helperOwnerState, helperSelectionIds, helperOwnerToggle, helperMemberToggle, HELPER_OWNER_STATE } from "./HelperGroup.jsx";
38
40
  export { default as Timeline, TimelineItem, ToolCall, ThinkingBlock } from "./Timeline.jsx";
39
41
  export { default as ToastProvider, useToast } from "./ToastHost.jsx";
40
42
  export { default as DateRange, DateRangeCalendar, formatRange, DATE_PRESETS } from "./DateRange.jsx";
@@ -12,7 +12,7 @@ export function providerBrand(harness: Harness): ProviderBrand;
12
12
  /** @param {Harness} harness @returns {ProviderAccent} */
13
13
  export function providerAccent(harness: Harness): ProviderAccent;
14
14
  /** @typedef {import('@peasant-labs/schema').Harness} Harness */
15
- /** @typedef {'claude'|'gemini'|'openai'|'opencode'|'cursor'|'strike'} ProviderBrand */
15
+ /** @typedef {'claude'|'gemini'|'openai'|'opencode'|'cursor'|'strike'|'pi'} ProviderBrand */
16
16
  /** @typedef {'amber'|'teal'|'olive'|'mauve'|'clay'} ProviderAccent */
17
17
  /** @type {readonly Harness[]} */
18
18
  export const PROVIDER_HARNESSES: readonly Harness[];
@@ -23,5 +23,5 @@ export const PROVIDER_BRANDS: Readonly<Record<Harness, ProviderBrand>>;
23
23
  /** @type {Readonly<Record<Harness, ProviderAccent>>} */
24
24
  export const PROVIDER_ACCENTS: Readonly<Record<Harness, ProviderAccent>>;
25
25
  export type Harness = import("@peasant-labs/schema").Harness;
26
- export type ProviderBrand = "claude" | "gemini" | "openai" | "opencode" | "cursor" | "strike";
26
+ export type ProviderBrand = "claude" | "gemini" | "openai" | "opencode" | "cursor" | "strike" | "pi";
27
27
  export type ProviderAccent = "amber" | "teal" | "olive" | "mauve" | "clay";
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Current-source navigation and retained history use only cooked evidence.
3
+ * No parent fetch occurs when a reader opens an earlier section.
4
+ * @param {object} props
5
+ * @param {import('./view-model.js').RelationshipVM[]} [props.relationships]
6
+ * @param {import('./view-model.js').EarlierHistoryVM[]} [props.earlierHistory]
7
+ * @param {import('./state-capabilities.js').ViewerCallbacks['onNavigateRelationship']} [props.onNavigate]
8
+ * @param {Record<string, boolean>} props.open
9
+ * @param {(id: string) => void} props.toggle
10
+ * @param {Record<string, boolean>} props.openTools
11
+ * @param {(id: string) => void} props.toggleTool
12
+ */
13
+ export default function TranscriptContext({ relationships, earlierHistory, onNavigate, open, toggle, openTools, toggleTool }: {
14
+ relationships?: import("./view-model.js").RelationshipVM[];
15
+ earlierHistory?: import("./view-model.js").EarlierHistoryVM[];
16
+ onNavigate?: import("./state-capabilities.js").ViewerCallbacks["onNavigateRelationship"];
17
+ open: Record<string, boolean>;
18
+ toggle: (id: string) => void;
19
+ openTools: Record<string, boolean>;
20
+ toggleTool: (id: string) => void;
21
+ }): import("react").JSX.Element;
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * @param {TranscriptViewerProps} props
3
3
  */
4
- export default function TranscriptViewer({ viewModel, capabilities, callbacks, theme: themeProp, onThemeChange, graphSlot, activeTab: activeTabProp, onTabChange, viewMode: viewModeProp, onViewModeChange, leftRailOpen: leftRailOpenProp, onLeftRailOpenChange, rightRailOpen: rightRailOpenProp, onRightRailOpenChange, openTools: openToolsProp, onOpenToolsChange, initialPosition: initialPositionProp, activeTurn: activeTurnProp, onActiveTurnChange, search: searchProp, onSearchChange, filters: filtersProp, onFiltersChange, savedLabels: savedLabelsProp, onSavedLabelsChange, shareOpen: shareOpenProp, onShareOpenChange, moreOpen: moreOpenProp, onMoreOpenChange, breadcrumb, LinkComponent, renderTurnPanel, renderTurnActions, anchorHref, headerActions, streamPrelude, }: TranscriptViewerProps): import("react").JSX.Element;
4
+ export default function TranscriptViewer({ viewModel, capabilities, callbacks, theme: themeProp, onThemeChange, graphSlot, activeTab: activeTabProp, onTabChange, viewMode: viewModeProp, onViewModeChange, leftRailOpen: leftRailOpenProp, onLeftRailOpenChange, rightRailOpen: rightRailOpenProp, onRightRailOpenChange, openTools: openToolsProp, onOpenToolsChange, earlierHistoryOpen: earlierHistoryOpenProp, onEarlierHistoryOpenChange, initialPosition: initialPositionProp, activeTurn: activeTurnProp, onActiveTurnChange, search: searchProp, onSearchChange, filters: filtersProp, onFiltersChange, savedLabels: savedLabelsProp, onSavedLabelsChange, shareOpen: shareOpenProp, onShareOpenChange, moreOpen: moreOpenProp, onMoreOpenChange, breadcrumb, LinkComponent, renderTurnPanel, renderTurnActions, anchorHref, headerActions, streamPrelude, }: TranscriptViewerProps): import("react").JSX.Element;
5
5
  export type TranscriptViewerProps = import("./state-capabilities.js").TranscriptViewerProps;
6
6
  export type TranscriptFilters = import("./state-capabilities.js").TranscriptFilters;
7
7
  export type TraceReadingSnapshot = {
@@ -0,0 +1,9 @@
1
+ /** @param {{usage?: import('@peasant-labs/schema').UsageDetail}} props */
2
+ export default function UsageDisclosure({ usage }: {
3
+ usage?: import("@peasant-labs/schema").UsageDetail;
4
+ }): import("react").JSX.Element;
5
+ /** @param {{scopes?: import('./view-model.js').UsageScopeVM[], label?: string}} props */
6
+ export function UsageScopes({ scopes, label }: {
7
+ scopes?: import("./view-model.js").UsageScopeVM[];
8
+ label?: string;
9
+ }): import("react").JSX.Element;
@@ -1,8 +1,8 @@
1
1
  /**
2
- * Default turn prefilter the adapter applies to `payload.turns`: drop turns with
3
- * neither content nor tool calls (and short tool-less system banners), then
4
- * collapse adjacent same-role turns with identical content (a streaming
5
- * artifact), preferring the tool-bearing copy. Pure, order-preserving. Exported
2
+ * Default turn prefilter the adapter applies independently per partition:
3
+ * preserve normalized evidence, including unknown provenance and folded refs.
4
+ * Only truly legacy rows lose empty/short banners or collapse equal adjacent
5
+ * content, preferring the tool-bearing copy. Pure, order-preserving. Exported
6
6
  * so a host that pre-scopes turns can run the SAME filter.
7
7
  * @param {TurnDetail[]} turns
8
8
  * @returns {TurnDetail[]}
@@ -59,4 +59,8 @@ export type AdaptTranscriptOptions = {
59
59
  * post-resolution projection by canonical turn index
60
60
  */
61
61
  visibleTurnIndices?: readonly number[];
62
+ /**
63
+ * separately authorized read metadata; never durable content
64
+ */
65
+ relationshipNavigation?: import("@peasant-labs/schema").SessionRelationshipNavigation[];
62
66
  };
@@ -9,8 +9,7 @@
9
9
  /**
10
10
  * A "task" is the span from a top-level user prompt up to (but not including)
11
11
  * the next one — one turn of human↔agent collaboration. The shape is the
12
- * canonical `TaskGroup` the transcript-browser already exports, kept stable for
13
- * back-compat re-export.
12
+ * canonical `TaskGroup` shape, kept stable for consumer back-compat.
14
13
  * @typedef {object} TaskGroup
15
14
  * @property {number} startIndex display position of the starting prompt
16
15
  * @property {number} endIndex display position of the last turn (inclusive)
@@ -123,8 +122,7 @@ export type TranscriptAnalyticsVM = import("./view-model.js").TranscriptAnalytic
123
122
  /**
124
123
  * A "task" is the span from a top-level user prompt up to (but not including)
125
124
  * the next one — one turn of human↔agent collaboration. The shape is the
126
- * canonical `TaskGroup` the transcript-browser already exports, kept stable for
127
- * back-compat re-export.
125
+ * canonical `TaskGroup` shape, kept stable for consumer back-compat.
128
126
  */
129
127
  export type TaskGroup = {
130
128
  /**
@@ -176,8 +174,7 @@ export type PersonalMedians = {
176
174
  };
177
175
  /**
178
176
  * A session sample for personal-median computation — the QualitySession subset
179
- * the medians read. Kept structural so the transcript-browser `QualitySession`
180
- * is assignable for back-compat.
177
+ * the medians read. Kept structural for consumer back-compat.
181
178
  */
182
179
  export type PersonalMedianSession = {
183
180
  totalTokens: number;
@@ -49,6 +49,9 @@ export type Theme = import("./state-capabilities.js").Theme;
49
49
  export type TranscriptTab = import("./state-capabilities.js").TranscriptTab;
50
50
  export type ViewMode = import("./state-capabilities.js").ViewMode;
51
51
  export type TranscriptViewModel = import("./view-model.js").TranscriptViewModel;
52
+ export type RelationshipVM = import("./view-model.js").RelationshipVM;
53
+ export type EarlierHistoryVM = import("./view-model.js").EarlierHistoryVM;
54
+ export type AdaptTranscriptOptions = import("./adapter.js").AdaptTranscriptOptions;
52
55
  export type SessionVM = import("./view-model.js").SessionVM;
53
56
  export type SessionGitVM = import("./view-model.js").SessionGitVM;
54
57
  export type CommitVM = import("./view-model.js").CommitVM;
@@ -79,6 +79,8 @@ export type ViewerCapabilities = {
79
79
  * capability is true (see ViewerCapabilities). `onLabel` carries the popover's
80
80
  * cooked result; `onExport` carries the requested format. The viewer never
81
81
  * mutates the host's data — it reports intent through these.
82
+ * Relationship navigation is gated by authorized read evidence rather than a
83
+ * mutation capability; no usable target or no callback means no active control.
82
84
  */
83
85
  export type ViewerCallbacks = {
84
86
  onEdit?: () => void;
@@ -87,11 +89,16 @@ export type ViewerCallbacks = {
87
89
  onCopyLink?: () => void;
88
90
  onChangeVisibility?: () => void;
89
91
  onExport?: (format: "json" | "jsonl" | "markdown") => void;
92
+ /**
93
+ * authorized read target only; host owns current route and Back restoration
94
+ */
95
+ onNavigateRelationship?: (navigation: import("@peasant-labs/schema").SessionRelationshipNavigation) => void;
90
96
  };
91
97
  /**
92
98
  * What the `graphSlot` render-prop receives. The composite owns NO graph engine
93
99
  * (no `@xyflow` dependency); in `viewMode: 'graph'` it hands the consumer this
94
- * cooked context and renders whatever the consumer returns (transcript-browser plugs its
100
+ * cooked context and renders whatever the consumer returns (a consuming app plugs
101
+ * fairtrade's own `/graph`
95
102
  */
96
103
  export type GraphSlotContext = {
97
104
  viewModel: import("./view-model.js").TranscriptViewModel;
@@ -150,6 +157,14 @@ export type TranscriptViewerProps = {
150
157
  */
151
158
  openTools?: Record<string, boolean>;
152
159
  onOpenToolsChange?: (openTools: Record<string, boolean>) => void;
160
+ /**
161
+ * section id to disclosure state, default closed
162
+ */
163
+ earlierHistoryOpen?: Record<string, boolean>;
164
+ /**
165
+ * persist with host route state for Back
166
+ */
167
+ onEarlierHistoryOpenChange?: (open: Record<string, boolean>) => void;
153
168
  /**
154
169
  * one-time position; null clears, and session/target/requestKey changes rearm
155
170
  */
@@ -0,0 +1,19 @@
1
+ /** @param {import('@peasant-labs/schema').TurnDetail[]} turns
2
+ * @returns {import('./view-model.js').UsageScopeVM[]} */
3
+ export function aggregateUsage(turns: import("@peasant-labs/schema").TurnDetail[]): import("./view-model.js").UsageScopeVM[];
4
+ export const TOKEN_FIELDS: Readonly<{
5
+ input: "input";
6
+ output: "output";
7
+ cacheRead: "cache read";
8
+ cacheWrite: "cache write";
9
+ cacheWrite1h: "cache write 1h (subset)";
10
+ reasoning: "reasoning (subset)";
11
+ totalTokens: "total tokens";
12
+ }>;
13
+ export const COST_FIELDS: Readonly<{
14
+ input: "input";
15
+ output: "output";
16
+ cacheRead: "cache read";
17
+ cacheWrite: "cache write";
18
+ total: "total";
19
+ }>;