@letpeoplework/lighthouse-client 1.8.1 → 1.9.0

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/index.d.ts CHANGED
@@ -1,191 +1,1340 @@
1
- type ClientCapability = "versioned-api-contracts" | "shared-domain-operations" | "connectivity-and-discovery-contracts" | "automation-auth-contracts";
2
- type ClientPackageContract = {
3
- readonly name: "@letpeoplework/lighthouse-client";
4
- readonly capabilities: readonly ClientCapability[];
5
- };
6
- declare const getClientPackageContract: () => ClientPackageContract;
7
- type ConnectivityCategory = "success" | "unreachable" | "misconfigured" | "unauthorized" | "dependency-failure" | "concurrency-conflict" | "unexpected";
8
- type StandaloneDiscoveryContract = {
9
- readonly contractVersion: 1;
10
- readonly lighthouseUrl: string;
11
- readonly detectedAtUtc: string;
12
- };
13
- type StandaloneDiscoveryContractParseResult = {
14
- readonly isValid: true;
15
- readonly contract: StandaloneDiscoveryContract;
1
+ //#region src/usageData.d.ts
2
+ /** Where a usage event came from, as Lighthouse names it. A client only ever declares its own. */
3
+ export type UsageDataSource = "Browser" | "Cli" | "Mcp";
4
+ export type ClientUsageDataSource = Exclude<UsageDataSource, "Browser">;
5
+ /** The usage events a client reports that carry nothing but their name. */
6
+ export type PlainUsageDataEventName = "TeamCreated" | "TeamDeleted" | "PortfolioCreated" | "PortfolioDeleted" | "TeamManualForecastRun" | "TeamRefreshTriggered" | "PortfolioRefreshTriggered";
7
+ /** The usage events that say when, relative to the Team's Refinement, a vote was cast. */
8
+ export type SizingUsageDataEventName = "TeamSizingVoteCast" | "TeamSizingReadinessReached";
9
+ /** The usage event that says which verdict a Team's Refinement showed on its Refinement day. */
10
+ export type VerdictUsageDataEventName = "TeamRefinementDayVerdictShown";
11
+ /** The usage events a client reports, by the names Lighthouse already counts for the web. */
12
+ export type UsageDataEventName = PlainUsageDataEventName | SizingUsageDataEventName | VerdictUsageDataEventName;
13
+ /** Fewer Work Items ready than needed, enough, more than enough, or no number at all. */
14
+ export type UsageDataRefinementVerdict = "Below" | "In" | "Above" | "None";
15
+ export type UsageDataSizingMoment = "NoCadence" | "OnRefinementDay" | "OnOtherDay";
16
+ /** Something a person did that is worth counting: names and values from closed lists, never free text. */
17
+ export type UsageDataOccurrence = {
18
+ readonly name: PlainUsageDataEventName;
16
19
  } | {
17
- readonly isValid: false;
18
- readonly reason: string;
20
+ readonly name: SizingUsageDataEventName;
21
+ readonly sizingMoment: UsageDataSizingMoment;
22
+ } | {
23
+ readonly name: VerdictUsageDataEventName;
24
+ readonly refinementVerdict: UsageDataRefinementVerdict;
25
+ };
26
+ /** What Lighthouse's answer about a Team's Refinement says about today. */
27
+ export type RefinementMomentFacts = {
28
+ readonly nextRefinementDate: string | null;
29
+ readonly isRefinementDay: boolean;
30
+ };
31
+ /**
32
+ * When a vote was cast, from Lighthouse's answer rather than this machine's clock: Lighthouse counts days in
33
+ * the instance's time zone and knows which cadence days are blacked out. The web counts it the same way.
34
+ */
35
+ export declare const sizingMomentOf: ({ nextRefinementDate, isRefinementDay }: RefinementMomentFacts) => UsageDataSizingMoment;
36
+ /** What Lighthouse's answer about a Team's Refinement says about today's verdict. */
37
+ export type RefinementDayFacts = {
38
+ readonly isRefinementDay: boolean;
39
+ readonly workItemsListed: number;
40
+ readonly verdict: "Below" | "In" | "Above" | null;
41
+ };
42
+ /**
43
+ * The verdict worth counting, or null when there is none: only a Refinement day with Work Items listed
44
+ * counts, since without any the Refinement says so instead of showing a verdict. The web counts it the same way.
45
+ */
46
+ export declare const refinementDayVerdictOf: ({ isRefinementDay, workItemsListed, verdict }: RefinementDayFacts) => UsageDataRefinementVerdict | null;
47
+ export type UsageDataEvent = UsageDataOccurrence & {
48
+ readonly offsetMs: number;
49
+ readonly sequence: number;
19
50
  };
20
- type LighthouseConnectionConfiguration = {
21
- readonly kind: "explicit";
22
- readonly lighthouseUrl: string;
51
+ export type UsageDataBatch = {
52
+ readonly source: ClientUsageDataSource;
53
+ readonly events: readonly UsageDataEvent[];
54
+ };
55
+ /** What Lighthouse says about usage data from this client; `acceptedSources` is null on a server that predates it. */
56
+ export type UsageDataState = {
57
+ readonly decision: string | null;
58
+ readonly mayAsk: boolean;
59
+ readonly administratorDisabled: boolean;
60
+ readonly acceptedSources: readonly string[] | null;
61
+ };
62
+ /** The answer a person gave for one Lighthouse. */
63
+ export type StoredUsageDataAnswer = {
64
+ readonly answer: "yes";
65
+ readonly token: string;
66
+ readonly confirmedAt: string;
23
67
  } | {
24
- readonly kind: "standalone";
25
- readonly getDiscoveryContract: () => Promise<StandaloneDiscoveryContract | null>;
26
- };
27
- type ConnectivityFetchResponse = {
28
- readonly ok: boolean;
29
- readonly status: number;
30
- readonly text: () => Promise<string>;
31
- readonly json?: () => Promise<unknown>;
32
- };
33
- type ConnectivityDependencies = {
34
- readonly fetch: (url: string, init?: RequestInit) => Promise<ConnectivityFetchResponse>;
35
- };
36
- type ResolvedLighthouseEndpoint = {
37
- readonly mode: "explicit" | "standalone";
38
- readonly lighthouseUrl: string;
39
- readonly apiBaseUrl: string;
40
- readonly healthCheckUrl: string;
41
- };
42
- type ConnectivityValidationResult = {
43
- readonly category: "success";
44
- readonly endpoint: ResolvedLighthouseEndpoint;
45
- readonly serverVersion: string;
68
+ readonly answer: "no";
69
+ readonly decidedAt: string;
70
+ };
71
+ /** Lighthouse's state answer, or null when it is not one. */
72
+ export declare const readUsageDataState: (json: unknown) => UsageDataState | null;
73
+ /** A stored answer, or null when the value is not one. */
74
+ export declare const readStoredUsageDataAnswer: (value: unknown) => StoredUsageDataAnswer | null;
75
+ /**
76
+ * `DO_NOT_TRACK` asks every tool to send nothing. Set to anything but empty, `0` or `false` (any case), it is
77
+ * honoured.
78
+ */
79
+ export declare const isDoNotTrackSet: (env: Readonly<Record<string, string | undefined>>) => boolean;
80
+ /** Which of a command line's three streams are terminals. */
81
+ export type TerminalStreams = {
82
+ readonly stdinIsTTY: boolean;
83
+ readonly stdoutIsTTY: boolean;
84
+ readonly stderrIsTTY: boolean;
85
+ };
86
+ /**
87
+ * A question needs a person: one who can type (stdin), sees the answer (stdout) and the question (stderr),
88
+ * and is not a build agent behind a pseudo-terminal (`CI` set to anything).
89
+ */
90
+ export declare const isAPersonAtTheTerminal: (streams: TerminalStreams, env: Readonly<Record<string, string | undefined>>) => boolean;
91
+ export type UsageDataStepFacts = {
92
+ readonly doNotTrack: boolean;
93
+ /** The answer kept for this Lighthouse: undefined when never asked there. */
94
+ readonly stored: StoredUsageDataAnswer | undefined | "unreadable";
95
+ /** Lighthouse's state: not read yet, or could not be read. */
96
+ readonly state: UsageDataState | "unread" | "unavailable";
97
+ readonly source: ClientUsageDataSource;
98
+ /** Whether a person is there to be asked. */
99
+ readonly mayPrompt: boolean;
100
+ /** Whether the command reached Lighthouse and succeeded. */
101
+ readonly reached: boolean;
102
+ readonly occurrences: readonly UsageDataOccurrence[];
103
+ readonly now: Date;
104
+ };
105
+ export type UsageDataPlan = {
106
+ readonly kind: "nothing";
46
107
  } | {
47
- readonly category: Exclude<ConnectivityCategory, "success">;
48
- readonly reason: string;
49
- readonly statusCode?: number;
50
- readonly endpoint?: ResolvedLighthouseEndpoint;
51
- };
52
- declare const parseStandaloneDiscoveryContract: (serializedContract: string) => StandaloneDiscoveryContractParseResult;
53
- declare const getStandaloneDiscoveryLockfilePath: () => string;
54
- declare const loadStandaloneDiscoveryContract: () => Promise<StandaloneDiscoveryContract | null>;
55
- declare const validateLighthouseConnectivity: (configuration: LighthouseConnectionConfiguration, dependencies: ConnectivityDependencies, requestInit?: RequestInit) => Promise<ConnectivityValidationResult>;
56
- type LighthouseClientAuth = {
57
- readonly kind: "none";
108
+ readonly kind: "read-state";
109
+ readonly token: string | undefined;
58
110
  } | {
59
- readonly kind: "api-key";
60
- readonly value: string;
61
- readonly headerName?: string;
111
+ readonly kind: "ask";
62
112
  } | {
63
- readonly kind: "bearer-token";
64
- readonly token: string;
113
+ readonly kind: "send";
114
+ readonly token: string;
115
+ readonly batch: UsageDataBatch;
116
+ /** Lighthouse has just confirmed the grant, so it is kept as confirmed now. */
117
+ readonly reconfirmed: boolean;
118
+ } | {
119
+ readonly kind: "re-grant-then-send";
120
+ readonly formerToken: string;
121
+ readonly batch: UsageDataBatch;
122
+ };
123
+ /** What to do about usage data after a command, decided from facts alone. */
124
+ export declare const planUsageDataStep: (facts: UsageDataStepFacts) => UsageDataPlan;
125
+ //#endregion
126
+ //#region src/terminology.d.ts
127
+ /** Every word an instance may rename under Settings → Terminology, by its key. */
128
+ export type TerminologyKey = "workItem" | "workItems" | "feature" | "features" | "cycleTime" | "throughput" | "workInProgress" | "wip" | "workItemAge" | "tag" | "workTrackingSystem" | "workTrackingSystems" | "blocked" | "serviceLevelExpectation" | "sle" | "team" | "teams" | "portfolio" | "portfolios" | "delivery" | "deliveries" | "refinement" | "refinements";
129
+ /** The instance's word for every configurable term. */
130
+ export type Terms = Readonly<Record<TerminologyKey, string>>;
131
+ /** The words a new Lighthouse instance starts with, as its seeder writes them. */
132
+ export declare const SEEDED_TERMS: Terms;
133
+ /**
134
+ * The instance's words, a blank or missing one falling back to its entry's default, then the seeded word, as on
135
+ * the web. A value that is not text at all falls back the same way, so a view never prints a number or an object
136
+ * where a word belongs.
137
+ */
138
+ export declare const resolveTerms: (entries: readonly TerminologyEntry[] | null) => Terms;
139
+ export type TermsSource = Pick<LighthouseClient, "getTerminology">;
140
+ /** The instance's words; when they cannot be read the seeded ones stand in, so this never fails. */
141
+ export declare const readTerms: (source: TermsSource) => Promise<Terms>;
142
+ //#endregion
143
+ //#region src/answerWording.d.ts
144
+ type Read$1 = {
145
+ readonly ok: true;
146
+ readonly value: unknown;
147
+ } | {
148
+ readonly ok: false;
149
+ readonly error: unknown;
150
+ };
151
+ /** What an answer is said with: the instance's words and the name of what it is about. */
152
+ export type AnswerWording = {
153
+ readonly terms: Terms;
154
+ readonly name: string;
155
+ };
156
+ /** What an answer is about: the term for its kind, its id, and the read that names it. */
157
+ export type AnswerSubject = {
158
+ readonly term: TerminologyKey;
159
+ readonly id: number;
160
+ readonly read: () => Promise<Read$1>;
161
+ };
162
+ /** The subject's name, or its term and id when the name cannot be had: "Team [id: 3]". */
163
+ export declare const nameOrFallback: (read: Read$1, subject: Pick<AnswerSubject, "term" | "id">, terms: Terms) => string;
164
+ /**
165
+ * Reads the instance's words and the subject's name together. Neither read can fail the answer: the
166
+ * seeded words and the term with the id stand in, because a heading is never worth an error.
167
+ */
168
+ export declare const readAnswerWording: (source: TermsSource, subject: AnswerSubject) => Promise<AnswerWording>;
169
+ /**
170
+ * The words for an answer about one Feature, named by its reference and name. The answer itself never
171
+ * carries the name, so it is read from the Feature.
172
+ */
173
+ export declare const readFeatureWording: (source: TermsSource & {
174
+ readonly getFeaturesByIds: (ids: readonly number[]) => Promise<Read$1>;
175
+ }, featureId: number) => Promise<AnswerWording>;
176
+ //#endregion
177
+ //#region src/calendarDates.d.ts
178
+ export declare const isCalendarDay: (value: string | null) => boolean;
179
+ /** "2026-10-30" or "2026-10-30T00:00:00Z" as "Fri 30 Oct 2026", whatever the reader's time zone; null for no such day. */
180
+ export declare const formatCalendarDay: (wire: string) => string | null;
181
+ /** A moment as "Tue 6 Oct 2026, 07:14" on the reader's own clock; null when it is not a moment. */
182
+ export declare const formatTimestamp: (wire: string) => string | null;
183
+ //#endregion
184
+ //#region src/deliveryWording.d.ts
185
+ /** One Delivery as its card's header states it. Facts an older Lighthouse may not send stay undefined. */
186
+ export type DeliveryListItem = {
187
+ readonly id: number;
188
+ readonly name: string;
189
+ readonly date: string;
190
+ readonly featureCount: number | undefined;
191
+ readonly totalWork: number;
192
+ readonly remainingWork: number;
193
+ readonly likelihood: number | null;
194
+ readonly cannotBeForecast: boolean;
195
+ readonly hasSufficientData: boolean | undefined;
196
+ readonly isOverdue: boolean | undefined;
197
+ readonly likelyBy: string | undefined;
198
+ };
199
+ /** The Portfolio whose Deliveries are listed; its name stays undefined when it could not be read. */
200
+ export type DeliveryListOwner = {
201
+ readonly id: number;
202
+ readonly name: string | undefined;
65
203
  };
66
- type StoredLighthouseAuth = Exclude<LighthouseClientAuth, {
67
- kind: "none";
204
+ /**
205
+ * Every Delivery in the list, or null when the answer is not a list or any one of them comes without its
206
+ * id, name, date or work: a row that cannot say what it is or when it is due would misstate the list.
207
+ */
208
+ export declare const readDeliveryList: (value: unknown) => DeliveryListItem[] | null;
209
+ /** "Ocean Explorer · Deliveries", or the Portfolio by its id when its name could not be read. */
210
+ export declare const describeDeliveryListTitle: (owner: DeliveryListOwner, terms: Terms) => string;
211
+ /** What a Portfolio without any Delivery shows instead of the table. */
212
+ export declare const describeNoDeliveries: (terms: Terms) => string;
213
+ /** How many Deliveries the list holds, in the instance's words: "No Deliveries", "1 Delivery", "4 Deliveries". */
214
+ export declare const describeDeliveryCount: (count: number, terms: Terms) => string;
215
+ /** The list's column headings: the card's header facts, its four forecast chances narrowed to the 85% one. */
216
+ export declare const describeDeliveryListHeadings: (terms: Terms) => string[];
217
+ /** How much of the Delivery's work is done: "34 of 55 Work Items". */
218
+ export declare const describeDeliveryDone: (delivery: Pick<DeliveryListItem, "totalWork" | "remainingWork">, terms: Terms) => string;
219
+ /** The card's likelihood answer: "78%", ">95%", "Overdue", "Not enough data", "Cannot forecast". */
220
+ export declare const describeDeliveryLikelihood: (delivery: DeliveryListItem) => string;
221
+ /** One Delivery as a row of the list, in the order of its headings. */
222
+ export declare const describeDeliveryRow: (delivery: DeliveryListItem, terms: Terms) => string[];
223
+ /**
224
+ * A Delivery's recorded days, or null when the answer lacks its Delivery Date or any day lacks a fact its
225
+ * row or detail states: a table with a hole in it would misstate the trend.
226
+ */
227
+ export declare const readDeliveryMetricsHistory: (value: unknown) => DeliveryMetricsHistory | null;
228
+ /** The most recent recorded day, whatever order the days arrive in; undefined when none is recorded. */
229
+ export declare const latestRecordedDay: (history: DeliveryMetricsHistory) => DeliveryMetricsHistoryPoint | undefined;
230
+ /**
231
+ * "Delivery [id: 11] · Delivery Date Tue 15 Dec 2026 · recorded since Tue 15 Sep 2026". The read carries no
232
+ * Delivery name, so its id stands in; the last part is left out until a first day is recorded.
233
+ */
234
+ export declare const describeDeliveryMetricsHeading: (history: DeliveryMetricsHistory, deliveryId: number, terms: Terms) => string;
235
+ /** The day-by-day table's column headings. */
236
+ export declare const describeRecordedDayHeadings: (terms: Terms) => string[];
237
+ /** One recorded day as a row, in the order of its headings. */
238
+ export declare const describeRecordedDayRow: (day: DeliveryMetricsHistoryPoint) => string[];
239
+ /** The title over one day's detail: "On Tue 6 Oct 2026". */
240
+ export declare const describeRecordedDayTitle: (day: DeliveryMetricsHistoryPoint) => string;
241
+ /** The per-Feature table's column headings, as the web's Feature grid names them. */
242
+ export declare const describeDeliveryFeatureHeadings: (terms: Terms) => string[];
243
+ /** One Feature as it stood that day, in the order of its headings. */
244
+ export declare const describeDeliveryFeatureRow: (feature: DeliveryFeatureMetric) => string[];
245
+ /** The forecast distribution's column headings. */
246
+ export declare const describeDeliveryChanceHeadings: () => string[];
247
+ /** One chance of the day's forecast: "85%" and the day it is that likely to be done by. */
248
+ export declare const describeDeliveryChanceRow: (chance: DeliveryWhenDistributionPoint) => string[];
249
+ //#endregion
250
+ //#region src/featureWording.d.ts
251
+ /** When work on a Feature begins, as the server decided it: observed, forecast, or not known. */
252
+ export type FeatureStart = {
253
+ readonly observedOn: string | undefined;
254
+ readonly likelyBy: string | undefined;
255
+ };
256
+ /** One Feature as a row of the Feature list states it. */
257
+ export type FeatureListItem = {
258
+ readonly referenceId: string;
259
+ readonly name: string;
260
+ readonly state: string;
261
+ readonly totalWork: number;
262
+ readonly remainingWork: number;
263
+ readonly cannotBeForecast: boolean;
264
+ readonly start: FeatureStart;
265
+ readonly likelyBy: string | undefined;
266
+ };
267
+ /**
268
+ * Every Feature in the answer, or null when it is not a list or any one of them comes without its
269
+ * reference, name, state or per-Team work: a row that cannot say how far along it is would misstate the list.
270
+ */
271
+ export declare const readFeatureList: (value: unknown) => FeatureListItem[] | null;
272
+ /** How many Features the answer holds, in the instance's words: "No Features", "1 Feature", "3 Features". */
273
+ export declare const describeFeatureListCount: (count: number, terms: Terms) => string;
274
+ /** The Feature list's column headings, narrowed to the 85% chance of its completion forecast. */
275
+ export declare const describeFeatureListHeadings: (terms: Terms) => string[];
276
+ /** How much of the Feature's work is done, over every Team: "8 of 13 Work Items". */
277
+ export declare const describeFeatureProgress: (feature: Pick<FeatureListItem, "totalWork" | "remainingWork">, terms: Terms) => string;
278
+ /**
279
+ * When work begins, as the web's Feature list says it. A day work already began is a fact, so it outranks a
280
+ * Team without history; that Team only stops anyone saying when work will begin.
281
+ */
282
+ export declare const describeFeatureStart: (feature: Pick<FeatureListItem, "start" | "cannotBeForecast">) => string;
283
+ /** The day the Feature is 85% likely to be done by, "Cannot forecast", or the mark when none was sent. */
284
+ export declare const describeFeatureCompletion: (feature: Pick<FeatureListItem, "likelyBy" | "cannotBeForecast">) => string;
285
+ /** One Feature as a row of the list, in the order of its headings. */
286
+ export declare const describeFeatureRow: (feature: FeatureListItem, terms: Terms) => string[];
287
+ /** One Work Item of a Feature as the Feature's Work Items list states it. */
288
+ export type FeatureWorkItem = {
289
+ readonly referenceId: string;
290
+ readonly name: string;
291
+ readonly type: string;
292
+ readonly state: string;
293
+ };
294
+ /** Every Work Item in the answer, or null when it is not a list or any one lacks its reference, name, type or state. */
295
+ export declare const readFeatureWorkItems: (value: unknown) => FeatureWorkItem[] | null;
296
+ /**
297
+ * The first Feature of an answer as a heading names it, its reference before its name:
298
+ * "OE-002 Deep-sea camera stream". Undefined when the answer holds no named Feature.
299
+ */
300
+ export declare const describeFeatureTitle: (value: unknown) => string | undefined;
301
+ /** "OE-002 Deep-sea camera stream · 3 Work Items", named by whatever stands in for the Feature. */
302
+ export declare const describeFeatureWorkItemsHeading: (featureName: string, count: number, terms: Terms) => string;
303
+ /** The column headings of a Feature's Work Items. */
304
+ export declare const describeFeatureWorkItemHeadings: () => string[];
305
+ /** One Work Item as a row of the list, in the order of its headings. */
306
+ export declare const describeFeatureWorkItemRow: (item: FeatureWorkItem) => string[];
307
+ //#endregion
308
+ //#region src/forecastDisplayRules.d.ts
309
+ export type ForecastLevelName = "Certain" | "Confident" | "Realistic" | "Risky";
310
+ export type LikelihoodPrecision = "round" | "fixed2";
311
+ export declare const CANNOT_FORECAST_SHORT = "Cannot forecast";
312
+ export declare const INSUFFICIENT_FORECAST_DATA_SHORT = "Not enough data";
313
+ export declare const INSUFFICIENT_FORECAST_DATA_SENTENCE = "Not enough data yet — need at least 5 days with completed items to forecast.";
314
+ export declare const levelOf: (chance: number | null) => ForecastLevelName | null;
315
+ export declare const formatLikelihood: (value: number, options: {
316
+ readonly hasRemainingWork: boolean;
317
+ readonly precision: LikelihoodPrecision;
318
+ }) => string;
319
+ export declare const likelihoodAnswer: (facts: {
320
+ readonly likelihood: number | null;
321
+ readonly cannotBeForecast: boolean;
322
+ readonly hasRemainingWork: boolean;
323
+ readonly hasSufficientData?: boolean;
324
+ readonly precision: LikelihoodPrecision;
325
+ }) => string;
326
+ export declare const OVERDUE_SHORT = "Overdue";
327
+ /**
328
+ * A Delivery card's answer: its likelihood, or "Overdue" once its date has passed. Overdue says more than a
329
+ * number for a date already gone, but not more than "Cannot forecast", so the web shows both of those.
330
+ */
331
+ export declare const deliveryLikelihoodAnswer: (facts: Parameters<typeof likelihoodAnswer>[0] & {
332
+ readonly isOverdue?: boolean;
333
+ }) => string;
334
+ //#endregion
335
+ //#region src/forecastWording.d.ts
336
+ /** One row of the When table: the chance of being done by a calendar day. */
337
+ export type ForecastChanceByDay = {
338
+ readonly probability: number;
339
+ readonly expectedDate: string;
340
+ };
341
+ /** One row of the How Many table: the chance of getting this many done. */
342
+ export type ForecastChanceOfCount = {
343
+ readonly probability: number;
344
+ readonly value: number;
345
+ };
346
+ /** The manual forecast as the Forecast tab states it. */
347
+ export type ManualForecastView = {
348
+ readonly remainingItems: number;
349
+ readonly targetDate: string | null;
350
+ readonly likelihood: number | null;
351
+ readonly whenForecasts: readonly ForecastChanceByDay[];
352
+ readonly howManyForecasts: readonly ForecastChanceOfCount[];
353
+ readonly filterApplied: boolean | undefined;
354
+ readonly hasSufficientData: boolean | undefined;
355
+ };
356
+ /** The manual forecast's facts, or null when one it cannot be stated without is missing or mistyped. */
357
+ export declare const readManualForecast: (value: unknown) => ManualForecastView | null;
358
+ /** "Gravity · 25 Work Items · target Fri 30 Oct 2026", naming the filtered Throughput when it was used. */
359
+ export declare const describeManualForecastSummary: (forecast: ManualForecastView, wording: AnswerWording) => string;
360
+ /** The When table's title, or null when there is no When table to show. */
361
+ export declare const describeWhenTitle: (forecast: ManualForecastView, wording: AnswerWording) => string | null;
362
+ /** The How Many table's title, or null when there is no How Many table to show. */
363
+ export declare const describeHowManyTitle: (forecast: ManualForecastView, wording: AnswerWording) => string | null;
364
+ /**
365
+ * "Likelihood to close 25 Work Items by Fri 30 Oct 2026: 48.20%", or why there is no number. Only a
366
+ * forecast asked both how many and by when has a likelihood to state.
367
+ */
368
+ export declare const describeManualForecastLikelihood: (forecast: ManualForecastView, wording: AnswerWording) => string | null;
369
+ /** The backtest as Backtest Results states it: the forecast percentiles for a past period and what was actually done. */
370
+ export type BacktestView = {
371
+ readonly startDate: string;
372
+ readonly endDate: string;
373
+ readonly historicalStartDate: string;
374
+ readonly historicalEndDate: string;
375
+ readonly percentiles: readonly ForecastChanceOfCount[];
376
+ readonly actualThroughput: number;
377
+ };
378
+ /** The backtest's facts, or null when one it cannot be stated without is missing or mistyped. */
379
+ export declare const readBacktest: (value: unknown) => BacktestView | null;
380
+ /**
381
+ * The percentiles lowest chance first, split where the actual falls, as the chart's dashed line sits
382
+ * among the bars. An actual equal to a percentile goes after it: that percentile was reached.
383
+ */
384
+ export declare const placeActualAmongPercentiles: ({ percentiles, actualThroughput }: Pick<BacktestView, "percentiles" | "actualThroughput">) => {
385
+ readonly above: ForecastChanceOfCount[];
386
+ readonly below: ForecastChanceOfCount[];
387
+ };
388
+ /** "Gravity · Backtest Results". */
389
+ export declare const describeBacktestSummary: (wording: AnswerWording) => string;
390
+ /** "Period: Tue 1 Sep 2026 to Wed 30 Sep 2026 (historical data: Wed 1 Jul 2026 to Mon 31 Aug 2026)". */
391
+ export declare const describeBacktestPeriod: (backtest: BacktestView) => string;
392
+ /** "Actual Throughput: 21 Work Items". */
393
+ export declare const describeBacktestActual: (backtest: BacktestView, wording: AnswerWording) => string;
394
+ //#endregion
395
+ //#region src/housekeepingWording.d.ts
396
+ /**
397
+ * Every recurring blackout rule in the list, or null when the answer is not a list or any one of them
398
+ * lacks the schedule Lighthouse words for it.
399
+ */
400
+ export declare const readBlackoutRules: (value: unknown) => RecurringBlackoutRule[] | null;
401
+ /** The list's title, as the settings page heads it. */
402
+ export declare const BLACKOUT_RULE_LIST_TITLE = "Recurring blackout rules";
403
+ /** The list's column headings, as the settings page heads them. */
404
+ export declare const BLACKOUT_RULE_LIST_HEADINGS: readonly ["Schedule", "Description"];
405
+ /** How many rules there are: "No recurring blackout rules", "1 recurring blackout rule", "2 recurring blackout rules". */
406
+ export declare const describeBlackoutRuleCount: (count: number) => string;
407
+ /** What the list says when there is nothing in it. */
408
+ export declare const describeNoBlackoutRules: () => string;
409
+ /** A rule's schedule cell: its id, then Lighthouse's own summary of the schedule, word for word. */
410
+ export declare const describeBlackoutRuleSchedule: ({ id, summary }: Pick<RecurringBlackoutRule, "id" | "summary">) => string;
411
+ /** "Lighthouse v26.10.3.6", as the footer shows it, or null when the answer is not a version. */
412
+ export declare const describeVersion: (value: unknown) => string | null;
413
+ /** The sentence a successful health check answers with, naming the Lighthouse it reached. */
414
+ export declare const describeReachable: (connection: CliConnection) => string;
415
+ /** What a successful health check says when it does not know which endpoint it reached. */
416
+ export declare const LIGHTHOUSE_IS_REACHABLE = "Lighthouse is reachable.";
417
+ /** One Work Tracking System connection as the Overview lists it. */
418
+ export type WorkTrackingConnectionListItem = {
419
+ readonly id: number;
420
+ readonly name: string;
421
+ readonly workTrackingSystem: string;
422
+ };
423
+ /** One option of a connection, labelled as the editor labels it; a secret carries no value at all. */
424
+ export type WorkTrackingConnectionOption = {
425
+ readonly label: string;
426
+ readonly isSecret: true;
427
+ } | {
428
+ readonly label: string;
429
+ readonly isSecret: false;
430
+ readonly value: string;
431
+ };
432
+ export type WorkTrackingConnectionDetails = WorkTrackingConnectionListItem & {
433
+ readonly options: readonly WorkTrackingConnectionOption[];
434
+ };
435
+ /** Every connection in the list, or null when the answer is not a list or any one of them lacks its name or type. */
436
+ export declare const readWorkTrackingConnections: (value: unknown) => WorkTrackingConnectionListItem[] | null;
437
+ /**
438
+ * One connection with its options labelled as the editor labels them, or null when it arrives without its
439
+ * options or any option lacks its key or its secret flag.
440
+ */
441
+ export declare const readWorkTrackingConnection: (value: unknown) => WorkTrackingConnectionDetails | null;
442
+ /**
443
+ * A copy of a connection, or a list of them, with every option value that is not known to be safe to show
444
+ * replaced by the secret stand-in. Only an option that says it is not secret, and that its authentication
445
+ * method does not declare secret, keeps its value: a server that sends a shape lh does not recognise has
446
+ * already shown it cannot be trusted to flag its secrets.
447
+ */
448
+ export declare const hideConnectionSecrets: (value: unknown) => unknown;
449
+ /** The list's column headings, as the Overview heads them. */
450
+ export declare const WORK_TRACKING_CONNECTION_LIST_HEADINGS: readonly ["Name", "Type"];
451
+ /** The option table's column headings. */
452
+ export declare const WORK_TRACKING_OPTION_HEADINGS: readonly ["Option", "Value"];
453
+ /** What stands in for a secret's value, which is never shown. */
454
+ export declare const SECRET_NOT_SHOWN = "(secret, not shown)";
455
+ /** A connection by name with its id beside it: "Letpeoplework Jira [id: 1]". */
456
+ export declare const describeConnectionName: ({ id, name }: Pick<WorkTrackingConnectionListItem, "id" | "name">) => string;
457
+ /** "Type: Jira". */
458
+ export declare const describeConnectionType: ({ workTrackingSystem }: Pick<WorkTrackingConnectionListItem, "workTrackingSystem">) => string;
459
+ /** An option's value cell; a secret's reads the same whatever Lighthouse sent. */
460
+ export declare const describeOptionValue: (option: WorkTrackingConnectionOption) => string;
461
+ /** How many connections there are, in the instance's words: "No Work Tracking Systems", "1 Work Tracking System". */
462
+ export declare const describeWorkTrackingSystemCount: (count: number, terms: Terms) => string;
463
+ /**
464
+ * A connection named with its type, or null when it lacks either. It is built from the name and type alone,
465
+ * so no option's value can ever reach it.
466
+ */
467
+ export declare const describeConnectionSummary: (value: unknown) => string | null;
468
+ //#endregion
469
+ //#region src/metricsWording.d.ts
470
+ type Facts = Readonly<Record<string, unknown>>;
471
+ /** A metric Lighthouse would not answer, in the words the command reports it with. */
472
+ export type MetricRefusal = {
473
+ readonly refused: string;
474
+ };
475
+ /** A metric's view, or why Lighthouse would not give it. */
476
+ export type MetricAnswer<T> = T | MetricRefusal;
477
+ export declare const isMetricRefusal: (value: unknown) => value is MetricRefusal;
478
+ /** The metric's view, its refusal, or null when it is in a shape no reader knows. */
479
+ export declare const readMetricAnswer: <T>(value: unknown, read: (value: unknown) => T | null) => MetricAnswer<T> | null;
480
+ export type MetricsScope = "team" | "portfolio";
481
+ /** What the metrics composite is about: whose metrics, and over which days. */
482
+ export type MetricsSubject = {
483
+ readonly scope: MetricsScope;
484
+ readonly id: number;
485
+ readonly startDate: string;
486
+ readonly endDate: string;
487
+ readonly sections: Facts;
488
+ };
489
+ export declare const readMetricsSubject: (value: unknown) => MetricsSubject | null;
490
+ export type DailyCount = {
491
+ readonly date: string;
492
+ readonly count: number;
493
+ };
494
+ /** Throughput or Arrivals: the total over the range and the count of each day. */
495
+ export type DailyCountChartView = {
496
+ readonly startDate: string;
497
+ readonly endDate: string;
498
+ readonly total: number;
499
+ readonly daily: readonly DailyCount[];
500
+ };
501
+ type DailyCountsView = Omit<DailyCountChartView, "total">;
502
+ declare const readDailyCountChart: (value: unknown) => DailyCountChartView | null;
503
+ export declare const readThroughput: typeof readDailyCountChart;
504
+ export declare const readArrivals: typeof readDailyCountChart;
505
+ /**
506
+ * A run chart as Lighthouse sends it, the Work Items counted on each day keyed by the day's offset from the
507
+ * range's first day, read as the total and the count of each day. Without a total the days are summed.
508
+ */
509
+ export declare const readRunChart: (value: unknown, range: MetricsDateRange) => DailyCountChartView | null;
510
+ /** A Work Item in progress; an older Lighthouse does not say whether it is blocked. */
511
+ export type InProgressItem = {
512
+ readonly isBlocked: boolean | undefined;
513
+ readonly referenceId?: string;
514
+ readonly name?: string;
515
+ readonly state?: string;
516
+ readonly workItemAge?: number;
517
+ readonly blockedSince?: string;
518
+ };
519
+ export type InProgressNowView = {
520
+ readonly asOfDate: string;
521
+ readonly count: number;
522
+ readonly items: readonly InProgressItem[];
523
+ };
524
+ export type WipView = {
525
+ readonly current: MetricAnswer<InProgressNowView>;
526
+ readonly overTime: MetricAnswer<DailyCountsView>;
527
+ };
528
+ /** What is in progress on a day, read from the bare list of Work Items the server answers with. */
529
+ export declare const readInProgressItems: (value: unknown, asOfDate: string) => InProgressNowView | null;
530
+ export declare const readWip: (value: unknown) => WipView | null;
531
+ export type PercentileValue = {
532
+ readonly percentile: number;
533
+ readonly value: number;
534
+ };
535
+ declare const readPercentileValues: (value: unknown) => readonly PercentileValue[] | null;
536
+ export type ClosedItem = {
537
+ readonly id: number;
538
+ readonly name: string;
539
+ readonly referenceId?: string;
540
+ readonly closedDate?: string;
541
+ readonly cycleTime?: number;
542
+ };
543
+ export type CycleTimeView = {
544
+ readonly percentiles: MetricAnswer<readonly PercentileValue[]>;
545
+ readonly closedItems: MetricAnswer<readonly ClosedItem[]>;
546
+ };
547
+ export declare const readCycleTime: (value: unknown) => CycleTimeView | null;
548
+ export declare const readWorkItemAgePercentiles: typeof readPercentileValues;
549
+ export declare const readCycleTimePercentiles: typeof readPercentileValues;
550
+ export declare const readWorkItemAge: (value: unknown) => WorkItemAgeOverTimeResult | null;
551
+ export declare const readTotalWorkItemAge: (value: unknown) => TotalWorkItemAgeOverTimeResult | null;
552
+ /** The score, absent when Lighthouse sent none. */
553
+ export type PredictabilityScoreView = {
554
+ readonly score: number | undefined;
555
+ };
556
+ export declare const readPredictabilityScore: (value: unknown) => PredictabilityScoreView | null;
557
+ /** A recorded history over the range, one entry per recorded day. */
558
+ export type MetricHistoryView<T> = {
559
+ readonly startDate: string;
560
+ readonly endDate: string;
561
+ readonly history: readonly T[];
562
+ };
563
+ export declare const readBlocked: (value: unknown) => MetricHistoryView<BlockedCountSnapshot> | null;
564
+ /** The percentiles' history and how many days back each day's percentiles look, when Lighthouse says. */
565
+ export type PercentilesOverTimeView = MetricHistoryView<PercentilesOverTimeSnapshot> & {
566
+ readonly horizon: number | undefined;
567
+ };
568
+ export declare const readPercentilesOverTime: (value: unknown) => PercentilesOverTimeView | null;
569
+ export declare const readProcessBehaviorOverTime: (value: unknown) => MetricHistoryView<ProcessBehaviorSnapshot> | null;
570
+ declare const readStates: (value: unknown) => CumulativeStateTimeResult | null;
571
+ declare const readContributors: (value: unknown) => CumulativeStateTimeItemsResult | null;
572
+ /** Time in State's bar on its own, as one read answers it. */
573
+ export declare const readTimeInStateBar: typeof readStates;
574
+ /** The Work Items contributing to one state of Time in State, as one read answers them. */
575
+ export declare const readTimeInStateContributors: typeof readContributors;
576
+ /** Time in State: the bar, the Work Items it can be narrowed to, and one state's contributors when one was asked for. */
577
+ export type CumulativeStateTimeView = {
578
+ readonly bar: MetricAnswer<CumulativeStateTimeResult>;
579
+ readonly candidates: MetricAnswer<CumulativeStateTimeCandidatesResult>;
580
+ readonly items: MetricAnswer<CumulativeStateTimeItemsResult> | undefined;
581
+ };
582
+ export declare const readCumulativeStateTime: (value: unknown) => CumulativeStateTimeView | null;
583
+ /** The Team's or Portfolio's System WIP Limit; absent when none is set, as the web leaves it out. */
584
+ export declare const readSystemWipLimit: (value: unknown) => number | undefined;
585
+ /** The name of the Team's cycle time definition with this id; absent when the settings do not carry it. */
586
+ export declare const readCycleTimeDefinitionName: (settings: unknown, definitionId: number) => string | undefined;
587
+ /** One line of the headline: what it is, its number, and what the number is out of. */
588
+ export type MetricLine = {
589
+ readonly label: string;
590
+ readonly value: string;
591
+ readonly detail: string;
592
+ };
593
+ export declare const UNKNOWN_SHAPE_NOTE = "shown only with --json (unknown shape)";
594
+ /** What the dashboard says under its Predictability Score, word for word. */
595
+ export declare const PREDICTABILITY_SCORE_EXPLANATION = "The predictability score shows how \"close\" the 50% and 95% chance are. The closer they are, the more predictable you are. 100% means they are exactly the same value. The higher number, the better.";
596
+ /** What an empty over-time chart says on the web. */
597
+ export declare const OVER_TIME_EMPTY_SENTENCE = "Nothing to show for the selected range. Days appear here as Lighthouse records them.";
598
+ /** Every part of the headline that can be refused or unreadable on its own. */
599
+ export type MetricsHeadlinePart = "wip" | "throughput" | "arrivals" | "blocked" | "totalWorkItemAge" | "predictabilityScore" | "cycleTimePercentiles" | "workItemAgePercentiles" | "workItemAge" | "cumulativeStateTime" | "percentilesOverTime" | "processBehaviorOverTime";
600
+ /** "1 day", "12 days". */
601
+ export declare const describeDays: (days: number) => string;
602
+ /** The label each part of the headline goes by, in the instance's words. */
603
+ export declare const metricsHeadlineLabel: (part: MetricsHeadlinePart, scope: MetricsScope, terms: Terms) => string;
604
+ /** A part Lighthouse refused, its reason in the number's place. */
605
+ export declare const describeRefusedMetric: (label: string, refusal: MetricRefusal) => MetricLine;
606
+ /** A part in a shape this version cannot read: the facts are still in --json. */
607
+ export declare const describeUnknownMetric: (label: string) => MetricLine;
608
+ /** How many days a range covers, both ends included. */
609
+ export declare const daysInRange: (startDate: string, endDate: string) => number;
610
+ /** "Gravity · Mon 7 Sep 2026 – Tue 6 Oct 2026 (30 days)". */
611
+ export declare const describeMetricsHeading: (subject: Pick<MetricsSubject, "startDate" | "endDate">, wording: AnswerWording) => string;
612
+ /** "Gravity · as of Tue 6 Oct 2026", for a metric that answers about the range's last day. */
613
+ export declare const describeAsOfHeading: (subject: Pick<MetricsSubject, "endDate">, wording: AnswerWording) => string;
614
+ /** "Work Items in Progress 9 System WIP Limit: 10 Work Items", the limit left out when none is set. */
615
+ export declare const describeInProgressNow: (now: InProgressNowView, scope: MetricsScope, terms: Terms, systemWipLimit: number | undefined) => MetricLine;
616
+ /** "Blocked Work Items 2", or null when Lighthouse does not say which items are blocked. */
617
+ export declare const describeBlockedNow: (now: InProgressNowView, scope: MetricsScope, terms: Terms) => MetricLine | null;
618
+ /**
619
+ * The sentences that stand in for what a WIP answer cannot show: no System WIP Limit, a Lighthouse that does
620
+ * not say which Work Items are Blocked (which is not the same as none being Blocked), and nothing in progress.
621
+ * A limit of null means the Team or Portfolio could not be read; it may well have one, so nothing is said.
622
+ */
623
+ export declare const describeWhatWipLeavesUnsaid: (now: InProgressNowView, scope: MetricsScope, terms: Terms, systemWipLimit: number | undefined | null) => readonly string[];
624
+ /** "Total Throughput 31 1.0 / day". */
625
+ export declare const describeTotalThroughput: (chart: DailyCountChartView, scope: MetricsScope, terms: Terms) => MetricLine;
626
+ /** "Total Arrivals 28 0.9 / day". */
627
+ export declare const describeTotalArrivals: (chart: DailyCountChartView, scope: MetricsScope, terms: Terms) => MetricLine;
628
+ /** "Total Work Item Age 84 days across 9 Work Items", as on the last recorded day. */
629
+ export declare const describeTotalWorkItemAge: (view: TotalWorkItemAgeOverTimeResult, scope: MetricsScope, terms: Terms) => MetricLine;
630
+ /** "Predictability Score 63.4%", as the web shows it to one decimal. */
631
+ export declare const describePredictabilityScore: (view: PredictabilityScoreView, scope: MetricsScope, terms: Terms) => MetricLine;
632
+ /** "95th", "1st", "22nd". */
633
+ export declare const ordinalOf: (value: number) => string;
634
+ /**
635
+ * The percentile table's rows, header first and the highest percentile next, Cycle Time beside Work Item
636
+ * Age; a side that has no value for a percentile reads "—". Empty when neither side can be shown.
637
+ */
638
+ export declare const describePercentileRows: (cycleTime: readonly PercentileValue[] | undefined, workItemAge: readonly PercentileValue[] | undefined, terms: Terms) => readonly (readonly string[])[];
639
+ /** "Over time (one row per recorded day: lh metrics team --id 3 --metrics <name>)". */
640
+ export declare const describeOverTimeHeading: (subject: Pick<MetricsSubject, "scope" | "id">) => string;
641
+ /** "Cycle Time 85th percentile 14 days on Mon 7 Sep → 12 days on Tue 6 Oct 29 days recorded". */
642
+ export declare const describePercentilesOverTime: (view: MetricHistoryView<PercentilesOverTimeSnapshot>, scope: MetricsScope, terms: Terms) => MetricLine;
643
+ /** "Throughput process limits 0 – 3.1 / day, average 1.0, on Tue 6 Oct 29 days recorded", as on the last recorded day. */
644
+ export declare const describeProcessBehaviorOverTime: (view: MetricHistoryView<ProcessBehaviorSnapshot>, scope: MetricsScope, terms: Terms) => MetricLine;
645
+ /** "Blocked Work Items 1 on Mon 7 Sep → 2 on Tue 6 Oct 30 days recorded". */
646
+ export declare const describeBlockedOverTime: (view: MetricHistoryView<BlockedCountSnapshot>, scope: MetricsScope, terms: Terms) => MetricLine;
647
+ /**
648
+ * One metric over its days: the sentence that answers it, its day table with the header row first, and
649
+ * the web's empty-chart sentence in place of a table when Lighthouse has recorded no day. A metric the
650
+ * dashboard shows as more than one table lists them in order, and one with only a sentence lists none.
651
+ */
652
+ export type MetricDayView = {
653
+ readonly sentence: string;
654
+ } & (MetricDays | {
655
+ readonly tables: readonly MetricDays[];
656
+ });
657
+ /** A table, or the sentence that stands in for it, with the title the dashboard puts above it, if any. */
658
+ export type MetricDays = {
659
+ readonly title?: string;
660
+ } & ({
661
+ readonly rows: readonly (readonly string[])[];
662
+ } | {
663
+ readonly note: string;
664
+ });
665
+ /** "Total Throughput: 31 Work Items, 1.0 / day", then the count closed on each day. */
666
+ export declare const describeThroughputDays: (chart: DailyCountChartView, scope: MetricsScope, terms: Terms) => MetricDayView;
667
+ /** "Total Arrivals: 28 Work Items, 0.9 / day", then the count started on each day. */
668
+ export declare const describeArrivalsDays: (chart: DailyCountChartView, scope: MetricsScope, terms: Terms) => MetricDayView;
669
+ /**
670
+ * "Work Items in Progress: 9 (System WIP Limit: 10 Work Items)", then each Work Item in progress, oldest
671
+ * first, and the count in progress on each day.
672
+ */
673
+ export declare const describeWipDays: (now: InProgressNowView, overTime: DailyCountsView, scope: MetricsScope, terms: Terms, systemWipLimit: number | undefined) => MetricDayView;
674
+ /** "Cycle Time Percentiles: 50th 5 days · … · 95th 21 days", then each closed Work Item and its Cycle Time. */
675
+ export declare const describeCycleTimeDays: (percentiles: readonly PercentileValue[], closedItems: readonly ClosedItem[], terms: Terms, definitionName?: string) => MetricDayView;
676
+ /** "Work Item Age Percentiles: 50th 3 days · 70th 6 days · 85th 11 days · 95th 18 days". */
677
+ export declare const describeWorkItemAgePercentiles: (percentiles: readonly PercentileValue[], terms: Terms) => string;
678
+ /**
679
+ * "Work Item Age Percentiles: 50th 3 days · … · 95th 18 days", then each day's oldest Work Item and how
680
+ * many were in progress; every item of a day is in --json.
681
+ */
682
+ export declare const describeWorkItemAgeDays: (percentiles: readonly PercentileValue[], overTime: WorkItemAgeOverTimeResult, scope: MetricsScope, terms: Terms) => MetricDayView;
683
+ /**
684
+ * "Predictability Score: 63.4%", then what the dashboard says the score means; no table, because the
685
+ * chart's marks need facts --json does not carry.
686
+ */
687
+ export declare const describePredictabilityScoreDays: (view: PredictabilityScoreView, scope: MetricsScope, terms: Terms) => MetricDayView;
688
+ /** "Blocked Work Items: 1 on Mon 7 Sep → 2 on Tue 6 Oct", then each recorded day's count. */
689
+ export declare const describeBlockedDays: (view: MetricHistoryView<BlockedCountSnapshot>, scope: MetricsScope, terms: Terms) => MetricDayView;
690
+ /** "Total Work Item Age: 84 days across 9 Work Items on Tue 6 Oct 2026", then each day's total. */
691
+ export declare const describeTotalWorkItemAgeDays: (view: TotalWorkItemAgeOverTimeResult, scope: MetricsScope, terms: Terms) => MetricDayView;
692
+ /** "Cycle Time over the last 30 days, per recorded day", then each recorded day's percentiles. */
693
+ export declare const describePercentilesOverTimeDays: (view: PercentilesOverTimeView, terms: Terms) => MetricDayView;
694
+ /** "Throughput natural process limits per recorded day", then each recorded day's limits. */
695
+ export declare const describeProcessBehaviorOverTimeDays: (view: MetricHistoryView<ProcessBehaviorSnapshot>, terms: Terms) => MetricDayView;
696
+ /** What the web's Time in State chart says when it has no state to show. */
697
+ export declare const NO_DATA_YET = "No data yet.";
698
+ /**
699
+ * How many Work Items Time in State is across: the ones picked with --item-ids, otherwise every one the web
700
+ * offers to pick from; absent when Lighthouse refused that list and none were picked.
701
+ */
702
+ export declare const timeInStateItemCount: (view: CumulativeStateTimeView, picked: number | undefined) => number | undefined;
703
+ /** "Time in State 4 states across 42 Work Items". */
704
+ export declare const describeTimeInState: (bar: CumulativeStateTimeResult, itemCount: number | undefined, scope: MetricsScope, terms: Terms) => MetricLine;
705
+ /**
706
+ * "Time in State across 42 Work Items", then one row per state in workflow order with the facts the web's
707
+ * tooltip shows, and the Work Items contributing to a state when one was asked for. Mean and median are
708
+ * printed as Lighthouse sent them, never worked out again.
709
+ */
710
+ export declare const describeTimeInStateDays: (bar: CumulativeStateTimeResult, itemCount: number | undefined, contributors: CumulativeStateTimeItemsResult | undefined, scope: MetricsScope, terms: Terms) => MetricDayView;
711
+ /** One state's drill-down on its own, answered with the title the web's dialog puts above it. */
712
+ export declare const describeTimeInStateContributorDays: (contributors: CumulativeStateTimeItemsResult, scope: MetricsScope, terms: Terms) => MetricDayView;
713
+ /**
714
+ * One metric as an assistant is told it: the heading and sentence lh prints above the metric's tables, and
715
+ * the web's words where a note stands in for a table, such as a history with no recorded day. Never a table.
716
+ */
717
+ export declare const describeMetricSummary: (heading: string, view: MetricDayView) => string;
718
+ /**
719
+ * Where "at risk" starts, the line Lighthouse's own SLE Risk widget draws. Seventy sits on the at-risk
720
+ * side; nothing else in the clients decides what counts as at risk.
721
+ */
722
+ export declare const SLE_RISK_AT_RISK_FROM = 70;
723
+ export declare const isAtRiskOfMissingTheSle: (risk: number) => boolean;
724
+ /** One Work Item's SLE Risk; the miss count is null for a Work Item already past the SLE. */
725
+ export type SleRiskView = {
726
+ readonly referenceId: string;
727
+ readonly risk: number;
728
+ readonly finishedItemsStillOpenAtThisAge: number;
729
+ readonly finishedItemsThatWentOnToMiss: number | null;
730
+ };
731
+ /** Every Work Item's SLE Risk as Lighthouse lists them, or null when the answer is in a shape it does not know. */
732
+ export declare const readSleRisk: (value: unknown) => readonly SleRiskView[] | null;
733
+ export type ServiceLevelExpectation = {
734
+ readonly probability: number;
735
+ readonly days: number;
736
+ };
737
+ /** The Team's SLE; absent when none is set, which Lighthouse stores as zeros. */
738
+ export declare const readServiceLevelExpectation: (value: unknown) => ServiceLevelExpectation | undefined;
739
+ /** The SLE Risk's title, the sentence that counts what is at risk, and one row per Work Item, highest risk first. */
740
+ export type SleRiskWording = {
741
+ readonly title: string;
742
+ readonly sentence: string | null;
743
+ readonly rows: readonly (readonly string[])[];
744
+ };
745
+ /**
746
+ * "2 of 8 Work Items in progress are at risk of missing the SLE (85% within 7 days).", then every Work Item
747
+ * highest risk first with its risk and the finished Work Items behind it. The names and ages come from
748
+ * today's Work Items in progress; without them each Work Item is still listed by its reference. An SLE of
749
+ * null means the Team could not be read: it may well have one, so an empty answer gets no sentence at all.
750
+ */
751
+ export declare const describeSleRiskNow: (entries: readonly SleRiskView[], wording: AnswerWording, sle: ServiceLevelExpectation | undefined | null, inProgress: readonly InProgressItem[] | undefined) => SleRiskWording;
752
+ /** One day on a chart, the signals Lighthouse found on it by their wire names, and whether it was a blackout day. */
753
+ export type ProcessBehaviorChartDay = {
754
+ readonly day: string;
755
+ readonly signals: readonly string[];
756
+ readonly blackout: boolean;
757
+ };
758
+ /**
759
+ * A chart as far as it can be said. `status` and `baselineConfigured` are null when the server did not send
760
+ * them (an older Lighthouse), so nothing is claimed about what was never said.
761
+ */
762
+ export type ProcessBehaviorChartView = {
763
+ readonly status: string | null;
764
+ readonly statusReason: string;
765
+ readonly baselineConfigured: boolean | null;
766
+ readonly days: readonly ProcessBehaviorChartDay[];
767
+ };
768
+ /**
769
+ * A chart's status, baseline and days with their signals, or null when a signal arrives as anything but its
770
+ * name: a number would have to be guessed at, and a guessed signal is worse than none.
771
+ */
772
+ export declare const readProcessBehaviorChart: (value: unknown) => ProcessBehaviorChartView | null;
773
+ /** "Total Work Item Age Process Behaviour Chart": a chart's title as the web titles it. */
774
+ export declare const processBehaviorChartTitle: (metricType: ProcessBehaviorMetricType, terms: Terms) => string;
775
+ /** A chart's title and what Lighthouse found on it. */
776
+ export type ProcessBehaviorChartWording = {
777
+ readonly title: string;
778
+ readonly sentence: string;
779
+ };
780
+ /**
781
+ * "Total Work Item Age Process Behaviour Chart", then each signal with the days it fired, or "No signals"; a chart
782
+ * that is not ready or has no baseline names no signal, and a blackout day is listed as one, never as a signal.
783
+ */
784
+ export declare const describeProcessBehaviorChart: (chart: ProcessBehaviorChartView, metricType: ProcessBehaviorMetricType, terms: Terms) => ProcessBehaviorChartWording;
785
+ //#endregion
786
+ //#region src/ownerWording.d.ts
787
+ /** What owns Features in Lighthouse: a Team or a Portfolio. */
788
+ export type OwnerKind = "team" | "portfolio";
789
+ /** One Team or Portfolio as a list row shows it. Fields Lighthouse did not send stay undefined. */
790
+ export type OwnerListItem = {
791
+ readonly id: number;
792
+ readonly name: string;
793
+ readonly featureCount: number | undefined;
794
+ readonly tags: readonly string[];
795
+ readonly lastUpdated: string | undefined;
796
+ };
797
+ /** A mark for a cell Lighthouse sent nothing for. */
798
+ export declare const NOT_SENT = "—";
799
+ /**
800
+ * Every Team or Portfolio in the list, or null when the answer is not a list or any one of them comes
801
+ * without its id or name: a row that cannot say what it is would misname the whole list.
802
+ */
803
+ export declare const readOwnerList: (value: unknown) => OwnerListItem[] | null;
804
+ /** The list's title, as the Overview heads it: "Teams" or "Portfolios" in the instance's words. */
805
+ export declare const describeOwnerListTitle: (kind: OwnerKind, terms: Terms) => string;
806
+ /** How many Teams or Portfolios the list holds, in the instance's words: "No Teams", "1 Team", "7 Teams". */
807
+ export declare const describeOwnerCount: (kind: OwnerKind, count: number, terms: Terms) => string;
808
+ /** The list's column headings, as the Overview's table has them. */
809
+ export declare const describeOwnerListHeadings: (terms: Terms) => string[];
810
+ /** A Team or Portfolio by name with its id beside it: "Gravity [id: 3]". */
811
+ export declare const describeOwnerName: ({ id, name }: Pick<OwnerListItem, "id" | "name">) => string;
812
+ /** How many Features it owns: "1 Feature", "6 Features", or the mark when Lighthouse sent none. */
813
+ export declare const describeFeatureCount: (count: number | undefined, terms: Terms) => string;
814
+ /** The tags as one cell, empty when there are none. */
815
+ export declare const describeTags: (tags: readonly string[]) => string;
816
+ /** When it was last updated, in the reader's local time; the mark when it never was. */
817
+ export declare const describeLastUpdated: (wire: string | undefined) => string;
818
+ /** A Team's Throughput dates, already resolved, and whether they roll forward or stay fixed. */
819
+ export type ThroughputDates = {
820
+ readonly start: string;
821
+ readonly end: string;
822
+ readonly fixed: boolean | undefined;
823
+ };
824
+ /** Another Team or Portfolio by what it is called and its id. */
825
+ export type OwnerReference = Pick<OwnerListItem, "id" | "name">;
826
+ /**
827
+ * A Team as its page states it. A setting left unset, which Lighthouse sends as 0, and a fact it did not
828
+ * send both stay undefined.
829
+ */
830
+ export type TeamSummary = {
831
+ readonly id: number;
832
+ readonly name: string;
833
+ readonly lastUpdated: string | undefined;
834
+ readonly sleProbability: number | undefined;
835
+ readonly sleRange: number | undefined;
836
+ readonly systemWipLimit: number | undefined;
837
+ readonly featureWip: number | undefined;
838
+ readonly throughput: ThroughputDates | undefined;
839
+ readonly portfolios: readonly OwnerReference[];
840
+ readonly featureCount: number | undefined;
841
+ readonly tags: readonly string[];
842
+ readonly workItemTypes: readonly string[];
843
+ };
844
+ /** What the Team page's quick settings say for a setting nobody gave a value. */
845
+ export declare const NOT_SET = "Not set";
846
+ /** The Team as its page states it, or null when the answer does not say which Team it is. */
847
+ export declare const readTeam: (value: unknown) => TeamSummary | null;
848
+ /**
849
+ * The Team page's heading and settings, one line each, in the instance's words. Tags get a line only
850
+ * when there are some, because Lighthouse sends a Team without them.
851
+ */
852
+ export declare const describeTeamSummary: (team: TeamSummary, terms: Terms) => string[];
853
+ /**
854
+ * A Portfolio as its page states it. Its Feature WIP is the number of Teams working on it, so it has no
855
+ * setting of its own.
856
+ */
857
+ export type PortfolioSummary = {
858
+ readonly id: number;
859
+ readonly name: string;
860
+ readonly lastUpdated: string | undefined;
861
+ readonly sleProbability: number | undefined;
862
+ readonly sleRange: number | undefined;
863
+ readonly systemWipLimit: number | undefined;
864
+ readonly teams: readonly OwnerReference[];
865
+ readonly featureCount: number | undefined;
866
+ };
867
+ /** The Portfolio as its page states it, or null when the answer does not say which Portfolio it is. */
868
+ export declare const readPortfolio: (value: unknown) => PortfolioSummary | null;
869
+ /**
870
+ * The Portfolio page's heading and settings, one line each, in the instance's words. Its Feature WIP
871
+ * reads 'Not set' when no Team works on it, as the page's quick setting does.
872
+ */
873
+ export declare const describePortfolioSummary: (portfolio: PortfolioSummary, terms: Terms) => string[];
874
+ //#endregion
875
+ //#region src/processBehaviorChartTypes.d.ts
876
+ /** Whether a text names a chart type Lighthouse draws a Process Behaviour Chart for. */
877
+ export declare const isProcessBehaviorMetricType: (value: string) => value is ProcessBehaviorMetricType;
878
+ //#endregion
879
+ //#region src/refinementWording.d.ts
880
+ /** The words an instance may rename that the refinement need is stated in. */
881
+ export type RefinementTerms = {
882
+ readonly workItem: string;
883
+ readonly workItems: string;
884
+ readonly team: string;
885
+ readonly refinement: string;
886
+ };
887
+ /** What the refinement need is stated with: the Team's name and the instance's words. */
888
+ export type RefinementWording = {
889
+ readonly teamName: string;
890
+ readonly terms: RefinementTerms;
891
+ };
892
+ type Read<TValue, TError> = {
893
+ readonly ok: true;
894
+ readonly value: TValue;
895
+ } | {
896
+ readonly ok: false;
897
+ readonly error: TError;
898
+ };
899
+ /** The two reads the wording comes from; each surface passes its own client. */
900
+ export type RefinementWordingSource<TError> = {
901
+ readonly getTeam: (teamId: number) => Promise<Read<unknown, TError>>;
902
+ readonly getTerminology: LighthouseClient["getTerminology"];
903
+ };
904
+ /**
905
+ * Reads the Team's name and the instance's terminology. Terminology that cannot be read leaves the
906
+ * seeded words standing rather than failing the answer; a Team that cannot be read fails it.
907
+ */
908
+ export declare const readRefinementWording: <TError>(source: RefinementWordingSource<TError>, teamId: number) => Promise<Read<RefinementWording, TError>>;
909
+ /**
910
+ * The heading and the need sentence together, as the web page states them, or that nothing is in
911
+ * refinement right now.
912
+ */
913
+ export declare const describeRefinementSummary: (refinement: TeamRefinement, wording: RefinementWording) => string;
914
+ /** Where the line goes among the listed Work Items: after this many rows, saying this. */
915
+ export type EnoughForLine = {
916
+ readonly afterRows: number;
917
+ readonly says: string;
918
+ };
919
+ /**
920
+ * The line follows the Work Item that makes up the number needed. When fewer are listed than that, it
921
+ * follows the last one and says all of them are needed; when none are needed, it comes first. Without
922
+ * a verdict to show there is no line.
923
+ */
924
+ export declare const placeEnoughForLine: (refinement: TeamRefinement, terms: RefinementTerms) => EnoughForLine | null;
925
+ /** How many of the listed Work Items carry a number: those needed, while a verdict is shown. */
926
+ export declare const countNumberedRows: (refinement: TeamRefinement) => number;
927
+ export type RefinementTermsSource = Pick<LighthouseClient, "getTerminology">;
928
+ /** The instance's words alone, the seeded ones standing in when terminology cannot be read. */
929
+ export declare const readRefinementTerms: (source: RefinementTermsSource) => Promise<RefinementTerms>;
930
+ //#endregion
931
+ //#region src/refinementVoteWording.d.ts
932
+ /** An answer as the web's buttons name it: "Yes", "Yes, if…" or "No". */
933
+ export declare const describeAnswer: (answer: RefinementAnswer) => string;
934
+ /** Where a Work Item stands by its votes, in the web's words: "Ready", "2 more Yes needed", … */
935
+ export declare const describeReadiness: (row: Pick<RefinementRow, "readiness" | "missingVotes">) => string;
936
+ /**
937
+ * How the votes split, parts in the order Yes · Yes, if… · No and zero parts left out, with a `*` when
938
+ * the caller has voted; "No votes" when nobody has.
939
+ */
940
+ export declare const describeVotes: (row: Pick<RefinementRow, "split" | "myVote">) => string;
941
+ /** What to look at on a Work Item: "open question", "stage disagrees", both, or nothing. */
942
+ export declare const describeWarnings: (row: Pick<RefinementRow, "hasOpenQuestion" | "signalsDisagree">) => string;
943
+ /** What a vote, comment or take-back is said about: the Work Item and, without sign-in, whose it is. */
944
+ export type RecordedFor = {
945
+ readonly workItem: string;
946
+ readonly voterName?: string | null;
947
+ };
948
+ /** "Recorded: Ana Lima — Yes, if… on GR-051. GR-051: 2 more Yes needed.", or "your Yes" with sign-in. */
949
+ export declare const describeRecordedVote: ({ workItem, voterName }: RecordedFor, answer: RefinementAnswer, row: VotedRow) => string;
950
+ /** "Recorded: Ana Lima's comment on GR-054." */
951
+ export declare const describeRecordedComment: ({ workItem, voterName }: RecordedFor) => string;
952
+ /** "Took back Ana Lima's vote on GR-051. GR-051: 3 more Yes needed." */
953
+ export declare const describeTakenBack: ({ workItem, voterName }: RecordedFor, row: VotedRow) => string;
954
+ /** Why a "Yes, if…" without its condition is not sent, ending in how this surface adds one. */
955
+ export declare const describeMissingCondition: (howToAddIt: string) => string;
956
+ /** Said instead of taking back when this client has no vote on the Work Item to take back. */
957
+ export declare const describeNothingToTakeBack: (workItem: string) => string;
958
+ export type VoteRefusalWording = {
959
+ /** The instance's words for the Work Item and the refinement. */
960
+ readonly terms: Pick<RefinementTerms, "workItem" | "refinement">;
961
+ /** What to say when Lighthouse needs a name, which each surface asks for its own way. */
962
+ readonly nameRequired: string;
963
+ /** What to say when Lighthouse needs a voter key, for a surface that keeps none to send. */
964
+ readonly keyRequired?: string;
965
+ };
966
+ /**
967
+ * Why Lighthouse would not take a vote, comment or take-back, in words the voter can act on: the web's
968
+ * sentence where it has one, the title of a name that is too long, otherwise its category and reason as
969
+ * every other command says a refusal.
970
+ */
971
+ export declare const describeVoteRefusal: (error: LighthouseApiError, { terms, nameRequired, keyRequired }: VoteRefusalWording) => string;
972
+ /** {@link describeVoteRefusal} in the instance's own words, read from the instance first. */
973
+ export declare const readVoteRefusal: (source: RefinementTermsSource, error: LighthouseApiError, nameRequired: string, keyRequired?: string) => Promise<string>;
974
+ //#endregion
975
+ //#region src/refinementVoting.d.ts
976
+ /** A "Yes, if…" names the condition it holds under, so without a comment it is not a vote yet. */
977
+ export declare const isMissingItsCondition: (answer: RefinementAnswer, comment: string | undefined) => boolean;
978
+ /**
979
+ * The reader's own vote on the Work Item, in a refinement read with this client's voter key or as the
980
+ * signed-in account; null when there is none. Lighthouse answers a take-back that found nothing exactly
981
+ * like one that did, so a client asks this first, sends nothing when there is no vote to take back, and
982
+ * otherwise names the answer it saw, so a vote changed since in another session is left standing.
983
+ */
984
+ export declare const myVoteOn: (refinement: Pick<TeamRefinement, "workItems">, workItem: string) => RefinementAnswer | null;
985
+ /** {@link nameOfMyVote}, read from Lighthouse; null when the log cannot be read either. */
986
+ export declare const readNameOfMyVote: (client: Pick<LighthouseClient, "getRefinementLog">, teamId: number, workItem: string, voterKey: string | undefined) => Promise<string | null>;
987
+ //#endregion
988
+ //#region src/usageDataStore.d.ts
989
+ /** The answer kept for a Lighthouse, undefined when never asked there, or "unreadable" when the file is not ours. */
990
+ export type UsageDataStoreReading = StoredUsageDataAnswer | undefined | "unreadable";
991
+ /**
992
+ * The usage data answers this machine keeps, one per Lighthouse, shared by the command line and the local
993
+ * MCP server. A separate file from the voter keys, so a client that only knows the voter keys never writes
994
+ * an answer away.
995
+ */
996
+ export type UsageDataStore = {
997
+ readonly read: (lighthouse: string) => Promise<UsageDataStoreReading>;
998
+ /** Keeps a question's answer only if none is kept yet: the first answer wins. True when it was kept. */
999
+ readonly answer: (lighthouse: string, answer: StoredUsageDataAnswer) => Promise<boolean>;
1000
+ /** Keeps the answer whatever was kept before. */
1001
+ readonly replace: (lighthouse: string, answer: StoredUsageDataAnswer) => Promise<void>;
1002
+ /**
1003
+ * Replaces a yes only while it still holds `token`. True when it was replaced. Waiting for another writer
1004
+ * stops, throwing, once `signal` aborts.
1005
+ */
1006
+ readonly renew: (lighthouse: string, token: string, answer: StoredUsageDataAnswer, signal?: AbortSignal) => Promise<boolean>;
1007
+ };
1008
+ /** The part of a store that holds one Lighthouse's answer. */
1009
+ export type LighthouseUsageDataStore = {
1010
+ readonly read: () => Promise<UsageDataStoreReading>;
1011
+ readonly answer: (answer: StoredUsageDataAnswer) => Promise<boolean>;
1012
+ readonly replace: (answer: StoredUsageDataAnswer) => Promise<void>;
1013
+ readonly renew: (token: string, answer: StoredUsageDataAnswer, signal?: AbortSignal) => Promise<boolean>;
1014
+ };
1015
+ export declare const usageDataStoreFor: (store: UsageDataStore, lighthouse: string) => LighthouseUsageDataStore;
1016
+ /** Beside the voter keys: `~/.config/lighthouse-clients/usage-data.json` by default. */
1017
+ export declare const getUsageDataStorePath: (env?: NodeJS.ProcessEnv) => string;
1018
+ /** A usage data store kept in one JSON file, readable by its owner only, never written over when unreadable. */
1019
+ export declare const createFileUsageDataStore: (filePath: string) => UsageDataStore;
1020
+ //#endregion
1021
+ //#region src/usageDataReporter.d.ts
1022
+ /** The Lighthouse calls a reporter makes, none of them with a credential. */
1023
+ export type UsageDataLighthouse = Pick<LighthouseClient, "getUsageDataState" | "grantUsageData" | "revokeUsageData" | "handInUsageData">;
1024
+ export type UsageDataReporterDependencies = {
1025
+ readonly lighthouse: UsageDataLighthouse;
1026
+ /** This Lighthouse's answer on this machine. */
1027
+ readonly store: LighthouseUsageDataStore;
1028
+ readonly source: ClientUsageDataSource;
1029
+ readonly env: Readonly<Record<string, string | undefined>>;
1030
+ readonly now: () => Date;
1031
+ };
1032
+ /** What a person answered to the question: null when they closed it without answering. */
1033
+ export type UsageDataQuestionAnswer = "yes" | "no" | null;
1034
+ /** What a command did, and how its person can be asked when nobody has answered yet. */
1035
+ export type UsageDataStep = {
1036
+ /** Whether the command reached Lighthouse and succeeded. */
1037
+ readonly reached: boolean;
1038
+ readonly occurrences: readonly UsageDataOccurrence[];
1039
+ /** Asks the person; absent when nobody is there who could answer. */
1040
+ readonly ask?: () => Promise<UsageDataQuestionAnswer>;
1041
+ };
1042
+ /** How a step ended. Never carries the consent token. */
1043
+ export type UsageDataOutcome = "nothing" | "sent" | "kept-yes" | "kept-no" | "unanswered" | "not-recorded";
1044
+ /** A command's own answer never waits on usage data for longer than this, whatever Lighthouse does. */
1045
+ export declare const USAGE_DATA_BUDGET_MS = 1000;
1046
+ /** How turning usage data off ended. Never carries the consent token. */
1047
+ export type UsageDataWithdrawal = "off" | "off-lighthouse-not-told" | "unreadable";
1048
+ export type UsageDataWithdrawalDependencies = {
1049
+ readonly lighthouse: Pick<LighthouseClient, "revokeUsageData">;
1050
+ readonly store: LighthouseUsageDataStore;
1051
+ readonly now: () => Date;
1052
+ };
1053
+ /**
1054
+ * Turns usage data off for one Lighthouse: keeps a No in place of whatever was kept, then withdraws a yes
1055
+ * at Lighthouse with its token. Off is kept even when Lighthouse cannot be told; an unreadable answers file
1056
+ * is left as it was.
1057
+ */
1058
+ export declare const withdrawUsageData: (dependencies: UsageDataWithdrawalDependencies) => Promise<UsageDataWithdrawal>;
1059
+ /** How turning usage data on ended. Never carries the consent token. */
1060
+ export type UsageDataSwitchOn = "on" | "do-not-track" | "administrator-stopped" | "predates" | "could-not-ask" | "not-recorded" | "unreadable";
1061
+ export type UsageDataSwitchOnDependencies = {
1062
+ readonly lighthouse: Pick<LighthouseClient, "getUsageDataState" | "grantUsageData" | "revokeUsageData">;
1063
+ readonly store: LighthouseUsageDataStore;
1064
+ readonly source: ClientUsageDataSource;
1065
+ readonly env: Readonly<Record<string, string | undefined>>;
1066
+ readonly now: () => Date;
1067
+ };
1068
+ /**
1069
+ * Turns usage data on for one Lighthouse without a question: a yes replaces whatever was kept. Nothing is
1070
+ * asked of Lighthouse under DO_NOT_TRACK, and nothing is kept when Lighthouse refuses, predates labelled
1071
+ * sources or cannot be asked; a yes already kept is left as it is, so no second grant is minted.
1072
+ */
1073
+ export declare const switchUsageDataOn: (dependencies: UsageDataSwitchOnDependencies) => Promise<UsageDataSwitchOn>;
1074
+ /**
1075
+ * Settles what a command did about usage data: asks when it should, records the answer, or sends the
1076
+ * command's events. It never prints and never throws; anything that goes wrong ends it quietly.
1077
+ */
1078
+ export declare const settleUsageDataStep: (dependencies: UsageDataReporterDependencies, step: UsageDataStep) => Promise<UsageDataOutcome>;
1079
+ //#endregion
1080
+ //#region src/voterKeyStore.d.ts
1081
+ /**
1082
+ * The voter keys this machine keeps, one per Lighthouse. The command line and the local MCP server share
1083
+ * it, so a person is one voter on a Lighthouse whichever of the two they vote from, and either can take
1084
+ * back what the other cast.
1085
+ */
1086
+ export type VoterKeyStore = {
1087
+ readonly load: (lighthouse: string) => Promise<string | null>;
1088
+ readonly save: (lighthouse: string, key: string) => Promise<void>;
1089
+ };
1090
+ /** The voter key a client keeps for the one Lighthouse it talks to. */
1091
+ export type LighthouseVoterKeyStore = {
1092
+ readonly load: () => Promise<string | null>;
1093
+ readonly save: (key: string) => Promise<void>;
1094
+ };
1095
+ /** The part of a store that holds one Lighthouse's key. */
1096
+ export declare const voterKeyStoreFor: (store: VoterKeyStore, lighthouse: string) => LighthouseVoterKeyStore;
1097
+ /** A fresh random voter key: 43 URL-safe characters from 32 random bytes. */
1098
+ export declare const mintVoterKey: () => string;
1099
+ /** The key already kept, or on a client's first write a fresh one, minted and kept from then on. */
1100
+ export declare const keepVoterKey: (store: LighthouseVoterKeyStore) => Promise<string>;
1101
+ /**
1102
+ * The name a standalone Lighthouse's key is kept under. The desktop app may come back on another port,
1103
+ * and it is still the same Lighthouse.
1104
+ */
1105
+ export declare const STANDALONE_VOTER_KEY_SCOPE = "standalone";
1106
+ /** Beside the command line's config file: `~/.config/lighthouse-clients/voter-keys.json` by default. */
1107
+ export declare const getVoterKeyStorePath: (env?: NodeJS.ProcessEnv) => string;
1108
+ /**
1109
+ * The name a Lighthouse's voter key is kept under: `standalone` for the desktop app, otherwise the server
1110
+ * as the client reaches it, so `HTTPS://Lighthouse.example:443/` and `https://lighthouse.example/api` are
1111
+ * one Lighthouse and one voter, whether `lh` or the local MCP server was given the URL.
1112
+ */
1113
+ export declare const getVoterKeyScope: (lighthouse: string) => string;
1114
+ /**
1115
+ * A voter key store kept in one JSON file, readable by its owner only. A file it cannot read is never
1116
+ * written over: it may hold the keys a person's earlier votes were cast with.
1117
+ */
1118
+ export declare const createFileVoterKeyStore: (filePath: string) => VoterKeyStore;
1119
+ //#endregion
1120
+ //#region src/writeWording.d.ts
1121
+ /** What a write did, as its confirmation opens: "Created:", "Updated:" or "Deleted:". */
1122
+ export type WriteVerb = "Created" | "Updated" | "Deleted";
1123
+ /** The Team or Portfolio a write is confirmed for: its id, and its name when there is one to give. */
1124
+ export type WrittenOwner = {
1125
+ readonly id: number;
1126
+ readonly name?: string;
1127
+ };
1128
+ /** The recurring blackout rule a write is confirmed for, with Lighthouse's own wording of its schedule. */
1129
+ export type WrittenBlackoutRule = Pick<RecurringBlackoutRule, "id"> & Partial<Pick<RecurringBlackoutRule, "summary" | "description">>;
1130
+ /** The id and name a Team or Portfolio write answered with, or null when the answer does not say which it is. */
1131
+ export declare const readWrittenOwner: (value: unknown) => WrittenOwner | null;
1132
+ /** The rule a blackout write answered with, or null when the answer does not say which rule it is. */
1133
+ export declare const readWrittenBlackoutRule: (value: unknown) => WrittenBlackoutRule | null;
1134
+ /** "Created: Team Lightspeed [id: 9]."; without a name, as a delete always is, "Deleted: Team [id: 9]." */
1135
+ export declare const describeOwnerWriteConfirmation: (verb: WriteVerb, kind: OwnerKind, { id, name }: WrittenOwner, terms: Terms) => string;
1136
+ /** A refresh only joins Lighthouse's queue, so the line says it was queued, not that it is done. */
1137
+ export declare const describeRefreshConfirmation: (kind: OwnerKind, id: number, terms: Terms) => string;
1138
+ /**
1139
+ * "Created: recurring blackout rule [id: 5] — Every Friday — every 2 weeks — from 2026-10-09 — no end
1140
+ * (Focus Friday)." The schedule is Lighthouse's own summary, word for word, so it reads as the settings
1141
+ * page states it; a delete names the id only.
1142
+ */
1143
+ export declare const describeBlackoutRuleWriteConfirmation: (verb: WriteVerb, { id, summary, description }: WrittenBlackoutRule) => string;
1144
+ //#endregion
1145
+ //#region src/index.d.ts
1146
+ export type ClientCapability = "versioned-api-contracts" | "shared-domain-operations" | "connectivity-and-discovery-contracts" | "automation-auth-contracts";
1147
+ export type ClientPackageContract = {
1148
+ readonly name: "@letpeoplework/lighthouse-client";
1149
+ readonly capabilities: readonly ClientCapability[];
1150
+ };
1151
+ export declare const getClientPackageContract: () => ClientPackageContract;
1152
+ export type ConnectivityCategory = "success" | "unreachable" | "misconfigured" | "unauthorized" | "dependency-failure" | "concurrency-conflict" | "unexpected";
1153
+ export type StandaloneDiscoveryContract = {
1154
+ readonly contractVersion: 1;
1155
+ readonly lighthouseUrl: string;
1156
+ readonly detectedAtUtc: string;
1157
+ };
1158
+ export type StandaloneDiscoveryContractParseResult = {
1159
+ readonly isValid: true;
1160
+ readonly contract: StandaloneDiscoveryContract;
1161
+ } | {
1162
+ readonly isValid: false;
1163
+ readonly reason: string;
1164
+ };
1165
+ export type LighthouseConnectionConfiguration = {
1166
+ readonly kind: "explicit";
1167
+ readonly lighthouseUrl: string;
1168
+ } | {
1169
+ readonly kind: "standalone";
1170
+ readonly getDiscoveryContract: () => Promise<StandaloneDiscoveryContract | null>;
1171
+ };
1172
+ export type ConnectivityFetchResponse = {
1173
+ readonly ok: boolean;
1174
+ readonly status: number;
1175
+ readonly text: () => Promise<string>;
1176
+ readonly json?: () => Promise<unknown>;
1177
+ };
1178
+ export type ConnectivityDependencies = {
1179
+ readonly fetch: (url: string, init?: RequestInit) => Promise<ConnectivityFetchResponse>;
1180
+ };
1181
+ export type ResolvedLighthouseEndpoint = {
1182
+ readonly mode: "explicit" | "standalone";
1183
+ readonly lighthouseUrl: string;
1184
+ readonly apiBaseUrl: string;
1185
+ readonly healthCheckUrl: string;
1186
+ };
1187
+ export type ConnectivityValidationResult = {
1188
+ readonly category: "success";
1189
+ readonly endpoint: ResolvedLighthouseEndpoint;
1190
+ readonly serverVersion: string;
1191
+ } | {
1192
+ readonly category: Exclude<ConnectivityCategory, "success">;
1193
+ readonly reason: string;
1194
+ readonly statusCode?: number;
1195
+ readonly endpoint?: ResolvedLighthouseEndpoint;
1196
+ };
1197
+ export declare const parseStandaloneDiscoveryContract: (serializedContract: string) => StandaloneDiscoveryContractParseResult;
1198
+ export declare const getStandaloneDiscoveryLockfilePath: () => string;
1199
+ export declare const loadStandaloneDiscoveryContract: () => Promise<StandaloneDiscoveryContract | null>;
1200
+ export declare const validateLighthouseConnectivity: (configuration: LighthouseConnectionConfiguration, dependencies: ConnectivityDependencies, requestInit?: RequestInit) => Promise<ConnectivityValidationResult>;
1201
+ export type LighthouseClientAuth = {
1202
+ readonly kind: "none";
1203
+ } | {
1204
+ readonly kind: "api-key";
1205
+ readonly value: string;
1206
+ readonly headerName?: string;
1207
+ } | {
1208
+ readonly kind: "bearer-token";
1209
+ readonly token: string;
1210
+ };
1211
+ export type StoredLighthouseAuth = Exclude<LighthouseClientAuth, {
1212
+ kind: "none";
68
1213
  }>;
69
- type LighthouseAuthOverrides = {
70
- readonly apiKey?: string;
71
- readonly bearerToken?: string;
72
- readonly apiKeyHeaderName?: string;
73
- };
74
- type LighthouseAuthStatus = {
75
- readonly isAuthenticated: boolean;
76
- readonly kind: LighthouseClientAuth["kind"];
77
- readonly source: "none" | "stored" | "override";
78
- };
79
- type LighthouseAuthStore = {
80
- readonly load: () => Promise<StoredLighthouseAuth | null>;
81
- readonly save: (auth: StoredLighthouseAuth) => Promise<void>;
82
- readonly clear: () => Promise<void>;
83
- };
84
- type LighthouseAuthContext = {
85
- readonly resolveAuth: (overrides?: LighthouseAuthOverrides) => Promise<LighthouseClientAuth>;
86
- readonly login: (overrides: LighthouseAuthOverrides) => Promise<void>;
87
- readonly logout: () => Promise<void>;
88
- readonly getStatus: (overrides?: LighthouseAuthOverrides) => Promise<LighthouseAuthStatus>;
89
- };
90
- declare const createLighthouseAuthContext: (store: LighthouseAuthStore) => LighthouseAuthContext;
91
- type CliServerAuthMode = "disabled" | "required" | "blocked" | "misconfigured";
92
- type ServerAuthModeResult = {
93
- readonly mode: CliServerAuthMode;
94
- readonly misconfigurationMessage?: string;
95
- };
96
- type CliAuthSessionStartResult = {
97
- readonly status: "started";
98
- readonly sessionId: string;
99
- readonly verificationUrl: string;
100
- readonly expiresAt: string;
101
- };
102
- type CliAuthSessionStartError = {
103
- readonly status: "error";
104
- readonly category: Exclude<ConnectivityCategory, "success">;
105
- readonly reason: string;
106
- readonly statusCode?: number;
107
- };
108
- type CliAuthSessionStartOutcome = CliAuthSessionStartResult | CliAuthSessionStartError;
109
- type CliAuthSessionPollResult = {
110
- readonly status: "pending";
1214
+ export type LighthouseAuthOverrides = {
1215
+ readonly apiKey?: string;
1216
+ readonly bearerToken?: string;
1217
+ readonly apiKeyHeaderName?: string;
1218
+ };
1219
+ export type LighthouseAuthStatus = {
1220
+ readonly isAuthenticated: boolean;
1221
+ readonly kind: LighthouseClientAuth["kind"];
1222
+ readonly source: "none" | "stored" | "override";
1223
+ };
1224
+ export type LighthouseAuthStore = {
1225
+ readonly load: () => Promise<StoredLighthouseAuth | null>;
1226
+ readonly save: (auth: StoredLighthouseAuth) => Promise<void>;
1227
+ readonly clear: () => Promise<void>;
1228
+ };
1229
+ export type LighthouseAuthContext = {
1230
+ readonly resolveAuth: (overrides?: LighthouseAuthOverrides) => Promise<LighthouseClientAuth>;
1231
+ readonly login: (overrides: LighthouseAuthOverrides) => Promise<void>;
1232
+ readonly logout: () => Promise<void>;
1233
+ readonly getStatus: (overrides?: LighthouseAuthOverrides) => Promise<LighthouseAuthStatus>;
1234
+ };
1235
+ export declare const createLighthouseAuthContext: (store: LighthouseAuthStore) => LighthouseAuthContext;
1236
+ export type CliServerAuthMode = "disabled" | "required" | "blocked" | "misconfigured";
1237
+ export type ServerAuthModeResult = {
1238
+ readonly mode: CliServerAuthMode;
1239
+ readonly misconfigurationMessage?: string;
1240
+ };
1241
+ export type CliAuthSessionStartResult = {
1242
+ readonly status: "started";
1243
+ readonly sessionId: string;
1244
+ readonly verificationUrl: string;
1245
+ readonly expiresAt: string;
1246
+ };
1247
+ export type CliAuthSessionStartError = {
1248
+ readonly status: "error";
1249
+ readonly category: Exclude<ConnectivityCategory, "success">;
1250
+ readonly reason: string;
1251
+ readonly statusCode?: number;
1252
+ };
1253
+ export type CliAuthSessionStartOutcome = CliAuthSessionStartResult | CliAuthSessionStartError;
1254
+ export type CliAuthSessionPollResult = {
1255
+ readonly status: "pending";
111
1256
  } | {
112
- readonly status: "approved";
113
- readonly token: string;
114
- readonly userName: string;
1257
+ readonly status: "approved";
1258
+ readonly token: string;
1259
+ readonly userName: string;
115
1260
  } | {
116
- readonly status: "expired";
1261
+ readonly status: "expired";
117
1262
  } | {
118
- readonly status: "denied";
1263
+ readonly status: "denied";
119
1264
  } | {
120
- readonly status: "not-found";
1265
+ readonly status: "not-found";
121
1266
  };
122
- type CliServerConnection = {
123
- readonly mode: "server";
124
- readonly endpointUrl: string;
125
- readonly authMode: "disabled" | "required";
126
- readonly insecure?: boolean;
127
- readonly auth?: StoredLighthouseAuth;
1267
+ export type CliServerConnection = {
1268
+ readonly mode: "server";
1269
+ readonly endpointUrl: string;
1270
+ readonly authMode: "disabled" | "required";
1271
+ readonly insecure?: boolean;
1272
+ readonly auth?: StoredLighthouseAuth;
128
1273
  };
129
- type CliStandaloneConnection = {
130
- readonly mode: "standalone";
131
- readonly authMode: "disabled";
1274
+ export type CliStandaloneConnection = {
1275
+ readonly mode: "standalone";
1276
+ readonly authMode: "disabled";
132
1277
  };
133
- type CliConnection = CliServerConnection | CliStandaloneConnection;
1278
+ export type CliConnection = CliServerConnection | CliStandaloneConnection;
134
1279
  type CliAuthDependencies = {
135
- readonly fetch: typeof globalThis.fetch;
136
- };
137
- declare const queryServerAuthMode: (endpointUrl: string, dependencies: CliAuthDependencies) => Promise<ServerAuthModeResult>;
138
- declare const startCliAuthSession: (endpointUrl: string, dependencies: CliAuthDependencies) => Promise<CliAuthSessionStartOutcome>;
139
- declare const pollCliAuthSession: (endpointUrl: string, sessionId: string, dependencies: CliAuthDependencies) => Promise<CliAuthSessionPollResult>;
140
- type LighthouseClientConfiguration = {
141
- readonly connection: LighthouseConnectionConfiguration;
142
- readonly auth?: LighthouseClientAuth;
143
- };
144
- type LighthouseApiError = {
145
- readonly category: ConnectivityCategory;
146
- readonly reason: string;
147
- readonly statusCode?: number;
148
- };
149
- type LighthouseApiResult<TValue> = {
150
- readonly ok: true;
151
- readonly value: TValue;
1280
+ readonly fetch: typeof globalThis.fetch;
1281
+ };
1282
+ export declare const queryServerAuthMode: (endpointUrl: string, dependencies: CliAuthDependencies) => Promise<ServerAuthModeResult>;
1283
+ export declare const startCliAuthSession: (endpointUrl: string, dependencies: CliAuthDependencies) => Promise<CliAuthSessionStartOutcome>;
1284
+ export declare const pollCliAuthSession: (endpointUrl: string, sessionId: string, dependencies: CliAuthDependencies) => Promise<CliAuthSessionPollResult>;
1285
+ export type LighthouseClientConfiguration = {
1286
+ readonly connection: LighthouseConnectionConfiguration;
1287
+ readonly auth?: LighthouseClientAuth;
1288
+ };
1289
+ export type LighthouseApiError = {
1290
+ readonly category: ConnectivityCategory;
1291
+ readonly reason: string;
1292
+ readonly statusCode?: number;
1293
+ /** The `code` a refusal names, so a surface can put it into its own words. */
1294
+ readonly problemCode?: string;
1295
+ /** The refusal's title as Lighthouse states it. */
1296
+ readonly problemTitle?: string;
1297
+ };
1298
+ export type LighthouseApiResult<TValue> = {
1299
+ readonly ok: true;
1300
+ readonly value: TValue;
152
1301
  } | {
153
- readonly ok: false;
154
- readonly error: LighthouseApiError;
155
- };
156
- type LighthouseWritePayload = Readonly<Record<string, unknown>>;
157
- type MetricsDateRange = {
158
- readonly startDate: string;
159
- readonly endDate: string;
160
- };
161
- declare const getDefaultMetricsDateRange: () => MetricsDateRange;
162
- type ManualForecastInput = {
163
- readonly remainingItems?: number;
164
- readonly targetDate?: string;
165
- /**
166
- * Override the team's forecast-filter setting for this forecast call:
167
- * - `true` — apply the team's exclusion rule (filtered throughput).
168
- * - `false` — skip the team's exclusion rule (raw throughput).
169
- * - omit — respect the team's current setting (default).
170
- *
171
- * Lighthouse v26.5.24.10+. Older servers ignore this field.
172
- */
173
- readonly applyFilterOverride?: boolean;
174
- };
175
- type BacktestInput = {
176
- readonly startDate: string;
177
- readonly endDate: string;
178
- readonly historicalStartDate: string;
179
- readonly historicalEndDate: string;
180
- /**
181
- * Override the team's forecast-filter setting for this backtest call:
182
- * - `true` — apply the team's exclusion rule (filtered throughput).
183
- * - `false` — skip the team's exclusion rule (raw throughput).
184
- * - omit — respect the team's current setting (default).
185
- *
186
- * Lighthouse v26.5.24.10+. Older servers ignore this field.
187
- */
188
- readonly applyFilterOverride?: boolean;
1302
+ readonly ok: false;
1303
+ readonly error: LighthouseApiError;
1304
+ };
1305
+ export type LighthouseWritePayload = Readonly<Record<string, unknown>>;
1306
+ export type MetricsDateRange = {
1307
+ readonly startDate: string;
1308
+ readonly endDate: string;
1309
+ };
1310
+ export declare const getDefaultMetricsDateRange: () => MetricsDateRange;
1311
+ export type ManualForecastInput = {
1312
+ readonly remainingItems?: number;
1313
+ readonly targetDate?: string;
1314
+ /**
1315
+ * Override the team's forecast-filter setting for this forecast call:
1316
+ * - `true` — apply the team's exclusion rule (filtered throughput).
1317
+ * - `false` — skip the team's exclusion rule (raw throughput).
1318
+ * - omit — respect the team's current setting (default).
1319
+ *
1320
+ * Lighthouse v26.5.24.10+. Older servers ignore this field.
1321
+ */
1322
+ readonly applyFilterOverride?: boolean;
1323
+ };
1324
+ export type BacktestInput = {
1325
+ readonly startDate: string;
1326
+ readonly endDate: string;
1327
+ readonly historicalStartDate: string;
1328
+ readonly historicalEndDate: string;
1329
+ /**
1330
+ * Override the team's forecast-filter setting for this backtest call:
1331
+ * - `true` — apply the team's exclusion rule (filtered throughput).
1332
+ * - `false` — skip the team's exclusion rule (raw throughput).
1333
+ * - omit — respect the team's current setting (default).
1334
+ *
1335
+ * Lighthouse v26.5.24.10+. Older servers ignore this field.
1336
+ */
1337
+ readonly applyFilterOverride?: boolean;
189
1338
  };
190
1339
  /**
191
1340
  * Forecast-filter view for team-level throughput / PBC / predictability metrics.
@@ -193,31 +1342,31 @@ type BacktestInput = {
193
1342
  * - `"filtered"` — apply the team's exclusion rule.
194
1343
  * - `"raw"` / omit — return unfiltered data (default).
195
1344
  */
196
- type ThroughputFilterView = "raw" | "filtered";
197
- type WorkItemAgeEntry = {
198
- readonly id: number;
199
- readonly name: string;
200
- readonly referenceId: string;
201
- readonly age: number;
1345
+ export type ThroughputFilterView = "raw" | "filtered";
1346
+ export type WorkItemAgeEntry = {
1347
+ readonly id: number;
1348
+ readonly name: string;
1349
+ readonly referenceId: string;
1350
+ readonly age: number;
202
1351
  };
203
- type DailyWorkItemAge = {
204
- readonly date: string;
205
- readonly items: readonly WorkItemAgeEntry[];
1352
+ export type DailyWorkItemAge = {
1353
+ readonly date: string;
1354
+ readonly items: readonly WorkItemAgeEntry[];
206
1355
  };
207
- type DailyTotalWorkItemAge = {
208
- readonly date: string;
209
- readonly totalAge: number;
210
- readonly itemCount: number;
1356
+ export type DailyTotalWorkItemAge = {
1357
+ readonly date: string;
1358
+ readonly totalAge: number;
1359
+ readonly itemCount: number;
211
1360
  };
212
- type WorkItemAgeOverTimeResult = {
213
- readonly startDate: string;
214
- readonly endDate: string;
215
- readonly daily: readonly DailyWorkItemAge[];
1361
+ export type WorkItemAgeOverTimeResult = {
1362
+ readonly startDate: string;
1363
+ readonly endDate: string;
1364
+ readonly daily: readonly DailyWorkItemAge[];
216
1365
  };
217
- type TotalWorkItemAgeOverTimeResult = {
218
- readonly startDate: string;
219
- readonly endDate: string;
220
- readonly daily: readonly DailyTotalWorkItemAge[];
1366
+ export type TotalWorkItemAgeOverTimeResult = {
1367
+ readonly startDate: string;
1368
+ readonly endDate: string;
1369
+ readonly daily: readonly DailyTotalWorkItemAge[];
221
1370
  };
222
1371
  /**
223
1372
  * One captured point on the blocked-items-over-time trend: how many items were
@@ -229,9 +1378,9 @@ type TotalWorkItemAgeOverTimeResult = {
229
1378
  * newer than v26.7.3.1 each WIP work item carries `isBlocked` and, when blocked,
230
1379
  * a `blockedSince` timestamp.
231
1380
  */
232
- type BlockedCountSnapshot = {
233
- readonly recordedAt: string;
234
- readonly blockedCount: number;
1381
+ export type BlockedCountSnapshot = {
1382
+ readonly recordedAt: string;
1383
+ readonly blockedCount: number;
235
1384
  };
236
1385
  /**
237
1386
  * One epic as it stood on the day a delivery snapshot was taken.
@@ -240,37 +1389,37 @@ type BlockedCountSnapshot = {
240
1389
  * `isUsingDefaultSize` are absent from every snapshot recorded before Lighthouse began writing
241
1390
  * sizes, so both are optional and a missing value means "not recorded", never zero.
242
1391
  */
243
- type DeliveryFeatureMetric = {
244
- readonly referenceId: string;
245
- readonly name: string;
246
- readonly completion: number;
247
- readonly likelihood: number | null;
248
- readonly totalItems?: number | null;
249
- readonly isUsingDefaultSize?: boolean | null;
1392
+ export type DeliveryFeatureMetric = {
1393
+ readonly referenceId: string;
1394
+ readonly name: string;
1395
+ readonly completion: number;
1396
+ readonly likelihood: number | null;
1397
+ readonly totalItems?: number | null;
1398
+ readonly isUsingDefaultSize?: boolean | null;
250
1399
  };
251
1400
  /** One point on a delivery's forecast distribution: the chance of finishing by a date. */
252
- type DeliveryWhenDistributionPoint = {
253
- readonly probability: number;
254
- readonly expectedDate: string;
1401
+ export type DeliveryWhenDistributionPoint = {
1402
+ readonly probability: number;
1403
+ readonly expectedDate: string;
255
1404
  };
256
1405
  /** A delivery as it stood on one recorded day. Dates are ISO strings. */
257
- type DeliveryMetricsHistoryPoint = {
258
- readonly date: string;
259
- readonly targetDateAtSnapshot: string | null;
260
- readonly totalWork: number;
261
- readonly doneWork: number;
262
- readonly remainingWork: number;
263
- readonly estimatedItemCount: number | null;
264
- readonly forecastHowMany: number | null;
265
- readonly likelihoodPercentage: number | null;
266
- readonly whenDistribution: readonly DeliveryWhenDistributionPoint[] | null;
267
- readonly featureBreakdown: readonly DeliveryFeatureMetric[];
1406
+ export type DeliveryMetricsHistoryPoint = {
1407
+ readonly date: string;
1408
+ readonly targetDateAtSnapshot: string | null;
1409
+ readonly totalWork: number;
1410
+ readonly doneWork: number;
1411
+ readonly remainingWork: number;
1412
+ readonly estimatedItemCount: number | null;
1413
+ readonly forecastHowMany: number | null;
1414
+ readonly likelihoodPercentage: number | null;
1415
+ readonly whenDistribution: readonly DeliveryWhenDistributionPoint[] | null;
1416
+ readonly featureBreakdown: readonly DeliveryFeatureMetric[];
268
1417
  };
269
1418
  /** The whole recorded trend for one delivery. Forward-only: it starts at the first snapshot. */
270
- type DeliveryMetricsHistory = {
271
- readonly deliveryDate: string;
272
- readonly firstSnapshotDate: string | null;
273
- readonly points: readonly DeliveryMetricsHistoryPoint[];
1419
+ export type DeliveryMetricsHistory = {
1420
+ readonly deliveryDate: string;
1421
+ readonly firstSnapshotDate: string | null;
1422
+ readonly points: readonly DeliveryMetricsHistoryPoint[];
274
1423
  };
275
1424
  /**
276
1425
  * One day of a delivery, without the per-epic breakdown or the forecast distribution.
@@ -279,14 +1428,14 @@ type DeliveryMetricsHistory = {
279
1428
  * distribution per day — more than an assistant should be handed by default (ADR-121), and more
280
1429
  * than a terminal can show. {@link summariseDeliveryMetricsHistory} projects to this.
281
1430
  */
282
- type DeliveryMetricsHistorySummaryRow = {
283
- readonly date: string;
284
- readonly totalWork: number;
285
- readonly doneWork: number;
286
- readonly remainingWork: number;
287
- readonly epicCount: number;
288
- readonly estimatedItemCount: number | null;
289
- readonly likelihoodPercentage: number | null;
1431
+ export type DeliveryMetricsHistorySummaryRow = {
1432
+ readonly date: string;
1433
+ readonly totalWork: number;
1434
+ readonly doneWork: number;
1435
+ readonly remainingWork: number;
1436
+ readonly epicCount: number;
1437
+ readonly estimatedItemCount: number | null;
1438
+ readonly likelihoodPercentage: number | null;
290
1439
  };
291
1440
  /**
292
1441
  * Projects a delivery history to one row per recorded day. Pure.
@@ -294,12 +1443,12 @@ type DeliveryMetricsHistorySummaryRow = {
294
1443
  * The client itself returns the payload whole: dropping data is the caller's choice, so the CLI and
295
1444
  * the MCP tool apply this by default and step around it when asked for per-epic detail.
296
1445
  */
297
- declare const summariseDeliveryMetricsHistory: (history: DeliveryMetricsHistory) => readonly DeliveryMetricsHistorySummaryRow[];
1446
+ export declare const summariseDeliveryMetricsHistory: (history: DeliveryMetricsHistory) => readonly DeliveryMetricsHistorySummaryRow[];
298
1447
  /**
299
1448
  * Percentile family recorded by the percentiles-over-time pipeline. Sent as the
300
1449
  * `metricType` query parameter, and echoed back on every returned row.
301
1450
  */
302
- type PercentilesOverTimeMetricType = "CycleTime" | "WorkItemAge";
1451
+ export type PercentilesOverTimeMetricType = "CycleTime" | "WorkItemAge";
303
1452
  /**
304
1453
  * One captured day on the percentiles-over-time trend: the percentile quartet
305
1454
  * recorded for {@link recordedAt} (an ISO date string, one row per calendar day,
@@ -320,13 +1469,13 @@ type PercentilesOverTimeMetricType = "CycleTime" | "WorkItemAge";
320
1469
  * shape carries no horizon field they cannot be told apart. Pass an explicit
321
1470
  * horizon whenever you ask for `CycleTime`.
322
1471
  */
323
- type PercentilesOverTimeSnapshot = {
324
- readonly recordedAt: string;
325
- readonly metricType: PercentilesOverTimeMetricType;
326
- readonly p50: number;
327
- readonly p70: number;
328
- readonly p85: number;
329
- readonly p95: number;
1472
+ export type PercentilesOverTimeSnapshot = {
1473
+ readonly recordedAt: string;
1474
+ readonly metricType: PercentilesOverTimeMetricType;
1475
+ readonly p50: number;
1476
+ readonly p70: number;
1477
+ readonly p85: number;
1478
+ readonly p95: number;
330
1479
  };
331
1480
  /**
332
1481
  * Process-behaviour family recorded by the natural-process-limits over-time
@@ -336,7 +1485,7 @@ type PercentilesOverTimeSnapshot = {
336
1485
  * never records it. The server answers a team asking for it with an empty
337
1486
  * series rather than an error.
338
1487
  */
339
- type ProcessBehaviorMetricType = "Throughput" | "WorkItemAge" | "Wip" | "CycleTime" | "Arrivals" | "FeatureSize";
1488
+ export type ProcessBehaviorMetricType = "Throughput" | "WorkItemAge" | "Wip" | "CycleTime" | "Arrivals" | "FeatureSize";
340
1489
  /**
341
1490
  * One captured day on the process-behaviour-over-time trend: the natural process
342
1491
  * limit triple recorded for {@link recordedAt} (an ISO date string, one row per
@@ -350,140 +1499,307 @@ type ProcessBehaviorMetricType = "Throughput" | "WorkItemAge" | "Wip" | "CycleTi
350
1499
  * series rather than present as a zeroed triple, so an empty array means
351
1500
  * "nothing recorded yet", never "a process pinned at zero".
352
1501
  */
353
- type ProcessBehaviorSnapshot = {
354
- readonly recordedAt: string;
355
- readonly unpl: number;
356
- readonly average: number;
357
- readonly lnpl: number;
358
- };
359
- type CumulativeStateTimeStateRow = {
360
- readonly state: string;
361
- readonly workflowOrder: number;
362
- readonly totalDays: number;
363
- readonly completedContributionDays: number;
364
- readonly ongoingContributionDays: number;
365
- readonly itemCount: number;
366
- readonly completedItemCount: number;
367
- readonly ongoingItemCount: number;
368
- readonly meanDays: number;
369
- readonly medianDays: number | null;
370
- };
371
- type CumulativeStateTimeResult = {
372
- readonly states: readonly CumulativeStateTimeStateRow[];
373
- };
374
- type CumulativeStateTimeItemRow = {
375
- readonly workItemId: number;
376
- readonly referenceId: string;
377
- readonly title: string;
378
- readonly type: string;
379
- readonly state: string;
380
- readonly stateCategory: string;
381
- readonly url: string | null;
382
- readonly daysContributed: number;
383
- };
384
- type CumulativeStateTimeItemsResult = {
385
- readonly state: string;
386
- readonly items: readonly CumulativeStateTimeItemRow[];
387
- };
388
- type CumulativeStateTimeCandidateRow = {
389
- readonly workItemId: number;
390
- readonly referenceId: string;
391
- readonly title: string;
392
- readonly workItemType: string;
393
- };
394
- type CumulativeStateTimeCandidatesResult = {
395
- readonly items: readonly CumulativeStateTimeCandidateRow[];
396
- };
397
- type DayOfWeek = "Sunday" | "Monday" | "Tuesday" | "Wednesday" | "Thursday" | "Friday" | "Saturday";
398
- type RecurringBlackoutRule = {
399
- readonly id: number;
400
- readonly weekdays: readonly DayOfWeek[];
401
- readonly intervalWeeks: number;
402
- readonly start: string;
403
- readonly end: string | null;
404
- readonly description: string;
405
- readonly summary: string;
406
- };
407
- type RecurringBlackoutRuleInput = {
408
- readonly weekdays: readonly DayOfWeek[];
409
- readonly intervalWeeks: number;
410
- readonly start: string;
411
- readonly end: string | null;
412
- readonly description: string;
413
- };
414
- type LighthouseClient = {
415
- readonly checkConnectivity: () => Promise<ConnectivityValidationResult>;
416
- readonly getVersion: () => Promise<LighthouseApiResult<string>>;
417
- readonly listWorkTrackingConnections: () => Promise<LighthouseApiResult<readonly unknown[]>>;
418
- readonly getWorkTrackingConnection: (connectionId: number) => Promise<LighthouseApiResult<unknown>>;
419
- readonly createWorkTrackingConnection: (payload: LighthouseWritePayload) => Promise<LighthouseApiResult<unknown>>;
420
- readonly updateWorkTrackingConnection: (connectionId: number, payload: LighthouseWritePayload) => Promise<LighthouseApiResult<unknown>>;
421
- readonly deleteWorkTrackingConnection: (connectionId: number) => Promise<LighthouseApiResult<void>>;
422
- readonly listTeams: () => Promise<LighthouseApiResult<readonly unknown[]>>;
423
- readonly getTeam: (teamId: number) => Promise<LighthouseApiResult<unknown>>;
424
- readonly createTeam: (payload: LighthouseWritePayload) => Promise<LighthouseApiResult<unknown>>;
425
- readonly updateTeam: (teamId: number, payload: LighthouseWritePayload) => Promise<LighthouseApiResult<unknown>>;
426
- readonly deleteTeam: (teamId: number) => Promise<LighthouseApiResult<void>>;
427
- readonly refreshTeam: (teamId: number) => Promise<LighthouseApiResult<void>>;
428
- readonly listPortfolios: () => Promise<LighthouseApiResult<readonly unknown[]>>;
429
- readonly getPortfolio: (portfolioId: number) => Promise<LighthouseApiResult<unknown>>;
430
- readonly createPortfolio: (payload: LighthouseWritePayload) => Promise<LighthouseApiResult<unknown>>;
431
- readonly updatePortfolio: (portfolioId: number, payload: LighthouseWritePayload) => Promise<LighthouseApiResult<unknown>>;
432
- readonly deletePortfolio: (portfolioId: number) => Promise<LighthouseApiResult<void>>;
433
- readonly refreshPortfolio: (portfolioId: number) => Promise<LighthouseApiResult<void>>;
434
- readonly getTeamThroughput: (teamId: number, range?: MetricsDateRange, view?: ThroughputFilterView) => Promise<LighthouseApiResult<unknown>>;
435
- readonly getTeamArrivals: (teamId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<unknown>>;
436
- readonly getTeamWipOverTime: (teamId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<unknown>>;
437
- readonly getTeamWip: (teamId: number, asOfDate: string) => Promise<LighthouseApiResult<readonly unknown[]>>;
438
- readonly getTeamCycleTimePercentiles: (teamId: number, range?: MetricsDateRange, definitionId?: number) => Promise<LighthouseApiResult<readonly unknown[]>>;
439
- readonly getTeamWorkItemAgePercentiles: (teamId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<readonly unknown[]>>;
440
- readonly getTeamCycleTimeData: (teamId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<readonly unknown[]>>;
441
- readonly getTeamPredictabilityScore: (teamId: number, range?: MetricsDateRange, view?: ThroughputFilterView) => Promise<LighthouseApiResult<unknown>>;
442
- readonly getTeamTotalWorkItemAge: (teamId: number, asOfDate: string) => Promise<LighthouseApiResult<number>>;
443
- readonly getTeamTotalWorkItemAgeInfo: (teamId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<unknown>>;
444
- readonly getPortfolioThroughput: (portfolioId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<unknown>>;
445
- readonly getPortfolioCycleTimePercentiles: (portfolioId: number, range?: MetricsDateRange, definitionId?: number) => Promise<LighthouseApiResult<readonly unknown[]>>;
446
- readonly getPortfolioWorkItemAgePercentiles: (portfolioId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<readonly unknown[]>>;
447
- readonly getPortfolioArrivals: (portfolioId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<unknown>>;
448
- readonly getPortfolioWipOverTime: (portfolioId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<unknown>>;
449
- readonly getPortfolioWip: (portfolioId: number, asOfDate: string) => Promise<LighthouseApiResult<readonly unknown[]>>;
450
- readonly getPortfolioCycleTimeData: (portfolioId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<readonly unknown[]>>;
451
- readonly getPortfolioPredictabilityScore: (portfolioId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<unknown>>;
452
- readonly getTeamWorkItemAgeOverTime: (teamId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<WorkItemAgeOverTimeResult>>;
453
- readonly getTeamTotalWorkItemAgeOverTime: (teamId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<TotalWorkItemAgeOverTimeResult>>;
454
- readonly getPortfolioTotalWorkItemAge: (portfolioId: number, asOfDate: string) => Promise<LighthouseApiResult<number>>;
455
- readonly getPortfolioTotalWorkItemAgeInfo: (portfolioId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<unknown>>;
456
- readonly getPortfolioWorkItemAgeOverTime: (portfolioId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<WorkItemAgeOverTimeResult>>;
457
- readonly getPortfolioTotalWorkItemAgeOverTime: (portfolioId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<TotalWorkItemAgeOverTimeResult>>;
458
- readonly getTeamBlockedCountHistory: (teamId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<readonly BlockedCountSnapshot[]>>;
459
- readonly getPortfolioBlockedCountHistory: (portfolioId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<readonly BlockedCountSnapshot[]>>;
460
- readonly getTeamPercentilesOverTime: (teamId: number, range?: MetricsDateRange, metricType?: PercentilesOverTimeMetricType, horizon?: number) => Promise<LighthouseApiResult<readonly PercentilesOverTimeSnapshot[]>>;
461
- readonly getPortfolioPercentilesOverTime: (portfolioId: number, range?: MetricsDateRange, metricType?: PercentilesOverTimeMetricType, horizon?: number) => Promise<LighthouseApiResult<readonly PercentilesOverTimeSnapshot[]>>;
462
- readonly getTeamProcessBehaviorOverTime: (teamId: number, range?: MetricsDateRange, metricType?: ProcessBehaviorMetricType) => Promise<LighthouseApiResult<readonly ProcessBehaviorSnapshot[]>>;
463
- readonly getPortfolioProcessBehaviorOverTime: (portfolioId: number, range?: MetricsDateRange, metricType?: ProcessBehaviorMetricType) => Promise<LighthouseApiResult<readonly ProcessBehaviorSnapshot[]>>;
464
- readonly getTeamCumulativeStateTime: (teamId: number, range?: MetricsDateRange, itemIds?: readonly number[]) => Promise<LighthouseApiResult<CumulativeStateTimeResult>>;
465
- readonly getTeamCumulativeStateTimeItems: (teamId: number, state: string, range?: MetricsDateRange, itemIds?: readonly number[]) => Promise<LighthouseApiResult<CumulativeStateTimeItemsResult>>;
466
- readonly getTeamCumulativeStateTimeCandidates: (teamId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<CumulativeStateTimeCandidatesResult>>;
467
- readonly getPortfolioCumulativeStateTime: (portfolioId: number, range?: MetricsDateRange, itemIds?: readonly number[]) => Promise<LighthouseApiResult<CumulativeStateTimeResult>>;
468
- readonly getPortfolioCumulativeStateTimeItems: (portfolioId: number, state: string, range?: MetricsDateRange, itemIds?: readonly number[]) => Promise<LighthouseApiResult<CumulativeStateTimeItemsResult>>;
469
- readonly getPortfolioCumulativeStateTimeCandidates: (portfolioId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<CumulativeStateTimeCandidatesResult>>;
470
- readonly getFeaturesByIds: (ids: readonly number[]) => Promise<LighthouseApiResult<readonly unknown[]>>;
471
- readonly getFeaturesByReferences: (refs: readonly string[]) => Promise<LighthouseApiResult<readonly unknown[]>>;
472
- readonly getFeatureWorkItems: (featureId: number) => Promise<LighthouseApiResult<readonly unknown[]>>;
473
- readonly listDeliveries: (portfolioId: number) => Promise<LighthouseApiResult<readonly unknown[]>>;
474
- readonly createDelivery: (portfolioId: number, payload: LighthouseWritePayload) => Promise<LighthouseApiResult<unknown>>;
475
- readonly updateDelivery: (deliveryId: number, payload: LighthouseWritePayload) => Promise<LighthouseApiResult<unknown>>;
476
- readonly deleteDelivery: (deliveryId: number) => Promise<LighthouseApiResult<undefined>>;
477
- readonly getDeliveryMetricsHistory: (deliveryId: number) => Promise<LighthouseApiResult<DeliveryMetricsHistory>>;
478
- readonly getRecurringBlackoutRules: () => Promise<LighthouseApiResult<readonly RecurringBlackoutRule[]>>;
479
- readonly createRecurringBlackoutRule: (payload: LighthouseWritePayload) => Promise<LighthouseApiResult<RecurringBlackoutRule>>;
480
- readonly updateRecurringBlackoutRule: (id: number, payload: LighthouseWritePayload) => Promise<LighthouseApiResult<RecurringBlackoutRule>>;
481
- readonly deleteRecurringBlackoutRule: (id: number) => Promise<LighthouseApiResult<undefined>>;
482
- readonly runManualForecast: (teamId: number, payload: ManualForecastInput) => Promise<LighthouseApiResult<unknown>>;
483
- readonly runBacktest: (teamId: number, payload: BacktestInput) => Promise<LighthouseApiResult<unknown>>;
484
- };
485
- type LighthouseClientDependencies = {
486
- readonly fetch?: (url: string, init?: RequestInit) => Promise<ConnectivityFetchResponse>;
1502
+ export type ProcessBehaviorSnapshot = {
1503
+ readonly recordedAt: string;
1504
+ readonly unpl: number;
1505
+ readonly average: number;
1506
+ readonly lnpl: number;
1507
+ };
1508
+ /** The chart types a Team has a Process Behaviour Chart for; Feature Size is charted for Portfolios only. */
1509
+ export type TeamProcessBehaviorMetricType = Exclude<ProcessBehaviorMetricType, "FeatureSize">;
1510
+ /** One day on a Process Behaviour Chart, with the signals Lighthouse found on it by name. */
1511
+ export type ProcessBehaviorChartDataPoint = {
1512
+ readonly xValue: string;
1513
+ readonly yValue: number;
1514
+ readonly specialCauses: readonly string[];
1515
+ readonly workItemIds: readonly number[];
1516
+ readonly isBlackout?: boolean;
1517
+ };
1518
+ /**
1519
+ * A Process Behaviour Chart as Lighthouse computes it: its limits, why it could not be computed when its
1520
+ * status is not Ready, and every day with the signals found on it. An older Lighthouse leaves out the
1521
+ * baseline flag and the blackout days.
1522
+ */
1523
+ export type ProcessBehaviorChart = {
1524
+ readonly status: string;
1525
+ readonly statusReason: string;
1526
+ readonly xAxisKind: string;
1527
+ readonly average: number;
1528
+ readonly upperNaturalProcessLimit: number;
1529
+ readonly lowerNaturalProcessLimit: number;
1530
+ readonly baselineConfigured?: boolean;
1531
+ readonly dataPoints: readonly ProcessBehaviorChartDataPoint[];
1532
+ };
1533
+ /**
1534
+ * One Work Item in progress and the chance it misses its Team's SLE, in percent. The miss count is
1535
+ * null when the Work Item is already past the SLE: that settles it without looking at any history.
1536
+ */
1537
+ export type SleRiskEntry = {
1538
+ readonly referenceId: string;
1539
+ readonly risk: number;
1540
+ readonly finishedItemsStillOpenAtThisAge: number;
1541
+ readonly finishedItemsThatWentOnToMiss: number | null;
1542
+ };
1543
+ export type CumulativeStateTimeStateRow = {
1544
+ readonly state: string;
1545
+ readonly workflowOrder: number;
1546
+ readonly totalDays: number;
1547
+ readonly completedContributionDays: number;
1548
+ readonly ongoingContributionDays: number;
1549
+ readonly itemCount: number;
1550
+ readonly completedItemCount: number;
1551
+ readonly ongoingItemCount: number;
1552
+ readonly meanDays: number;
1553
+ readonly medianDays: number | null;
1554
+ };
1555
+ export type CumulativeStateTimeResult = {
1556
+ readonly states: readonly CumulativeStateTimeStateRow[];
1557
+ };
1558
+ export type CumulativeStateTimeItemRow = {
1559
+ readonly workItemId: number;
1560
+ readonly referenceId: string;
1561
+ readonly title: string;
1562
+ readonly type: string;
1563
+ readonly state: string;
1564
+ readonly stateCategory: string;
1565
+ readonly url: string | null;
1566
+ readonly daysContributed: number;
1567
+ };
1568
+ export type CumulativeStateTimeItemsResult = {
1569
+ readonly state: string;
1570
+ readonly items: readonly CumulativeStateTimeItemRow[];
1571
+ };
1572
+ export type CumulativeStateTimeCandidateRow = {
1573
+ readonly workItemId: number;
1574
+ readonly referenceId: string;
1575
+ readonly title: string;
1576
+ readonly workItemType: string;
1577
+ };
1578
+ export type CumulativeStateTimeCandidatesResult = {
1579
+ readonly items: readonly CumulativeStateTimeCandidateRow[];
1580
+ };
1581
+ export type DayOfWeek = "Sunday" | "Monday" | "Tuesday" | "Wednesday" | "Thursday" | "Friday" | "Saturday";
1582
+ export type RecurringBlackoutRule = {
1583
+ readonly id: number;
1584
+ readonly weekdays: readonly DayOfWeek[];
1585
+ readonly intervalWeeks: number;
1586
+ readonly start: string;
1587
+ readonly end: string | null;
1588
+ readonly description: string;
1589
+ readonly summary: string;
1590
+ };
1591
+ export type RecurringBlackoutRuleInput = {
1592
+ readonly weekdays: readonly DayOfWeek[];
1593
+ readonly intervalWeeks: number;
1594
+ readonly start: string;
1595
+ readonly end: string | null;
1596
+ readonly description: string;
1597
+ };
1598
+ export type RefinementVerdict = "Below" | "In" | "Above";
1599
+ export type NeedUnavailableReason = "NoCadence" | "InsufficientData" | "NoRefinementStates";
1600
+ export type RefinementNeed = {
1601
+ readonly verdict: RefinementVerdict | null;
1602
+ readonly unavailableReason: NeedUnavailableReason | null;
1603
+ readonly low: number | null;
1604
+ readonly high: number | null;
1605
+ readonly lowPercentile: number | null;
1606
+ readonly highPercentile: number | null;
1607
+ readonly horizonWorkingDays: number | null;
1608
+ readonly cycleStart: string | null;
1609
+ readonly cycleEnd: string | null;
1610
+ };
1611
+ export type RefinementRow = {
1612
+ readonly referenceId: string;
1613
+ readonly name: string;
1614
+ readonly url: string | null;
1615
+ readonly state: string;
1616
+ readonly parentReferenceId: string;
1617
+ readonly voteCount: number;
1618
+ readonly myVote: RefinementAnswer | null;
1619
+ readonly split: {
1620
+ readonly yes: number;
1621
+ readonly yesBut: number;
1622
+ readonly no: number;
1623
+ };
1624
+ readonly readiness: "Ready" | "MoreYesNeeded" | "MoreVotersNeeded" | "NeedsDiscussion";
1625
+ readonly missingVotes: number | null;
1626
+ readonly stage: "Waiting" | "BeingRefined" | "Ready" | null;
1627
+ readonly signalsDisagree: boolean;
1628
+ readonly hasComments: boolean;
1629
+ readonly hasOpenQuestion: boolean;
1630
+ };
1631
+ /** The answers a vote can give, in the order the web's buttons show them. */
1632
+ export declare const REFINEMENT_ANSWERS: readonly ["Yes", "YesBut", "No"];
1633
+ export type RefinementAnswer = (typeof REFINEMENT_ANSWERS)[number];
1634
+ export declare const isRefinementAnswer: (value: unknown) => value is RefinementAnswer;
1635
+ /** Where a vote, comment or take-back was sent from. */
1636
+ export type RefinementChannel = "Cli" | "Assistant";
1637
+ /** A Work Item in refinement as a vote, comment or take-back left it. */
1638
+ export type VotedRow = RefinementRow & {
1639
+ readonly madeReady: boolean;
1640
+ };
1641
+ export type RefinementReadOptions = {
1642
+ readonly voterKey?: string;
1643
+ };
1644
+ export type RefinementVoteInput = {
1645
+ readonly answer: RefinementAnswer;
1646
+ readonly channel: RefinementChannel;
1647
+ readonly comment?: string;
1648
+ readonly voterName?: string;
1649
+ readonly voterKey?: string;
1650
+ };
1651
+ export type RefinementCommentInput = {
1652
+ readonly comment: string;
1653
+ readonly channel: RefinementChannel;
1654
+ readonly voterName?: string;
1655
+ readonly voterKey?: string;
1656
+ };
1657
+ export type RefinementTakeBackInput = {
1658
+ readonly channel: RefinementChannel;
1659
+ readonly voterKey?: string;
1660
+ /** The answer the caller saw as theirs, so a vote changed since in another session is left standing. */
1661
+ readonly answer?: RefinementAnswer;
1662
+ };
1663
+ /** One line of a Work Item's sizing log, oldest first; `isMine` marks the reader's own. */
1664
+ export type SizingLogEntry = {
1665
+ readonly kind: "Vote" | "Comment" | "Revocation";
1666
+ readonly answer: RefinementAnswer | null;
1667
+ readonly comment: string | null;
1668
+ readonly voterName: string;
1669
+ readonly channel: string;
1670
+ readonly recordedAt: string;
1671
+ readonly isMine: boolean;
1672
+ readonly isOpenQuestion: boolean;
1673
+ };
1674
+ export type SizingLog = {
1675
+ readonly entries: readonly SizingLogEntry[];
1676
+ readonly voters: {
1677
+ readonly yes: readonly string[];
1678
+ readonly yesBut: readonly string[];
1679
+ readonly no: readonly string[];
1680
+ };
1681
+ };
1682
+ export type TeamRefinement = {
1683
+ readonly refinementConfigured: boolean;
1684
+ readonly workItems: readonly RefinementRow[];
1685
+ readonly yardstick: {
1686
+ readonly source: "Sle" | "CycleTimeFallback" | "Unavailable";
1687
+ readonly days: number | null;
1688
+ readonly probability: number | null;
1689
+ };
1690
+ readonly voterIdentity: "Account" | "SelfDeclared";
1691
+ readonly readyByVotesCount: number;
1692
+ readonly stagesConfigured: boolean;
1693
+ readonly readyCount: number;
1694
+ readonly readySource: "Votes" | "Stages";
1695
+ readonly nextRefinementDate: string | null;
1696
+ readonly isRefinementDay: boolean;
1697
+ readonly daysUntilNextRefinement: number | null;
1698
+ readonly need: RefinementNeed;
1699
+ };
1700
+ export type TerminologyEntry = {
1701
+ readonly id: number;
1702
+ readonly key: string;
1703
+ readonly description: string;
1704
+ readonly defaultValue: string;
1705
+ readonly value: string;
1706
+ };
1707
+ export type LighthouseClient = {
1708
+ readonly checkConnectivity: () => Promise<ConnectivityValidationResult>;
1709
+ readonly getVersion: () => Promise<LighthouseApiResult<string>>;
1710
+ readonly listWorkTrackingConnections: () => Promise<LighthouseApiResult<readonly unknown[]>>;
1711
+ readonly getWorkTrackingConnection: (connectionId: number) => Promise<LighthouseApiResult<unknown>>;
1712
+ readonly createWorkTrackingConnection: (payload: LighthouseWritePayload) => Promise<LighthouseApiResult<unknown>>;
1713
+ readonly updateWorkTrackingConnection: (connectionId: number, payload: LighthouseWritePayload) => Promise<LighthouseApiResult<unknown>>;
1714
+ readonly deleteWorkTrackingConnection: (connectionId: number) => Promise<LighthouseApiResult<void>>;
1715
+ readonly listTeams: () => Promise<LighthouseApiResult<readonly unknown[]>>;
1716
+ readonly getTeam: (teamId: number) => Promise<LighthouseApiResult<unknown>>;
1717
+ readonly getTeamSettings: (teamId: number) => Promise<LighthouseApiResult<unknown>>;
1718
+ readonly createTeam: (payload: LighthouseWritePayload) => Promise<LighthouseApiResult<unknown>>;
1719
+ readonly updateTeam: (teamId: number, payload: LighthouseWritePayload) => Promise<LighthouseApiResult<unknown>>;
1720
+ readonly deleteTeam: (teamId: number) => Promise<LighthouseApiResult<void>>;
1721
+ readonly refreshTeam: (teamId: number) => Promise<LighthouseApiResult<void>>;
1722
+ readonly getTeamRefinement: (teamId: number, options?: RefinementReadOptions) => Promise<LighthouseApiResult<TeamRefinement>>;
1723
+ readonly castRefinementVote: (teamId: number, workItem: string, vote: RefinementVoteInput) => Promise<LighthouseApiResult<VotedRow>>;
1724
+ readonly addRefinementComment: (teamId: number, workItem: string, comment: RefinementCommentInput) => Promise<LighthouseApiResult<VotedRow>>;
1725
+ readonly takeBackRefinementVote: (teamId: number, workItem: string, takeBack: RefinementTakeBackInput) => Promise<LighthouseApiResult<VotedRow>>;
1726
+ readonly getRefinementLog: (teamId: number, workItem: string, options?: RefinementReadOptions) => Promise<LighthouseApiResult<SizingLog>>;
1727
+ readonly getTerminology: () => Promise<LighthouseApiResult<readonly TerminologyEntry[]>>;
1728
+ readonly listPortfolios: () => Promise<LighthouseApiResult<readonly unknown[]>>;
1729
+ readonly getPortfolio: (portfolioId: number) => Promise<LighthouseApiResult<unknown>>;
1730
+ readonly createPortfolio: (payload: LighthouseWritePayload) => Promise<LighthouseApiResult<unknown>>;
1731
+ readonly updatePortfolio: (portfolioId: number, payload: LighthouseWritePayload) => Promise<LighthouseApiResult<unknown>>;
1732
+ readonly deletePortfolio: (portfolioId: number) => Promise<LighthouseApiResult<void>>;
1733
+ readonly refreshPortfolio: (portfolioId: number) => Promise<LighthouseApiResult<void>>;
1734
+ readonly getTeamThroughput: (teamId: number, range?: MetricsDateRange, view?: ThroughputFilterView) => Promise<LighthouseApiResult<unknown>>;
1735
+ readonly getTeamArrivals: (teamId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<unknown>>;
1736
+ readonly getTeamWipOverTime: (teamId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<unknown>>;
1737
+ readonly getTeamWip: (teamId: number, asOfDate: string) => Promise<LighthouseApiResult<readonly unknown[]>>;
1738
+ readonly getTeamCycleTimePercentiles: (teamId: number, range?: MetricsDateRange, definitionId?: number) => Promise<LighthouseApiResult<readonly unknown[]>>;
1739
+ readonly getTeamWorkItemAgePercentiles: (teamId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<readonly unknown[]>>;
1740
+ readonly getTeamCycleTimeData: (teamId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<readonly unknown[]>>;
1741
+ readonly getTeamPredictabilityScore: (teamId: number, range?: MetricsDateRange, view?: ThroughputFilterView) => Promise<LighthouseApiResult<unknown>>;
1742
+ readonly getTeamTotalWorkItemAge: (teamId: number, asOfDate: string) => Promise<LighthouseApiResult<number>>;
1743
+ readonly getTeamTotalWorkItemAgeInfo: (teamId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<unknown>>;
1744
+ readonly getPortfolioThroughput: (portfolioId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<unknown>>;
1745
+ readonly getPortfolioCycleTimePercentiles: (portfolioId: number, range?: MetricsDateRange, definitionId?: number) => Promise<LighthouseApiResult<readonly unknown[]>>;
1746
+ readonly getPortfolioWorkItemAgePercentiles: (portfolioId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<readonly unknown[]>>;
1747
+ readonly getPortfolioArrivals: (portfolioId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<unknown>>;
1748
+ readonly getPortfolioWipOverTime: (portfolioId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<unknown>>;
1749
+ readonly getPortfolioWip: (portfolioId: number, asOfDate: string) => Promise<LighthouseApiResult<readonly unknown[]>>;
1750
+ readonly getPortfolioCycleTimeData: (portfolioId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<readonly unknown[]>>;
1751
+ readonly getPortfolioPredictabilityScore: (portfolioId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<unknown>>;
1752
+ readonly getTeamWorkItemAgeOverTime: (teamId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<WorkItemAgeOverTimeResult>>;
1753
+ readonly getTeamTotalWorkItemAgeOverTime: (teamId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<TotalWorkItemAgeOverTimeResult>>;
1754
+ readonly getPortfolioTotalWorkItemAge: (portfolioId: number, asOfDate: string) => Promise<LighthouseApiResult<number>>;
1755
+ readonly getPortfolioTotalWorkItemAgeInfo: (portfolioId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<unknown>>;
1756
+ readonly getPortfolioWorkItemAgeOverTime: (portfolioId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<WorkItemAgeOverTimeResult>>;
1757
+ readonly getPortfolioTotalWorkItemAgeOverTime: (portfolioId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<TotalWorkItemAgeOverTimeResult>>;
1758
+ readonly getTeamBlockedCountHistory: (teamId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<readonly BlockedCountSnapshot[]>>;
1759
+ readonly getPortfolioBlockedCountHistory: (portfolioId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<readonly BlockedCountSnapshot[]>>;
1760
+ readonly getTeamPercentilesOverTime: (teamId: number, range?: MetricsDateRange, metricType?: PercentilesOverTimeMetricType, horizon?: number) => Promise<LighthouseApiResult<readonly PercentilesOverTimeSnapshot[]>>;
1761
+ readonly getPortfolioPercentilesOverTime: (portfolioId: number, range?: MetricsDateRange, metricType?: PercentilesOverTimeMetricType, horizon?: number) => Promise<LighthouseApiResult<readonly PercentilesOverTimeSnapshot[]>>;
1762
+ readonly getTeamProcessBehaviorOverTime: (teamId: number, range?: MetricsDateRange, metricType?: ProcessBehaviorMetricType) => Promise<LighthouseApiResult<readonly ProcessBehaviorSnapshot[]>>;
1763
+ readonly getPortfolioProcessBehaviorOverTime: (portfolioId: number, range?: MetricsDateRange, metricType?: ProcessBehaviorMetricType) => Promise<LighthouseApiResult<readonly ProcessBehaviorSnapshot[]>>;
1764
+ readonly getTeamProcessBehaviorChart: (teamId: number, range: MetricsDateRange | undefined, metricType: TeamProcessBehaviorMetricType) => Promise<LighthouseApiResult<ProcessBehaviorChart>>;
1765
+ readonly getPortfolioProcessBehaviorChart: (portfolioId: number, range: MetricsDateRange | undefined, metricType: ProcessBehaviorMetricType) => Promise<LighthouseApiResult<ProcessBehaviorChart>>;
1766
+ readonly getTeamSleRisk: (teamId: number) => Promise<LighthouseApiResult<readonly SleRiskEntry[]>>;
1767
+ readonly getTeamCumulativeStateTime: (teamId: number, range?: MetricsDateRange, itemIds?: readonly number[]) => Promise<LighthouseApiResult<CumulativeStateTimeResult>>;
1768
+ readonly getTeamCumulativeStateTimeItems: (teamId: number, state: string, range?: MetricsDateRange, itemIds?: readonly number[]) => Promise<LighthouseApiResult<CumulativeStateTimeItemsResult>>;
1769
+ readonly getTeamCumulativeStateTimeCandidates: (teamId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<CumulativeStateTimeCandidatesResult>>;
1770
+ readonly getPortfolioCumulativeStateTime: (portfolioId: number, range?: MetricsDateRange, itemIds?: readonly number[]) => Promise<LighthouseApiResult<CumulativeStateTimeResult>>;
1771
+ readonly getPortfolioCumulativeStateTimeItems: (portfolioId: number, state: string, range?: MetricsDateRange, itemIds?: readonly number[]) => Promise<LighthouseApiResult<CumulativeStateTimeItemsResult>>;
1772
+ readonly getPortfolioCumulativeStateTimeCandidates: (portfolioId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<CumulativeStateTimeCandidatesResult>>;
1773
+ readonly getFeaturesByIds: (ids: readonly number[]) => Promise<LighthouseApiResult<readonly unknown[]>>;
1774
+ readonly getFeaturesByReferences: (refs: readonly string[]) => Promise<LighthouseApiResult<readonly unknown[]>>;
1775
+ readonly getFeatureWorkItems: (featureId: number) => Promise<LighthouseApiResult<readonly unknown[]>>;
1776
+ readonly listDeliveries: (portfolioId: number) => Promise<LighthouseApiResult<readonly unknown[]>>;
1777
+ readonly createDelivery: (portfolioId: number, payload: LighthouseWritePayload) => Promise<LighthouseApiResult<unknown>>;
1778
+ readonly updateDelivery: (deliveryId: number, payload: LighthouseWritePayload) => Promise<LighthouseApiResult<unknown>>;
1779
+ readonly deleteDelivery: (deliveryId: number) => Promise<LighthouseApiResult<undefined>>;
1780
+ readonly getDeliveryMetricsHistory: (deliveryId: number) => Promise<LighthouseApiResult<DeliveryMetricsHistory>>;
1781
+ readonly getRecurringBlackoutRules: () => Promise<LighthouseApiResult<readonly RecurringBlackoutRule[]>>;
1782
+ readonly createRecurringBlackoutRule: (payload: LighthouseWritePayload) => Promise<LighthouseApiResult<RecurringBlackoutRule>>;
1783
+ readonly updateRecurringBlackoutRule: (id: number, payload: LighthouseWritePayload) => Promise<LighthouseApiResult<RecurringBlackoutRule>>;
1784
+ readonly deleteRecurringBlackoutRule: (id: number) => Promise<LighthouseApiResult<undefined>>;
1785
+ readonly runManualForecast: (teamId: number, payload: ManualForecastInput) => Promise<LighthouseApiResult<unknown>>;
1786
+ readonly runBacktest: (teamId: number, payload: BacktestInput) => Promise<LighthouseApiResult<unknown>>;
1787
+ readonly getUsageDataState: (options?: UsageDataCallOptions) => Promise<LighthouseApiResult<UsageDataState>>;
1788
+ /** Records a yes; the value is the consent token Lighthouse minted for it. */
1789
+ readonly grantUsageData: (options?: UsageDataCallOptions) => Promise<LighthouseApiResult<string>>;
1790
+ readonly revokeUsageData: (options: UsageDataCallOptions & {
1791
+ readonly token: string;
1792
+ }) => Promise<LighthouseApiResult<undefined>>;
1793
+ readonly handInUsageData: (batch: UsageDataBatch, options: UsageDataCallOptions & {
1794
+ readonly token: string;
1795
+ }) => Promise<LighthouseApiResult<undefined>>;
1796
+ };
1797
+ export type UsageDataCallOptions = {
1798
+ readonly token?: string;
1799
+ readonly signal?: AbortSignal;
1800
+ };
1801
+ export type LighthouseClientDependencies = {
1802
+ readonly fetch?: (url: string, init?: RequestInit) => Promise<ConnectivityFetchResponse>;
487
1803
  };
488
1804
  /**
489
1805
  * Server-version gating for endpoints that did not exist in older Lighthouse
@@ -493,22 +1809,26 @@ type LighthouseClientDependencies = {
493
1809
  * callable. Update the baseline to the current latest release whenever a new
494
1810
  * server-dependent feature is wrapped.
495
1811
  */
496
- declare const FEATURE_REQUIRES_SERVER_NEWER_THAN: {
497
- readonly cumulativeStateTime: "v26.5.24.10";
498
- readonly recurringBlackoutRules: "v26.5.29.5";
499
- readonly workItemAgePercentiles: "v26.6.7.1";
500
- readonly mcpOAuthPassThrough: "v26.6.16.14";
501
- readonly blockedCountHistory: "v26.7.3.1";
502
- readonly percentilesOverTime: "v26.7.11.4";
503
- readonly processBehaviorOverTime: "v26.7.11.4";
504
- readonly deliveryMetricsHistory: "v26.5.29.5";
1812
+ export declare const FEATURE_REQUIRES_SERVER_NEWER_THAN: {
1813
+ readonly cumulativeStateTime: "v26.5.24.10";
1814
+ readonly recurringBlackoutRules: "v26.5.29.5";
1815
+ readonly workItemAgePercentiles: "v26.6.7.1";
1816
+ readonly mcpOAuthPassThrough: "v26.6.16.14";
1817
+ readonly blockedCountHistory: "v26.7.3.1";
1818
+ readonly percentilesOverTime: "v26.7.11.4";
1819
+ readonly processBehaviorOverTime: "v26.7.11.4";
1820
+ readonly deliveryMetricsHistory: "v26.5.29.5";
1821
+ readonly sleRisk: "v26.9.19.10";
1822
+ readonly teamRefinement: "v26.10.3.6";
1823
+ readonly refinementVotes: "v26.10.3.6";
505
1824
  };
506
1825
  /**
507
1826
  * Returns true when `candidate` is strictly newer than `baseline`, false when
508
1827
  * it is equal-or-older, and null when either string is unparseable (treat as
509
1828
  * "unknown — do not block").
510
1829
  */
511
- declare const isServerVersionNewerThan: (candidate: string, baseline: string) => boolean | null;
512
- declare const createLighthouseClient: (configuration: LighthouseClientConfiguration, dependencies?: LighthouseClientDependencies) => LighthouseClient;
513
-
514
- export { type BacktestInput, type BlockedCountSnapshot, type CliAuthSessionPollResult, type CliAuthSessionStartError, type CliAuthSessionStartOutcome, type CliAuthSessionStartResult, type CliConnection, type CliServerAuthMode, type CliServerConnection, type CliStandaloneConnection, type ClientCapability, type ClientPackageContract, type ConnectivityCategory, type ConnectivityDependencies, type ConnectivityFetchResponse, type ConnectivityValidationResult, type CumulativeStateTimeCandidateRow, type CumulativeStateTimeCandidatesResult, type CumulativeStateTimeItemRow, type CumulativeStateTimeItemsResult, type CumulativeStateTimeResult, type CumulativeStateTimeStateRow, type DailyTotalWorkItemAge, type DailyWorkItemAge, type DayOfWeek, type DeliveryFeatureMetric, type DeliveryMetricsHistory, type DeliveryMetricsHistoryPoint, type DeliveryMetricsHistorySummaryRow, type DeliveryWhenDistributionPoint, FEATURE_REQUIRES_SERVER_NEWER_THAN, type LighthouseApiError, type LighthouseApiResult, type LighthouseAuthContext, type LighthouseAuthOverrides, type LighthouseAuthStatus, type LighthouseAuthStore, type LighthouseClient, type LighthouseClientAuth, type LighthouseClientConfiguration, type LighthouseClientDependencies, type LighthouseConnectionConfiguration, type LighthouseWritePayload, type ManualForecastInput, type MetricsDateRange, type PercentilesOverTimeMetricType, type PercentilesOverTimeSnapshot, type ProcessBehaviorMetricType, type ProcessBehaviorSnapshot, type RecurringBlackoutRule, type RecurringBlackoutRuleInput, type ResolvedLighthouseEndpoint, type ServerAuthModeResult, type StandaloneDiscoveryContract, type StandaloneDiscoveryContractParseResult, type StoredLighthouseAuth, type ThroughputFilterView, type TotalWorkItemAgeOverTimeResult, type WorkItemAgeEntry, type WorkItemAgeOverTimeResult, createLighthouseAuthContext, createLighthouseClient, getClientPackageContract, getDefaultMetricsDateRange, getStandaloneDiscoveryLockfilePath, isServerVersionNewerThan, loadStandaloneDiscoveryContract, parseStandaloneDiscoveryContract, pollCliAuthSession, queryServerAuthMode, startCliAuthSession, summariseDeliveryMetricsHistory, validateLighthouseConnectivity };
1830
+ export declare const isServerVersionNewerThan: (candidate: string, baseline: string) => boolean | null;
1831
+ /** The header a client sends its voter key in, so Lighthouse can tell its votes from anyone else's. */
1832
+ export declare const VOTER_KEY_HEADER = "X-Lighthouse-Voter-Key";
1833
+ export declare const createLighthouseClient: (configuration: LighthouseClientConfiguration, dependencies?: LighthouseClientDependencies) => LighthouseClient;
1834
+ //#endregion