@peasant-labs/fairtrade 0.0.40 → 0.0.41

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.
Files changed (37) hide show
  1. package/THIRD_PARTY_NOTICES.md +14 -0
  2. package/dist/lib/{GraphLegend-nwqBLEcI.js → GraphLegend-CBKZsRta.js} +1259 -1399
  3. package/dist/lib/adapter-Dulh38C2.js +1214 -0
  4. package/dist/lib/commons.js +202 -201
  5. package/dist/lib/graph.js +477 -476
  6. package/dist/lib/share-fonts/AtkinsonHyperlegible-Bold.ttf +0 -0
  7. package/dist/lib/share-fonts/AtkinsonHyperlegible-Regular.ttf +0 -0
  8. package/dist/lib/share-fonts/AtkinsonHyperlegibleMono-Bold.ttf +0 -0
  9. package/dist/lib/share-fonts/AtkinsonHyperlegibleMono-Regular.ttf +0 -0
  10. package/dist/lib/share-fonts/OFL-AtkinsonHyperlegible.txt +92 -0
  11. package/dist/lib/share-fonts/OFL-AtkinsonHyperlegibleMono.txt +93 -0
  12. package/dist/lib/share.js +1311 -0
  13. package/dist/lib/time-CpVBzcqQ.js +157 -0
  14. package/dist/lib/types/BrandMark.d.ts +2 -6
  15. package/dist/lib/types/brand-geometry.d.ts +22 -0
  16. package/dist/lib/types/commons/providers.d.ts +1 -1
  17. package/dist/lib/types/share/ShareCard.d.ts +40 -0
  18. package/dist/lib/types/share/data.d.ts +54 -0
  19. package/dist/lib/types/share/fonts.d.ts +16 -0
  20. package/dist/lib/types/share/index.d.ts +5 -0
  21. package/dist/lib/types/share/marks.d.ts +23 -0
  22. package/dist/lib/types/share/metrics.d.ts +10 -0
  23. package/dist/lib/types/transcript/title.d.ts +21 -0
  24. package/dist/lib/types/ui/brand-geometry.d.ts +22 -0
  25. package/dist/lib/types/ui/format.d.ts +35 -0
  26. package/dist/lib/types/ui/provider-policy.d.ts +27 -0
  27. package/dist/lib/types/ui/transcript/adapter.d.ts +66 -0
  28. package/dist/lib/types/ui/transcript/adapter.parse.d.ts +103 -0
  29. package/dist/lib/types/ui/transcript/analytics.d.ts +213 -0
  30. package/dist/lib/types/ui/transcript/time.d.ts +47 -0
  31. package/dist/lib/types/ui/transcript/title.d.ts +84 -0
  32. package/dist/lib/types/ui/transcript/usage.d.ts +19 -0
  33. package/dist/lib/types/ui/transcript/view-model.d.ts +700 -0
  34. package/dist/lib/types/ui/transcript/wire-types.d.ts +63 -0
  35. package/dist/lib/{ui-DMUCYaeU.js → ui-Bhk29YuW.js} +3700 -4896
  36. package/dist/lib/ui.js +7 -5
  37. package/package.json +14 -4
@@ -0,0 +1,213 @@
1
+ /** @typedef {import('./wire-types.js').TurnDetail} TurnDetail */
2
+ /** @typedef {import('./wire-types.js').ToolCallDetail} ToolCallDetail */
3
+ /** @typedef {import('./wire-types.js').SessionScorecard} SessionScorecard */
4
+ /** @typedef {import('./view-model.js').PhaseVM} PhaseVM */
5
+ /** @typedef {import('./view-model.js').ScorecardBandVM} ScorecardBandVM */
6
+ /** @typedef {import('./view-model.js').AnnotationVM} AnnotationVM */
7
+ /** @typedef {import('./view-model.js').TaskGroupVM} TaskGroupVM */
8
+ /** @typedef {import('./view-model.js').TranscriptAnalyticsVM} TranscriptAnalyticsVM */
9
+ /**
10
+ * A "task" is the span from a top-level user prompt up to (but not including)
11
+ * the next one — one turn of human↔agent collaboration. The shape is the
12
+ * canonical `TaskGroup` shape, kept stable for consumer back-compat.
13
+ * @typedef {object} TaskGroup
14
+ * @property {number} startIndex display position of the starting prompt
15
+ * @property {number} endIndex display position of the last turn (inclusive)
16
+ * @property {number} promptEntryIndex wire entry index of the prompt (anchor)
17
+ * @property {number} [finalEntryIndex] wire entry index of the final assistant turn
18
+ * @property {string} prompt untruncated user prompt
19
+ * @property {number} toolCallCount
20
+ * @property {string[]} filesTouched
21
+ * @property {number} insertions
22
+ * @property {number} deletions
23
+ * @property {number} durationMs
24
+ * @property {boolean} hasErrors
25
+ * @property {number} tokens
26
+ */
27
+ /**
28
+ * Split a turn list into task groups. Each top-level (depth-0) user turn starts
29
+ * a new task; depth-1+ user turns are content blocks, NOT boundaries. A session
30
+ * that starts without a user prompt is a single task spanning everything.
31
+ * @param {TurnDetail[]} turns
32
+ * @returns {TaskGroup[]}
33
+ */
34
+ export function computeTasks(turns: TurnDetail[]): TaskGroup[];
35
+ /**
36
+ * Per-turn display labels: `"1"`, `"2"` for the prompts that open a task, and
37
+ * `"2a"`, `"2b"` for the follow-ups within it.
38
+ * @param {TurnDetail[]} turns
39
+ * @returns {string[]}
40
+ */
41
+ export function computeTurnLabels(turns: TurnDetail[]): string[];
42
+ /**
43
+ * One segment of the proportional task waterfall: a task's share of the total
44
+ * work time and the cumulative share before it (segments tile back-to-back).
45
+ * @typedef {object} WaterfallSegment
46
+ * @property {number} promptEntryIndex
47
+ * @property {number} offsetPct
48
+ * @property {number} widthPct
49
+ * @property {number} durationMs
50
+ */
51
+ /**
52
+ * Turn task groups into a relative-duration lane. When the total duration is 0
53
+ * (untimed transcript) every segment is zero-width at offset 0 — the caller
54
+ * renders the task list without bars rather than dividing by zero.
55
+ * @param {TaskGroup[]} tasks
56
+ * @returns {WaterfallSegment[]}
57
+ */
58
+ export function buildTaskWaterfall(tasks: TaskGroup[]): WaterfallSegment[];
59
+ /**
60
+ * Walk a transcript and surface error / retry / revert / subagent moments,
61
+ * sorted by display position.
62
+ * @param {TurnDetail[]} turns
63
+ * @returns {TranscriptAnnotation[]}
64
+ */
65
+ export function annotateTranscript(turns: TurnDetail[]): TranscriptAnnotation[];
66
+ /** Display label for a phase type, falling back to the raw value. @param {string} type @returns {string} */
67
+ export function phaseLabel(type: string): string;
68
+ /**
69
+ * Segment a transcript into rendered phases. `from` / `to` are WIRE turn indices
70
+ * (matching `TurnVM.index`), so a divider component can anchor by them directly.
71
+ * @param {TurnDetail[]} turns
72
+ * @returns {PhaseVM[]}
73
+ */
74
+ export function detectPhases(turns: TurnDetail[]): PhaseVM[];
75
+ /**
76
+ * Per-metric medians across the user's sessions, each field undefined when the
77
+ * sample yields no value (so the comparison line degrades rather than fabricate
78
+ * a baseline). The host supplies the sessions; the viewer never fetches them.
79
+ * @param {PersonalMedianSession[] | undefined} sessions
80
+ * @returns {PersonalMedians}
81
+ */
82
+ export function computePersonalMedians(sessions: PersonalMedianSession[] | undefined): PersonalMedians;
83
+ /**
84
+ * Derive the three scorecard axis verdict bands (token / prompt / loop
85
+ * efficiency) from the raw numeric signals. Returns `[]` when the scorecard
86
+ * carries no usable signal, so the card is omitted cleanly.
87
+ * @param {SessionScorecard | null | undefined} sc
88
+ * @param {PersonalMedians} [medians]
89
+ * @returns {ScorecardBandVM[]}
90
+ */
91
+ export function assessScorecard(sc: SessionScorecard | null | undefined, medians?: PersonalMedians): ScorecardBandVM[];
92
+ /**
93
+ * The cooked task groups for a turn list (`computeTasks` mapped onto
94
+ * `TaskGroupVM`). Exported so the adapter can populate the always-present
95
+ * `vm.tasks` from the same single computation `computeAnalytics` uses.
96
+ * @param {TurnDetail[]} turns
97
+ * @returns {TaskGroupVM[]}
98
+ */
99
+ export function computeTaskGroups(turns: TurnDetail[]): TaskGroupVM[];
100
+ /**
101
+ * Compute the cooked single-session analytics block from a (prefiltered) turn
102
+ * list. Each field is omitted when empty so the block is genuinely
103
+ * render-when-present. The adapter calls this on demand when no precomputed
104
+ * analytics is supplied, and reuses the returned `patternAnnotations` /
105
+ * `taskGroups` so nothing is derived twice.
106
+ * @param {TurnDetail[]} turns
107
+ * @param {{ scorecard?: SessionScorecard | null, medians?: PersonalMedians }} [opts]
108
+ * @returns {TranscriptAnalyticsVM}
109
+ */
110
+ export function computeAnalytics(turns: TurnDetail[], opts?: {
111
+ scorecard?: SessionScorecard | null;
112
+ medians?: PersonalMedians;
113
+ }): TranscriptAnalyticsVM;
114
+ export type TurnDetail = import("./wire-types.js").TurnDetail;
115
+ export type ToolCallDetail = import("./wire-types.js").ToolCallDetail;
116
+ export type SessionScorecard = import("./wire-types.js").SessionScorecard;
117
+ export type PhaseVM = import("./view-model.js").PhaseVM;
118
+ export type ScorecardBandVM = import("./view-model.js").ScorecardBandVM;
119
+ export type AnnotationVM = import("./view-model.js").AnnotationVM;
120
+ export type TaskGroupVM = import("./view-model.js").TaskGroupVM;
121
+ export type TranscriptAnalyticsVM = import("./view-model.js").TranscriptAnalyticsVM;
122
+ /**
123
+ * A "task" is the span from a top-level user prompt up to (but not including)
124
+ * the next one — one turn of human↔agent collaboration. The shape is the
125
+ * canonical `TaskGroup` shape, kept stable for consumer back-compat.
126
+ */
127
+ export type TaskGroup = {
128
+ /**
129
+ * display position of the starting prompt
130
+ */
131
+ startIndex: number;
132
+ /**
133
+ * display position of the last turn (inclusive)
134
+ */
135
+ endIndex: number;
136
+ /**
137
+ * wire entry index of the prompt (anchor)
138
+ */
139
+ promptEntryIndex: number;
140
+ /**
141
+ * wire entry index of the final assistant turn
142
+ */
143
+ finalEntryIndex?: number;
144
+ /**
145
+ * untruncated user prompt
146
+ */
147
+ prompt: string;
148
+ toolCallCount: number;
149
+ filesTouched: string[];
150
+ insertions: number;
151
+ deletions: number;
152
+ durationMs: number;
153
+ hasErrors: boolean;
154
+ tokens: number;
155
+ };
156
+ /**
157
+ * One segment of the proportional task waterfall: a task's share of the total
158
+ * work time and the cumulative share before it (segments tile back-to-back).
159
+ */
160
+ export type WaterfallSegment = {
161
+ promptEntryIndex: number;
162
+ offsetPct: number;
163
+ widthPct: number;
164
+ durationMs: number;
165
+ };
166
+ export type FailedAttempt = {
167
+ tools: string[];
168
+ turnRange: [number, number];
169
+ };
170
+ export type PersonalMedians = {
171
+ retryShare?: number;
172
+ specQualityScore?: number;
173
+ withinSessionReverts?: number;
174
+ };
175
+ /**
176
+ * A session sample for personal-median computation — the QualitySession subset
177
+ * the medians read. Kept structural for consumer back-compat.
178
+ */
179
+ export type PersonalMedianSession = {
180
+ totalTokens: number;
181
+ retryTokensWasted: number;
182
+ specQualityScore: number;
183
+ withinSessionReverts: number;
184
+ };
185
+ /**
186
+ * A client-side detected pattern moment. Canonical `TranscriptAnnotation` shape
187
+ * kept stable for back-compat re-export.
188
+ */
189
+ export type TranscriptAnnotation = {
190
+ /**
191
+ * display position
192
+ */
193
+ turnIndex: number;
194
+ type: "retry" | "error" | "revert" | "subagent";
195
+ label: string;
196
+ severity: "info" | "warning" | "error";
197
+ };
198
+ export type PhaseType = "planning" | "exploration" | "implementation" | "testing" | "error" | "debug" | "retry-loop" | "user-correction" | "recovery" | "abandonment";
199
+ export type PhaseSegment = {
200
+ type: PhaseType;
201
+ /**
202
+ * display position (inclusive)
203
+ */
204
+ startTurn: number;
205
+ /**
206
+ * display position (inclusive)
207
+ */
208
+ endTurn: number;
209
+ badges: {
210
+ type: PhaseType;
211
+ count: number;
212
+ }[];
213
+ };
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Is this a real recorded time? A missing, unparseable, zero, epoch or Go zero-time value
3
+ * ("0001-01-01T00:00:00Z") is unknown: nothing may render it, and no "ago" math runs on it.
4
+ *
5
+ * @param {string | null | undefined} iso
6
+ * @returns {boolean}
7
+ */
8
+ export function isKnownTime(iso: string | null | undefined): boolean;
9
+ /**
10
+ * Human-readable relative time: "just now", "3m ago", "2h ago", "4d ago"; past a week it reads as
11
+ * a date ("oct 14", or "oct 14, 2025" in another year). An unknown time reads as nothing.
12
+ *
13
+ * @param {string} iso an ISO 8601 timestamp
14
+ * @param {number} [now] reference "now" in epoch millis (defaults to `Date.now()`; pass explicitly for deterministic tests)
15
+ * @returns {string}
16
+ */
17
+ export function formatRelative(iso: string, now?: number): string;
18
+ /**
19
+ * The one duration format: human and short. "12s", "4m 30s", "4m", "1h 12m", "1h"; under a
20
+ * second "<1s"; zero, negative or unknown reads as nothing, so a caller hides the figure.
21
+ *
22
+ * @param {number | null | undefined} seconds
23
+ * @returns {string}
24
+ */
25
+ export function formatDurationSeconds(seconds: number | null | undefined): string;
26
+ /**
27
+ * A duration in minutes, in the one format: 4.5 -> "4m 30s", 76 -> "1h 16m", 0 -> "".
28
+ *
29
+ * @param {number | null | undefined} mins
30
+ * @returns {string}
31
+ */
32
+ export function formatDurationMins(mins: number | null | undefined): string;
33
+ /**
34
+ * A duration in milliseconds: a tool call reads "820ms" or "1.4s" while short, then the one
35
+ * format ("1m 15s"); zero or unknown reads as nothing.
36
+ *
37
+ * @param {number | null | undefined} ms
38
+ * @returns {string}
39
+ */
40
+ export function formatDurationMs(ms: number | null | undefined): string;
41
+ /**
42
+ * "Jan 12, 4:23 PM" — long datetime for tooltips.
43
+ *
44
+ * @param {string} iso
45
+ * @returns {string}
46
+ */
47
+ export function formatDateLong(iso: string): string;
@@ -0,0 +1,84 @@
1
+ /**
2
+ * The prompt without a harness's <user_query> wrapper: the user's own text, untouched otherwise.
3
+ * @param {string | undefined} text
4
+ * @returns {string}
5
+ */
6
+ export function unwrapUserQuery(text: string | undefined): string;
7
+ /**
8
+ * A stored session title, shown as written: the harness's <user_query> wrapper dropped and the
9
+ * whitespace collapsed, but every word, its case, its dots and an existing trailing "…" kept. For a
10
+ * title, never `summarizePrompt`, which cuts at the first sentence and recases.
11
+ * @param {string | undefined} text
12
+ * @returns {string}
13
+ */
14
+ export function cleanSessionTitle(text: string | undefined): string;
15
+ /**
16
+ * The transcript page's title, the one rule the viewer's header and the share card both use: a
17
+ * curated title (an empty one is kept), else, when the session has no normalized evidence, the
18
+ * first task's prompt or the first user turn's text, else the session id, else "transcript".
19
+ * Session titles are often a whole first prompt, so the title is bounded to 160 characters: a
20
+ * longer one is cut to 159 and "…", never through a surrogate pair.
21
+ * @param {object} parts
22
+ * @param {string} [parts.title] curated session title
23
+ * @param {boolean} [parts.hasNormalizedEvidence] true when a title must not be inferred from a prompt
24
+ * @param {string} [parts.firstTaskPrompt]
25
+ * @param {string} [parts.firstUserContent]
26
+ * @param {string} [parts.id] session id
27
+ * @returns {string}
28
+ */
29
+ export function transcriptTitle({ title, hasNormalizedEvidence, firstTaskPrompt, firstUserContent, id }: {
30
+ title?: string;
31
+ hasNormalizedEvidence?: boolean;
32
+ firstTaskPrompt?: string;
33
+ firstUserContent?: string;
34
+ id?: string;
35
+ }): string;
36
+ /**
37
+ * Produce a short, human-readable summary of a raw prompt. Heuristic, in order:
38
+ * 0. Drop a harness's <user_query> wrapper (cleanSessionTitle's rule).
39
+ * 1. Strip leading <system-reminder> blocks and leading fenced code blocks.
40
+ * 2. Pull out a <command-name> (e.g. `/mcp`) if present, keep following prose.
41
+ * 3. Strip remaining XML-ish tags, collapse whitespace, take the first sentence.
42
+ * 4. Capitalize the first letter and cap at `limit` chars with `…`.
43
+ *
44
+ * @param {string | undefined} raw
45
+ * @param {number} [limit]
46
+ * @returns {string}
47
+ */
48
+ export function summarizePrompt(raw: string | undefined, limit?: number): string;
49
+ /**
50
+ * Last path segment of a project string. `/Users/x/Projects/phaze` → `phaze`.
51
+ * Falls back to the whole string if there's no separator. Returns `''` when the
52
+ * input is empty/undefined.
53
+ *
54
+ * @param {string | undefined} project
55
+ * @returns {string}
56
+ */
57
+ export function projectLabel(project: string | undefined): string;
58
+ /**
59
+ * Compose the session detail h1.
60
+ *
61
+ * • {project}: {Summary} — project + meaningful prompt
62
+ * • {project}, {shortId} — project, no usable prompt
63
+ * • {shortId} — {Summary} — no project, but a prompt
64
+ * • Session {shortId} — nothing useful at all
65
+ *
66
+ * The full prompt text (or composed title) is returned alongside as a tooltip
67
+ * string so `<h1 title=…>` can expose the raw prompt on hover.
68
+ *
69
+ * @param {object} args
70
+ * @param {string} args.id
71
+ * @param {string | undefined} args.project
72
+ * @param {string | undefined} args.promptContent
73
+ * @param {number} [args.limit]
74
+ * @returns {{ title: string, tooltip: string }}
75
+ */
76
+ export function composeSessionTitle(args: {
77
+ id: string;
78
+ project: string | undefined;
79
+ promptContent: string | undefined;
80
+ limit?: number;
81
+ }): {
82
+ title: string;
83
+ tooltip: string;
84
+ };
@@ -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
+ }>;