@peasant-labs/fairtrade 0.0.40 → 0.0.42
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/THIRD_PARTY_NOTICES.md +14 -0
- package/dist/lib/{GraphLegend-nwqBLEcI.js → GraphLegend-CBKZsRta.js} +1259 -1399
- package/dist/lib/adapter-Dulh38C2.js +1214 -0
- package/dist/lib/commons.js +202 -201
- package/dist/lib/components.css +1 -1
- package/dist/lib/graph.js +474 -471
- package/dist/lib/share-fonts/AtkinsonHyperlegible-Bold.ttf +0 -0
- package/dist/lib/share-fonts/AtkinsonHyperlegible-Regular.ttf +0 -0
- package/dist/lib/share-fonts/AtkinsonHyperlegibleMono-Bold.ttf +0 -0
- package/dist/lib/share-fonts/AtkinsonHyperlegibleMono-Regular.ttf +0 -0
- package/dist/lib/share-fonts/OFL-AtkinsonHyperlegible.txt +92 -0
- package/dist/lib/share-fonts/OFL-AtkinsonHyperlegibleMono.txt +93 -0
- package/dist/lib/share.js +1311 -0
- package/dist/lib/time-CpVBzcqQ.js +157 -0
- package/dist/lib/types/AppSidebar.d.ts +2 -0
- package/dist/lib/types/BrandMark.d.ts +2 -6
- package/dist/lib/types/Menu.d.ts +7 -1
- package/dist/lib/types/brand-geometry.d.ts +22 -0
- package/dist/lib/types/commons/providers.d.ts +1 -1
- package/dist/lib/types/graph/CodeMapComposition.d.ts +4 -1
- package/dist/lib/types/graph/CodeMapNavigator.d.ts +5 -1
- package/dist/lib/types/share/ShareCard.d.ts +40 -0
- package/dist/lib/types/share/data.d.ts +54 -0
- package/dist/lib/types/share/fonts.d.ts +16 -0
- package/dist/lib/types/share/index.d.ts +5 -0
- package/dist/lib/types/share/marks.d.ts +23 -0
- package/dist/lib/types/share/metrics.d.ts +10 -0
- package/dist/lib/types/transcript/title.d.ts +21 -0
- package/dist/lib/types/ui/brand-geometry.d.ts +22 -0
- package/dist/lib/types/ui/format.d.ts +35 -0
- package/dist/lib/types/ui/provider-policy.d.ts +27 -0
- package/dist/lib/types/ui/transcript/adapter.d.ts +66 -0
- package/dist/lib/types/ui/transcript/adapter.parse.d.ts +103 -0
- package/dist/lib/types/ui/transcript/analytics.d.ts +213 -0
- package/dist/lib/types/ui/transcript/time.d.ts +47 -0
- package/dist/lib/types/ui/transcript/title.d.ts +84 -0
- package/dist/lib/types/ui/transcript/usage.d.ts +19 -0
- package/dist/lib/types/ui/transcript/view-model.d.ts +700 -0
- package/dist/lib/types/ui/transcript/wire-types.d.ts +63 -0
- package/dist/lib/{ui-DMUCYaeU.js → ui-BxiVcGs3.js} +3724 -4913
- package/dist/lib/ui.js +7 -5
- package/package.json +18 -6
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/** @typedef {import('./wire-types.js').ToolCallDetail} ToolCallDetail */
|
|
2
|
+
/** @typedef {import('./view-model.js').DiffLineVM} DiffLineVM */
|
|
3
|
+
/**
|
|
4
|
+
* The SOLE `JSON.parse` of a wire-encoded tool string in the lifted code. Every
|
|
5
|
+
* other parse helper here, the adapter, and the analytics util route through it,
|
|
6
|
+
* so a grep for `JSON.parse` of tool args/result yields exactly one hit. Returns
|
|
7
|
+
* `undefined` for empty or malformed input — callers degrade rather than throw.
|
|
8
|
+
*
|
|
9
|
+
* @param {string | undefined | null} raw
|
|
10
|
+
* @returns {unknown}
|
|
11
|
+
*/
|
|
12
|
+
export function parseJson(raw: string | undefined | null): unknown;
|
|
13
|
+
/**
|
|
14
|
+
* Parse a tool call's `arguments` JSON string. Thin named entry point over the
|
|
15
|
+
* one `parseJson` site; the cooked `ToolCallVM.args` is this value (shape varies
|
|
16
|
+
* by tool, hence `unknown`).
|
|
17
|
+
* @param {string | undefined | null} raw
|
|
18
|
+
* @returns {unknown}
|
|
19
|
+
*/
|
|
20
|
+
export function parseArgs(raw: string | undefined | null): unknown;
|
|
21
|
+
/**
|
|
22
|
+
* Parse a tool call's `result` JSON string. Thin named entry point over the one
|
|
23
|
+
* `parseJson` site; the cooked `ToolCallVM.output` is this value.
|
|
24
|
+
* @param {string | undefined | null} raw
|
|
25
|
+
* @returns {unknown}
|
|
26
|
+
*/
|
|
27
|
+
export function parseResult(raw: string | undefined | null): unknown;
|
|
28
|
+
/**
|
|
29
|
+
* Extract the file path a tool call targets, preferring the wire `filePath`
|
|
30
|
+
* field and falling back to the common `file_path` / `path` / `notebook_path`
|
|
31
|
+
* argument keys. Consolidates the THREE duplicate `extractPath` definitions
|
|
32
|
+
* (tasks.ts, FilesView.tsx, file-rollup.ts) into one.
|
|
33
|
+
* @param {ToolCallDetail} call
|
|
34
|
+
* @returns {string | undefined}
|
|
35
|
+
*/
|
|
36
|
+
export function extractPath(call: ToolCallDetail): string | undefined;
|
|
37
|
+
/**
|
|
38
|
+
* One old→new replacement inside an Edit / MultiEdit / NotebookEdit call.
|
|
39
|
+
* @typedef {object} EditPair
|
|
40
|
+
* @property {string} old_string
|
|
41
|
+
* @property {string} new_string
|
|
42
|
+
*/
|
|
43
|
+
/**
|
|
44
|
+
* The list of old→new replacements for an edit-family tool call: the `edits[]`
|
|
45
|
+
* array for MultiEdit, else the single `old_string` / `new_string` pair. Used by
|
|
46
|
+
* BOTH the diff-hunk builder (adapter) and the churn counter (`countDiff`), so
|
|
47
|
+
* the argument shape is parsed in exactly one place.
|
|
48
|
+
* @param {ToolCallDetail} call
|
|
49
|
+
* @returns {EditPair[]}
|
|
50
|
+
*/
|
|
51
|
+
export function editPairs(call: ToolCallDetail): EditPair[];
|
|
52
|
+
/**
|
|
53
|
+
* The full-file body a Write tool call lays down (its `content` argument).
|
|
54
|
+
* @param {ToolCallDetail} call
|
|
55
|
+
* @returns {string}
|
|
56
|
+
*/
|
|
57
|
+
export function writeContent(call: ToolCallDetail): string;
|
|
58
|
+
/**
|
|
59
|
+
* Dependency-free line diff (LCS) → cooked `DiffLineVM[]`. fairtrade ships no
|
|
60
|
+
* `diff` package, so the adapter computes hunks itself. Line numbers are 1-based
|
|
61
|
+
* within the supplied snippet (the wire carries the edit snippet, not the file
|
|
62
|
+
* offset). Deterministic — no clock/randomness — so it is screenshot-stable.
|
|
63
|
+
* @param {string} oldText
|
|
64
|
+
* @param {string} newText
|
|
65
|
+
* @returns {DiffLineVM[]}
|
|
66
|
+
*/
|
|
67
|
+
export function diffLines(oldText: string, newText: string): DiffLineVM[];
|
|
68
|
+
/**
|
|
69
|
+
* The cooked line diff of an edit-family or write tool call (one line list per replaced span) and
|
|
70
|
+
* its churn: the + and − lines of that same diff, so a rewrite of three lines counts +3 −3 and every
|
|
71
|
+
* count (the tool call, the diffs tab, a task's churn) agrees with the lines it heads. A span's
|
|
72
|
+
* trailing empty line is the newline artifact, not a line anyone wrote, so it is not counted, as the
|
|
73
|
+
* renderer does not show it. Undefined for any other kind, or an edit with no replacement. Memoised
|
|
74
|
+
* per call object, because the adapter and the analytics both ask and the line diff is quadratic in
|
|
75
|
+
* the span length.
|
|
76
|
+
* @param {ToolCallDetail} call
|
|
77
|
+
* @returns {{ spans: DiffLineVM[][], adds: number, dels: number } | undefined}
|
|
78
|
+
*/
|
|
79
|
+
export function callDiff(call: ToolCallDetail): {
|
|
80
|
+
spans: DiffLineVM[][];
|
|
81
|
+
adds: number;
|
|
82
|
+
dels: number;
|
|
83
|
+
} | undefined;
|
|
84
|
+
/**
|
|
85
|
+
* Lines inserted / removed for an edit-family or write tool call: the churn of `callDiff`, zero
|
|
86
|
+
* for any other kind. Consolidates the THREE duplicate `countDiff` definitions. Pure: depends only
|
|
87
|
+
* on the parsed arguments, never a clock or the file system.
|
|
88
|
+
* @param {ToolCallDetail} call
|
|
89
|
+
* @returns {{ adds: number, dels: number }}
|
|
90
|
+
*/
|
|
91
|
+
export function countDiff(call: ToolCallDetail): {
|
|
92
|
+
adds: number;
|
|
93
|
+
dels: number;
|
|
94
|
+
};
|
|
95
|
+
export type ToolCallDetail = import("./wire-types.js").ToolCallDetail;
|
|
96
|
+
export type DiffLineVM = import("./view-model.js").DiffLineVM;
|
|
97
|
+
/**
|
|
98
|
+
* One old→new replacement inside an Edit / MultiEdit / NotebookEdit call.
|
|
99
|
+
*/
|
|
100
|
+
export type EditPair = {
|
|
101
|
+
old_string: string;
|
|
102
|
+
new_string: string;
|
|
103
|
+
};
|
|
@@ -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
|
+
}>;
|