@letpeoplework/lighthouse-mcp-core 1.7.0 → 1.8.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.cjs +1930 -1660
- package/dist/index.d.cts +684 -549
- package/dist/index.d.ts +684 -549
- package/dist/index.js +1919 -1635
- package/package.json +9 -6
package/dist/index.cjs
CHANGED
|
@@ -1,1669 +1,1939 @@
|
|
|
1
|
-
"
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
// src/index.ts
|
|
21
|
-
var index_exports = {};
|
|
22
|
-
__export(index_exports, {
|
|
23
|
-
createMcpCoreRuntime: () => createMcpCoreRuntime,
|
|
24
|
-
getMcpCorePackageContract: () => getMcpCorePackageContract,
|
|
25
|
-
registerMcpTools: () => registerMcpTools
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
let _letpeoplework_lighthouse_client = require("@letpeoplework/lighthouse-client");
|
|
3
|
+
let _modelcontextprotocol_sdk_types_js = require("@modelcontextprotocol/sdk/types.js");
|
|
4
|
+
let zod = require("zod");
|
|
5
|
+
let _toon_format_toon = require("@toon-format/toon");
|
|
6
|
+
//#region src/toolResult.ts
|
|
7
|
+
const encodePayload = (value) => {
|
|
8
|
+
try {
|
|
9
|
+
return (0, _toon_format_toon.encode)(value);
|
|
10
|
+
} catch {
|
|
11
|
+
return JSON.stringify(value);
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
const getSuccessToolResult = (text) => ({
|
|
15
|
+
isError: false,
|
|
16
|
+
content: [{
|
|
17
|
+
type: "text",
|
|
18
|
+
text
|
|
19
|
+
}]
|
|
26
20
|
});
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
21
|
+
const isFactsObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
22
|
+
/**
|
|
23
|
+
* The facts under their label, with the answer stated as the web does beside them. Without a summary the
|
|
24
|
+
* facts go out exactly as they always have, so an assistant reading them never sees a different shape.
|
|
25
|
+
* An object takes the summary as a field. A list, a single value, or an object that already has a
|
|
26
|
+
* `summary` of its own cannot take one without changing its facts, so its summary follows in a second
|
|
27
|
+
* block.
|
|
28
|
+
*/
|
|
29
|
+
const withSummary = (label, facts, summary) => {
|
|
30
|
+
if (summary !== null && isFactsObject(facts) && !("summary" in facts)) return getSuccessToolResult(`${label}: ${encodePayload({
|
|
31
|
+
summary,
|
|
32
|
+
...facts
|
|
33
|
+
})}`);
|
|
34
|
+
return withSummaryBlock(`${label}: ${encodePayload(facts)}`, summary);
|
|
35
|
+
};
|
|
36
|
+
/** A text block exactly as it is, with the summary in a second block after it; without one, the text alone. */
|
|
37
|
+
const withSummaryBlock = (text, summary) => summary === null ? getSuccessToolResult(text) : {
|
|
38
|
+
isError: false,
|
|
39
|
+
content: [{
|
|
40
|
+
type: "text",
|
|
41
|
+
text
|
|
42
|
+
}, {
|
|
43
|
+
type: "text",
|
|
44
|
+
text: `summary: ${summary}`
|
|
45
|
+
}]
|
|
46
|
+
};
|
|
47
|
+
const getErrorToolResult = (text) => ({
|
|
48
|
+
isError: true,
|
|
49
|
+
content: [{
|
|
50
|
+
type: "text",
|
|
51
|
+
text
|
|
52
|
+
}]
|
|
35
53
|
});
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
},
|
|
238
|
-
required: ["id"],
|
|
239
|
-
additionalProperties: false
|
|
240
|
-
}
|
|
241
|
-
},
|
|
242
|
-
{
|
|
243
|
-
name: "lighthouse_portfolio_metrics_workItemAgePercentiles",
|
|
244
|
-
description: "Get work-item age percentiles for a portfolio by ID, optionally filtered by start and end dates. Ages are measured as of the last day of the selected range, not as of today \u2014 a historical range reports how old the items were at the end of that period, so do not present the result as the portfolio's current ages unless the range ends today.",
|
|
245
|
-
inputSchema: {
|
|
246
|
-
type: "object",
|
|
247
|
-
properties: {
|
|
248
|
-
...idInputSchema.properties,
|
|
249
|
-
...dateRangeProperties
|
|
250
|
-
},
|
|
251
|
-
required: ["id"],
|
|
252
|
-
additionalProperties: false
|
|
253
|
-
}
|
|
254
|
-
},
|
|
255
|
-
{
|
|
256
|
-
name: "lighthouse_team_metrics_blockedCountHistory",
|
|
257
|
-
description: "Get the blocked-items-over-time trend for a team by ID: how many work items were blocked on each captured day, optionally filtered by start and end dates. To see what is blocked right now and for how long, read the team's current WIP \u2014 each item carries isBlocked and, when blocked, a blockedSince timestamp.",
|
|
258
|
-
inputSchema: {
|
|
259
|
-
type: "object",
|
|
260
|
-
properties: {
|
|
261
|
-
...idInputSchema.properties,
|
|
262
|
-
...dateRangeProperties
|
|
263
|
-
},
|
|
264
|
-
required: ["id"],
|
|
265
|
-
additionalProperties: false
|
|
266
|
-
}
|
|
267
|
-
},
|
|
268
|
-
{
|
|
269
|
-
name: "lighthouse_portfolio_metrics_blockedCountHistory",
|
|
270
|
-
description: "Get the blocked-items-over-time trend for a portfolio by ID: how many work items were blocked on each captured day, optionally filtered by start and end dates. To see what is blocked right now and for how long, read the portfolio's current WIP \u2014 each item carries isBlocked and, when blocked, a blockedSince timestamp.",
|
|
271
|
-
inputSchema: {
|
|
272
|
-
type: "object",
|
|
273
|
-
properties: {
|
|
274
|
-
...idInputSchema.properties,
|
|
275
|
-
...dateRangeProperties
|
|
276
|
-
},
|
|
277
|
-
required: ["id"],
|
|
278
|
-
additionalProperties: false
|
|
279
|
-
}
|
|
280
|
-
},
|
|
281
|
-
{
|
|
282
|
-
name: "lighthouse_team_metrics_percentilesOverTime",
|
|
283
|
-
description: "Get the percentiles-over-time trend for a team by ID: the p50/p70/p85/p95 quartet recorded on each captured day, optionally filtered by start and end dates. Recording is forward-only \u2014 Lighthouse never backfills days it did not observe, so a recently upgraded server returns an empty series until it has recorded some. Use metricType to pick the family and horizon to pick the cycle-time window.",
|
|
284
|
-
inputSchema: {
|
|
285
|
-
type: "object",
|
|
286
|
-
properties: {
|
|
287
|
-
...idInputSchema.properties,
|
|
288
|
-
...dateRangeProperties,
|
|
289
|
-
...percentilesOverTimeProperties
|
|
290
|
-
},
|
|
291
|
-
required: ["id"],
|
|
292
|
-
additionalProperties: false
|
|
293
|
-
}
|
|
294
|
-
},
|
|
295
|
-
{
|
|
296
|
-
name: "lighthouse_portfolio_metrics_percentilesOverTime",
|
|
297
|
-
description: "Get the percentiles-over-time trend for a portfolio by ID: the p50/p70/p85/p95 quartet recorded on each captured day, optionally filtered by start and end dates. Recording is forward-only \u2014 Lighthouse never backfills days it did not observe, so a recently upgraded server returns an empty series until it has recorded some. Use metricType to pick the family and horizon to pick the cycle-time window.",
|
|
298
|
-
inputSchema: {
|
|
299
|
-
type: "object",
|
|
300
|
-
properties: {
|
|
301
|
-
...idInputSchema.properties,
|
|
302
|
-
...dateRangeProperties,
|
|
303
|
-
...percentilesOverTimeProperties
|
|
304
|
-
},
|
|
305
|
-
required: ["id"],
|
|
306
|
-
additionalProperties: false
|
|
307
|
-
}
|
|
308
|
-
},
|
|
309
|
-
{
|
|
310
|
-
name: "lighthouse_team_metrics_processBehaviorOverTime",
|
|
311
|
-
description: "Get the process-behaviour-limits-over-time trend for a team by ID: the upper limit, average and lower limit (UNPL/Average/LNPL) recorded on each captured day, optionally filtered by start and end dates. Recording is forward-only, and days without a usable baseline are absent rather than zeroed \u2014 an empty series means nothing was recorded, never a process pinned at zero.",
|
|
312
|
-
inputSchema: {
|
|
313
|
-
type: "object",
|
|
314
|
-
properties: {
|
|
315
|
-
...idInputSchema.properties,
|
|
316
|
-
...dateRangeProperties,
|
|
317
|
-
...processBehaviorOverTimeProperties
|
|
318
|
-
},
|
|
319
|
-
required: ["id"],
|
|
320
|
-
additionalProperties: false
|
|
321
|
-
}
|
|
322
|
-
},
|
|
323
|
-
{
|
|
324
|
-
name: "lighthouse_portfolio_metrics_processBehaviorOverTime",
|
|
325
|
-
description: "Get the process-behaviour-limits-over-time trend for a portfolio by ID: the upper limit, average and lower limit (UNPL/Average/LNPL) recorded on each captured day, optionally filtered by start and end dates. Recording is forward-only, and days without a usable baseline are absent rather than zeroed \u2014 an empty series means nothing was recorded, never a process pinned at zero. FeatureSize is available here and not on teams.",
|
|
326
|
-
inputSchema: {
|
|
327
|
-
type: "object",
|
|
328
|
-
properties: {
|
|
329
|
-
...idInputSchema.properties,
|
|
330
|
-
...dateRangeProperties,
|
|
331
|
-
...processBehaviorOverTimeProperties
|
|
332
|
-
},
|
|
333
|
-
required: ["id"],
|
|
334
|
-
additionalProperties: false
|
|
335
|
-
}
|
|
336
|
-
},
|
|
337
|
-
{
|
|
338
|
-
name: "lighthouse_portfolio_metrics_throughput",
|
|
339
|
-
description: "Get throughput run-chart data for a portfolio by ID, optionally filtered by start and end dates.",
|
|
340
|
-
inputSchema: {
|
|
341
|
-
type: "object",
|
|
342
|
-
properties: {
|
|
343
|
-
...idInputSchema.properties,
|
|
344
|
-
...dateRangeProperties
|
|
345
|
-
},
|
|
346
|
-
required: ["id"],
|
|
347
|
-
additionalProperties: false
|
|
348
|
-
}
|
|
349
|
-
},
|
|
350
|
-
{
|
|
351
|
-
name: "lighthouse_team_metrics_workItemAge",
|
|
352
|
-
description: "Get per-item work item age over time for a team by ID. Returns daily snapshots with each in-progress item's age in days derived from its startedDate. Items without a startedDate are omitted.",
|
|
353
|
-
inputSchema: {
|
|
354
|
-
type: "object",
|
|
355
|
-
properties: {
|
|
356
|
-
...idInputSchema.properties,
|
|
357
|
-
...dateRangeProperties
|
|
358
|
-
},
|
|
359
|
-
required: ["id"],
|
|
360
|
-
additionalProperties: false
|
|
361
|
-
}
|
|
362
|
-
},
|
|
363
|
-
{
|
|
364
|
-
name: "lighthouse_team_metrics_totalWorkItemAge",
|
|
365
|
-
description: "Get the total (summed) work item age over time for a team by ID. Returns daily totals of all in-progress item ages derived from startedDate. Items without a startedDate are not counted.",
|
|
366
|
-
inputSchema: {
|
|
367
|
-
type: "object",
|
|
368
|
-
properties: {
|
|
369
|
-
...idInputSchema.properties,
|
|
370
|
-
...dateRangeProperties
|
|
371
|
-
},
|
|
372
|
-
required: ["id"],
|
|
373
|
-
additionalProperties: false
|
|
374
|
-
}
|
|
375
|
-
},
|
|
376
|
-
{
|
|
377
|
-
name: "lighthouse_portfolio_metrics_workItemAge",
|
|
378
|
-
description: "Get per-item work item age over time for a portfolio by ID. Returns daily snapshots with each in-progress item's age in days derived from its startedDate. Items without a startedDate are omitted.",
|
|
379
|
-
inputSchema: {
|
|
380
|
-
type: "object",
|
|
381
|
-
properties: {
|
|
382
|
-
...idInputSchema.properties,
|
|
383
|
-
...dateRangeProperties
|
|
384
|
-
},
|
|
385
|
-
required: ["id"],
|
|
386
|
-
additionalProperties: false
|
|
387
|
-
}
|
|
388
|
-
},
|
|
389
|
-
{
|
|
390
|
-
name: "lighthouse_portfolio_metrics_totalWorkItemAge",
|
|
391
|
-
description: "Get the total (summed) work item age over time for a portfolio by ID. Returns daily totals of all in-progress item ages derived from startedDate. Items without a startedDate are not counted.",
|
|
392
|
-
inputSchema: {
|
|
393
|
-
type: "object",
|
|
394
|
-
properties: {
|
|
395
|
-
...idInputSchema.properties,
|
|
396
|
-
...dateRangeProperties
|
|
397
|
-
},
|
|
398
|
-
required: ["id"],
|
|
399
|
-
additionalProperties: false
|
|
400
|
-
}
|
|
401
|
-
},
|
|
402
|
-
{
|
|
403
|
-
name: "lighthouse_feature_get",
|
|
404
|
-
description: "Get feature details by numeric IDs or external reference IDs.",
|
|
405
|
-
inputSchema: {
|
|
406
|
-
type: "object",
|
|
407
|
-
properties: {
|
|
408
|
-
ids: {
|
|
409
|
-
type: "array",
|
|
410
|
-
items: {
|
|
411
|
-
type: "integer"
|
|
412
|
-
},
|
|
413
|
-
description: "Feature IDs."
|
|
414
|
-
},
|
|
415
|
-
refs: {
|
|
416
|
-
type: "array",
|
|
417
|
-
items: {
|
|
418
|
-
type: "string"
|
|
419
|
-
},
|
|
420
|
-
description: "Feature reference identifiers."
|
|
421
|
-
}
|
|
422
|
-
},
|
|
423
|
-
additionalProperties: false
|
|
424
|
-
}
|
|
425
|
-
},
|
|
426
|
-
{
|
|
427
|
-
name: "lighthouse_feature_workitems",
|
|
428
|
-
description: "Get work items linked to a feature by ID.",
|
|
429
|
-
inputSchema: idInputSchema
|
|
430
|
-
},
|
|
431
|
-
{
|
|
432
|
-
name: "lighthouse_delivery_list",
|
|
433
|
-
description: "List deliveries for a portfolio by portfolio ID.",
|
|
434
|
-
inputSchema: idInputSchema
|
|
435
|
-
},
|
|
436
|
-
{
|
|
437
|
-
name: "lighthouse_delivery_metrics",
|
|
438
|
-
description: `Get a delivery's recorded trend by delivery ID: one row per day with total, done and remaining work, the epic count and the likelihood. Set detail to "epics" for the per-epic breakdown and the forecast distribution, which are far larger. Forward-only, so it starts at the first recorded snapshot. Requires Lighthouse newer than v26.5.29.5.`,
|
|
439
|
-
inputSchema: {
|
|
440
|
-
type: "object",
|
|
441
|
-
properties: {
|
|
442
|
-
id: { type: "number", description: "Delivery ID." },
|
|
443
|
-
detail: {
|
|
444
|
-
type: "string",
|
|
445
|
-
enum: ["epics"],
|
|
446
|
-
description: 'Omit for one row per day. "epics" returns the whole recorded payload.'
|
|
447
|
-
}
|
|
448
|
-
},
|
|
449
|
-
required: ["id"],
|
|
450
|
-
additionalProperties: false
|
|
451
|
-
}
|
|
452
|
-
},
|
|
453
|
-
{
|
|
454
|
-
name: "lighthouse_blackout_list",
|
|
455
|
-
description: "List the recurring blackout rules (recurring non-working days excluded from forecasts). Requires Lighthouse newer than v26.5.29.5.",
|
|
456
|
-
inputSchema: emptyInputSchema
|
|
457
|
-
},
|
|
458
|
-
{
|
|
459
|
-
name: "lighthouse_blackout_create",
|
|
460
|
-
description: "Create a recurring blackout rule (weekdays + every-N-weeks interval + start date + optional open end). Premium, system-admin only. Requires Lighthouse newer than v26.5.29.5.",
|
|
461
|
-
inputSchema: {
|
|
462
|
-
type: "object",
|
|
463
|
-
properties: {
|
|
464
|
-
...recurringBlackoutRuleProperties
|
|
465
|
-
},
|
|
466
|
-
required: ["weekdays", "intervalWeeks", "start", "description"],
|
|
467
|
-
additionalProperties: false
|
|
468
|
-
}
|
|
469
|
-
},
|
|
470
|
-
{
|
|
471
|
-
name: "lighthouse_blackout_update",
|
|
472
|
-
description: "Update a recurring blackout rule by ID. Premium, system-admin only. Requires Lighthouse newer than v26.5.29.5.",
|
|
473
|
-
inputSchema: {
|
|
474
|
-
type: "object",
|
|
475
|
-
properties: {
|
|
476
|
-
...idInputSchema.properties,
|
|
477
|
-
...recurringBlackoutRuleProperties
|
|
478
|
-
},
|
|
479
|
-
required: ["id", "weekdays", "intervalWeeks", "start", "description"],
|
|
480
|
-
additionalProperties: false
|
|
481
|
-
}
|
|
482
|
-
},
|
|
483
|
-
{
|
|
484
|
-
name: "lighthouse_blackout_delete",
|
|
485
|
-
description: "Delete a recurring blackout rule by ID. Premium, system-admin only. Requires Lighthouse newer than v26.5.29.5.",
|
|
486
|
-
inputSchema: idInputSchema
|
|
487
|
-
},
|
|
488
|
-
{
|
|
489
|
-
name: "lighthouse_forecast_manual",
|
|
490
|
-
description: "Run a manual forecast for a team by ID with optional remaining items and target date. Pass applyFilterOverride=true to apply the team's forecast filter, false to skip it, or omit to respect the team setting (Lighthouse v26.5.24.10+). The response includes filterApplied (boolean) and excludedSummary (string) when a filter was applied.",
|
|
491
|
-
inputSchema: {
|
|
492
|
-
type: "object",
|
|
493
|
-
properties: {
|
|
494
|
-
...idInputSchema.properties,
|
|
495
|
-
remainingItems: {
|
|
496
|
-
type: "integer",
|
|
497
|
-
description: "Remaining items to forecast."
|
|
498
|
-
},
|
|
499
|
-
targetDate: {
|
|
500
|
-
type: "string",
|
|
501
|
-
description: "Optional target date in ISO format (YYYY-MM-DD)."
|
|
502
|
-
},
|
|
503
|
-
...forecastFilterOverrideProperty
|
|
504
|
-
},
|
|
505
|
-
required: ["id"],
|
|
506
|
-
additionalProperties: false
|
|
507
|
-
}
|
|
508
|
-
},
|
|
509
|
-
{
|
|
510
|
-
name: "lighthouse_forecast_backtest",
|
|
511
|
-
description: "Run a forecast backtest for a team by ID using forecast and historical date ranges. Pass applyFilterOverride=true to apply the team's forecast filter, false to skip it, or omit to respect the team setting (Lighthouse v26.5.24.10+). The response includes filterApplied (boolean) and excludedSummary (string) when a filter was applied.",
|
|
512
|
-
inputSchema: {
|
|
513
|
-
type: "object",
|
|
514
|
-
properties: {
|
|
515
|
-
...idInputSchema.properties,
|
|
516
|
-
startDate: {
|
|
517
|
-
type: "string",
|
|
518
|
-
description: "Forecast start date in ISO format (YYYY-MM-DD)."
|
|
519
|
-
},
|
|
520
|
-
endDate: {
|
|
521
|
-
type: "string",
|
|
522
|
-
description: "Forecast end date in ISO format (YYYY-MM-DD)."
|
|
523
|
-
},
|
|
524
|
-
historicalStartDate: {
|
|
525
|
-
type: "string",
|
|
526
|
-
description: "Historical sample start date in ISO format (YYYY-MM-DD)."
|
|
527
|
-
},
|
|
528
|
-
historicalEndDate: {
|
|
529
|
-
type: "string",
|
|
530
|
-
description: "Historical sample end date in ISO format (YYYY-MM-DD)."
|
|
531
|
-
},
|
|
532
|
-
...forecastFilterOverrideProperty
|
|
533
|
-
},
|
|
534
|
-
required: [
|
|
535
|
-
"id",
|
|
536
|
-
"startDate",
|
|
537
|
-
"endDate",
|
|
538
|
-
"historicalStartDate",
|
|
539
|
-
"historicalEndDate"
|
|
540
|
-
],
|
|
541
|
-
additionalProperties: false
|
|
542
|
-
}
|
|
543
|
-
},
|
|
544
|
-
{
|
|
545
|
-
name: "lighthouse_team_metrics_cumulativeStateTime",
|
|
546
|
-
description: "Get cumulative time-per-state bar data for a team by ID: one entry per Doing-category workflow state with total/completed/ongoing contribution days and item counts. Optionally filter by date range and a subset of work-item IDs.",
|
|
547
|
-
inputSchema: {
|
|
548
|
-
type: "object",
|
|
549
|
-
properties: {
|
|
550
|
-
...idInputSchema.properties,
|
|
551
|
-
...dateRangeProperties,
|
|
552
|
-
...itemIdsProperty
|
|
553
|
-
},
|
|
554
|
-
required: ["id"],
|
|
555
|
-
additionalProperties: false
|
|
556
|
-
}
|
|
557
|
-
},
|
|
558
|
-
{
|
|
559
|
-
name: "lighthouse_team_metrics_cumulativeStateTimeItems",
|
|
560
|
-
description: "Get the per-item drill-down for ONE state of a team's cumulative time-per-state chart: the work items that contributed to that state, with days contributed. Requires the state name.",
|
|
561
|
-
inputSchema: {
|
|
562
|
-
type: "object",
|
|
563
|
-
properties: {
|
|
564
|
-
...idInputSchema.properties,
|
|
565
|
-
...cumulativeStateProperty,
|
|
566
|
-
...dateRangeProperties,
|
|
567
|
-
...itemIdsProperty
|
|
568
|
-
},
|
|
569
|
-
required: ["id", "state"],
|
|
570
|
-
additionalProperties: false
|
|
571
|
-
}
|
|
572
|
-
},
|
|
573
|
-
{
|
|
574
|
-
name: "lighthouse_team_metrics_cumulativeStateTimeCandidates",
|
|
575
|
-
description: "List the work items selectable in a team's cumulative time-per-state item picker for the window (the in-scope candidate set). Search keys are referenceId and title.",
|
|
576
|
-
inputSchema: {
|
|
577
|
-
type: "object",
|
|
578
|
-
properties: {
|
|
579
|
-
...idInputSchema.properties,
|
|
580
|
-
...dateRangeProperties
|
|
581
|
-
},
|
|
582
|
-
required: ["id"],
|
|
583
|
-
additionalProperties: false
|
|
584
|
-
}
|
|
585
|
-
},
|
|
586
|
-
{
|
|
587
|
-
name: "lighthouse_portfolio_metrics_cumulativeStateTime",
|
|
588
|
-
description: "Get cumulative time-per-state bar data for a portfolio by ID: one entry per Doing-category workflow state with total/completed/ongoing contribution days and item counts. Optionally filter by date range and a subset of work-item IDs.",
|
|
589
|
-
inputSchema: {
|
|
590
|
-
type: "object",
|
|
591
|
-
properties: {
|
|
592
|
-
...idInputSchema.properties,
|
|
593
|
-
...dateRangeProperties,
|
|
594
|
-
...itemIdsProperty
|
|
595
|
-
},
|
|
596
|
-
required: ["id"],
|
|
597
|
-
additionalProperties: false
|
|
598
|
-
}
|
|
599
|
-
},
|
|
600
|
-
{
|
|
601
|
-
name: "lighthouse_portfolio_metrics_cumulativeStateTimeItems",
|
|
602
|
-
description: "Get the per-item drill-down for ONE state of a portfolio's cumulative time-per-state chart: the work items that contributed to that state, with days contributed. Requires the state name.",
|
|
603
|
-
inputSchema: {
|
|
604
|
-
type: "object",
|
|
605
|
-
properties: {
|
|
606
|
-
...idInputSchema.properties,
|
|
607
|
-
...cumulativeStateProperty,
|
|
608
|
-
...dateRangeProperties,
|
|
609
|
-
...itemIdsProperty
|
|
610
|
-
},
|
|
611
|
-
required: ["id", "state"],
|
|
612
|
-
additionalProperties: false
|
|
613
|
-
}
|
|
614
|
-
},
|
|
615
|
-
{
|
|
616
|
-
name: "lighthouse_portfolio_metrics_cumulativeStateTimeCandidates",
|
|
617
|
-
description: "List the work items selectable in a portfolio's cumulative time-per-state item picker for the window (the in-scope candidate set). Search keys are referenceId and title.",
|
|
618
|
-
inputSchema: {
|
|
619
|
-
type: "object",
|
|
620
|
-
properties: {
|
|
621
|
-
...idInputSchema.properties,
|
|
622
|
-
...dateRangeProperties
|
|
623
|
-
},
|
|
624
|
-
required: ["id"],
|
|
625
|
-
additionalProperties: false
|
|
626
|
-
}
|
|
627
|
-
}
|
|
54
|
+
const isToolResult = (value) => typeof value === "object" && value !== null && "isError" in value && "content" in value;
|
|
55
|
+
const getNumericId = (argumentsPayload) => {
|
|
56
|
+
if (typeof argumentsPayload !== "object" || argumentsPayload === null || Array.isArray(argumentsPayload)) return null;
|
|
57
|
+
const value = argumentsPayload.id;
|
|
58
|
+
if (typeof value === "number" && Number.isInteger(value)) return value;
|
|
59
|
+
return null;
|
|
60
|
+
};
|
|
61
|
+
//#endregion
|
|
62
|
+
//#region src/usageDataPort.ts
|
|
63
|
+
const USAGE_DATA_ELICITATION_MESSAGE = [
|
|
64
|
+
"May Lighthouse send usage data?",
|
|
65
|
+
"The Lighthouse MCP server tells your Lighthouse which tools you use (never names, ids, URLs or anything you typed), so we can see what helps.",
|
|
66
|
+
"Details: https://docs.lighthouse.letpeople.work/settings/usagedata.html",
|
|
67
|
+
"(change any time: lh config usage-data on|off)"
|
|
68
|
+
].join("\n");
|
|
69
|
+
const USAGE_DATA_QUESTION_TIMEOUT_MS = 5e4;
|
|
70
|
+
const ANSWERS = {
|
|
71
|
+
accept: "yes",
|
|
72
|
+
decline: "no",
|
|
73
|
+
cancel: null
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* Puts the usage data question through the assistant. Accepting is a yes and declining a No; a cancel, a
|
|
77
|
+
* closed question, an error or no answer in time is no answer at all.
|
|
78
|
+
*/
|
|
79
|
+
const askThroughTheAssistant = (send) => async () => {
|
|
80
|
+
try {
|
|
81
|
+
const { action } = await send({
|
|
82
|
+
message: USAGE_DATA_ELICITATION_MESSAGE,
|
|
83
|
+
requestedSchema: {
|
|
84
|
+
type: "object",
|
|
85
|
+
properties: {}
|
|
86
|
+
}
|
|
87
|
+
}, { timeout: USAGE_DATA_QUESTION_TIMEOUT_MS });
|
|
88
|
+
return ANSWERS[action] ?? null;
|
|
89
|
+
} catch {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
const QUESTION_RETRY_INTERVAL_MS = 36e5;
|
|
94
|
+
/**
|
|
95
|
+
* A port that puts the question at most once in this process. Only a call that might ask waits for its
|
|
96
|
+
* step; every other call, and every call once the question has been put, hands its step over and returns.
|
|
97
|
+
* Calls that reach the question while it is being put get no answer at once rather than a second question.
|
|
98
|
+
*/
|
|
99
|
+
const askingOnceInThisProcess = (dependencies) => {
|
|
100
|
+
let asked = false;
|
|
101
|
+
let notAskableUntil = Number.NEGATIVE_INFINITY;
|
|
102
|
+
const now = () => (dependencies.now?.() ?? /* @__PURE__ */ new Date()).getTime();
|
|
103
|
+
const once = (ask) => async () => {
|
|
104
|
+
if (asked) return null;
|
|
105
|
+
asked = true;
|
|
106
|
+
return ask();
|
|
107
|
+
};
|
|
108
|
+
const settleQuietly = async (step) => {
|
|
109
|
+
try {
|
|
110
|
+
await dependencies.settle(step);
|
|
111
|
+
} catch {}
|
|
112
|
+
};
|
|
113
|
+
const mightAskQuietly = async () => {
|
|
114
|
+
try {
|
|
115
|
+
return await dependencies.mightAsk();
|
|
116
|
+
} catch {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
return async (step) => {
|
|
121
|
+
const { ask, ...withoutAsk } = step;
|
|
122
|
+
if (ask === void 0 || asked || !step.reached || now() < notAskableUntil || !await mightAskQuietly()) {
|
|
123
|
+
settleQuietly(withoutAsk);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
await settleQuietly({
|
|
127
|
+
...withoutAsk,
|
|
128
|
+
ask: once(ask)
|
|
129
|
+
});
|
|
130
|
+
if (!asked) notAskableUntil = now() + QUESTION_RETRY_INTERVAL_MS;
|
|
131
|
+
};
|
|
132
|
+
};
|
|
133
|
+
const TOOL_EVENTS = {
|
|
134
|
+
lighthouse_forecast_manual: "TeamManualForecastRun",
|
|
135
|
+
lighthouse_team_refresh: "TeamRefreshTriggered",
|
|
136
|
+
lighthouse_portfolio_refresh: "PortfolioRefreshTriggered"
|
|
137
|
+
};
|
|
138
|
+
/** What a tool call that succeeded did that the web counts too. */
|
|
139
|
+
const usageDataOccurrencesOf = (toolName) => {
|
|
140
|
+
const name = TOOL_EVENTS[toolName];
|
|
141
|
+
return name === void 0 ? [] : [{ name }];
|
|
142
|
+
};
|
|
143
|
+
const countedToolResult = (result, occurrences) => ({
|
|
144
|
+
result,
|
|
145
|
+
occurrences: result.isError ? [] : occurrences
|
|
146
|
+
});
|
|
147
|
+
/**
|
|
148
|
+
* A vote Lighthouse took, at the moment the Refinement read before it says, and the Work Item becoming
|
|
149
|
+
* Ready when only Lighthouse's answer can say this vote made it so.
|
|
150
|
+
*/
|
|
151
|
+
const usageDataOccurrencesOfAVote = (readBeforeTheVote, answered) => {
|
|
152
|
+
if (!answered.ok) return [];
|
|
153
|
+
const sizingMoment = (0, _letpeoplework_lighthouse_client.sizingMomentOf)(readBeforeTheVote);
|
|
154
|
+
const cast = {
|
|
155
|
+
name: "TeamSizingVoteCast",
|
|
156
|
+
sizingMoment
|
|
157
|
+
};
|
|
158
|
+
return answered.value.madeReady ? [cast, {
|
|
159
|
+
name: "TeamSizingReadinessReached",
|
|
160
|
+
sizingMoment
|
|
161
|
+
}] : [cast];
|
|
162
|
+
};
|
|
163
|
+
/** The verdict a Refinement Lighthouse answered shows, when it is a Refinement day's. */
|
|
164
|
+
const usageDataOccurrencesOfARead = (answered) => {
|
|
165
|
+
if (!answered.ok) return [];
|
|
166
|
+
const refinementVerdict = (0, _letpeoplework_lighthouse_client.refinementDayVerdictOf)({
|
|
167
|
+
isRefinementDay: answered.value.isRefinementDay,
|
|
168
|
+
workItemsListed: answered.value.workItems.length,
|
|
169
|
+
verdict: answered.value.need.verdict
|
|
170
|
+
});
|
|
171
|
+
return refinementVerdict === null ? [] : [{
|
|
172
|
+
name: "TeamRefinementDayVerdictShown",
|
|
173
|
+
refinementVerdict
|
|
174
|
+
}];
|
|
175
|
+
};
|
|
176
|
+
//#endregion
|
|
177
|
+
//#region src/refinementTools.ts
|
|
178
|
+
const CHANNEL = "Assistant";
|
|
179
|
+
const ASK_FOR_THE_NAME = "Ask the user for their name and send it as voterName; never guess it.";
|
|
180
|
+
const workItemProperty = {
|
|
181
|
+
type: "string",
|
|
182
|
+
description: "The work item's reference, as referenceId shows it in lighthouse_team_refinement_get (for example GR-051)."
|
|
183
|
+
};
|
|
184
|
+
const voterNameProperty = {
|
|
185
|
+
type: "string",
|
|
186
|
+
description: "The user's own name, needed when Lighthouse runs without sign-in. Ask the user for their name and never infer it, not from the system, an account or earlier messages. Leave it out with sign-in."
|
|
187
|
+
};
|
|
188
|
+
const teamIdProperty = {
|
|
189
|
+
type: "integer",
|
|
190
|
+
description: "The team's numeric id."
|
|
191
|
+
};
|
|
192
|
+
const refinementWriteToolDefinitions = [
|
|
193
|
+
{
|
|
194
|
+
name: "lighthouse_team_refinement_vote",
|
|
195
|
+
description: "Records the USER's own sizing judgement under their name. Never call this on your own initiative or on someone else's behalf: show the user the Work Item, the answer and any comment you intend to send, and call only after they explicitly confirm. answer is Yes (ready to be pulled), YesBut (\"Yes, if…\": ready under a condition, which goes in comment) or No; voting again replaces the user's earlier vote. Returns the work item as the vote left it, with `summary` stating where it now stands. Lighthouse newer than v26.10.3.6.",
|
|
196
|
+
inputSchema: {
|
|
197
|
+
type: "object",
|
|
198
|
+
properties: {
|
|
199
|
+
id: teamIdProperty,
|
|
200
|
+
workItem: workItemProperty,
|
|
201
|
+
answer: {
|
|
202
|
+
type: "string",
|
|
203
|
+
enum: [..._letpeoplework_lighthouse_client.REFINEMENT_ANSWERS],
|
|
204
|
+
description: "The user's answer: Yes, YesBut (\"Yes, if…\") or No, as myVote and split name them."
|
|
205
|
+
},
|
|
206
|
+
comment: {
|
|
207
|
+
type: "string",
|
|
208
|
+
description: "Optional; required with YesBut, where it says what has to be true."
|
|
209
|
+
},
|
|
210
|
+
voterName: voterNameProperty
|
|
211
|
+
},
|
|
212
|
+
required: [
|
|
213
|
+
"id",
|
|
214
|
+
"workItem",
|
|
215
|
+
"answer"
|
|
216
|
+
],
|
|
217
|
+
additionalProperties: false
|
|
218
|
+
}
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
name: "lighthouse_team_refinement_comment",
|
|
222
|
+
description: "Records a comment or question of the USER's on a work item in refinement, under their name, without a vote. Never call this on your own initiative or on someone else's behalf: show the user the work item and the comment you intend to send, and call only after they explicitly confirm. Returns the work item as the comment left it, with a `summary`. Lighthouse newer than v26.10.3.6.",
|
|
223
|
+
inputSchema: {
|
|
224
|
+
type: "object",
|
|
225
|
+
properties: {
|
|
226
|
+
id: teamIdProperty,
|
|
227
|
+
workItem: workItemProperty,
|
|
228
|
+
comment: {
|
|
229
|
+
type: "string",
|
|
230
|
+
description: "The user's comment."
|
|
231
|
+
},
|
|
232
|
+
voterName: voterNameProperty
|
|
233
|
+
},
|
|
234
|
+
required: [
|
|
235
|
+
"id",
|
|
236
|
+
"workItem",
|
|
237
|
+
"comment"
|
|
238
|
+
],
|
|
239
|
+
additionalProperties: false
|
|
240
|
+
}
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
name: "lighthouse_team_refinement_voteTakeBack",
|
|
244
|
+
description: "Takes back the vote the USER cast on a work item from this assistant. Call only when the user asks for it. When this assistant holds no vote of theirs on the work item it says so and takes nothing back. Returns the work item as the take-back left it, with `summary` stating where it now stands. Lighthouse newer than v26.10.3.6.",
|
|
245
|
+
inputSchema: {
|
|
246
|
+
type: "object",
|
|
247
|
+
properties: {
|
|
248
|
+
id: teamIdProperty,
|
|
249
|
+
workItem: workItemProperty
|
|
250
|
+
},
|
|
251
|
+
required: ["id", "workItem"],
|
|
252
|
+
additionalProperties: false
|
|
253
|
+
}
|
|
254
|
+
}
|
|
628
255
|
];
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
256
|
+
const refinementWriteInputSchemas = {
|
|
257
|
+
lighthouse_team_refinement_vote: zod.z.object({
|
|
258
|
+
id: zod.z.number().int(),
|
|
259
|
+
workItem: zod.z.string(),
|
|
260
|
+
answer: zod.z.enum(_letpeoplework_lighthouse_client.REFINEMENT_ANSWERS),
|
|
261
|
+
comment: zod.z.string().optional(),
|
|
262
|
+
voterName: zod.z.string().optional()
|
|
263
|
+
}),
|
|
264
|
+
lighthouse_team_refinement_comment: zod.z.object({
|
|
265
|
+
id: zod.z.number().int(),
|
|
266
|
+
workItem: zod.z.string(),
|
|
267
|
+
comment: zod.z.string(),
|
|
268
|
+
voterName: zod.z.string().optional()
|
|
269
|
+
}),
|
|
270
|
+
lighthouse_team_refinement_voteTakeBack: zod.z.object({
|
|
271
|
+
id: zod.z.number().int(),
|
|
272
|
+
workItem: zod.z.string()
|
|
273
|
+
})
|
|
274
|
+
};
|
|
275
|
+
const getArgument = (argumentsPayload, key) => typeof argumentsPayload === "object" && argumentsPayload !== null && !Array.isArray(argumentsPayload) ? argumentsPayload[key] : void 0;
|
|
276
|
+
const getNonBlankArgument = (argumentsPayload, key) => {
|
|
277
|
+
const value = getArgument(argumentsPayload, key);
|
|
278
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
|
|
279
|
+
};
|
|
280
|
+
/** The team and work item a write names, or the house "invalid …" refusal under its label. */
|
|
281
|
+
const getRefinementWriteTarget = (argumentsPayload, label) => {
|
|
282
|
+
const teamId = getNumericId(argumentsPayload);
|
|
283
|
+
if (teamId === null) return getErrorToolResult(`${label}: invalid id`);
|
|
284
|
+
const workItem = getNonBlankArgument(argumentsPayload, "workItem");
|
|
285
|
+
if (workItem === void 0) return getErrorToolResult(`${label}: invalid workItem`);
|
|
286
|
+
return {
|
|
287
|
+
teamId,
|
|
288
|
+
workItem
|
|
289
|
+
};
|
|
290
|
+
};
|
|
291
|
+
/**
|
|
292
|
+
* The key this server keeps, minted and kept on its first write; none on a server that keeps none; or why
|
|
293
|
+
* it could not be kept.
|
|
294
|
+
*/
|
|
295
|
+
const keepServerVoterKey = async (label, store) => {
|
|
296
|
+
if (store === void 0) return;
|
|
297
|
+
try {
|
|
298
|
+
return await (0, _letpeoplework_lighthouse_client.keepVoterKey)(store);
|
|
299
|
+
} catch (error) {
|
|
300
|
+
return getErrorToolResult(`${label}: ${error instanceof Error ? error.message : "the voter key was not kept."}`);
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
const loadServerVoterKey = async (dependencies) => await dependencies.voterKeyStore?.load() ?? void 0;
|
|
304
|
+
const getVoteRefusalToolResult = async (label, error, client, dependencies) => getErrorToolResult(`${label}: ${await (0, _letpeoplework_lighthouse_client.readVoteRefusal)(client, error, ASK_FOR_THE_NAME, dependencies.voterKeyRequired)}`);
|
|
305
|
+
const isSignedIn = (refinement) => refinement.voterIdentity === "Account";
|
|
306
|
+
const readRefinementFor = async (label, client, dependencies, teamId, voterKey) => {
|
|
307
|
+
const refinement = await client.getTeamRefinement(teamId, { voterKey });
|
|
308
|
+
return refinement.ok ? refinement.value : getVoteRefusalToolResult(label, refinement.error, client, dependencies);
|
|
309
|
+
};
|
|
310
|
+
const resolveWriter = async (label, argumentsPayload, client, dependencies, teamId) => {
|
|
311
|
+
const refinement = await readRefinementFor(label, client, dependencies, teamId);
|
|
312
|
+
if (isToolResult(refinement)) return refinement;
|
|
313
|
+
if (isSignedIn(refinement)) return {
|
|
314
|
+
voter: {},
|
|
315
|
+
refinement
|
|
316
|
+
};
|
|
317
|
+
const voterName = getNonBlankArgument(argumentsPayload, "voterName");
|
|
318
|
+
if (voterName === void 0) return getErrorToolResult(`${label}: ${ASK_FOR_THE_NAME}`);
|
|
319
|
+
const voterKey = await keepServerVoterKey(label, dependencies.voterKeyStore);
|
|
320
|
+
return isToolResult(voterKey) ? voterKey : {
|
|
321
|
+
voter: {
|
|
322
|
+
voterName,
|
|
323
|
+
voterKey
|
|
324
|
+
},
|
|
325
|
+
refinement
|
|
326
|
+
};
|
|
327
|
+
};
|
|
328
|
+
const getRefinementWriteToolResult = async (label, result, client, dependencies, describe) => {
|
|
329
|
+
if (!result.ok) return getVoteRefusalToolResult(label, result.error, client, dependencies);
|
|
330
|
+
const written = {
|
|
331
|
+
summary: describe(result.value),
|
|
332
|
+
...result.value
|
|
333
|
+
};
|
|
334
|
+
return getSuccessToolResult(`${label}: ${encodePayload(written)}`);
|
|
335
|
+
};
|
|
336
|
+
const refusedVoting = async (label, dependencies) => {
|
|
337
|
+
const refusal = await dependencies.refuseVoting?.() ?? null;
|
|
338
|
+
return refusal === null ? null : getErrorToolResult(`${label}: ${refusal}`);
|
|
339
|
+
};
|
|
340
|
+
const getRefinementErrorToolResult = (error) => getErrorToolResult(`refinement: ${error.category} (${error.reason})`);
|
|
341
|
+
const getRefinement = async (argumentsPayload, client, dependencies) => {
|
|
342
|
+
const teamId = getNumericId(argumentsPayload);
|
|
343
|
+
if (teamId === null) return getErrorToolResult("refinement: invalid id");
|
|
344
|
+
const voterKey = await loadServerVoterKey(dependencies);
|
|
345
|
+
const [refinement, wording] = await Promise.all([client.getTeamRefinement(teamId, { voterKey }), (0, _letpeoplework_lighthouse_client.readRefinementWording)(client, teamId)]);
|
|
346
|
+
if (!refinement.ok) return getRefinementErrorToolResult(refinement.error);
|
|
347
|
+
if (!wording.ok) return getRefinementErrorToolResult(wording.error);
|
|
348
|
+
const summary = (0, _letpeoplework_lighthouse_client.describeRefinementSummary)(refinement.value, wording.value);
|
|
349
|
+
return countedToolResult(getSuccessToolResult(`refinement: ${encodePayload({
|
|
350
|
+
summary,
|
|
351
|
+
...refinement.value
|
|
352
|
+
})}`), usageDataOccurrencesOfARead(refinement));
|
|
353
|
+
};
|
|
354
|
+
const castVote = async (argumentsPayload, client, dependencies) => {
|
|
355
|
+
const target = getRefinementWriteTarget(argumentsPayload, "vote");
|
|
356
|
+
if (isToolResult(target)) return target;
|
|
357
|
+
const answer = getArgument(argumentsPayload, "answer");
|
|
358
|
+
if (!(0, _letpeoplework_lighthouse_client.isRefinementAnswer)(answer)) return getErrorToolResult("vote: invalid answer");
|
|
359
|
+
const comment = getNonBlankArgument(argumentsPayload, "comment");
|
|
360
|
+
if ((0, _letpeoplework_lighthouse_client.isMissingItsCondition)(answer, comment)) return getErrorToolResult(`vote: ${(0, _letpeoplework_lighthouse_client.describeMissingCondition)("add a comment saying what has to be true.")}`);
|
|
361
|
+
const refused = await refusedVoting("vote", dependencies);
|
|
362
|
+
if (refused !== null) return refused;
|
|
363
|
+
const writer = await resolveWriter("vote", argumentsPayload, client, dependencies, target.teamId);
|
|
364
|
+
if (isToolResult(writer)) return writer;
|
|
365
|
+
const { voter, refinement } = writer;
|
|
366
|
+
const result = await client.castRefinementVote(target.teamId, target.workItem, {
|
|
367
|
+
answer,
|
|
368
|
+
channel: CHANNEL,
|
|
369
|
+
comment,
|
|
370
|
+
...voter
|
|
371
|
+
});
|
|
372
|
+
return countedToolResult(await getRefinementWriteToolResult("vote", result, client, dependencies, (row) => (0, _letpeoplework_lighthouse_client.describeRecordedVote)({
|
|
373
|
+
workItem: target.workItem,
|
|
374
|
+
voterName: voter.voterName
|
|
375
|
+
}, answer, row)), usageDataOccurrencesOfAVote(refinement, result));
|
|
376
|
+
};
|
|
377
|
+
const addComment = async (argumentsPayload, client, dependencies) => {
|
|
378
|
+
const target = getRefinementWriteTarget(argumentsPayload, "comment");
|
|
379
|
+
if (isToolResult(target)) return target;
|
|
380
|
+
const comment = getNonBlankArgument(argumentsPayload, "comment");
|
|
381
|
+
if (comment === void 0) return getErrorToolResult("comment: invalid comment");
|
|
382
|
+
const refused = await refusedVoting("comment", dependencies);
|
|
383
|
+
if (refused !== null) return refused;
|
|
384
|
+
const writer = await resolveWriter("comment", argumentsPayload, client, dependencies, target.teamId);
|
|
385
|
+
if (isToolResult(writer)) return writer;
|
|
386
|
+
const { voter } = writer;
|
|
387
|
+
const result = await client.addRefinementComment(target.teamId, target.workItem, {
|
|
388
|
+
comment,
|
|
389
|
+
channel: CHANNEL,
|
|
390
|
+
...voter
|
|
391
|
+
});
|
|
392
|
+
return getRefinementWriteToolResult("comment", result, client, dependencies, () => (0, _letpeoplework_lighthouse_client.describeRecordedComment)({
|
|
393
|
+
workItem: target.workItem,
|
|
394
|
+
voterName: voter.voterName
|
|
395
|
+
}));
|
|
396
|
+
};
|
|
397
|
+
const takeBackVote = async (argumentsPayload, client, dependencies) => {
|
|
398
|
+
const target = getRefinementWriteTarget(argumentsPayload, "takeBack");
|
|
399
|
+
if (isToolResult(target)) return target;
|
|
400
|
+
const refused = await refusedVoting("takeBack", dependencies);
|
|
401
|
+
if (refused !== null) return refused;
|
|
402
|
+
const nothingToTakeBack = getSuccessToolResult(`takeBack: ${encodePayload({ summary: (0, _letpeoplework_lighthouse_client.describeNothingToTakeBack)(target.workItem) })}`);
|
|
403
|
+
const keptVoterKey = await loadServerVoterKey(dependencies);
|
|
404
|
+
const refinement = await readRefinementFor("takeBack", client, dependencies, target.teamId, keptVoterKey);
|
|
405
|
+
if (isToolResult(refinement)) return refinement;
|
|
406
|
+
const myVote = (0, _letpeoplework_lighthouse_client.myVoteOn)(refinement, target.workItem);
|
|
407
|
+
if (myVote === null) return nothingToTakeBack;
|
|
408
|
+
const signedIn = isSignedIn(refinement);
|
|
409
|
+
const voterName = signedIn ? null : await (0, _letpeoplework_lighthouse_client.readNameOfMyVote)(client, target.teamId, target.workItem, keptVoterKey);
|
|
410
|
+
const result = await client.takeBackRefinementVote(target.teamId, target.workItem, {
|
|
411
|
+
channel: CHANNEL,
|
|
412
|
+
voterKey: signedIn ? void 0 : keptVoterKey,
|
|
413
|
+
answer: myVote
|
|
414
|
+
});
|
|
415
|
+
return getRefinementWriteToolResult("takeBack", result, client, dependencies, (takenBack) => (0, _letpeoplework_lighthouse_client.describeTakenBack)({
|
|
416
|
+
workItem: target.workItem,
|
|
417
|
+
voterName
|
|
418
|
+
}, takenBack));
|
|
419
|
+
};
|
|
420
|
+
const REFINEMENT_TOOLS = /* @__PURE__ */ new Map([
|
|
421
|
+
["lighthouse_team_refinement_get", getRefinement],
|
|
422
|
+
["lighthouse_team_refinement_vote", castVote],
|
|
423
|
+
["lighthouse_team_refinement_comment", addComment],
|
|
424
|
+
["lighthouse_team_refinement_voteTakeBack", takeBackVote]
|
|
425
|
+
]);
|
|
426
|
+
/** The handler of a refinement tool, or undefined for a tool that is not one. */
|
|
427
|
+
const findRefinementTool = (name) => REFINEMENT_TOOLS.get(name);
|
|
428
|
+
//#endregion
|
|
429
|
+
//#region src/index.ts
|
|
430
|
+
const getMcpCorePackageContract = () => ({
|
|
431
|
+
name: "@letpeoplework/lighthouse-mcp-core",
|
|
432
|
+
dependsOn: "@letpeoplework/lighthouse-client",
|
|
433
|
+
transports: ["stdio", "streamable-http"]
|
|
644
434
|
});
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
435
|
+
const emptyInputSchema = {
|
|
436
|
+
type: "object",
|
|
437
|
+
properties: {},
|
|
438
|
+
additionalProperties: false
|
|
439
|
+
};
|
|
440
|
+
const idInputSchema = {
|
|
441
|
+
type: "object",
|
|
442
|
+
properties: { id: {
|
|
443
|
+
type: "integer",
|
|
444
|
+
description: "Unique numeric identifier."
|
|
445
|
+
} },
|
|
446
|
+
required: ["id"],
|
|
447
|
+
additionalProperties: false
|
|
448
|
+
};
|
|
449
|
+
const dateRangeProperties = {
|
|
450
|
+
startDate: {
|
|
451
|
+
type: "string",
|
|
452
|
+
description: "Inclusive start date in ISO format (YYYY-MM-DD)."
|
|
453
|
+
},
|
|
454
|
+
endDate: {
|
|
455
|
+
type: "string",
|
|
456
|
+
description: "Inclusive end date in ISO format (YYYY-MM-DD)."
|
|
457
|
+
}
|
|
458
|
+
};
|
|
459
|
+
const throughputFilterViewProperty = { view: {
|
|
460
|
+
type: "string",
|
|
461
|
+
enum: ["raw", "filtered"],
|
|
462
|
+
description: "Forecast-filter view (Lighthouse v26.5.24.10+). \"filtered\" applies the team's exclusion rule to throughput. Omit or \"raw\" returns unfiltered data."
|
|
463
|
+
} };
|
|
464
|
+
const percentilesOverTimeProperties = {
|
|
465
|
+
metricType: {
|
|
466
|
+
type: "string",
|
|
467
|
+
enum: ["CycleTime", "WorkItemAge"],
|
|
468
|
+
description: "Percentile family to read. Defaults to \"CycleTime\" when omitted."
|
|
469
|
+
},
|
|
470
|
+
horizon: {
|
|
471
|
+
type: "number",
|
|
472
|
+
description: "Cycle-time horizon in days (30, 60 or 90). Ignored for WorkItemAge, which is always as-of-today and has no horizon dimension."
|
|
473
|
+
}
|
|
474
|
+
};
|
|
475
|
+
const processBehaviorOverTimeProperties = { metricType: {
|
|
476
|
+
type: "string",
|
|
477
|
+
enum: [
|
|
478
|
+
"Throughput",
|
|
479
|
+
"WorkItemAge",
|
|
480
|
+
"Wip",
|
|
481
|
+
"CycleTime",
|
|
482
|
+
"Arrivals",
|
|
483
|
+
"FeatureSize"
|
|
484
|
+
],
|
|
485
|
+
description: "Process-behaviour family to read. Defaults to \"Throughput\" when omitted. \"FeatureSize\" is portfolio-only — a team never records it and returns an empty series."
|
|
486
|
+
} };
|
|
487
|
+
const processBehaviorMetricTypes = [
|
|
488
|
+
"Throughput",
|
|
489
|
+
"WorkItemAge",
|
|
490
|
+
"Wip",
|
|
491
|
+
"CycleTime",
|
|
492
|
+
"Arrivals",
|
|
493
|
+
"FeatureSize"
|
|
494
|
+
];
|
|
495
|
+
const TEAM_CHART_TYPES = [
|
|
496
|
+
"Throughput",
|
|
497
|
+
"WorkItemAge",
|
|
498
|
+
"Wip",
|
|
499
|
+
"CycleTime",
|
|
500
|
+
"Arrivals"
|
|
501
|
+
];
|
|
502
|
+
const chartTypeProperty = (chartTypes) => ({ metricType: {
|
|
503
|
+
type: "string",
|
|
504
|
+
enum: chartTypes,
|
|
505
|
+
description: "Which Process Behaviour Chart to read."
|
|
506
|
+
} });
|
|
507
|
+
const chartInputSchema = (chartTypes) => ({
|
|
508
|
+
type: "object",
|
|
509
|
+
properties: {
|
|
510
|
+
...idInputSchema.properties,
|
|
511
|
+
...chartTypeProperty(chartTypes),
|
|
512
|
+
...dateRangeProperties
|
|
513
|
+
},
|
|
514
|
+
required: ["id", "metricType"],
|
|
515
|
+
additionalProperties: false
|
|
653
516
|
});
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
}
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
}
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
517
|
+
const cumulativeStateProperty = { state: {
|
|
518
|
+
type: "string",
|
|
519
|
+
description: "Workflow state name to drill into (must match a bar's state from the cumulativeStateTime response)."
|
|
520
|
+
} };
|
|
521
|
+
const itemIdsProperty = { itemIds: {
|
|
522
|
+
type: "array",
|
|
523
|
+
items: { type: "integer" },
|
|
524
|
+
description: "Optional work-item IDs to narrow the computation to a selected subset; omit for all in-scope items."
|
|
525
|
+
} };
|
|
526
|
+
const forecastFilterOverrideProperty = { applyFilterOverride: {
|
|
527
|
+
type: "boolean",
|
|
528
|
+
description: "Override the team's forecast-filter setting (Lighthouse v26.5.24.10+). true = apply the team filter; false = skip the filter (raw); omit = respect the team setting."
|
|
529
|
+
} };
|
|
530
|
+
const recurringBlackoutRuleProperties = {
|
|
531
|
+
weekdays: {
|
|
532
|
+
type: "array",
|
|
533
|
+
items: {
|
|
534
|
+
type: "string",
|
|
535
|
+
enum: [
|
|
536
|
+
"Sunday",
|
|
537
|
+
"Monday",
|
|
538
|
+
"Tuesday",
|
|
539
|
+
"Wednesday",
|
|
540
|
+
"Thursday",
|
|
541
|
+
"Friday",
|
|
542
|
+
"Saturday"
|
|
543
|
+
]
|
|
544
|
+
},
|
|
545
|
+
description: "Weekdays the rule applies to."
|
|
546
|
+
},
|
|
547
|
+
intervalWeeks: {
|
|
548
|
+
type: "integer",
|
|
549
|
+
description: "Repeat every N weeks (1 = every week)."
|
|
550
|
+
},
|
|
551
|
+
start: {
|
|
552
|
+
type: "string",
|
|
553
|
+
description: "Rule start date in ISO format (YYYY-MM-DD)."
|
|
554
|
+
},
|
|
555
|
+
end: {
|
|
556
|
+
type: ["string", "null"],
|
|
557
|
+
description: "Optional end date in ISO format (YYYY-MM-DD), or null for an open end."
|
|
558
|
+
},
|
|
559
|
+
description: {
|
|
560
|
+
type: "string",
|
|
561
|
+
description: "Human-readable description of the rule."
|
|
562
|
+
}
|
|
563
|
+
};
|
|
564
|
+
const toolDefinitions = [
|
|
565
|
+
{
|
|
566
|
+
name: "lighthouse_health_check",
|
|
567
|
+
description: "Check connectivity to Lighthouse and return whether the configured endpoint is reachable. A second text block, `summary`, says that Lighthouse is reachable; the first block is the facts, unchanged.",
|
|
568
|
+
inputSchema: emptyInputSchema
|
|
569
|
+
},
|
|
570
|
+
{
|
|
571
|
+
name: "lighthouse_version_get",
|
|
572
|
+
description: "Retrieve the Lighthouse server version from the version endpoint. A second text block, `summary`, names it as the web's footer does; the first block is the facts, unchanged.",
|
|
573
|
+
inputSchema: emptyInputSchema
|
|
574
|
+
},
|
|
575
|
+
{
|
|
576
|
+
name: "lighthouse_worktracking_list",
|
|
577
|
+
description: "List configured work-tracking system connections in Lighthouse. A second text block, `summary`, counts them in the instance's terminology; the first block is the facts, unchanged.",
|
|
578
|
+
inputSchema: emptyInputSchema
|
|
579
|
+
},
|
|
580
|
+
{
|
|
581
|
+
name: "lighthouse_worktracking_get",
|
|
582
|
+
description: "Get a single work-tracking system connection by ID. `summary` names the connection and its type as the Overview does, and never carries an option's value.",
|
|
583
|
+
inputSchema: idInputSchema
|
|
584
|
+
},
|
|
585
|
+
{
|
|
586
|
+
name: "lighthouse_team_list",
|
|
587
|
+
description: "List all teams available in Lighthouse. A second text block, `summary`, counts them in the instance's terminology; the first block is the facts, unchanged.",
|
|
588
|
+
inputSchema: emptyInputSchema
|
|
589
|
+
},
|
|
590
|
+
{
|
|
591
|
+
name: "lighthouse_team_get",
|
|
592
|
+
description: "Get full details for one team by ID. `summary` states the page's heading and settings as the web does, in the instance's terminology.",
|
|
593
|
+
inputSchema: idInputSchema
|
|
594
|
+
},
|
|
595
|
+
{
|
|
596
|
+
name: "lighthouse_team_refresh",
|
|
597
|
+
description: "Trigger data refresh for a team by ID. A second text block, `summary`, confirms it in one line as lh does, in the instance's terminology; the first block is the facts, unchanged.",
|
|
598
|
+
inputSchema: idInputSchema
|
|
599
|
+
},
|
|
600
|
+
{
|
|
601
|
+
name: "lighthouse_team_refinement_get",
|
|
602
|
+
description: "How many work items a team should refine before its next Refinement, as on the team's Refinement tab (Lighthouse newer than v26.10.3.6). `summary` is the sentence the web page states, in the instance's terminology. need.low and need.high are the range of work items the team is likely to pull over one cycle (need.cycleStart to need.cycleEnd: from the next Refinement to the one after, or from today on a Refinement day), read at need.lowPercentile and need.highPercentile. need.verdict says where readyCount sits against that range: Below, In or Above. Without a verdict, need.unavailableReason says why: NoCadence, InsufficientData or NoRefinementStates. isRefinementDay is true on a Refinement day, when the cycle starts today. daysUntilNextRefinement counts the days from the instance's today to nextRefinementDate. readySource says what readyCount counts: work items ready by Votes, or by Stages on a team with stage rules. workItems are the items in refinement, in the order the Refinement tab lists them.",
|
|
603
|
+
inputSchema: idInputSchema
|
|
604
|
+
},
|
|
605
|
+
...refinementWriteToolDefinitions,
|
|
606
|
+
{
|
|
607
|
+
name: "lighthouse_portfolio_list",
|
|
608
|
+
description: "List all portfolios in Lighthouse. A second text block, `summary`, counts them in the instance's terminology; the first block is the facts, unchanged.",
|
|
609
|
+
inputSchema: emptyInputSchema
|
|
610
|
+
},
|
|
611
|
+
{
|
|
612
|
+
name: "lighthouse_portfolio_get",
|
|
613
|
+
description: "Get full details for one portfolio by ID. `summary` states the page's heading and settings as the web does, in the instance's terminology.",
|
|
614
|
+
inputSchema: idInputSchema
|
|
615
|
+
},
|
|
616
|
+
{
|
|
617
|
+
name: "lighthouse_portfolio_refresh",
|
|
618
|
+
description: "Trigger data refresh for a portfolio by ID. A second text block, `summary`, confirms it in one line as lh does, in the instance's terminology; the first block is the facts, unchanged.",
|
|
619
|
+
inputSchema: idInputSchema
|
|
620
|
+
},
|
|
621
|
+
{
|
|
622
|
+
name: "lighthouse_team_metrics_throughput",
|
|
623
|
+
description: "Get throughput run-chart data for a team by ID, optionally filtered by start and end dates. Pass view=\"filtered\" to apply the team's forecast-exclusion rule (Lighthouse v26.5.24.10+); omit or \"raw\" returns unfiltered data. `summary` states the answer as the dashboard does, in the instance's terminology: the heading and its sentence.",
|
|
624
|
+
inputSchema: {
|
|
625
|
+
type: "object",
|
|
626
|
+
properties: {
|
|
627
|
+
...idInputSchema.properties,
|
|
628
|
+
...dateRangeProperties,
|
|
629
|
+
...throughputFilterViewProperty
|
|
630
|
+
},
|
|
631
|
+
required: ["id"],
|
|
632
|
+
additionalProperties: false
|
|
633
|
+
}
|
|
634
|
+
},
|
|
635
|
+
{
|
|
636
|
+
name: "lighthouse_team_metrics_cycleTimePercentiles",
|
|
637
|
+
description: "Get cycle-time percentiles for a team by ID, optionally filtered by start and end dates. Pass definitionId to get the percentiles for a named cycle time (premium) instead of the default cycle time. A second text block, `summary: …`, states the answer as the dashboard does, in the instance's terminology: the heading and its sentence; the first block is the facts, unchanged.",
|
|
638
|
+
inputSchema: {
|
|
639
|
+
type: "object",
|
|
640
|
+
properties: {
|
|
641
|
+
...idInputSchema.properties,
|
|
642
|
+
...dateRangeProperties,
|
|
643
|
+
definitionId: {
|
|
644
|
+
type: "number",
|
|
645
|
+
description: "Optional named cycle time definition ID; omit for the default cycle time."
|
|
646
|
+
}
|
|
647
|
+
},
|
|
648
|
+
required: ["id"],
|
|
649
|
+
additionalProperties: false
|
|
650
|
+
}
|
|
651
|
+
},
|
|
652
|
+
{
|
|
653
|
+
name: "lighthouse_team_metrics_workItemAgePercentiles",
|
|
654
|
+
description: "Get work-item age percentiles for a team by ID, optionally filtered by start and end dates. Ages are measured as of the last day of the selected range, not as of today — a historical range reports how old the items were at the end of that period, so do not present the result as the team's current ages unless the range ends today. A second text block, `summary: …`, states the answer as the dashboard does, in the instance's terminology: the heading and its sentence; the first block is the facts, unchanged.",
|
|
655
|
+
inputSchema: {
|
|
656
|
+
type: "object",
|
|
657
|
+
properties: {
|
|
658
|
+
...idInputSchema.properties,
|
|
659
|
+
...dateRangeProperties
|
|
660
|
+
},
|
|
661
|
+
required: ["id"],
|
|
662
|
+
additionalProperties: false
|
|
663
|
+
}
|
|
664
|
+
},
|
|
665
|
+
{
|
|
666
|
+
name: "lighthouse_portfolio_metrics_workItemAgePercentiles",
|
|
667
|
+
description: "Get work-item age percentiles for a portfolio by ID, optionally filtered by start and end dates. Ages are measured as of the last day of the selected range, not as of today — a historical range reports how old the items were at the end of that period, so do not present the result as the portfolio's current ages unless the range ends today. A second text block, `summary: …`, states the answer as the dashboard does, in the instance's terminology: the heading and its sentence; the first block is the facts, unchanged.",
|
|
668
|
+
inputSchema: {
|
|
669
|
+
type: "object",
|
|
670
|
+
properties: {
|
|
671
|
+
...idInputSchema.properties,
|
|
672
|
+
...dateRangeProperties
|
|
673
|
+
},
|
|
674
|
+
required: ["id"],
|
|
675
|
+
additionalProperties: false
|
|
676
|
+
}
|
|
677
|
+
},
|
|
678
|
+
{
|
|
679
|
+
name: "lighthouse_team_metrics_blockedCountHistory",
|
|
680
|
+
description: "Get the blocked-items-over-time trend for a team by ID: how many work items were blocked on each captured day, optionally filtered by start and end dates. To see what is blocked right now and for how long, call lighthouse_team_metrics_wip — each item carries isBlocked and, when blocked, a blockedSince timestamp. A second text block, `summary: …`, states the answer as the dashboard does, in the instance's terminology: the heading and its sentence; the first block is the facts, unchanged.",
|
|
681
|
+
inputSchema: {
|
|
682
|
+
type: "object",
|
|
683
|
+
properties: {
|
|
684
|
+
...idInputSchema.properties,
|
|
685
|
+
...dateRangeProperties
|
|
686
|
+
},
|
|
687
|
+
required: ["id"],
|
|
688
|
+
additionalProperties: false
|
|
689
|
+
}
|
|
690
|
+
},
|
|
691
|
+
{
|
|
692
|
+
name: "lighthouse_portfolio_metrics_blockedCountHistory",
|
|
693
|
+
description: "Get the blocked-items-over-time trend for a portfolio by ID: how many work items were blocked on each captured day, optionally filtered by start and end dates. No tool reads what is blocked right now for a portfolio: name the command `lh metrics portfolio --metrics wip --id <id>`, whose items each carry isBlocked and, when blocked, a blockedSince timestamp. A second text block, `summary: …`, states the answer as the dashboard does, in the instance's terminology: the heading and its sentence; the first block is the facts, unchanged.",
|
|
694
|
+
inputSchema: {
|
|
695
|
+
type: "object",
|
|
696
|
+
properties: {
|
|
697
|
+
...idInputSchema.properties,
|
|
698
|
+
...dateRangeProperties
|
|
699
|
+
},
|
|
700
|
+
required: ["id"],
|
|
701
|
+
additionalProperties: false
|
|
702
|
+
}
|
|
703
|
+
},
|
|
704
|
+
{
|
|
705
|
+
name: "lighthouse_team_metrics_percentilesOverTime",
|
|
706
|
+
description: "Get the percentiles-over-time trend for a team by ID: the p50/p70/p85/p95 quartet recorded on each captured day, optionally filtered by start and end dates. By default Lighthouse only returns days it recorded, so a recently upgraded server returns an empty series until it has recorded some; where a System Admin has switched on filling in past days (a Preview), the read starts filling missing days in the background and a later call may return more. Use metricType to pick the family and horizon to pick the cycle-time window. A second text block, `summary: …`, states the answer as the dashboard does, in the instance's terminology: the heading and its sentence; the first block is the facts, unchanged.",
|
|
707
|
+
inputSchema: {
|
|
708
|
+
type: "object",
|
|
709
|
+
properties: {
|
|
710
|
+
...idInputSchema.properties,
|
|
711
|
+
...dateRangeProperties,
|
|
712
|
+
...percentilesOverTimeProperties
|
|
713
|
+
},
|
|
714
|
+
required: ["id"],
|
|
715
|
+
additionalProperties: false
|
|
716
|
+
}
|
|
717
|
+
},
|
|
718
|
+
{
|
|
719
|
+
name: "lighthouse_portfolio_metrics_percentilesOverTime",
|
|
720
|
+
description: "Get the percentiles-over-time trend for a portfolio by ID: the p50/p70/p85/p95 quartet recorded on each captured day, optionally filtered by start and end dates. By default Lighthouse only returns days it recorded, so a recently upgraded server returns an empty series until it has recorded some; where a System Admin has switched on filling in past days (a Preview), the read starts filling missing days in the background and a later call may return more. Use metricType to pick the family and horizon to pick the cycle-time window. A second text block, `summary: …`, states the answer as the dashboard does, in the instance's terminology: the heading and its sentence; the first block is the facts, unchanged.",
|
|
721
|
+
inputSchema: {
|
|
722
|
+
type: "object",
|
|
723
|
+
properties: {
|
|
724
|
+
...idInputSchema.properties,
|
|
725
|
+
...dateRangeProperties,
|
|
726
|
+
...percentilesOverTimeProperties
|
|
727
|
+
},
|
|
728
|
+
required: ["id"],
|
|
729
|
+
additionalProperties: false
|
|
730
|
+
}
|
|
731
|
+
},
|
|
732
|
+
{
|
|
733
|
+
name: "lighthouse_team_metrics_processBehaviorOverTime",
|
|
734
|
+
description: "Get the process-behaviour-limits-over-time trend for a team by ID: the upper limit, average and lower limit (UNPL/Average/LNPL) recorded on each captured day, optionally filtered by start and end dates. Days are recorded on refresh (and, where a System Admin has switched on filling in past days, filled in the background after a read), and days without a usable baseline are absent rather than zeroed — an empty series means nothing was recorded, never a process pinned at zero. A second text block, `summary: …`, states the answer as the dashboard does, in the instance's terminology: the heading and its sentence; the first block is the facts, unchanged.",
|
|
735
|
+
inputSchema: {
|
|
736
|
+
type: "object",
|
|
737
|
+
properties: {
|
|
738
|
+
...idInputSchema.properties,
|
|
739
|
+
...dateRangeProperties,
|
|
740
|
+
...processBehaviorOverTimeProperties
|
|
741
|
+
},
|
|
742
|
+
required: ["id"],
|
|
743
|
+
additionalProperties: false
|
|
744
|
+
}
|
|
745
|
+
},
|
|
746
|
+
{
|
|
747
|
+
name: "lighthouse_portfolio_metrics_processBehaviorOverTime",
|
|
748
|
+
description: "Get the process-behaviour-limits-over-time trend for a portfolio by ID: the upper limit, average and lower limit (UNPL/Average/LNPL) recorded on each captured day, optionally filtered by start and end dates. Days are recorded on refresh (and, where a System Admin has switched on filling in past days, filled in the background after a read), and days without a usable baseline are absent rather than zeroed — an empty series means nothing was recorded, never a process pinned at zero. FeatureSize is available here and not on teams. A second text block, `summary: …`, states the answer as the dashboard does, in the instance's terminology: the heading and its sentence; the first block is the facts, unchanged.",
|
|
749
|
+
inputSchema: {
|
|
750
|
+
type: "object",
|
|
751
|
+
properties: {
|
|
752
|
+
...idInputSchema.properties,
|
|
753
|
+
...dateRangeProperties,
|
|
754
|
+
...processBehaviorOverTimeProperties
|
|
755
|
+
},
|
|
756
|
+
required: ["id"],
|
|
757
|
+
additionalProperties: false
|
|
758
|
+
}
|
|
759
|
+
},
|
|
760
|
+
{
|
|
761
|
+
name: "lighthouse_portfolio_metrics_throughput",
|
|
762
|
+
description: "Get throughput run-chart data for a portfolio by ID, optionally filtered by start and end dates. `summary` states the answer as the dashboard does, in the instance's terminology: the heading and its sentence.",
|
|
763
|
+
inputSchema: {
|
|
764
|
+
type: "object",
|
|
765
|
+
properties: {
|
|
766
|
+
...idInputSchema.properties,
|
|
767
|
+
...dateRangeProperties
|
|
768
|
+
},
|
|
769
|
+
required: ["id"],
|
|
770
|
+
additionalProperties: false
|
|
771
|
+
}
|
|
772
|
+
},
|
|
773
|
+
{
|
|
774
|
+
name: "lighthouse_team_metrics_workItemAge",
|
|
775
|
+
description: "Get per-item work item age over time for a team by ID. Returns daily snapshots with each in-progress item's age in days derived from its startedDate. Items without a startedDate are omitted. `summary` states the answer as the dashboard does, in the instance's terminology: the heading and its sentence.",
|
|
776
|
+
inputSchema: {
|
|
777
|
+
type: "object",
|
|
778
|
+
properties: {
|
|
779
|
+
...idInputSchema.properties,
|
|
780
|
+
...dateRangeProperties
|
|
781
|
+
},
|
|
782
|
+
required: ["id"],
|
|
783
|
+
additionalProperties: false
|
|
784
|
+
}
|
|
785
|
+
},
|
|
786
|
+
{
|
|
787
|
+
name: "lighthouse_team_metrics_totalWorkItemAge",
|
|
788
|
+
description: "Get the total (summed) work item age over time for a team by ID. Returns daily totals of all in-progress item ages derived from startedDate. Items without a startedDate are not counted. `summary` states the answer as the dashboard does, in the instance's terminology: the heading and its sentence.",
|
|
789
|
+
inputSchema: {
|
|
790
|
+
type: "object",
|
|
791
|
+
properties: {
|
|
792
|
+
...idInputSchema.properties,
|
|
793
|
+
...dateRangeProperties
|
|
794
|
+
},
|
|
795
|
+
required: ["id"],
|
|
796
|
+
additionalProperties: false
|
|
797
|
+
}
|
|
798
|
+
},
|
|
799
|
+
{
|
|
800
|
+
name: "lighthouse_portfolio_metrics_workItemAge",
|
|
801
|
+
description: "Get per-item work item age over time for a portfolio by ID. Returns daily snapshots with each in-progress item's age in days derived from its startedDate. Items without a startedDate are omitted. `summary` states the answer as the dashboard does, in the instance's terminology: the heading and its sentence.",
|
|
802
|
+
inputSchema: {
|
|
803
|
+
type: "object",
|
|
804
|
+
properties: {
|
|
805
|
+
...idInputSchema.properties,
|
|
806
|
+
...dateRangeProperties
|
|
807
|
+
},
|
|
808
|
+
required: ["id"],
|
|
809
|
+
additionalProperties: false
|
|
810
|
+
}
|
|
811
|
+
},
|
|
812
|
+
{
|
|
813
|
+
name: "lighthouse_portfolio_metrics_totalWorkItemAge",
|
|
814
|
+
description: "Get the total (summed) work item age over time for a portfolio by ID. Returns daily totals of all in-progress item ages derived from startedDate. Items without a startedDate are not counted. `summary` states the answer as the dashboard does, in the instance's terminology: the heading and its sentence.",
|
|
815
|
+
inputSchema: {
|
|
816
|
+
type: "object",
|
|
817
|
+
properties: {
|
|
818
|
+
...idInputSchema.properties,
|
|
819
|
+
...dateRangeProperties
|
|
820
|
+
},
|
|
821
|
+
required: ["id"],
|
|
822
|
+
additionalProperties: false
|
|
823
|
+
}
|
|
824
|
+
},
|
|
825
|
+
{
|
|
826
|
+
name: "lighthouse_feature_get",
|
|
827
|
+
description: "Get feature details by numeric IDs or external reference IDs. A second text block, `summary`, counts them in the instance's terminology; the first block is the facts, unchanged.",
|
|
828
|
+
inputSchema: {
|
|
829
|
+
type: "object",
|
|
830
|
+
properties: {
|
|
831
|
+
ids: {
|
|
832
|
+
type: "array",
|
|
833
|
+
items: { type: "integer" },
|
|
834
|
+
description: "Feature IDs."
|
|
835
|
+
},
|
|
836
|
+
refs: {
|
|
837
|
+
type: "array",
|
|
838
|
+
items: { type: "string" },
|
|
839
|
+
description: "Feature reference identifiers."
|
|
840
|
+
}
|
|
841
|
+
},
|
|
842
|
+
additionalProperties: false
|
|
843
|
+
}
|
|
844
|
+
},
|
|
845
|
+
{
|
|
846
|
+
name: "lighthouse_feature_workitems",
|
|
847
|
+
description: "Get work items linked to a feature by ID. A second text block, `summary`, heads them as lh does: the feature and how many work items it holds, in the instance's terminology; the first block is the facts, unchanged.",
|
|
848
|
+
inputSchema: idInputSchema
|
|
849
|
+
},
|
|
850
|
+
{
|
|
851
|
+
name: "lighthouse_delivery_list",
|
|
852
|
+
description: "List deliveries for a portfolio by portfolio ID. A second text block, `summary`, counts them in the instance's terminology; the first block is the facts, unchanged.",
|
|
853
|
+
inputSchema: idInputSchema
|
|
854
|
+
},
|
|
855
|
+
{
|
|
856
|
+
name: "lighthouse_delivery_metrics",
|
|
857
|
+
description: "Get a delivery's recorded trend by delivery ID: one row per day with total, done and remaining work, the epic count and the likelihood. Set detail to \"epics\" for the per-epic breakdown and the forecast distribution, which are far larger. Forward-only, so it starts at the first recorded snapshot. `summary` states the delivery and its date as lh heads them, in the instance's terminology: a second text block beside the rows, a field of the detailed payload. Requires Lighthouse newer than v26.5.29.5.",
|
|
858
|
+
inputSchema: {
|
|
859
|
+
type: "object",
|
|
860
|
+
properties: {
|
|
861
|
+
id: {
|
|
862
|
+
type: "number",
|
|
863
|
+
description: "Delivery ID."
|
|
864
|
+
},
|
|
865
|
+
detail: {
|
|
866
|
+
type: "string",
|
|
867
|
+
enum: ["epics"],
|
|
868
|
+
description: "Omit for one row per day. \"epics\" returns the whole recorded payload."
|
|
869
|
+
}
|
|
870
|
+
},
|
|
871
|
+
required: ["id"],
|
|
872
|
+
additionalProperties: false
|
|
873
|
+
}
|
|
874
|
+
},
|
|
875
|
+
{
|
|
876
|
+
name: "lighthouse_blackout_list",
|
|
877
|
+
description: "List the recurring blackout rules (recurring non-working days excluded from forecasts). Requires Lighthouse newer than v26.5.29.5. A second text block, `summary`, counts them as the settings page does; the first block is the facts, unchanged, each rule's own `summary` field included.",
|
|
878
|
+
inputSchema: emptyInputSchema
|
|
879
|
+
},
|
|
880
|
+
{
|
|
881
|
+
name: "lighthouse_blackout_create",
|
|
882
|
+
description: "Create a recurring blackout rule (weekdays + every-N-weeks interval + start date + optional open end). Premium, system-admin only. Requires Lighthouse newer than v26.5.29.5. A second text block, `summary`, confirms it in one line as lh does; the first block is the facts, unchanged, the rule's own `summary` field included.",
|
|
883
|
+
inputSchema: {
|
|
884
|
+
type: "object",
|
|
885
|
+
properties: { ...recurringBlackoutRuleProperties },
|
|
886
|
+
required: [
|
|
887
|
+
"weekdays",
|
|
888
|
+
"intervalWeeks",
|
|
889
|
+
"start",
|
|
890
|
+
"description"
|
|
891
|
+
],
|
|
892
|
+
additionalProperties: false
|
|
893
|
+
}
|
|
894
|
+
},
|
|
895
|
+
{
|
|
896
|
+
name: "lighthouse_blackout_update",
|
|
897
|
+
description: "Update a recurring blackout rule by ID. Premium, system-admin only. Requires Lighthouse newer than v26.5.29.5. A second text block, `summary`, confirms it in one line as lh does; the first block is the facts, unchanged, the rule's own `summary` field included.",
|
|
898
|
+
inputSchema: {
|
|
899
|
+
type: "object",
|
|
900
|
+
properties: {
|
|
901
|
+
...idInputSchema.properties,
|
|
902
|
+
...recurringBlackoutRuleProperties
|
|
903
|
+
},
|
|
904
|
+
required: [
|
|
905
|
+
"id",
|
|
906
|
+
"weekdays",
|
|
907
|
+
"intervalWeeks",
|
|
908
|
+
"start",
|
|
909
|
+
"description"
|
|
910
|
+
],
|
|
911
|
+
additionalProperties: false
|
|
912
|
+
}
|
|
913
|
+
},
|
|
914
|
+
{
|
|
915
|
+
name: "lighthouse_blackout_delete",
|
|
916
|
+
description: "Delete a recurring blackout rule by ID. Premium, system-admin only. Requires Lighthouse newer than v26.5.29.5. A second text block, `summary`, confirms it in one line as lh does; the first block is the facts, unchanged.",
|
|
917
|
+
inputSchema: idInputSchema
|
|
918
|
+
},
|
|
919
|
+
{
|
|
920
|
+
name: "lighthouse_forecast_manual",
|
|
921
|
+
description: "Run a manual forecast for a team by ID with optional remaining items and target date. Pass applyFilterOverride=true to apply the team's forecast filter, false to skip it, or omit to respect the team setting (Lighthouse v26.5.24.10+). The response includes filterApplied (boolean) and excludedSummary (string) when a filter was applied. `summary` states the answer as the web does, in the instance's terminology: the heading, then the likelihood sentence when both remaining items and a target date were given.",
|
|
922
|
+
inputSchema: {
|
|
923
|
+
type: "object",
|
|
924
|
+
properties: {
|
|
925
|
+
...idInputSchema.properties,
|
|
926
|
+
remainingItems: {
|
|
927
|
+
type: "integer",
|
|
928
|
+
description: "Remaining items to forecast."
|
|
929
|
+
},
|
|
930
|
+
targetDate: {
|
|
931
|
+
type: "string",
|
|
932
|
+
description: "Optional target date in ISO format (YYYY-MM-DD)."
|
|
933
|
+
},
|
|
934
|
+
...forecastFilterOverrideProperty
|
|
935
|
+
},
|
|
936
|
+
required: ["id"],
|
|
937
|
+
additionalProperties: false
|
|
938
|
+
}
|
|
939
|
+
},
|
|
940
|
+
{
|
|
941
|
+
name: "lighthouse_forecast_backtest",
|
|
942
|
+
description: "Run a forecast backtest for a team by ID using forecast and historical date ranges. Pass applyFilterOverride=true to apply the team's forecast filter, false to skip it, or omit to respect the team setting (Lighthouse v26.5.24.10+). The response includes filterApplied (boolean) and excludedSummary (string) when a filter was applied. `summary` states the answer as the web does, in the instance's terminology: the heading, the period with its historical data, and the actual throughput.",
|
|
943
|
+
inputSchema: {
|
|
944
|
+
type: "object",
|
|
945
|
+
properties: {
|
|
946
|
+
...idInputSchema.properties,
|
|
947
|
+
startDate: {
|
|
948
|
+
type: "string",
|
|
949
|
+
description: "Forecast start date in ISO format (YYYY-MM-DD)."
|
|
950
|
+
},
|
|
951
|
+
endDate: {
|
|
952
|
+
type: "string",
|
|
953
|
+
description: "Forecast end date in ISO format (YYYY-MM-DD)."
|
|
954
|
+
},
|
|
955
|
+
historicalStartDate: {
|
|
956
|
+
type: "string",
|
|
957
|
+
description: "Historical sample start date in ISO format (YYYY-MM-DD)."
|
|
958
|
+
},
|
|
959
|
+
historicalEndDate: {
|
|
960
|
+
type: "string",
|
|
961
|
+
description: "Historical sample end date in ISO format (YYYY-MM-DD)."
|
|
962
|
+
},
|
|
963
|
+
...forecastFilterOverrideProperty
|
|
964
|
+
},
|
|
965
|
+
required: [
|
|
966
|
+
"id",
|
|
967
|
+
"startDate",
|
|
968
|
+
"endDate",
|
|
969
|
+
"historicalStartDate",
|
|
970
|
+
"historicalEndDate"
|
|
971
|
+
],
|
|
972
|
+
additionalProperties: false
|
|
973
|
+
}
|
|
974
|
+
},
|
|
975
|
+
{
|
|
976
|
+
name: "lighthouse_team_metrics_cumulativeStateTime",
|
|
977
|
+
description: "Get cumulative time-per-state bar data for a team by ID: one entry per Doing-category workflow state with total/completed/ongoing contribution days and item counts. Optionally filter by date range and a subset of work-item IDs. `summary` states the answer as the dashboard does, in the instance's terminology: the heading and its sentence.",
|
|
978
|
+
inputSchema: {
|
|
979
|
+
type: "object",
|
|
980
|
+
properties: {
|
|
981
|
+
...idInputSchema.properties,
|
|
982
|
+
...dateRangeProperties,
|
|
983
|
+
...itemIdsProperty
|
|
984
|
+
},
|
|
985
|
+
required: ["id"],
|
|
986
|
+
additionalProperties: false
|
|
987
|
+
}
|
|
988
|
+
},
|
|
989
|
+
{
|
|
990
|
+
name: "lighthouse_team_metrics_cumulativeStateTimeItems",
|
|
991
|
+
description: "Get the per-item drill-down for ONE state of a team's cumulative time-per-state chart: the work items that contributed to that state, with days contributed. Requires the state name. `summary` states the answer as the dashboard does, in the instance's terminology: the heading and the drill-down's title.",
|
|
992
|
+
inputSchema: {
|
|
993
|
+
type: "object",
|
|
994
|
+
properties: {
|
|
995
|
+
...idInputSchema.properties,
|
|
996
|
+
...cumulativeStateProperty,
|
|
997
|
+
...dateRangeProperties,
|
|
998
|
+
...itemIdsProperty
|
|
999
|
+
},
|
|
1000
|
+
required: ["id", "state"],
|
|
1001
|
+
additionalProperties: false
|
|
1002
|
+
}
|
|
1003
|
+
},
|
|
1004
|
+
{
|
|
1005
|
+
name: "lighthouse_team_metrics_cumulativeStateTimeCandidates",
|
|
1006
|
+
description: "List the work items selectable in a team's cumulative time-per-state item picker for the window (the in-scope candidate set). Search keys are referenceId and title.",
|
|
1007
|
+
inputSchema: {
|
|
1008
|
+
type: "object",
|
|
1009
|
+
properties: {
|
|
1010
|
+
...idInputSchema.properties,
|
|
1011
|
+
...dateRangeProperties
|
|
1012
|
+
},
|
|
1013
|
+
required: ["id"],
|
|
1014
|
+
additionalProperties: false
|
|
1015
|
+
}
|
|
1016
|
+
},
|
|
1017
|
+
{
|
|
1018
|
+
name: "lighthouse_portfolio_metrics_cumulativeStateTime",
|
|
1019
|
+
description: "Get cumulative time-per-state bar data for a portfolio by ID: one entry per Doing-category workflow state with total/completed/ongoing contribution days and item counts. Optionally filter by date range and a subset of work-item IDs. `summary` states the answer as the dashboard does, in the instance's terminology: the heading and its sentence.",
|
|
1020
|
+
inputSchema: {
|
|
1021
|
+
type: "object",
|
|
1022
|
+
properties: {
|
|
1023
|
+
...idInputSchema.properties,
|
|
1024
|
+
...dateRangeProperties,
|
|
1025
|
+
...itemIdsProperty
|
|
1026
|
+
},
|
|
1027
|
+
required: ["id"],
|
|
1028
|
+
additionalProperties: false
|
|
1029
|
+
}
|
|
1030
|
+
},
|
|
1031
|
+
{
|
|
1032
|
+
name: "lighthouse_portfolio_metrics_cumulativeStateTimeItems",
|
|
1033
|
+
description: "Get the per-item drill-down for ONE state of a portfolio's cumulative time-per-state chart: the work items that contributed to that state, with days contributed. Requires the state name. `summary` states the answer as the dashboard does, in the instance's terminology: the heading and the drill-down's title.",
|
|
1034
|
+
inputSchema: {
|
|
1035
|
+
type: "object",
|
|
1036
|
+
properties: {
|
|
1037
|
+
...idInputSchema.properties,
|
|
1038
|
+
...cumulativeStateProperty,
|
|
1039
|
+
...dateRangeProperties,
|
|
1040
|
+
...itemIdsProperty
|
|
1041
|
+
},
|
|
1042
|
+
required: ["id", "state"],
|
|
1043
|
+
additionalProperties: false
|
|
1044
|
+
}
|
|
1045
|
+
},
|
|
1046
|
+
{
|
|
1047
|
+
name: "lighthouse_portfolio_metrics_cumulativeStateTimeCandidates",
|
|
1048
|
+
description: "List the work items selectable in a portfolio's cumulative time-per-state item picker for the window (the in-scope candidate set). Search keys are referenceId and title.",
|
|
1049
|
+
inputSchema: {
|
|
1050
|
+
type: "object",
|
|
1051
|
+
properties: {
|
|
1052
|
+
...idInputSchema.properties,
|
|
1053
|
+
...dateRangeProperties
|
|
1054
|
+
},
|
|
1055
|
+
required: ["id"],
|
|
1056
|
+
additionalProperties: false
|
|
1057
|
+
}
|
|
1058
|
+
},
|
|
1059
|
+
{
|
|
1060
|
+
name: "lighthouse_team_metrics_wip",
|
|
1061
|
+
description: "Get what a team has in progress right now by ID: each work item in progress today with its age (workItemAge), state, whether it is blocked (isBlocked) and since when (blockedSince), and its link (url). Use it for what is blocked or aging today; for how many were blocked on past days use lighthouse_team_metrics_blockedCountHistory. A second text block, `summary: …`, states the answer as lh does, in the instance's terminology: the heading, how many are in progress against the System WIP Limit, and how many are blocked; the first block is the facts, unchanged.",
|
|
1062
|
+
inputSchema: idInputSchema
|
|
1063
|
+
},
|
|
1064
|
+
{
|
|
1065
|
+
name: "lighthouse_team_metrics_sleRisk",
|
|
1066
|
+
description: "Get how likely each work item a team has in progress is to miss the team's SLE, by team ID: Lighthouse's own risk per work item (referenceId, risk in percent), with the finished work items that reached the same age (finishedItemsStillOpenAtThisAge) and how many of those went on to miss (finishedItemsThatWentOnToMiss, null when the work item is already past the SLE). A work item counts as at risk from 70%. Use it for \"which work items will miss our SLE\" and \"what should we swarm on\"; never compute a risk yourself. Needs a Lighthouse newer than v26.9.19.10. A second text block, `summary: …`, states the answer as lh does, in the instance's terminology: the heading, how many are at risk against the SLE, then every work item highest risk first with its name and age; the first block is the facts, unchanged.",
|
|
1067
|
+
inputSchema: idInputSchema
|
|
1068
|
+
},
|
|
1069
|
+
{
|
|
1070
|
+
name: "lighthouse_team_metrics_processBehaviorChart",
|
|
1071
|
+
description: "Get one Process Behaviour Chart of a team by ID, as Lighthouse computes it: its status (and statusReason when it is not Ready), the average and natural process limits, whether a baseline is configured, and every point (xValue, yValue) with the signals Lighthouse found on it (specialCauses: LargeChange, ModerateChange, ModerateShift, SmallShift; None means no signal) and whether it falls on a blackout day (isBlackout). metricType picks the chart: Throughput, Arrivals, Wip, WorkItemAge (the Total Work Item Age chart) or CycleTime; a team has no FeatureSize chart. A point is a day, except on CycleTime, which has one point per finished work item, dated when it finished, so several can share a day. Use it for \"is something unusual going on\" and \"did our process change\"; never work a signal out yourself. Optionally filtered by start and end dates. A second text block, `summary: …`, states the answer as lh does, in the instance's terminology: the heading, the chart's title, and each signal with the days it fired, or that there are no signals; the facts are unchanged.",
|
|
1072
|
+
inputSchema: chartInputSchema(TEAM_CHART_TYPES)
|
|
1073
|
+
},
|
|
1074
|
+
{
|
|
1075
|
+
name: "lighthouse_portfolio_metrics_processBehaviorChart",
|
|
1076
|
+
description: "Get one Process Behaviour Chart of a portfolio by ID, as Lighthouse computes it: its status (and statusReason when it is not Ready), the average and natural process limits, whether a baseline is configured, and every point (xValue, yValue) with the signals Lighthouse found on it (specialCauses: LargeChange, ModerateChange, ModerateShift, SmallShift; None means no signal) and whether it falls on a blackout day (isBlackout). metricType picks the chart: Throughput, Arrivals, Wip, WorkItemAge (the Total Work Item Age chart), CycleTime or FeatureSize. A point is a day, except on CycleTime, which has one point per finished work item, and FeatureSize, which has one per finished feature, each dated when it finished, so several can share a day. Use it for \"is something unusual going on\" and \"did our process change\"; never work a signal out yourself. Optionally filtered by start and end dates. A second text block, `summary: …`, states the answer as lh does, in the instance's terminology: the heading, the chart's title, and each signal with the days it fired, or that there are no signals; the facts are unchanged.",
|
|
1077
|
+
inputSchema: chartInputSchema(processBehaviorMetricTypes)
|
|
1078
|
+
}
|
|
724
1079
|
];
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
};
|
|
736
|
-
var getApplyFilterOverride = (argumentsPayload) => {
|
|
737
|
-
if (!isObjectRecord(argumentsPayload)) {
|
|
738
|
-
return void 0;
|
|
739
|
-
}
|
|
740
|
-
const value = argumentsPayload.applyFilterOverride;
|
|
741
|
-
return typeof value === "boolean" ? value : void 0;
|
|
742
|
-
};
|
|
743
|
-
var isoDateStringSchema = import_zod.z.string().regex(/^\d{4}-\d{2}-\d{2}$/u, "Expected ISO date in YYYY-MM-DD format.");
|
|
744
|
-
var weekdaySchema = import_zod.z.enum([
|
|
745
|
-
"Sunday",
|
|
746
|
-
"Monday",
|
|
747
|
-
"Tuesday",
|
|
748
|
-
"Wednesday",
|
|
749
|
-
"Thursday",
|
|
750
|
-
"Friday",
|
|
751
|
-
"Saturday"
|
|
752
|
-
]);
|
|
753
|
-
var recurringBlackoutRuleInputSchema = import_zod.z.object({
|
|
754
|
-
weekdays: import_zod.z.array(weekdaySchema),
|
|
755
|
-
intervalWeeks: import_zod.z.number().int(),
|
|
756
|
-
start: isoDateStringSchema,
|
|
757
|
-
end: isoDateStringSchema.nullable().optional(),
|
|
758
|
-
description: import_zod.z.string()
|
|
1080
|
+
const getDefinitionId = (argumentsPayload) => {
|
|
1081
|
+
if (typeof argumentsPayload !== "object" || argumentsPayload === null || Array.isArray(argumentsPayload)) return;
|
|
1082
|
+
const value = argumentsPayload.definitionId;
|
|
1083
|
+
return typeof value === "number" && Number.isInteger(value) ? value : void 0;
|
|
1084
|
+
};
|
|
1085
|
+
const linesOf = (...lines) => lines.filter((line) => line !== null).join("\n");
|
|
1086
|
+
const readTeamWording = (client, teamId) => (0, _letpeoplework_lighthouse_client.readAnswerWording)(client, {
|
|
1087
|
+
term: "team",
|
|
1088
|
+
id: teamId,
|
|
1089
|
+
read: () => client.getTeam(teamId)
|
|
759
1090
|
});
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
lighthouse_worktracking_get: import_zod.z.object({ id: import_zod.z.number().int() }),
|
|
765
|
-
lighthouse_team_list: import_zod.z.object({}),
|
|
766
|
-
lighthouse_team_get: import_zod.z.object({ id: import_zod.z.number().int() }),
|
|
767
|
-
lighthouse_team_refresh: import_zod.z.object({ id: import_zod.z.number().int() }),
|
|
768
|
-
lighthouse_portfolio_list: import_zod.z.object({}),
|
|
769
|
-
lighthouse_portfolio_get: import_zod.z.object({ id: import_zod.z.number().int() }),
|
|
770
|
-
lighthouse_portfolio_refresh: import_zod.z.object({ id: import_zod.z.number().int() }),
|
|
771
|
-
lighthouse_team_metrics_throughput: import_zod.z.object({
|
|
772
|
-
id: import_zod.z.number().int(),
|
|
773
|
-
startDate: isoDateStringSchema.optional(),
|
|
774
|
-
endDate: isoDateStringSchema.optional(),
|
|
775
|
-
view: import_zod.z.enum(["raw", "filtered"]).optional()
|
|
776
|
-
}),
|
|
777
|
-
lighthouse_team_metrics_cycleTimePercentiles: import_zod.z.object({
|
|
778
|
-
id: import_zod.z.number().int(),
|
|
779
|
-
startDate: isoDateStringSchema.optional(),
|
|
780
|
-
endDate: isoDateStringSchema.optional(),
|
|
781
|
-
definitionId: import_zod.z.number().int().optional()
|
|
782
|
-
}),
|
|
783
|
-
lighthouse_team_metrics_workItemAgePercentiles: import_zod.z.object({
|
|
784
|
-
id: import_zod.z.number().int(),
|
|
785
|
-
startDate: isoDateStringSchema.optional(),
|
|
786
|
-
endDate: isoDateStringSchema.optional()
|
|
787
|
-
}),
|
|
788
|
-
lighthouse_portfolio_metrics_workItemAgePercentiles: import_zod.z.object({
|
|
789
|
-
id: import_zod.z.number().int(),
|
|
790
|
-
startDate: isoDateStringSchema.optional(),
|
|
791
|
-
endDate: isoDateStringSchema.optional()
|
|
792
|
-
}),
|
|
793
|
-
lighthouse_team_metrics_blockedCountHistory: import_zod.z.object({
|
|
794
|
-
id: import_zod.z.number().int(),
|
|
795
|
-
startDate: isoDateStringSchema.optional(),
|
|
796
|
-
endDate: isoDateStringSchema.optional()
|
|
797
|
-
}),
|
|
798
|
-
lighthouse_portfolio_metrics_blockedCountHistory: import_zod.z.object({
|
|
799
|
-
id: import_zod.z.number().int(),
|
|
800
|
-
startDate: isoDateStringSchema.optional(),
|
|
801
|
-
endDate: isoDateStringSchema.optional()
|
|
802
|
-
}),
|
|
803
|
-
lighthouse_team_metrics_percentilesOverTime: import_zod.z.object({
|
|
804
|
-
id: import_zod.z.number().int(),
|
|
805
|
-
startDate: isoDateStringSchema.optional(),
|
|
806
|
-
endDate: isoDateStringSchema.optional(),
|
|
807
|
-
metricType: import_zod.z.enum(["CycleTime", "WorkItemAge"]).optional(),
|
|
808
|
-
horizon: import_zod.z.number().int().optional()
|
|
809
|
-
}),
|
|
810
|
-
lighthouse_portfolio_metrics_percentilesOverTime: import_zod.z.object({
|
|
811
|
-
id: import_zod.z.number().int(),
|
|
812
|
-
startDate: isoDateStringSchema.optional(),
|
|
813
|
-
endDate: isoDateStringSchema.optional(),
|
|
814
|
-
metricType: import_zod.z.enum(["CycleTime", "WorkItemAge"]).optional(),
|
|
815
|
-
horizon: import_zod.z.number().int().optional()
|
|
816
|
-
}),
|
|
817
|
-
lighthouse_team_metrics_processBehaviorOverTime: import_zod.z.object({
|
|
818
|
-
id: import_zod.z.number().int(),
|
|
819
|
-
startDate: isoDateStringSchema.optional(),
|
|
820
|
-
endDate: isoDateStringSchema.optional(),
|
|
821
|
-
metricType: import_zod.z.enum([
|
|
822
|
-
"Throughput",
|
|
823
|
-
"WorkItemAge",
|
|
824
|
-
"Wip",
|
|
825
|
-
"CycleTime",
|
|
826
|
-
"Arrivals",
|
|
827
|
-
"FeatureSize"
|
|
828
|
-
]).optional()
|
|
829
|
-
}),
|
|
830
|
-
lighthouse_portfolio_metrics_processBehaviorOverTime: import_zod.z.object({
|
|
831
|
-
id: import_zod.z.number().int(),
|
|
832
|
-
startDate: isoDateStringSchema.optional(),
|
|
833
|
-
endDate: isoDateStringSchema.optional(),
|
|
834
|
-
metricType: import_zod.z.enum([
|
|
835
|
-
"Throughput",
|
|
836
|
-
"WorkItemAge",
|
|
837
|
-
"Wip",
|
|
838
|
-
"CycleTime",
|
|
839
|
-
"Arrivals",
|
|
840
|
-
"FeatureSize"
|
|
841
|
-
]).optional()
|
|
842
|
-
}),
|
|
843
|
-
lighthouse_team_metrics_workItemAge: import_zod.z.object({
|
|
844
|
-
id: import_zod.z.number().int(),
|
|
845
|
-
startDate: isoDateStringSchema.optional(),
|
|
846
|
-
endDate: isoDateStringSchema.optional()
|
|
847
|
-
}),
|
|
848
|
-
lighthouse_team_metrics_totalWorkItemAge: import_zod.z.object({
|
|
849
|
-
id: import_zod.z.number().int(),
|
|
850
|
-
startDate: isoDateStringSchema.optional(),
|
|
851
|
-
endDate: isoDateStringSchema.optional()
|
|
852
|
-
}),
|
|
853
|
-
lighthouse_portfolio_metrics_throughput: import_zod.z.object({
|
|
854
|
-
id: import_zod.z.number().int(),
|
|
855
|
-
startDate: isoDateStringSchema.optional(),
|
|
856
|
-
endDate: isoDateStringSchema.optional()
|
|
857
|
-
}),
|
|
858
|
-
lighthouse_portfolio_metrics_workItemAge: import_zod.z.object({
|
|
859
|
-
id: import_zod.z.number().int(),
|
|
860
|
-
startDate: isoDateStringSchema.optional(),
|
|
861
|
-
endDate: isoDateStringSchema.optional()
|
|
862
|
-
}),
|
|
863
|
-
lighthouse_portfolio_metrics_totalWorkItemAge: import_zod.z.object({
|
|
864
|
-
id: import_zod.z.number().int(),
|
|
865
|
-
startDate: isoDateStringSchema.optional(),
|
|
866
|
-
endDate: isoDateStringSchema.optional()
|
|
867
|
-
}),
|
|
868
|
-
lighthouse_team_metrics_cumulativeStateTime: import_zod.z.object({
|
|
869
|
-
id: import_zod.z.number().int(),
|
|
870
|
-
startDate: isoDateStringSchema.optional(),
|
|
871
|
-
endDate: isoDateStringSchema.optional(),
|
|
872
|
-
itemIds: import_zod.z.array(import_zod.z.number().int()).optional()
|
|
873
|
-
}),
|
|
874
|
-
lighthouse_team_metrics_cumulativeStateTimeItems: import_zod.z.object({
|
|
875
|
-
id: import_zod.z.number().int(),
|
|
876
|
-
state: import_zod.z.string(),
|
|
877
|
-
startDate: isoDateStringSchema.optional(),
|
|
878
|
-
endDate: isoDateStringSchema.optional(),
|
|
879
|
-
itemIds: import_zod.z.array(import_zod.z.number().int()).optional()
|
|
880
|
-
}),
|
|
881
|
-
lighthouse_team_metrics_cumulativeStateTimeCandidates: import_zod.z.object({
|
|
882
|
-
id: import_zod.z.number().int(),
|
|
883
|
-
startDate: isoDateStringSchema.optional(),
|
|
884
|
-
endDate: isoDateStringSchema.optional()
|
|
885
|
-
}),
|
|
886
|
-
lighthouse_portfolio_metrics_cumulativeStateTime: import_zod.z.object({
|
|
887
|
-
id: import_zod.z.number().int(),
|
|
888
|
-
startDate: isoDateStringSchema.optional(),
|
|
889
|
-
endDate: isoDateStringSchema.optional(),
|
|
890
|
-
itemIds: import_zod.z.array(import_zod.z.number().int()).optional()
|
|
891
|
-
}),
|
|
892
|
-
lighthouse_portfolio_metrics_cumulativeStateTimeItems: import_zod.z.object({
|
|
893
|
-
id: import_zod.z.number().int(),
|
|
894
|
-
state: import_zod.z.string(),
|
|
895
|
-
startDate: isoDateStringSchema.optional(),
|
|
896
|
-
endDate: isoDateStringSchema.optional(),
|
|
897
|
-
itemIds: import_zod.z.array(import_zod.z.number().int()).optional()
|
|
898
|
-
}),
|
|
899
|
-
lighthouse_portfolio_metrics_cumulativeStateTimeCandidates: import_zod.z.object({
|
|
900
|
-
id: import_zod.z.number().int(),
|
|
901
|
-
startDate: isoDateStringSchema.optional(),
|
|
902
|
-
endDate: isoDateStringSchema.optional()
|
|
903
|
-
}),
|
|
904
|
-
lighthouse_feature_get: import_zod.z.object({
|
|
905
|
-
ids: import_zod.z.array(import_zod.z.number().int()).optional(),
|
|
906
|
-
refs: import_zod.z.array(import_zod.z.string()).optional()
|
|
907
|
-
}),
|
|
908
|
-
lighthouse_feature_workitems: import_zod.z.object({ id: import_zod.z.number().int() }),
|
|
909
|
-
lighthouse_delivery_list: import_zod.z.object({ id: import_zod.z.number().int() }),
|
|
910
|
-
lighthouse_delivery_metrics: import_zod.z.object({
|
|
911
|
-
id: import_zod.z.number().int(),
|
|
912
|
-
detail: import_zod.z.literal("epics").optional()
|
|
913
|
-
}),
|
|
914
|
-
lighthouse_blackout_list: import_zod.z.object({}),
|
|
915
|
-
lighthouse_blackout_create: recurringBlackoutRuleInputSchema,
|
|
916
|
-
lighthouse_blackout_update: recurringBlackoutRuleInputSchema.extend({
|
|
917
|
-
id: import_zod.z.number().int()
|
|
918
|
-
}),
|
|
919
|
-
lighthouse_blackout_delete: import_zod.z.object({ id: import_zod.z.number().int() }),
|
|
920
|
-
lighthouse_forecast_manual: import_zod.z.object({
|
|
921
|
-
id: import_zod.z.number().int(),
|
|
922
|
-
remainingItems: import_zod.z.number().int().optional(),
|
|
923
|
-
targetDate: isoDateStringSchema.optional(),
|
|
924
|
-
applyFilterOverride: import_zod.z.boolean().optional()
|
|
925
|
-
}),
|
|
926
|
-
lighthouse_forecast_backtest: import_zod.z.object({
|
|
927
|
-
id: import_zod.z.number().int(),
|
|
928
|
-
startDate: isoDateStringSchema,
|
|
929
|
-
endDate: isoDateStringSchema,
|
|
930
|
-
historicalStartDate: isoDateStringSchema,
|
|
931
|
-
historicalEndDate: isoDateStringSchema,
|
|
932
|
-
applyFilterOverride: import_zod.z.boolean().optional()
|
|
933
|
-
})
|
|
934
|
-
};
|
|
935
|
-
var isReadOnlyTool = (toolName) => !(toolName.endsWith("_refresh") || toolName.endsWith("_create") || toolName.endsWith("_update") || toolName.endsWith("_delete"));
|
|
936
|
-
var createMcpCoreRuntime = (dependencies) => ({
|
|
937
|
-
listTools: () => toolDefinitions,
|
|
938
|
-
callTool: async (name, argumentsPayload) => {
|
|
939
|
-
const client = dependencies.createClient();
|
|
940
|
-
if (name === "lighthouse_health_check") {
|
|
941
|
-
const health = await client.checkConnectivity();
|
|
942
|
-
if (health.category === "success") {
|
|
943
|
-
return getSuccessToolResult("connectivity: success");
|
|
944
|
-
}
|
|
945
|
-
const healthReasonSuffix = health.reason === void 0 ? "" : ` (${health.reason})`;
|
|
946
|
-
return getErrorToolResult(
|
|
947
|
-
`connectivity: ${health.category}${healthReasonSuffix}`
|
|
948
|
-
);
|
|
949
|
-
}
|
|
950
|
-
if (name === "lighthouse_version_get") {
|
|
951
|
-
const version = await client.getVersion();
|
|
952
|
-
if (version.ok) {
|
|
953
|
-
return getSuccessToolResult(`version: ${version.value}`);
|
|
954
|
-
}
|
|
955
|
-
return getErrorToolResult(
|
|
956
|
-
`version: ${version.error.category} (${version.error.reason})`
|
|
957
|
-
);
|
|
958
|
-
}
|
|
959
|
-
if (name === "lighthouse_worktracking_list") {
|
|
960
|
-
const connections = await client.listWorkTrackingConnections();
|
|
961
|
-
if (connections.ok) {
|
|
962
|
-
return getSuccessToolResult(
|
|
963
|
-
`worktracking: ${encodePayload(connections.value)}`
|
|
964
|
-
);
|
|
965
|
-
}
|
|
966
|
-
return getErrorToolResult(
|
|
967
|
-
`worktracking: ${connections.error.category} (${connections.error.reason})`
|
|
968
|
-
);
|
|
969
|
-
}
|
|
970
|
-
if (name === "lighthouse_worktracking_get") {
|
|
971
|
-
const id = getNumericId(argumentsPayload);
|
|
972
|
-
if (id === null) {
|
|
973
|
-
return getErrorToolResult("worktracking: invalid id");
|
|
974
|
-
}
|
|
975
|
-
const connection = await client.getWorkTrackingConnection(id);
|
|
976
|
-
if (connection.ok) {
|
|
977
|
-
return getSuccessToolResult(
|
|
978
|
-
`worktracking: ${encodePayload(connection.value)}`
|
|
979
|
-
);
|
|
980
|
-
}
|
|
981
|
-
return getErrorToolResult(
|
|
982
|
-
`worktracking: ${connection.error.category} (${connection.error.reason})`
|
|
983
|
-
);
|
|
984
|
-
}
|
|
985
|
-
if (name === "lighthouse_team_list") {
|
|
986
|
-
const teams = await client.listTeams();
|
|
987
|
-
if (teams.ok) {
|
|
988
|
-
return getSuccessToolResult(`teams: ${encodePayload(teams.value)}`);
|
|
989
|
-
}
|
|
990
|
-
return getErrorToolResult(
|
|
991
|
-
`teams: ${teams.error.category} (${teams.error.reason})`
|
|
992
|
-
);
|
|
993
|
-
}
|
|
994
|
-
if (name === "lighthouse_team_get") {
|
|
995
|
-
const id = getNumericId(argumentsPayload);
|
|
996
|
-
if (id === null) {
|
|
997
|
-
return getErrorToolResult("team: invalid id");
|
|
998
|
-
}
|
|
999
|
-
const team = await client.getTeam(id);
|
|
1000
|
-
if (team.ok) {
|
|
1001
|
-
return getSuccessToolResult(`team: ${encodePayload(team.value)}`);
|
|
1002
|
-
}
|
|
1003
|
-
return getErrorToolResult(
|
|
1004
|
-
`team: ${team.error.category} (${team.error.reason})`
|
|
1005
|
-
);
|
|
1006
|
-
}
|
|
1007
|
-
if (name === "lighthouse_team_refresh") {
|
|
1008
|
-
const id = getNumericId(argumentsPayload);
|
|
1009
|
-
if (id === null) {
|
|
1010
|
-
return getErrorToolResult("team: invalid id");
|
|
1011
|
-
}
|
|
1012
|
-
const result = await client.refreshTeam(id);
|
|
1013
|
-
if (result.ok) {
|
|
1014
|
-
return getSuccessToolResult(`team refreshed: ${id}`);
|
|
1015
|
-
}
|
|
1016
|
-
return getErrorToolResult(
|
|
1017
|
-
`team refresh: ${result.error.category} (${result.error.reason})`
|
|
1018
|
-
);
|
|
1019
|
-
}
|
|
1020
|
-
if (name === "lighthouse_portfolio_list") {
|
|
1021
|
-
const portfolios = await client.listPortfolios();
|
|
1022
|
-
if (portfolios.ok) {
|
|
1023
|
-
return getSuccessToolResult(
|
|
1024
|
-
`portfolios: ${encodePayload(portfolios.value)}`
|
|
1025
|
-
);
|
|
1026
|
-
}
|
|
1027
|
-
return getErrorToolResult(
|
|
1028
|
-
`portfolios: ${portfolios.error.category} (${portfolios.error.reason})`
|
|
1029
|
-
);
|
|
1030
|
-
}
|
|
1031
|
-
if (name === "lighthouse_portfolio_get") {
|
|
1032
|
-
const id = getNumericId(argumentsPayload);
|
|
1033
|
-
if (id === null) {
|
|
1034
|
-
return getErrorToolResult("portfolio: invalid id");
|
|
1035
|
-
}
|
|
1036
|
-
const portfolio = await client.getPortfolio(id);
|
|
1037
|
-
if (portfolio.ok) {
|
|
1038
|
-
return getSuccessToolResult(
|
|
1039
|
-
`portfolio: ${encodePayload(portfolio.value)}`
|
|
1040
|
-
);
|
|
1041
|
-
}
|
|
1042
|
-
return getErrorToolResult(
|
|
1043
|
-
`portfolio: ${portfolio.error.category} (${portfolio.error.reason})`
|
|
1044
|
-
);
|
|
1045
|
-
}
|
|
1046
|
-
if (name === "lighthouse_portfolio_refresh") {
|
|
1047
|
-
const id = getNumericId(argumentsPayload);
|
|
1048
|
-
if (id === null) {
|
|
1049
|
-
return getErrorToolResult("portfolio: invalid id");
|
|
1050
|
-
}
|
|
1051
|
-
const result = await client.refreshPortfolio(id);
|
|
1052
|
-
if (result.ok) {
|
|
1053
|
-
return getSuccessToolResult(`portfolio refreshed: ${id}`);
|
|
1054
|
-
}
|
|
1055
|
-
return getErrorToolResult(
|
|
1056
|
-
`portfolio refresh: ${result.error.category} (${result.error.reason})`
|
|
1057
|
-
);
|
|
1058
|
-
}
|
|
1059
|
-
if (name === "lighthouse_team_metrics_throughput") {
|
|
1060
|
-
const id = getNumericId(argumentsPayload);
|
|
1061
|
-
if (id === null) {
|
|
1062
|
-
return getErrorToolResult("team metrics: invalid id");
|
|
1063
|
-
}
|
|
1064
|
-
const range = getDateRange(argumentsPayload);
|
|
1065
|
-
const view = getThroughputFilterView(argumentsPayload);
|
|
1066
|
-
const result = await client.getTeamThroughput(id, range, view);
|
|
1067
|
-
if (result.ok) {
|
|
1068
|
-
return getSuccessToolResult(
|
|
1069
|
-
`team throughput: ${encodePayload(result.value)}`
|
|
1070
|
-
);
|
|
1071
|
-
}
|
|
1072
|
-
return getErrorToolResult(
|
|
1073
|
-
`team metrics: ${result.error.category} (${result.error.reason})`
|
|
1074
|
-
);
|
|
1075
|
-
}
|
|
1076
|
-
if (name === "lighthouse_team_metrics_cycleTimePercentiles") {
|
|
1077
|
-
const id = getNumericId(argumentsPayload);
|
|
1078
|
-
if (id === null) {
|
|
1079
|
-
return getErrorToolResult("team metrics: invalid id");
|
|
1080
|
-
}
|
|
1081
|
-
const range = getDateRange(argumentsPayload);
|
|
1082
|
-
const definitionId = getDefinitionId(argumentsPayload);
|
|
1083
|
-
const result = await client.getTeamCycleTimePercentiles(
|
|
1084
|
-
id,
|
|
1085
|
-
range,
|
|
1086
|
-
definitionId
|
|
1087
|
-
);
|
|
1088
|
-
if (result.ok) {
|
|
1089
|
-
return getSuccessToolResult(
|
|
1090
|
-
`team cycleTimePercentiles: ${encodePayload(result.value)}`
|
|
1091
|
-
);
|
|
1092
|
-
}
|
|
1093
|
-
return getErrorToolResult(
|
|
1094
|
-
`team metrics: ${result.error.category} (${result.error.reason})`
|
|
1095
|
-
);
|
|
1096
|
-
}
|
|
1097
|
-
if (name === "lighthouse_team_metrics_workItemAgePercentiles") {
|
|
1098
|
-
const id = getNumericId(argumentsPayload);
|
|
1099
|
-
if (id === null) {
|
|
1100
|
-
return getErrorToolResult("team metrics: invalid id");
|
|
1101
|
-
}
|
|
1102
|
-
const range = getDateRange(argumentsPayload);
|
|
1103
|
-
const result = await client.getTeamWorkItemAgePercentiles(id, range);
|
|
1104
|
-
if (result.ok) {
|
|
1105
|
-
return getSuccessToolResult(
|
|
1106
|
-
`team workItemAgePercentiles: ${encodePayload(result.value)}`
|
|
1107
|
-
);
|
|
1108
|
-
}
|
|
1109
|
-
return getErrorToolResult(
|
|
1110
|
-
`team metrics: ${result.error.category} (${result.error.reason})`
|
|
1111
|
-
);
|
|
1112
|
-
}
|
|
1113
|
-
if (name === "lighthouse_portfolio_metrics_workItemAgePercentiles") {
|
|
1114
|
-
const id = getNumericId(argumentsPayload);
|
|
1115
|
-
if (id === null) {
|
|
1116
|
-
return getErrorToolResult("portfolio metrics: invalid id");
|
|
1117
|
-
}
|
|
1118
|
-
const range = getDateRange(argumentsPayload);
|
|
1119
|
-
const result = await client.getPortfolioWorkItemAgePercentiles(id, range);
|
|
1120
|
-
if (result.ok) {
|
|
1121
|
-
return getSuccessToolResult(
|
|
1122
|
-
`portfolio workItemAgePercentiles: ${encodePayload(result.value)}`
|
|
1123
|
-
);
|
|
1124
|
-
}
|
|
1125
|
-
return getErrorToolResult(
|
|
1126
|
-
`portfolio metrics: ${result.error.category} (${result.error.reason})`
|
|
1127
|
-
);
|
|
1128
|
-
}
|
|
1129
|
-
if (name === "lighthouse_team_metrics_blockedCountHistory") {
|
|
1130
|
-
const id = getNumericId(argumentsPayload);
|
|
1131
|
-
if (id === null) {
|
|
1132
|
-
return getErrorToolResult("team metrics: invalid id");
|
|
1133
|
-
}
|
|
1134
|
-
const range = getDateRange(argumentsPayload);
|
|
1135
|
-
const result = await client.getTeamBlockedCountHistory(id, range);
|
|
1136
|
-
if (result.ok) {
|
|
1137
|
-
return getSuccessToolResult(
|
|
1138
|
-
`team blockedCountHistory: ${encodePayload(result.value)}`
|
|
1139
|
-
);
|
|
1140
|
-
}
|
|
1141
|
-
return getErrorToolResult(
|
|
1142
|
-
`team metrics: ${result.error.category} (${result.error.reason})`
|
|
1143
|
-
);
|
|
1144
|
-
}
|
|
1145
|
-
if (name === "lighthouse_portfolio_metrics_blockedCountHistory") {
|
|
1146
|
-
const id = getNumericId(argumentsPayload);
|
|
1147
|
-
if (id === null) {
|
|
1148
|
-
return getErrorToolResult("portfolio metrics: invalid id");
|
|
1149
|
-
}
|
|
1150
|
-
const range = getDateRange(argumentsPayload);
|
|
1151
|
-
const result = await client.getPortfolioBlockedCountHistory(id, range);
|
|
1152
|
-
if (result.ok) {
|
|
1153
|
-
return getSuccessToolResult(
|
|
1154
|
-
`portfolio blockedCountHistory: ${encodePayload(result.value)}`
|
|
1155
|
-
);
|
|
1156
|
-
}
|
|
1157
|
-
return getErrorToolResult(
|
|
1158
|
-
`portfolio metrics: ${result.error.category} (${result.error.reason})`
|
|
1159
|
-
);
|
|
1160
|
-
}
|
|
1161
|
-
if (name === "lighthouse_team_metrics_percentilesOverTime") {
|
|
1162
|
-
const id = getNumericId(argumentsPayload);
|
|
1163
|
-
if (id === null) {
|
|
1164
|
-
return getErrorToolResult("team metrics: invalid id");
|
|
1165
|
-
}
|
|
1166
|
-
const range = getDateRange(argumentsPayload);
|
|
1167
|
-
const result = await client.getTeamPercentilesOverTime(
|
|
1168
|
-
id,
|
|
1169
|
-
range,
|
|
1170
|
-
getPercentilesOverTimeMetricType(argumentsPayload),
|
|
1171
|
-
getHorizonArgument(argumentsPayload)
|
|
1172
|
-
);
|
|
1173
|
-
if (result.ok) {
|
|
1174
|
-
return getSuccessToolResult(
|
|
1175
|
-
`team percentilesOverTime: ${encodePayload(result.value)}`
|
|
1176
|
-
);
|
|
1177
|
-
}
|
|
1178
|
-
return getErrorToolResult(
|
|
1179
|
-
`team metrics: ${result.error.category} (${result.error.reason})`
|
|
1180
|
-
);
|
|
1181
|
-
}
|
|
1182
|
-
if (name === "lighthouse_portfolio_metrics_percentilesOverTime") {
|
|
1183
|
-
const id = getNumericId(argumentsPayload);
|
|
1184
|
-
if (id === null) {
|
|
1185
|
-
return getErrorToolResult("portfolio metrics: invalid id");
|
|
1186
|
-
}
|
|
1187
|
-
const range = getDateRange(argumentsPayload);
|
|
1188
|
-
const result = await client.getPortfolioPercentilesOverTime(
|
|
1189
|
-
id,
|
|
1190
|
-
range,
|
|
1191
|
-
getPercentilesOverTimeMetricType(argumentsPayload),
|
|
1192
|
-
getHorizonArgument(argumentsPayload)
|
|
1193
|
-
);
|
|
1194
|
-
if (result.ok) {
|
|
1195
|
-
return getSuccessToolResult(
|
|
1196
|
-
`portfolio percentilesOverTime: ${encodePayload(result.value)}`
|
|
1197
|
-
);
|
|
1198
|
-
}
|
|
1199
|
-
return getErrorToolResult(
|
|
1200
|
-
`portfolio metrics: ${result.error.category} (${result.error.reason})`
|
|
1201
|
-
);
|
|
1202
|
-
}
|
|
1203
|
-
if (name === "lighthouse_team_metrics_processBehaviorOverTime") {
|
|
1204
|
-
const id = getNumericId(argumentsPayload);
|
|
1205
|
-
if (id === null) {
|
|
1206
|
-
return getErrorToolResult("team metrics: invalid id");
|
|
1207
|
-
}
|
|
1208
|
-
const range = getDateRange(argumentsPayload);
|
|
1209
|
-
const result = await client.getTeamProcessBehaviorOverTime(
|
|
1210
|
-
id,
|
|
1211
|
-
range,
|
|
1212
|
-
getProcessBehaviorMetricType(argumentsPayload)
|
|
1213
|
-
);
|
|
1214
|
-
if (result.ok) {
|
|
1215
|
-
return getSuccessToolResult(
|
|
1216
|
-
`team processBehaviorOverTime: ${encodePayload(result.value)}`
|
|
1217
|
-
);
|
|
1218
|
-
}
|
|
1219
|
-
return getErrorToolResult(
|
|
1220
|
-
`team metrics: ${result.error.category} (${result.error.reason})`
|
|
1221
|
-
);
|
|
1222
|
-
}
|
|
1223
|
-
if (name === "lighthouse_portfolio_metrics_processBehaviorOverTime") {
|
|
1224
|
-
const id = getNumericId(argumentsPayload);
|
|
1225
|
-
if (id === null) {
|
|
1226
|
-
return getErrorToolResult("portfolio metrics: invalid id");
|
|
1227
|
-
}
|
|
1228
|
-
const range = getDateRange(argumentsPayload);
|
|
1229
|
-
const result = await client.getPortfolioProcessBehaviorOverTime(
|
|
1230
|
-
id,
|
|
1231
|
-
range,
|
|
1232
|
-
getProcessBehaviorMetricType(argumentsPayload)
|
|
1233
|
-
);
|
|
1234
|
-
if (result.ok) {
|
|
1235
|
-
return getSuccessToolResult(
|
|
1236
|
-
`portfolio processBehaviorOverTime: ${encodePayload(result.value)}`
|
|
1237
|
-
);
|
|
1238
|
-
}
|
|
1239
|
-
return getErrorToolResult(
|
|
1240
|
-
`portfolio metrics: ${result.error.category} (${result.error.reason})`
|
|
1241
|
-
);
|
|
1242
|
-
}
|
|
1243
|
-
if (name === "lighthouse_team_metrics_cumulativeStateTime") {
|
|
1244
|
-
const id = getNumericId(argumentsPayload);
|
|
1245
|
-
if (id === null) {
|
|
1246
|
-
return getErrorToolResult("team metrics: invalid id");
|
|
1247
|
-
}
|
|
1248
|
-
const result = await client.getTeamCumulativeStateTime(
|
|
1249
|
-
id,
|
|
1250
|
-
getDateRange(argumentsPayload),
|
|
1251
|
-
getItemIdsArgument(argumentsPayload)
|
|
1252
|
-
);
|
|
1253
|
-
if (result.ok) {
|
|
1254
|
-
return getSuccessToolResult(
|
|
1255
|
-
`team cumulativeStateTime: ${encodePayload(result.value)}`
|
|
1256
|
-
);
|
|
1257
|
-
}
|
|
1258
|
-
return getErrorToolResult(
|
|
1259
|
-
`team metrics: ${result.error.category} (${result.error.reason})`
|
|
1260
|
-
);
|
|
1261
|
-
}
|
|
1262
|
-
if (name === "lighthouse_team_metrics_cumulativeStateTimeItems") {
|
|
1263
|
-
const id = getNumericId(argumentsPayload);
|
|
1264
|
-
if (id === null) {
|
|
1265
|
-
return getErrorToolResult("team metrics: invalid id");
|
|
1266
|
-
}
|
|
1267
|
-
const state = getStringArgument(argumentsPayload, "state");
|
|
1268
|
-
if (state === void 0) {
|
|
1269
|
-
return getErrorToolResult("team metrics: missing state");
|
|
1270
|
-
}
|
|
1271
|
-
const result = await client.getTeamCumulativeStateTimeItems(
|
|
1272
|
-
id,
|
|
1273
|
-
state,
|
|
1274
|
-
getDateRange(argumentsPayload),
|
|
1275
|
-
getItemIdsArgument(argumentsPayload)
|
|
1276
|
-
);
|
|
1277
|
-
if (result.ok) {
|
|
1278
|
-
return getSuccessToolResult(
|
|
1279
|
-
`team cumulativeStateTimeItems: ${encodePayload(result.value)}`
|
|
1280
|
-
);
|
|
1281
|
-
}
|
|
1282
|
-
return getErrorToolResult(
|
|
1283
|
-
`team metrics: ${result.error.category} (${result.error.reason})`
|
|
1284
|
-
);
|
|
1285
|
-
}
|
|
1286
|
-
if (name === "lighthouse_team_metrics_cumulativeStateTimeCandidates") {
|
|
1287
|
-
const id = getNumericId(argumentsPayload);
|
|
1288
|
-
if (id === null) {
|
|
1289
|
-
return getErrorToolResult("team metrics: invalid id");
|
|
1290
|
-
}
|
|
1291
|
-
const result = await client.getTeamCumulativeStateTimeCandidates(
|
|
1292
|
-
id,
|
|
1293
|
-
getDateRange(argumentsPayload)
|
|
1294
|
-
);
|
|
1295
|
-
if (result.ok) {
|
|
1296
|
-
return getSuccessToolResult(
|
|
1297
|
-
`team cumulativeStateTimeCandidates: ${encodePayload(result.value)}`
|
|
1298
|
-
);
|
|
1299
|
-
}
|
|
1300
|
-
return getErrorToolResult(
|
|
1301
|
-
`team metrics: ${result.error.category} (${result.error.reason})`
|
|
1302
|
-
);
|
|
1303
|
-
}
|
|
1304
|
-
if (name === "lighthouse_portfolio_metrics_cumulativeStateTime") {
|
|
1305
|
-
const id = getNumericId(argumentsPayload);
|
|
1306
|
-
if (id === null) {
|
|
1307
|
-
return getErrorToolResult("portfolio metrics: invalid id");
|
|
1308
|
-
}
|
|
1309
|
-
const result = await client.getPortfolioCumulativeStateTime(
|
|
1310
|
-
id,
|
|
1311
|
-
getDateRange(argumentsPayload),
|
|
1312
|
-
getItemIdsArgument(argumentsPayload)
|
|
1313
|
-
);
|
|
1314
|
-
if (result.ok) {
|
|
1315
|
-
return getSuccessToolResult(
|
|
1316
|
-
`portfolio cumulativeStateTime: ${encodePayload(result.value)}`
|
|
1317
|
-
);
|
|
1318
|
-
}
|
|
1319
|
-
return getErrorToolResult(
|
|
1320
|
-
`portfolio metrics: ${result.error.category} (${result.error.reason})`
|
|
1321
|
-
);
|
|
1322
|
-
}
|
|
1323
|
-
if (name === "lighthouse_portfolio_metrics_cumulativeStateTimeItems") {
|
|
1324
|
-
const id = getNumericId(argumentsPayload);
|
|
1325
|
-
if (id === null) {
|
|
1326
|
-
return getErrorToolResult("portfolio metrics: invalid id");
|
|
1327
|
-
}
|
|
1328
|
-
const state = getStringArgument(argumentsPayload, "state");
|
|
1329
|
-
if (state === void 0) {
|
|
1330
|
-
return getErrorToolResult("portfolio metrics: missing state");
|
|
1331
|
-
}
|
|
1332
|
-
const result = await client.getPortfolioCumulativeStateTimeItems(
|
|
1333
|
-
id,
|
|
1334
|
-
state,
|
|
1335
|
-
getDateRange(argumentsPayload),
|
|
1336
|
-
getItemIdsArgument(argumentsPayload)
|
|
1337
|
-
);
|
|
1338
|
-
if (result.ok) {
|
|
1339
|
-
return getSuccessToolResult(
|
|
1340
|
-
`portfolio cumulativeStateTimeItems: ${encodePayload(result.value)}`
|
|
1341
|
-
);
|
|
1342
|
-
}
|
|
1343
|
-
return getErrorToolResult(
|
|
1344
|
-
`portfolio metrics: ${result.error.category} (${result.error.reason})`
|
|
1345
|
-
);
|
|
1346
|
-
}
|
|
1347
|
-
if (name === "lighthouse_portfolio_metrics_cumulativeStateTimeCandidates") {
|
|
1348
|
-
const id = getNumericId(argumentsPayload);
|
|
1349
|
-
if (id === null) {
|
|
1350
|
-
return getErrorToolResult("portfolio metrics: invalid id");
|
|
1351
|
-
}
|
|
1352
|
-
const result = await client.getPortfolioCumulativeStateTimeCandidates(
|
|
1353
|
-
id,
|
|
1354
|
-
getDateRange(argumentsPayload)
|
|
1355
|
-
);
|
|
1356
|
-
if (result.ok) {
|
|
1357
|
-
return getSuccessToolResult(
|
|
1358
|
-
`portfolio cumulativeStateTimeCandidates: ${encodePayload(result.value)}`
|
|
1359
|
-
);
|
|
1360
|
-
}
|
|
1361
|
-
return getErrorToolResult(
|
|
1362
|
-
`portfolio metrics: ${result.error.category} (${result.error.reason})`
|
|
1363
|
-
);
|
|
1364
|
-
}
|
|
1365
|
-
if (name === "lighthouse_portfolio_metrics_throughput") {
|
|
1366
|
-
const id = getNumericId(argumentsPayload);
|
|
1367
|
-
if (id === null) {
|
|
1368
|
-
return getErrorToolResult("portfolio metrics: invalid id");
|
|
1369
|
-
}
|
|
1370
|
-
const range = getDateRange(argumentsPayload);
|
|
1371
|
-
const result = await client.getPortfolioThroughput(id, range);
|
|
1372
|
-
if (result.ok) {
|
|
1373
|
-
return getSuccessToolResult(
|
|
1374
|
-
`portfolio throughput: ${encodePayload(result.value)}`
|
|
1375
|
-
);
|
|
1376
|
-
}
|
|
1377
|
-
return getErrorToolResult(
|
|
1378
|
-
`portfolio metrics: ${result.error.category} (${result.error.reason})`
|
|
1379
|
-
);
|
|
1380
|
-
}
|
|
1381
|
-
if (name === "lighthouse_team_metrics_workItemAge") {
|
|
1382
|
-
const id = getNumericId(argumentsPayload);
|
|
1383
|
-
if (id === null) {
|
|
1384
|
-
return getErrorToolResult("team metrics: invalid id");
|
|
1385
|
-
}
|
|
1386
|
-
const range = getDateRange(argumentsPayload);
|
|
1387
|
-
const result = await client.getTeamWorkItemAgeOverTime(id, range);
|
|
1388
|
-
if (result.ok) {
|
|
1389
|
-
return getSuccessToolResult(
|
|
1390
|
-
`team workItemAge: ${encodePayload(result.value)}`
|
|
1391
|
-
);
|
|
1392
|
-
}
|
|
1393
|
-
return getErrorToolResult(
|
|
1394
|
-
`team metrics: ${result.error.category} (${result.error.reason})`
|
|
1395
|
-
);
|
|
1396
|
-
}
|
|
1397
|
-
if (name === "lighthouse_team_metrics_totalWorkItemAge") {
|
|
1398
|
-
const id = getNumericId(argumentsPayload);
|
|
1399
|
-
if (id === null) {
|
|
1400
|
-
return getErrorToolResult("team metrics: invalid id");
|
|
1401
|
-
}
|
|
1402
|
-
const range = getDateRange(argumentsPayload);
|
|
1403
|
-
const result = await client.getTeamTotalWorkItemAgeOverTime(id, range);
|
|
1404
|
-
if (result.ok) {
|
|
1405
|
-
return getSuccessToolResult(
|
|
1406
|
-
`team totalWorkItemAge: ${encodePayload(result.value)}`
|
|
1407
|
-
);
|
|
1408
|
-
}
|
|
1409
|
-
return getErrorToolResult(
|
|
1410
|
-
`team metrics: ${result.error.category} (${result.error.reason})`
|
|
1411
|
-
);
|
|
1412
|
-
}
|
|
1413
|
-
if (name === "lighthouse_portfolio_metrics_workItemAge") {
|
|
1414
|
-
const id = getNumericId(argumentsPayload);
|
|
1415
|
-
if (id === null) {
|
|
1416
|
-
return getErrorToolResult("portfolio metrics: invalid id");
|
|
1417
|
-
}
|
|
1418
|
-
const range = getDateRange(argumentsPayload);
|
|
1419
|
-
const result = await client.getPortfolioWorkItemAgeOverTime(id, range);
|
|
1420
|
-
if (result.ok) {
|
|
1421
|
-
return getSuccessToolResult(
|
|
1422
|
-
`portfolio workItemAge: ${encodePayload(result.value)}`
|
|
1423
|
-
);
|
|
1424
|
-
}
|
|
1425
|
-
return getErrorToolResult(
|
|
1426
|
-
`portfolio metrics: ${result.error.category} (${result.error.reason})`
|
|
1427
|
-
);
|
|
1428
|
-
}
|
|
1429
|
-
if (name === "lighthouse_portfolio_metrics_totalWorkItemAge") {
|
|
1430
|
-
const id = getNumericId(argumentsPayload);
|
|
1431
|
-
if (id === null) {
|
|
1432
|
-
return getErrorToolResult("portfolio metrics: invalid id");
|
|
1433
|
-
}
|
|
1434
|
-
const range = getDateRange(argumentsPayload);
|
|
1435
|
-
const result = await client.getPortfolioTotalWorkItemAgeOverTime(
|
|
1436
|
-
id,
|
|
1437
|
-
range
|
|
1438
|
-
);
|
|
1439
|
-
if (result.ok) {
|
|
1440
|
-
return getSuccessToolResult(
|
|
1441
|
-
`portfolio totalWorkItemAge: ${encodePayload(result.value)}`
|
|
1442
|
-
);
|
|
1443
|
-
}
|
|
1444
|
-
return getErrorToolResult(
|
|
1445
|
-
`portfolio metrics: ${result.error.category} (${result.error.reason})`
|
|
1446
|
-
);
|
|
1447
|
-
}
|
|
1448
|
-
if (name === "lighthouse_feature_get") {
|
|
1449
|
-
const payload = isObjectRecord(argumentsPayload) ? argumentsPayload : {};
|
|
1450
|
-
const idsValue = payload.ids;
|
|
1451
|
-
const refsValue = payload.refs;
|
|
1452
|
-
if (Array.isArray(idsValue) && idsValue.length > 0) {
|
|
1453
|
-
const ids = idsValue.filter((v) => typeof v === "number");
|
|
1454
|
-
const result = await client.getFeaturesByIds(ids);
|
|
1455
|
-
if (result.ok) {
|
|
1456
|
-
return getSuccessToolResult(
|
|
1457
|
-
`features: ${encodePayload(result.value)}`
|
|
1458
|
-
);
|
|
1459
|
-
}
|
|
1460
|
-
return getErrorToolResult(
|
|
1461
|
-
`features: ${result.error.category} (${result.error.reason})`
|
|
1462
|
-
);
|
|
1463
|
-
}
|
|
1464
|
-
if (Array.isArray(refsValue) && refsValue.length > 0) {
|
|
1465
|
-
const refs = refsValue.filter(
|
|
1466
|
-
(v) => typeof v === "string"
|
|
1467
|
-
);
|
|
1468
|
-
const result = await client.getFeaturesByReferences(refs);
|
|
1469
|
-
if (result.ok) {
|
|
1470
|
-
return getSuccessToolResult(
|
|
1471
|
-
`features: ${encodePayload(result.value)}`
|
|
1472
|
-
);
|
|
1473
|
-
}
|
|
1474
|
-
return getErrorToolResult(
|
|
1475
|
-
`features: ${result.error.category} (${result.error.reason})`
|
|
1476
|
-
);
|
|
1477
|
-
}
|
|
1478
|
-
return getErrorToolResult(
|
|
1479
|
-
"features: provide ids (array of numbers) or refs (array of strings)"
|
|
1480
|
-
);
|
|
1481
|
-
}
|
|
1482
|
-
if (name === "lighthouse_feature_workitems") {
|
|
1483
|
-
const id = getNumericId(argumentsPayload);
|
|
1484
|
-
if (id === null) {
|
|
1485
|
-
return getErrorToolResult("feature workitems: invalid id");
|
|
1486
|
-
}
|
|
1487
|
-
const result = await client.getFeatureWorkItems(id);
|
|
1488
|
-
if (result.ok) {
|
|
1489
|
-
return getSuccessToolResult(
|
|
1490
|
-
`feature workitems: ${encodePayload(result.value)}`
|
|
1491
|
-
);
|
|
1492
|
-
}
|
|
1493
|
-
return getErrorToolResult(
|
|
1494
|
-
`feature workitems: ${result.error.category} (${result.error.reason})`
|
|
1495
|
-
);
|
|
1496
|
-
}
|
|
1497
|
-
if (name === "lighthouse_delivery_list") {
|
|
1498
|
-
const id = getNumericId(argumentsPayload);
|
|
1499
|
-
if (id === null) {
|
|
1500
|
-
return getErrorToolResult(
|
|
1501
|
-
"delivery: invalid id (portfolio id required)"
|
|
1502
|
-
);
|
|
1503
|
-
}
|
|
1504
|
-
const result = await client.listDeliveries(id);
|
|
1505
|
-
if (result.ok) {
|
|
1506
|
-
return getSuccessToolResult(
|
|
1507
|
-
`deliveries: ${encodePayload(result.value)}`
|
|
1508
|
-
);
|
|
1509
|
-
}
|
|
1510
|
-
return getErrorToolResult(
|
|
1511
|
-
`delivery: ${result.error.category} (${result.error.reason})`
|
|
1512
|
-
);
|
|
1513
|
-
}
|
|
1514
|
-
if (name === "lighthouse_delivery_metrics") {
|
|
1515
|
-
const id = getNumericId(argumentsPayload);
|
|
1516
|
-
if (id === null) {
|
|
1517
|
-
return getErrorToolResult(
|
|
1518
|
-
"delivery metrics: invalid id (delivery id required)"
|
|
1519
|
-
);
|
|
1520
|
-
}
|
|
1521
|
-
const wantsEpics = argumentsPayload?.detail === "epics";
|
|
1522
|
-
const result = await client.getDeliveryMetricsHistory(id);
|
|
1523
|
-
if (!result.ok) {
|
|
1524
|
-
return getErrorToolResult(
|
|
1525
|
-
`delivery metrics: ${result.error.category} (${result.error.reason})`
|
|
1526
|
-
);
|
|
1527
|
-
}
|
|
1528
|
-
const payload = wantsEpics ? result.value : (0, import_lighthouse_client.summariseDeliveryMetricsHistory)(result.value);
|
|
1529
|
-
return getSuccessToolResult(
|
|
1530
|
-
`delivery metrics: ${encodePayload(payload)}`
|
|
1531
|
-
);
|
|
1532
|
-
}
|
|
1533
|
-
if (name === "lighthouse_blackout_list") {
|
|
1534
|
-
const result = await client.getRecurringBlackoutRules();
|
|
1535
|
-
if (result.ok) {
|
|
1536
|
-
return getSuccessToolResult(
|
|
1537
|
-
`recurringBlackoutRules: ${encodePayload(result.value)}`
|
|
1538
|
-
);
|
|
1539
|
-
}
|
|
1540
|
-
return getErrorToolResult(
|
|
1541
|
-
`blackout: ${result.error.category} (${result.error.reason})`
|
|
1542
|
-
);
|
|
1543
|
-
}
|
|
1544
|
-
if (name === "lighthouse_blackout_create") {
|
|
1545
|
-
const payload = isObjectRecord(argumentsPayload) ? argumentsPayload : {};
|
|
1546
|
-
const result = await client.createRecurringBlackoutRule(payload);
|
|
1547
|
-
if (result.ok) {
|
|
1548
|
-
return getSuccessToolResult(
|
|
1549
|
-
`recurringBlackoutRule: ${encodePayload(result.value)}`
|
|
1550
|
-
);
|
|
1551
|
-
}
|
|
1552
|
-
return getErrorToolResult(
|
|
1553
|
-
`blackout: ${result.error.category} (${result.error.reason})`
|
|
1554
|
-
);
|
|
1555
|
-
}
|
|
1556
|
-
if (name === "lighthouse_blackout_update") {
|
|
1557
|
-
const id = getNumericId(argumentsPayload);
|
|
1558
|
-
if (id === null) {
|
|
1559
|
-
return getErrorToolResult("blackout: invalid id (rule id required)");
|
|
1560
|
-
}
|
|
1561
|
-
const payload = isObjectRecord(argumentsPayload) ? argumentsPayload : {};
|
|
1562
|
-
const { id: _ignoredId, ...rulePayload } = payload;
|
|
1563
|
-
const result = await client.updateRecurringBlackoutRule(id, rulePayload);
|
|
1564
|
-
if (result.ok) {
|
|
1565
|
-
return getSuccessToolResult(
|
|
1566
|
-
`recurringBlackoutRule: ${encodePayload(result.value)}`
|
|
1567
|
-
);
|
|
1568
|
-
}
|
|
1569
|
-
return getErrorToolResult(
|
|
1570
|
-
`blackout: ${result.error.category} (${result.error.reason})`
|
|
1571
|
-
);
|
|
1572
|
-
}
|
|
1573
|
-
if (name === "lighthouse_blackout_delete") {
|
|
1574
|
-
const id = getNumericId(argumentsPayload);
|
|
1575
|
-
if (id === null) {
|
|
1576
|
-
return getErrorToolResult("blackout: invalid id (rule id required)");
|
|
1577
|
-
}
|
|
1578
|
-
const result = await client.deleteRecurringBlackoutRule(id);
|
|
1579
|
-
if (result.ok) {
|
|
1580
|
-
return getSuccessToolResult(`recurringBlackoutRule deleted: ${id}`);
|
|
1581
|
-
}
|
|
1582
|
-
return getErrorToolResult(
|
|
1583
|
-
`blackout: ${result.error.category} (${result.error.reason})`
|
|
1584
|
-
);
|
|
1585
|
-
}
|
|
1586
|
-
if (name === "lighthouse_forecast_manual") {
|
|
1587
|
-
const id = getNumericId(argumentsPayload);
|
|
1588
|
-
if (id === null) {
|
|
1589
|
-
return getErrorToolResult("forecast: invalid id (team id required)");
|
|
1590
|
-
}
|
|
1591
|
-
const payload = isObjectRecord(argumentsPayload) ? argumentsPayload : {};
|
|
1592
|
-
const remainingItems = typeof payload.remainingItems === "number" ? payload.remainingItems : void 0;
|
|
1593
|
-
const targetDate = typeof payload.targetDate === "string" ? payload.targetDate : void 0;
|
|
1594
|
-
const applyFilterOverride = getApplyFilterOverride(argumentsPayload);
|
|
1595
|
-
const result = await client.runManualForecast(id, {
|
|
1596
|
-
remainingItems,
|
|
1597
|
-
targetDate,
|
|
1598
|
-
applyFilterOverride
|
|
1599
|
-
});
|
|
1600
|
-
if (result.ok) {
|
|
1601
|
-
return getSuccessToolResult(`forecast: ${encodePayload(result.value)}`);
|
|
1602
|
-
}
|
|
1603
|
-
return getErrorToolResult(
|
|
1604
|
-
`forecast: ${result.error.category} (${result.error.reason})`
|
|
1605
|
-
);
|
|
1606
|
-
}
|
|
1607
|
-
if (name === "lighthouse_forecast_backtest") {
|
|
1608
|
-
const id = getNumericId(argumentsPayload);
|
|
1609
|
-
if (id === null) {
|
|
1610
|
-
return getErrorToolResult("backtest: invalid id (team id required)");
|
|
1611
|
-
}
|
|
1612
|
-
const payload = isObjectRecord(argumentsPayload) ? argumentsPayload : {};
|
|
1613
|
-
const startDate = typeof payload.startDate === "string" ? payload.startDate : void 0;
|
|
1614
|
-
const endDate = typeof payload.endDate === "string" ? payload.endDate : void 0;
|
|
1615
|
-
const historicalStartDate = typeof payload.historicalStartDate === "string" ? payload.historicalStartDate : void 0;
|
|
1616
|
-
const historicalEndDate = typeof payload.historicalEndDate === "string" ? payload.historicalEndDate : void 0;
|
|
1617
|
-
if (!startDate || !endDate || !historicalStartDate || !historicalEndDate) {
|
|
1618
|
-
return getErrorToolResult(
|
|
1619
|
-
"backtest: startDate, endDate, historicalStartDate, and historicalEndDate are required"
|
|
1620
|
-
);
|
|
1621
|
-
}
|
|
1622
|
-
const applyFilterOverride = getApplyFilterOverride(argumentsPayload);
|
|
1623
|
-
const result = await client.runBacktest(id, {
|
|
1624
|
-
startDate,
|
|
1625
|
-
endDate,
|
|
1626
|
-
historicalStartDate,
|
|
1627
|
-
historicalEndDate,
|
|
1628
|
-
applyFilterOverride
|
|
1629
|
-
});
|
|
1630
|
-
if (result.ok) {
|
|
1631
|
-
return getSuccessToolResult(`backtest: ${encodePayload(result.value)}`);
|
|
1632
|
-
}
|
|
1633
|
-
return getErrorToolResult(
|
|
1634
|
-
`backtest: ${result.error.category} (${result.error.reason})`
|
|
1635
|
-
);
|
|
1636
|
-
}
|
|
1637
|
-
return getErrorToolResult(`Unknown tool: ${name}`);
|
|
1638
|
-
}
|
|
1091
|
+
const readPortfolioWording = (client, portfolioId) => (0, _letpeoplework_lighthouse_client.readAnswerWording)(client, {
|
|
1092
|
+
term: "portfolio",
|
|
1093
|
+
id: portfolioId,
|
|
1094
|
+
read: () => client.getPortfolio(portfolioId)
|
|
1639
1095
|
});
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
createMcpCoreRuntime,
|
|
1667
|
-
getMcpCorePackageContract,
|
|
1668
|
-
registerMcpTools
|
|
1096
|
+
const readMetricsWording = (client, scope, id) => scope === "team" ? readTeamWording(client, id) : readPortfolioWording(client, id);
|
|
1097
|
+
const readForSummary = async (read) => {
|
|
1098
|
+
try {
|
|
1099
|
+
return await read();
|
|
1100
|
+
} catch {
|
|
1101
|
+
return;
|
|
1102
|
+
}
|
|
1103
|
+
};
|
|
1104
|
+
const answeredValue = (read) => read?.ok === true ? read.value : void 0;
|
|
1105
|
+
const summaryOrNull = (summarise) => {
|
|
1106
|
+
try {
|
|
1107
|
+
return summarise();
|
|
1108
|
+
} catch {
|
|
1109
|
+
return null;
|
|
1110
|
+
}
|
|
1111
|
+
};
|
|
1112
|
+
/**
|
|
1113
|
+
* A write's facts block exactly as before, with the line lh confirms it with in a second block. The
|
|
1114
|
+
* confirmation never sits inside the facts: a blackout rule's own `summary` field is Lighthouse's
|
|
1115
|
+
* wording of its schedule and must reach the assistant untouched.
|
|
1116
|
+
*/
|
|
1117
|
+
const withConfirmation = (facts, confirm) => withSummaryBlock(facts, summaryOrNull(confirm));
|
|
1118
|
+
/** How many a list holds, in words; left out when the list cannot be read. */
|
|
1119
|
+
const countSummary = (facts, readList, describeCount) => summaryOrNull(() => {
|
|
1120
|
+
const listed = readList(facts);
|
|
1121
|
+
return listed === null ? null : describeCount(listed.length);
|
|
1669
1122
|
});
|
|
1123
|
+
/** A refresh as before, confirmed as queued in the instance's word for a Team or Portfolio. */
|
|
1124
|
+
const answerRefresh = async (client, kind, id, refresh) => {
|
|
1125
|
+
const [result, terms] = await Promise.all([refresh, (0, _letpeoplework_lighthouse_client.readTerms)(client)]);
|
|
1126
|
+
if (!result.ok) return getErrorToolResult(`${kind} refresh: ${result.error.category} (${result.error.reason})`);
|
|
1127
|
+
return withConfirmation(`${kind} refreshed: ${id}`, () => (0, _letpeoplework_lighthouse_client.describeRefreshConfirmation)(kind, id, terms));
|
|
1128
|
+
};
|
|
1129
|
+
/** A written blackout rule as before, confirmed with Lighthouse's own wording of its schedule. */
|
|
1130
|
+
const answerBlackoutRuleWrite = async (verb, write) => {
|
|
1131
|
+
const result = await write;
|
|
1132
|
+
if (!result.ok) return getErrorToolResult(`blackout: ${result.error.category} (${result.error.reason})`);
|
|
1133
|
+
return withConfirmation(`recurringBlackoutRule: ${encodePayload(result.value)}`, () => {
|
|
1134
|
+
const rule = (0, _letpeoplework_lighthouse_client.readWrittenBlackoutRule)(result.value);
|
|
1135
|
+
return rule === null ? null : (0, _letpeoplework_lighthouse_client.describeBlackoutRuleWriteConfirmation)(verb, rule);
|
|
1136
|
+
});
|
|
1137
|
+
};
|
|
1138
|
+
/** The Features under their label with their count in the instance's words, or Lighthouse's refusal as before. */
|
|
1139
|
+
const answerFeatures = async (client, read) => {
|
|
1140
|
+
const [result, terms] = await Promise.all([read, (0, _letpeoplework_lighthouse_client.readTerms)(client)]);
|
|
1141
|
+
if (!result.ok) return getErrorToolResult(`features: ${result.error.category} (${result.error.reason})`);
|
|
1142
|
+
return withSummary("features", result.value, countSummary(result.value, _letpeoplework_lighthouse_client.readFeatureList, (count) => (0, _letpeoplework_lighthouse_client.describeFeatureListCount)(count, terms)));
|
|
1143
|
+
};
|
|
1144
|
+
/**
|
|
1145
|
+
* One per-metric tool's answer: the facts under their label with the metric stated as lh states it, or
|
|
1146
|
+
* Lighthouse's refusal exactly as before. The summary's own reads run beside the metric's.
|
|
1147
|
+
*/
|
|
1148
|
+
const answerMetric = async (labels, read, context, summarise) => {
|
|
1149
|
+
const [result, known] = await Promise.all([read, context]);
|
|
1150
|
+
if (!result.ok) return getErrorToolResult(`${labels.refusal}: ${result.error.category} (${result.error.reason})`);
|
|
1151
|
+
return withSummary(labels.answer, result.value, summaryOrNull(() => summarise(result.value, known)));
|
|
1152
|
+
};
|
|
1153
|
+
/** A Team or Portfolio list's facts, then how many it holds, unless a row cannot say what it is. */
|
|
1154
|
+
const answerOwnerList = async (kind, label, read, client) => {
|
|
1155
|
+
const [result, terms] = await Promise.all([read, (0, _letpeoplework_lighthouse_client.readTerms)(client)]);
|
|
1156
|
+
if (!result.ok) return getErrorToolResult(`${label}: ${result.error.category} (${result.error.reason})`);
|
|
1157
|
+
return withSummary(label, result.value, countSummary(result.value, _letpeoplework_lighthouse_client.readOwnerList, (count) => (0, _letpeoplework_lighthouse_client.describeOwnerCount)(kind, count, terms)));
|
|
1158
|
+
};
|
|
1159
|
+
/** One Team or Portfolio: its facts, with the page's heading and settings as its summary when it can be read. */
|
|
1160
|
+
const answerOwner = async (label, read, client, describe) => {
|
|
1161
|
+
const [result, terms] = await Promise.all([read, (0, _letpeoplework_lighthouse_client.readTerms)(client)]);
|
|
1162
|
+
if (!result.ok) return getErrorToolResult(`${label}: ${result.error.category} (${result.error.reason})`);
|
|
1163
|
+
return withSummary(label, result.value, summaryOrNull(() => {
|
|
1164
|
+
const owner = describe.read(result.value);
|
|
1165
|
+
return owner === null ? null : linesOf(...describe.lines(owner, terms));
|
|
1166
|
+
}));
|
|
1167
|
+
};
|
|
1168
|
+
const metricLabels = (scope, metric) => ({
|
|
1169
|
+
answer: `${scope} ${metric}`,
|
|
1170
|
+
refusal: `${scope} metrics`
|
|
1171
|
+
});
|
|
1172
|
+
const overTheRange = (range, wording, view) => view === null ? null : (0, _letpeoplework_lighthouse_client.describeMetricSummary)((0, _letpeoplework_lighthouse_client.describeMetricsHeading)(range, wording), view);
|
|
1173
|
+
const summariseThroughput = (scope, range) => (facts, wording) => {
|
|
1174
|
+
const chart = (0, _letpeoplework_lighthouse_client.readRunChart)(facts, range);
|
|
1175
|
+
return overTheRange(range, wording, chart === null ? null : (0, _letpeoplework_lighthouse_client.describeThroughputDays)(chart, scope, wording.terms));
|
|
1176
|
+
};
|
|
1177
|
+
const summariseCycleTimePercentiles = (range) => (facts, known) => {
|
|
1178
|
+
const percentiles = (0, _letpeoplework_lighthouse_client.readCycleTimePercentiles)({ values: facts });
|
|
1179
|
+
return overTheRange(range, known.wording, percentiles === null ? null : (0, _letpeoplework_lighthouse_client.describeCycleTimeDays)(percentiles, [], known.wording.terms, known.definitionName));
|
|
1180
|
+
};
|
|
1181
|
+
const summariseWorkItemAgePercentiles = (range) => (facts, wording) => {
|
|
1182
|
+
const percentiles = (0, _letpeoplework_lighthouse_client.readWorkItemAgePercentiles)({ values: facts });
|
|
1183
|
+
return percentiles === null ? null : linesOf((0, _letpeoplework_lighthouse_client.describeAsOfHeading)(range, wording), (0, _letpeoplework_lighthouse_client.describeWorkItemAgePercentiles)(percentiles, wording.terms));
|
|
1184
|
+
};
|
|
1185
|
+
const summariseWorkItemAge = (scope) => (facts, known) => {
|
|
1186
|
+
const overTime = (0, _letpeoplework_lighthouse_client.readWorkItemAge)(facts);
|
|
1187
|
+
const percentiles = (0, _letpeoplework_lighthouse_client.readWorkItemAgePercentiles)({ values: known.percentiles });
|
|
1188
|
+
return overTime === null || percentiles === null ? null : (0, _letpeoplework_lighthouse_client.describeMetricSummary)((0, _letpeoplework_lighthouse_client.describeAsOfHeading)(overTime, known.wording), (0, _letpeoplework_lighthouse_client.describeWorkItemAgeDays)(percentiles, overTime, scope, known.wording.terms));
|
|
1189
|
+
};
|
|
1190
|
+
const summariseTotalWorkItemAge = (scope) => (facts, wording) => {
|
|
1191
|
+
const view = (0, _letpeoplework_lighthouse_client.readTotalWorkItemAge)(facts);
|
|
1192
|
+
return view === null ? null : overTheRange(view, wording, (0, _letpeoplework_lighthouse_client.describeTotalWorkItemAgeDays)(view, scope, wording.terms));
|
|
1193
|
+
};
|
|
1194
|
+
const sentenceOf = (line) => line.detail === "" ? `${line.label}: ${line.value}` : `${line.label}: ${line.value} (${line.detail})`;
|
|
1195
|
+
const summariseCurrentWip = (today) => (facts, known) => {
|
|
1196
|
+
const now = (0, _letpeoplework_lighthouse_client.readInProgressItems)(facts, today);
|
|
1197
|
+
if (now === null) return null;
|
|
1198
|
+
const { terms } = known.wording;
|
|
1199
|
+
const blocked = (0, _letpeoplework_lighthouse_client.describeBlockedNow)(now, "team", terms);
|
|
1200
|
+
return linesOf((0, _letpeoplework_lighthouse_client.describeAsOfHeading)({ endDate: today }, known.wording), sentenceOf((0, _letpeoplework_lighthouse_client.describeInProgressNow)(now, "team", terms, known.systemWipLimit ?? void 0)), blocked === null ? null : sentenceOf(blocked), ...(0, _letpeoplework_lighthouse_client.describeWhatWipLeavesUnsaid)(now, "team", terms, known.systemWipLimit));
|
|
1201
|
+
};
|
|
1202
|
+
const readTeamForSummary = async (client, teamId) => {
|
|
1203
|
+
const team = client.getTeam(teamId);
|
|
1204
|
+
const [wording, teamRead] = await Promise.all([(0, _letpeoplework_lighthouse_client.readAnswerWording)(client, {
|
|
1205
|
+
term: "team",
|
|
1206
|
+
id: teamId,
|
|
1207
|
+
read: () => team
|
|
1208
|
+
}), readForSummary(() => team)]);
|
|
1209
|
+
return {
|
|
1210
|
+
wording,
|
|
1211
|
+
team: teamRead?.ok === true ? teamRead : null
|
|
1212
|
+
};
|
|
1213
|
+
};
|
|
1214
|
+
const teamSettingOf = (team, read) => team === null ? null : read(team.value);
|
|
1215
|
+
const readCurrentWipContext = async (client, teamId) => {
|
|
1216
|
+
const { wording, team } = await readTeamForSummary(client, teamId);
|
|
1217
|
+
return {
|
|
1218
|
+
wording,
|
|
1219
|
+
systemWipLimit: teamSettingOf(team, _letpeoplework_lighthouse_client.readSystemWipLimit)
|
|
1220
|
+
};
|
|
1221
|
+
};
|
|
1222
|
+
const sleRiskLines = (view) => [
|
|
1223
|
+
view.title,
|
|
1224
|
+
...view.sentence === null ? [] : [view.sentence],
|
|
1225
|
+
...view.rows.map((row) => row.filter((cell) => cell !== "").join(" · "))
|
|
1226
|
+
].join("\n");
|
|
1227
|
+
const summariseSleRisk = (today) => (facts, known) => {
|
|
1228
|
+
const entries = (0, _letpeoplework_lighthouse_client.readSleRisk)(facts);
|
|
1229
|
+
return entries === null ? null : linesOf((0, _letpeoplework_lighthouse_client.describeAsOfHeading)({ endDate: today }, known.wording), sleRiskLines((0, _letpeoplework_lighthouse_client.describeSleRiskNow)(entries, known.wording, known.serviceLevelExpectation, known.inProgress)));
|
|
1230
|
+
};
|
|
1231
|
+
const readSleRiskContext = async (client, teamId, today) => {
|
|
1232
|
+
const [{ wording, team }, wipRead] = await Promise.all([readTeamForSummary(client, teamId), readForSummary(() => client.getTeamWip(teamId, today))]);
|
|
1233
|
+
return {
|
|
1234
|
+
wording,
|
|
1235
|
+
serviceLevelExpectation: teamSettingOf(team, _letpeoplework_lighthouse_client.readServiceLevelExpectation),
|
|
1236
|
+
inProgress: (0, _letpeoplework_lighthouse_client.readInProgressItems)(answeredValue(wipRead), today)?.items
|
|
1237
|
+
};
|
|
1238
|
+
};
|
|
1239
|
+
const summariseProcessBehaviorChart = (range, chartType) => (facts, wording) => {
|
|
1240
|
+
const chart = (0, _letpeoplework_lighthouse_client.readProcessBehaviorChart)(facts);
|
|
1241
|
+
if (chart === null) return null;
|
|
1242
|
+
const said = (0, _letpeoplework_lighthouse_client.describeProcessBehaviorChart)(chart, chartType, wording.terms);
|
|
1243
|
+
return linesOf((0, _letpeoplework_lighthouse_client.describeMetricsHeading)(range, wording), said.title, said.sentence);
|
|
1244
|
+
};
|
|
1245
|
+
const summariseTimeInState = (scope, range) => (facts, wording) => {
|
|
1246
|
+
const bar = (0, _letpeoplework_lighthouse_client.readTimeInStateBar)(facts);
|
|
1247
|
+
return overTheRange(range, wording, bar === null ? null : (0, _letpeoplework_lighthouse_client.describeTimeInStateDays)(bar, void 0, void 0, scope, wording.terms));
|
|
1248
|
+
};
|
|
1249
|
+
const summariseTimeInStateContributors = (scope, range) => (facts, wording) => {
|
|
1250
|
+
const contributors = (0, _letpeoplework_lighthouse_client.readTimeInStateContributors)(facts);
|
|
1251
|
+
return overTheRange(range, wording, contributors === null ? null : (0, _letpeoplework_lighthouse_client.describeTimeInStateContributorDays)(contributors, scope, wording.terms));
|
|
1252
|
+
};
|
|
1253
|
+
const summariseBlocked = (scope, range) => (facts, wording) => {
|
|
1254
|
+
const view = (0, _letpeoplework_lighthouse_client.readBlocked)({
|
|
1255
|
+
...range,
|
|
1256
|
+
history: facts
|
|
1257
|
+
});
|
|
1258
|
+
return overTheRange(range, wording, view === null ? null : (0, _letpeoplework_lighthouse_client.describeBlockedDays)(view, scope, wording.terms));
|
|
1259
|
+
};
|
|
1260
|
+
const summarisePercentilesOverTime = (range, argumentsPayload) => (facts, wording) => {
|
|
1261
|
+
const view = (0, _letpeoplework_lighthouse_client.readPercentilesOverTime)({
|
|
1262
|
+
...range,
|
|
1263
|
+
history: facts,
|
|
1264
|
+
horizon: getHorizonArgument(argumentsPayload)
|
|
1265
|
+
});
|
|
1266
|
+
const ofCycleTime = getPercentilesOverTimeMetricType(argumentsPayload) !== "WorkItemAge" && view !== null && view.history.every((day) => day.metricType === "CycleTime");
|
|
1267
|
+
return overTheRange(range, wording, view !== null && ofCycleTime ? (0, _letpeoplework_lighthouse_client.describePercentilesOverTimeDays)(view, wording.terms) : null);
|
|
1268
|
+
};
|
|
1269
|
+
const summariseProcessBehaviorOverTime = (range, argumentsPayload) => (facts, wording) => {
|
|
1270
|
+
const family = getProcessBehaviorMetricType(argumentsPayload);
|
|
1271
|
+
const view = (0, _letpeoplework_lighthouse_client.readProcessBehaviorOverTime)({
|
|
1272
|
+
...range,
|
|
1273
|
+
history: facts
|
|
1274
|
+
});
|
|
1275
|
+
return overTheRange(range, wording, view !== null && (family === void 0 || family === "Throughput") ? (0, _letpeoplework_lighthouse_client.describeProcessBehaviorOverTimeDays)(view, wording.terms) : null);
|
|
1276
|
+
};
|
|
1277
|
+
const describeManualForecastAnswer = (facts, wording) => {
|
|
1278
|
+
const forecast = (0, _letpeoplework_lighthouse_client.readManualForecast)(facts);
|
|
1279
|
+
return forecast === null ? null : linesOf((0, _letpeoplework_lighthouse_client.describeManualForecastSummary)(forecast, wording), (0, _letpeoplework_lighthouse_client.describeManualForecastLikelihood)(forecast, wording));
|
|
1280
|
+
};
|
|
1281
|
+
const describeBacktestAnswer = (facts, wording) => {
|
|
1282
|
+
const backtest = (0, _letpeoplework_lighthouse_client.readBacktest)(facts);
|
|
1283
|
+
return backtest === null ? null : linesOf((0, _letpeoplework_lighthouse_client.describeBacktestSummary)(wording), (0, _letpeoplework_lighthouse_client.describeBacktestPeriod)(backtest), (0, _letpeoplework_lighthouse_client.describeBacktestActual)(backtest, wording));
|
|
1284
|
+
};
|
|
1285
|
+
const isObjectRecord = (value) => {
|
|
1286
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1287
|
+
};
|
|
1288
|
+
const getDateRange = (argumentsPayload) => {
|
|
1289
|
+
if (!isObjectRecord(argumentsPayload)) return;
|
|
1290
|
+
const startDate = argumentsPayload.startDate;
|
|
1291
|
+
const endDate = argumentsPayload.endDate;
|
|
1292
|
+
if (typeof startDate === "string" && typeof endDate === "string") return {
|
|
1293
|
+
startDate,
|
|
1294
|
+
endDate
|
|
1295
|
+
};
|
|
1296
|
+
};
|
|
1297
|
+
const getStringArgument = (argumentsPayload, key) => {
|
|
1298
|
+
if (!isObjectRecord(argumentsPayload)) return;
|
|
1299
|
+
const value = argumentsPayload[key];
|
|
1300
|
+
return typeof value === "string" ? value : void 0;
|
|
1301
|
+
};
|
|
1302
|
+
const getItemIdsArgument = (argumentsPayload) => {
|
|
1303
|
+
if (!isObjectRecord(argumentsPayload)) return;
|
|
1304
|
+
const value = argumentsPayload.itemIds;
|
|
1305
|
+
if (!Array.isArray(value)) return;
|
|
1306
|
+
const ids = value.filter((entry) => typeof entry === "number" && Number.isInteger(entry));
|
|
1307
|
+
return ids.length > 0 ? ids : void 0;
|
|
1308
|
+
};
|
|
1309
|
+
const getThroughputFilterView = (argumentsPayload) => {
|
|
1310
|
+
if (!isObjectRecord(argumentsPayload)) return;
|
|
1311
|
+
const view = argumentsPayload.view;
|
|
1312
|
+
return view === "raw" || view === "filtered" ? view : void 0;
|
|
1313
|
+
};
|
|
1314
|
+
const percentilesOverTimeMetricTypes = ["CycleTime", "WorkItemAge"];
|
|
1315
|
+
const getPercentilesOverTimeMetricType = (argumentsPayload) => {
|
|
1316
|
+
const raw = getStringArgument(argumentsPayload, "metricType");
|
|
1317
|
+
return percentilesOverTimeMetricTypes.find((candidate) => candidate === raw);
|
|
1318
|
+
};
|
|
1319
|
+
const getChartType = (argumentsPayload, chartTypes) => {
|
|
1320
|
+
const raw = getStringArgument(argumentsPayload, "metricType");
|
|
1321
|
+
return chartTypes.find((candidate) => candidate === raw);
|
|
1322
|
+
};
|
|
1323
|
+
const getProcessBehaviorMetricType = (argumentsPayload) => {
|
|
1324
|
+
const raw = getStringArgument(argumentsPayload, "metricType");
|
|
1325
|
+
return processBehaviorMetricTypes.find((candidate) => candidate === raw);
|
|
1326
|
+
};
|
|
1327
|
+
const getHorizonArgument = (argumentsPayload) => {
|
|
1328
|
+
if (!isObjectRecord(argumentsPayload)) return;
|
|
1329
|
+
const horizon = argumentsPayload.horizon;
|
|
1330
|
+
return typeof horizon === "number" && Number.isInteger(horizon) ? horizon : void 0;
|
|
1331
|
+
};
|
|
1332
|
+
const getApplyFilterOverride = (argumentsPayload) => {
|
|
1333
|
+
if (!isObjectRecord(argumentsPayload)) return;
|
|
1334
|
+
const value = argumentsPayload.applyFilterOverride;
|
|
1335
|
+
return typeof value === "boolean" ? value : void 0;
|
|
1336
|
+
};
|
|
1337
|
+
const isoDateStringSchema = zod.z.string().regex(/^\d{4}-\d{2}-\d{2}$/u, "Expected ISO date in YYYY-MM-DD format.");
|
|
1338
|
+
const weekdaySchema = zod.z.enum([
|
|
1339
|
+
"Sunday",
|
|
1340
|
+
"Monday",
|
|
1341
|
+
"Tuesday",
|
|
1342
|
+
"Wednesday",
|
|
1343
|
+
"Thursday",
|
|
1344
|
+
"Friday",
|
|
1345
|
+
"Saturday"
|
|
1346
|
+
]);
|
|
1347
|
+
const recurringBlackoutRuleInputSchema = zod.z.object({
|
|
1348
|
+
weekdays: zod.z.array(weekdaySchema),
|
|
1349
|
+
intervalWeeks: zod.z.number().int(),
|
|
1350
|
+
start: isoDateStringSchema,
|
|
1351
|
+
end: isoDateStringSchema.nullable().optional(),
|
|
1352
|
+
description: zod.z.string()
|
|
1353
|
+
});
|
|
1354
|
+
const toolInputSchemas = {
|
|
1355
|
+
lighthouse_health_check: zod.z.object({}),
|
|
1356
|
+
lighthouse_version_get: zod.z.object({}),
|
|
1357
|
+
lighthouse_worktracking_list: zod.z.object({}),
|
|
1358
|
+
lighthouse_worktracking_get: zod.z.object({ id: zod.z.number().int() }),
|
|
1359
|
+
lighthouse_team_list: zod.z.object({}),
|
|
1360
|
+
lighthouse_team_get: zod.z.object({ id: zod.z.number().int() }),
|
|
1361
|
+
lighthouse_team_refresh: zod.z.object({ id: zod.z.number().int() }),
|
|
1362
|
+
lighthouse_team_refinement_get: zod.z.object({ id: zod.z.number().int() }),
|
|
1363
|
+
...refinementWriteInputSchemas,
|
|
1364
|
+
lighthouse_portfolio_list: zod.z.object({}),
|
|
1365
|
+
lighthouse_portfolio_get: zod.z.object({ id: zod.z.number().int() }),
|
|
1366
|
+
lighthouse_portfolio_refresh: zod.z.object({ id: zod.z.number().int() }),
|
|
1367
|
+
lighthouse_team_metrics_throughput: zod.z.object({
|
|
1368
|
+
id: zod.z.number().int(),
|
|
1369
|
+
startDate: isoDateStringSchema.optional(),
|
|
1370
|
+
endDate: isoDateStringSchema.optional(),
|
|
1371
|
+
view: zod.z.enum(["raw", "filtered"]).optional()
|
|
1372
|
+
}),
|
|
1373
|
+
lighthouse_team_metrics_cycleTimePercentiles: zod.z.object({
|
|
1374
|
+
id: zod.z.number().int(),
|
|
1375
|
+
startDate: isoDateStringSchema.optional(),
|
|
1376
|
+
endDate: isoDateStringSchema.optional(),
|
|
1377
|
+
definitionId: zod.z.number().int().optional()
|
|
1378
|
+
}),
|
|
1379
|
+
lighthouse_team_metrics_workItemAgePercentiles: zod.z.object({
|
|
1380
|
+
id: zod.z.number().int(),
|
|
1381
|
+
startDate: isoDateStringSchema.optional(),
|
|
1382
|
+
endDate: isoDateStringSchema.optional()
|
|
1383
|
+
}),
|
|
1384
|
+
lighthouse_portfolio_metrics_workItemAgePercentiles: zod.z.object({
|
|
1385
|
+
id: zod.z.number().int(),
|
|
1386
|
+
startDate: isoDateStringSchema.optional(),
|
|
1387
|
+
endDate: isoDateStringSchema.optional()
|
|
1388
|
+
}),
|
|
1389
|
+
lighthouse_team_metrics_blockedCountHistory: zod.z.object({
|
|
1390
|
+
id: zod.z.number().int(),
|
|
1391
|
+
startDate: isoDateStringSchema.optional(),
|
|
1392
|
+
endDate: isoDateStringSchema.optional()
|
|
1393
|
+
}),
|
|
1394
|
+
lighthouse_portfolio_metrics_blockedCountHistory: zod.z.object({
|
|
1395
|
+
id: zod.z.number().int(),
|
|
1396
|
+
startDate: isoDateStringSchema.optional(),
|
|
1397
|
+
endDate: isoDateStringSchema.optional()
|
|
1398
|
+
}),
|
|
1399
|
+
lighthouse_team_metrics_wip: zod.z.object({ id: zod.z.number().int() }),
|
|
1400
|
+
lighthouse_team_metrics_sleRisk: zod.z.object({ id: zod.z.number().int() }),
|
|
1401
|
+
lighthouse_team_metrics_processBehaviorChart: zod.z.object({
|
|
1402
|
+
id: zod.z.number().int(),
|
|
1403
|
+
metricType: zod.z.enum(TEAM_CHART_TYPES),
|
|
1404
|
+
startDate: isoDateStringSchema.optional(),
|
|
1405
|
+
endDate: isoDateStringSchema.optional()
|
|
1406
|
+
}),
|
|
1407
|
+
lighthouse_portfolio_metrics_processBehaviorChart: zod.z.object({
|
|
1408
|
+
id: zod.z.number().int(),
|
|
1409
|
+
metricType: zod.z.enum(processBehaviorMetricTypes),
|
|
1410
|
+
startDate: isoDateStringSchema.optional(),
|
|
1411
|
+
endDate: isoDateStringSchema.optional()
|
|
1412
|
+
}),
|
|
1413
|
+
lighthouse_team_metrics_percentilesOverTime: zod.z.object({
|
|
1414
|
+
id: zod.z.number().int(),
|
|
1415
|
+
startDate: isoDateStringSchema.optional(),
|
|
1416
|
+
endDate: isoDateStringSchema.optional(),
|
|
1417
|
+
metricType: zod.z.enum(["CycleTime", "WorkItemAge"]).optional(),
|
|
1418
|
+
horizon: zod.z.number().int().optional()
|
|
1419
|
+
}),
|
|
1420
|
+
lighthouse_portfolio_metrics_percentilesOverTime: zod.z.object({
|
|
1421
|
+
id: zod.z.number().int(),
|
|
1422
|
+
startDate: isoDateStringSchema.optional(),
|
|
1423
|
+
endDate: isoDateStringSchema.optional(),
|
|
1424
|
+
metricType: zod.z.enum(["CycleTime", "WorkItemAge"]).optional(),
|
|
1425
|
+
horizon: zod.z.number().int().optional()
|
|
1426
|
+
}),
|
|
1427
|
+
lighthouse_team_metrics_processBehaviorOverTime: zod.z.object({
|
|
1428
|
+
id: zod.z.number().int(),
|
|
1429
|
+
startDate: isoDateStringSchema.optional(),
|
|
1430
|
+
endDate: isoDateStringSchema.optional(),
|
|
1431
|
+
metricType: zod.z.enum([
|
|
1432
|
+
"Throughput",
|
|
1433
|
+
"WorkItemAge",
|
|
1434
|
+
"Wip",
|
|
1435
|
+
"CycleTime",
|
|
1436
|
+
"Arrivals",
|
|
1437
|
+
"FeatureSize"
|
|
1438
|
+
]).optional()
|
|
1439
|
+
}),
|
|
1440
|
+
lighthouse_portfolio_metrics_processBehaviorOverTime: zod.z.object({
|
|
1441
|
+
id: zod.z.number().int(),
|
|
1442
|
+
startDate: isoDateStringSchema.optional(),
|
|
1443
|
+
endDate: isoDateStringSchema.optional(),
|
|
1444
|
+
metricType: zod.z.enum([
|
|
1445
|
+
"Throughput",
|
|
1446
|
+
"WorkItemAge",
|
|
1447
|
+
"Wip",
|
|
1448
|
+
"CycleTime",
|
|
1449
|
+
"Arrivals",
|
|
1450
|
+
"FeatureSize"
|
|
1451
|
+
]).optional()
|
|
1452
|
+
}),
|
|
1453
|
+
lighthouse_team_metrics_workItemAge: zod.z.object({
|
|
1454
|
+
id: zod.z.number().int(),
|
|
1455
|
+
startDate: isoDateStringSchema.optional(),
|
|
1456
|
+
endDate: isoDateStringSchema.optional()
|
|
1457
|
+
}),
|
|
1458
|
+
lighthouse_team_metrics_totalWorkItemAge: zod.z.object({
|
|
1459
|
+
id: zod.z.number().int(),
|
|
1460
|
+
startDate: isoDateStringSchema.optional(),
|
|
1461
|
+
endDate: isoDateStringSchema.optional()
|
|
1462
|
+
}),
|
|
1463
|
+
lighthouse_portfolio_metrics_throughput: zod.z.object({
|
|
1464
|
+
id: zod.z.number().int(),
|
|
1465
|
+
startDate: isoDateStringSchema.optional(),
|
|
1466
|
+
endDate: isoDateStringSchema.optional()
|
|
1467
|
+
}),
|
|
1468
|
+
lighthouse_portfolio_metrics_workItemAge: zod.z.object({
|
|
1469
|
+
id: zod.z.number().int(),
|
|
1470
|
+
startDate: isoDateStringSchema.optional(),
|
|
1471
|
+
endDate: isoDateStringSchema.optional()
|
|
1472
|
+
}),
|
|
1473
|
+
lighthouse_portfolio_metrics_totalWorkItemAge: zod.z.object({
|
|
1474
|
+
id: zod.z.number().int(),
|
|
1475
|
+
startDate: isoDateStringSchema.optional(),
|
|
1476
|
+
endDate: isoDateStringSchema.optional()
|
|
1477
|
+
}),
|
|
1478
|
+
lighthouse_team_metrics_cumulativeStateTime: zod.z.object({
|
|
1479
|
+
id: zod.z.number().int(),
|
|
1480
|
+
startDate: isoDateStringSchema.optional(),
|
|
1481
|
+
endDate: isoDateStringSchema.optional(),
|
|
1482
|
+
itemIds: zod.z.array(zod.z.number().int()).optional()
|
|
1483
|
+
}),
|
|
1484
|
+
lighthouse_team_metrics_cumulativeStateTimeItems: zod.z.object({
|
|
1485
|
+
id: zod.z.number().int(),
|
|
1486
|
+
state: zod.z.string(),
|
|
1487
|
+
startDate: isoDateStringSchema.optional(),
|
|
1488
|
+
endDate: isoDateStringSchema.optional(),
|
|
1489
|
+
itemIds: zod.z.array(zod.z.number().int()).optional()
|
|
1490
|
+
}),
|
|
1491
|
+
lighthouse_team_metrics_cumulativeStateTimeCandidates: zod.z.object({
|
|
1492
|
+
id: zod.z.number().int(),
|
|
1493
|
+
startDate: isoDateStringSchema.optional(),
|
|
1494
|
+
endDate: isoDateStringSchema.optional()
|
|
1495
|
+
}),
|
|
1496
|
+
lighthouse_portfolio_metrics_cumulativeStateTime: zod.z.object({
|
|
1497
|
+
id: zod.z.number().int(),
|
|
1498
|
+
startDate: isoDateStringSchema.optional(),
|
|
1499
|
+
endDate: isoDateStringSchema.optional(),
|
|
1500
|
+
itemIds: zod.z.array(zod.z.number().int()).optional()
|
|
1501
|
+
}),
|
|
1502
|
+
lighthouse_portfolio_metrics_cumulativeStateTimeItems: zod.z.object({
|
|
1503
|
+
id: zod.z.number().int(),
|
|
1504
|
+
state: zod.z.string(),
|
|
1505
|
+
startDate: isoDateStringSchema.optional(),
|
|
1506
|
+
endDate: isoDateStringSchema.optional(),
|
|
1507
|
+
itemIds: zod.z.array(zod.z.number().int()).optional()
|
|
1508
|
+
}),
|
|
1509
|
+
lighthouse_portfolio_metrics_cumulativeStateTimeCandidates: zod.z.object({
|
|
1510
|
+
id: zod.z.number().int(),
|
|
1511
|
+
startDate: isoDateStringSchema.optional(),
|
|
1512
|
+
endDate: isoDateStringSchema.optional()
|
|
1513
|
+
}),
|
|
1514
|
+
lighthouse_feature_get: zod.z.object({
|
|
1515
|
+
ids: zod.z.array(zod.z.number().int()).optional(),
|
|
1516
|
+
refs: zod.z.array(zod.z.string()).optional()
|
|
1517
|
+
}),
|
|
1518
|
+
lighthouse_feature_workitems: zod.z.object({ id: zod.z.number().int() }),
|
|
1519
|
+
lighthouse_delivery_list: zod.z.object({ id: zod.z.number().int() }),
|
|
1520
|
+
lighthouse_delivery_metrics: zod.z.object({
|
|
1521
|
+
id: zod.z.number().int(),
|
|
1522
|
+
detail: zod.z.literal("epics").optional()
|
|
1523
|
+
}),
|
|
1524
|
+
lighthouse_blackout_list: zod.z.object({}),
|
|
1525
|
+
lighthouse_blackout_create: recurringBlackoutRuleInputSchema,
|
|
1526
|
+
lighthouse_blackout_update: recurringBlackoutRuleInputSchema.extend({ id: zod.z.number().int() }),
|
|
1527
|
+
lighthouse_blackout_delete: zod.z.object({ id: zod.z.number().int() }),
|
|
1528
|
+
lighthouse_forecast_manual: zod.z.object({
|
|
1529
|
+
id: zod.z.number().int(),
|
|
1530
|
+
remainingItems: zod.z.number().int().optional(),
|
|
1531
|
+
targetDate: isoDateStringSchema.optional(),
|
|
1532
|
+
applyFilterOverride: zod.z.boolean().optional()
|
|
1533
|
+
}),
|
|
1534
|
+
lighthouse_forecast_backtest: zod.z.object({
|
|
1535
|
+
id: zod.z.number().int(),
|
|
1536
|
+
startDate: isoDateStringSchema,
|
|
1537
|
+
endDate: isoDateStringSchema,
|
|
1538
|
+
historicalStartDate: isoDateStringSchema,
|
|
1539
|
+
historicalEndDate: isoDateStringSchema,
|
|
1540
|
+
applyFilterOverride: zod.z.boolean().optional()
|
|
1541
|
+
})
|
|
1542
|
+
};
|
|
1543
|
+
const WRITING_TOOLS = /* @__PURE__ */ new Set([
|
|
1544
|
+
"lighthouse_team_refinement_vote",
|
|
1545
|
+
"lighthouse_team_refinement_comment",
|
|
1546
|
+
"lighthouse_team_refinement_voteTakeBack"
|
|
1547
|
+
]);
|
|
1548
|
+
const isReadOnlyTool = (toolName) => !(WRITING_TOOLS.has(toolName) || toolName.endsWith("_refresh") || toolName.endsWith("_create") || toolName.endsWith("_update") || toolName.endsWith("_delete"));
|
|
1549
|
+
const answerToolCall = (dependencies) => async (name, argumentsPayload) => {
|
|
1550
|
+
const client = dependencies.createClient();
|
|
1551
|
+
if (name === "lighthouse_health_check") {
|
|
1552
|
+
const health = await client.checkConnectivity();
|
|
1553
|
+
if (health.category === "success") return withConfirmation("connectivity: success", () => _letpeoplework_lighthouse_client.LIGHTHOUSE_IS_REACHABLE);
|
|
1554
|
+
const healthReasonSuffix = health.reason === void 0 ? "" : ` (${health.reason})`;
|
|
1555
|
+
return getErrorToolResult(`connectivity: ${health.category}${healthReasonSuffix}`);
|
|
1556
|
+
}
|
|
1557
|
+
if (name === "lighthouse_version_get") {
|
|
1558
|
+
const version = await client.getVersion();
|
|
1559
|
+
if (version.ok) return withConfirmation(`version: ${version.value}`, () => (0, _letpeoplework_lighthouse_client.describeVersion)(version.value));
|
|
1560
|
+
return getErrorToolResult(`version: ${version.error.category} (${version.error.reason})`);
|
|
1561
|
+
}
|
|
1562
|
+
if (name === "lighthouse_worktracking_list") {
|
|
1563
|
+
const [connections, terms] = await Promise.all([client.listWorkTrackingConnections(), (0, _letpeoplework_lighthouse_client.readTerms)(client)]);
|
|
1564
|
+
if (connections.ok) return withSummary("worktracking", connections.value, countSummary(connections.value, _letpeoplework_lighthouse_client.readWorkTrackingConnections, (count) => (0, _letpeoplework_lighthouse_client.describeWorkTrackingSystemCount)(count, terms)));
|
|
1565
|
+
return getErrorToolResult(`worktracking: ${connections.error.category} (${connections.error.reason})`);
|
|
1566
|
+
}
|
|
1567
|
+
if (name === "lighthouse_worktracking_get") {
|
|
1568
|
+
const id = getNumericId(argumentsPayload);
|
|
1569
|
+
if (id === null) return getErrorToolResult("worktracking: invalid id");
|
|
1570
|
+
const connection = await client.getWorkTrackingConnection(id);
|
|
1571
|
+
if (connection.ok) return withSummary("worktracking", connection.value, summaryOrNull(() => (0, _letpeoplework_lighthouse_client.describeConnectionSummary)(connection.value)));
|
|
1572
|
+
return getErrorToolResult(`worktracking: ${connection.error.category} (${connection.error.reason})`);
|
|
1573
|
+
}
|
|
1574
|
+
if (name === "lighthouse_team_list") return answerOwnerList("team", "teams", client.listTeams(), client);
|
|
1575
|
+
if (name === "lighthouse_team_get") {
|
|
1576
|
+
const id = getNumericId(argumentsPayload);
|
|
1577
|
+
if (id === null) return getErrorToolResult("team: invalid id");
|
|
1578
|
+
return answerOwner("team", client.getTeam(id), client, {
|
|
1579
|
+
read: _letpeoplework_lighthouse_client.readTeam,
|
|
1580
|
+
lines: _letpeoplework_lighthouse_client.describeTeamSummary
|
|
1581
|
+
});
|
|
1582
|
+
}
|
|
1583
|
+
if (name === "lighthouse_team_refresh") {
|
|
1584
|
+
const id = getNumericId(argumentsPayload);
|
|
1585
|
+
if (id === null) return getErrorToolResult("team: invalid id");
|
|
1586
|
+
return answerRefresh(client, "team", id, client.refreshTeam(id));
|
|
1587
|
+
}
|
|
1588
|
+
const refinementTool = findRefinementTool(name);
|
|
1589
|
+
if (refinementTool !== void 0) return refinementTool(argumentsPayload, client, dependencies);
|
|
1590
|
+
if (name === "lighthouse_portfolio_list") return answerOwnerList("portfolio", "portfolios", client.listPortfolios(), client);
|
|
1591
|
+
if (name === "lighthouse_portfolio_get") {
|
|
1592
|
+
const id = getNumericId(argumentsPayload);
|
|
1593
|
+
if (id === null) return getErrorToolResult("portfolio: invalid id");
|
|
1594
|
+
return answerOwner("portfolio", client.getPortfolio(id), client, {
|
|
1595
|
+
read: _letpeoplework_lighthouse_client.readPortfolio,
|
|
1596
|
+
lines: _letpeoplework_lighthouse_client.describePortfolioSummary
|
|
1597
|
+
});
|
|
1598
|
+
}
|
|
1599
|
+
if (name === "lighthouse_portfolio_refresh") {
|
|
1600
|
+
const id = getNumericId(argumentsPayload);
|
|
1601
|
+
if (id === null) return getErrorToolResult("portfolio: invalid id");
|
|
1602
|
+
return answerRefresh(client, "portfolio", id, client.refreshPortfolio(id));
|
|
1603
|
+
}
|
|
1604
|
+
if (name === "lighthouse_team_metrics_throughput") {
|
|
1605
|
+
const id = getNumericId(argumentsPayload);
|
|
1606
|
+
if (id === null) return getErrorToolResult("team metrics: invalid id");
|
|
1607
|
+
const range = getDateRange(argumentsPayload);
|
|
1608
|
+
const view = getThroughputFilterView(argumentsPayload);
|
|
1609
|
+
const summaryRange = range ?? (0, _letpeoplework_lighthouse_client.getDefaultMetricsDateRange)();
|
|
1610
|
+
return answerMetric(metricLabels("team", "throughput"), client.getTeamThroughput(id, range, view), readMetricsWording(client, "team", id), summariseThroughput("team", summaryRange));
|
|
1611
|
+
}
|
|
1612
|
+
if (name === "lighthouse_team_metrics_cycleTimePercentiles") {
|
|
1613
|
+
const id = getNumericId(argumentsPayload);
|
|
1614
|
+
if (id === null) return getErrorToolResult("team metrics: invalid id");
|
|
1615
|
+
const range = getDateRange(argumentsPayload);
|
|
1616
|
+
const definitionId = getDefinitionId(argumentsPayload);
|
|
1617
|
+
const summaryRange = range ?? (0, _letpeoplework_lighthouse_client.getDefaultMetricsDateRange)();
|
|
1618
|
+
return answerMetric(metricLabels("team", "cycleTimePercentiles"), client.getTeamCycleTimePercentiles(id, range, definitionId), Promise.all([readTeamWording(client, id), definitionId === void 0 ? void 0 : readForSummary(() => client.getTeamSettings(id)).then((settings) => (0, _letpeoplework_lighthouse_client.readCycleTimeDefinitionName)(answeredValue(settings), definitionId))]).then(([wording, definitionName]) => ({
|
|
1619
|
+
wording,
|
|
1620
|
+
definitionName
|
|
1621
|
+
})), summariseCycleTimePercentiles(summaryRange));
|
|
1622
|
+
}
|
|
1623
|
+
if (name === "lighthouse_team_metrics_workItemAgePercentiles") {
|
|
1624
|
+
const id = getNumericId(argumentsPayload);
|
|
1625
|
+
if (id === null) return getErrorToolResult("team metrics: invalid id");
|
|
1626
|
+
const range = getDateRange(argumentsPayload);
|
|
1627
|
+
const summaryRange = range ?? (0, _letpeoplework_lighthouse_client.getDefaultMetricsDateRange)();
|
|
1628
|
+
return answerMetric(metricLabels("team", "workItemAgePercentiles"), client.getTeamWorkItemAgePercentiles(id, range), readMetricsWording(client, "team", id), summariseWorkItemAgePercentiles(summaryRange));
|
|
1629
|
+
}
|
|
1630
|
+
if (name === "lighthouse_portfolio_metrics_workItemAgePercentiles") {
|
|
1631
|
+
const id = getNumericId(argumentsPayload);
|
|
1632
|
+
if (id === null) return getErrorToolResult("portfolio metrics: invalid id");
|
|
1633
|
+
const range = getDateRange(argumentsPayload);
|
|
1634
|
+
const summaryRange = range ?? (0, _letpeoplework_lighthouse_client.getDefaultMetricsDateRange)();
|
|
1635
|
+
return answerMetric(metricLabels("portfolio", "workItemAgePercentiles"), client.getPortfolioWorkItemAgePercentiles(id, range), readMetricsWording(client, "portfolio", id), summariseWorkItemAgePercentiles(summaryRange));
|
|
1636
|
+
}
|
|
1637
|
+
if (name === "lighthouse_team_metrics_blockedCountHistory") {
|
|
1638
|
+
const id = getNumericId(argumentsPayload);
|
|
1639
|
+
if (id === null) return getErrorToolResult("team metrics: invalid id");
|
|
1640
|
+
const range = getDateRange(argumentsPayload);
|
|
1641
|
+
const summaryRange = range ?? (0, _letpeoplework_lighthouse_client.getDefaultMetricsDateRange)();
|
|
1642
|
+
return answerMetric(metricLabels("team", "blockedCountHistory"), client.getTeamBlockedCountHistory(id, range), readMetricsWording(client, "team", id), summariseBlocked("team", summaryRange));
|
|
1643
|
+
}
|
|
1644
|
+
if (name === "lighthouse_portfolio_metrics_blockedCountHistory") {
|
|
1645
|
+
const id = getNumericId(argumentsPayload);
|
|
1646
|
+
if (id === null) return getErrorToolResult("portfolio metrics: invalid id");
|
|
1647
|
+
const range = getDateRange(argumentsPayload);
|
|
1648
|
+
const summaryRange = range ?? (0, _letpeoplework_lighthouse_client.getDefaultMetricsDateRange)();
|
|
1649
|
+
return answerMetric(metricLabels("portfolio", "blockedCountHistory"), client.getPortfolioBlockedCountHistory(id, range), readMetricsWording(client, "portfolio", id), summariseBlocked("portfolio", summaryRange));
|
|
1650
|
+
}
|
|
1651
|
+
if (name === "lighthouse_team_metrics_wip") {
|
|
1652
|
+
const id = getNumericId(argumentsPayload);
|
|
1653
|
+
if (id === null) return getErrorToolResult("team metrics: invalid id");
|
|
1654
|
+
const today = (0, _letpeoplework_lighthouse_client.getDefaultMetricsDateRange)().endDate;
|
|
1655
|
+
return answerMetric(metricLabels("team", "wip"), client.getTeamWip(id, today), readCurrentWipContext(client, id), summariseCurrentWip(today));
|
|
1656
|
+
}
|
|
1657
|
+
if (name === "lighthouse_team_metrics_sleRisk") {
|
|
1658
|
+
const id = getNumericId(argumentsPayload);
|
|
1659
|
+
if (id === null) return getErrorToolResult("team metrics: invalid id");
|
|
1660
|
+
const today = (0, _letpeoplework_lighthouse_client.getDefaultMetricsDateRange)().endDate;
|
|
1661
|
+
return answerMetric(metricLabels("team", "sleRisk"), client.getTeamSleRisk(id), readSleRiskContext(client, id, today), summariseSleRisk(today));
|
|
1662
|
+
}
|
|
1663
|
+
if (name === "lighthouse_team_metrics_processBehaviorChart") {
|
|
1664
|
+
const id = getNumericId(argumentsPayload);
|
|
1665
|
+
if (id === null) return getErrorToolResult("team metrics: invalid id");
|
|
1666
|
+
const chartType = getChartType(argumentsPayload, TEAM_CHART_TYPES);
|
|
1667
|
+
if (chartType === void 0) return getErrorToolResult("team metrics: invalid metricType");
|
|
1668
|
+
const range = getDateRange(argumentsPayload) ?? (0, _letpeoplework_lighthouse_client.getDefaultMetricsDateRange)();
|
|
1669
|
+
return answerMetric(metricLabels("team", "processBehaviorChart"), client.getTeamProcessBehaviorChart(id, range, chartType), readMetricsWording(client, "team", id), summariseProcessBehaviorChart(range, chartType));
|
|
1670
|
+
}
|
|
1671
|
+
if (name === "lighthouse_portfolio_metrics_processBehaviorChart") {
|
|
1672
|
+
const id = getNumericId(argumentsPayload);
|
|
1673
|
+
if (id === null) return getErrorToolResult("portfolio metrics: invalid id");
|
|
1674
|
+
const chartType = getChartType(argumentsPayload, processBehaviorMetricTypes);
|
|
1675
|
+
if (chartType === void 0) return getErrorToolResult("portfolio metrics: invalid metricType");
|
|
1676
|
+
const range = getDateRange(argumentsPayload) ?? (0, _letpeoplework_lighthouse_client.getDefaultMetricsDateRange)();
|
|
1677
|
+
return answerMetric(metricLabels("portfolio", "processBehaviorChart"), client.getPortfolioProcessBehaviorChart(id, range, chartType), readMetricsWording(client, "portfolio", id), summariseProcessBehaviorChart(range, chartType));
|
|
1678
|
+
}
|
|
1679
|
+
if (name === "lighthouse_team_metrics_percentilesOverTime") {
|
|
1680
|
+
const id = getNumericId(argumentsPayload);
|
|
1681
|
+
if (id === null) return getErrorToolResult("team metrics: invalid id");
|
|
1682
|
+
const range = getDateRange(argumentsPayload);
|
|
1683
|
+
const summaryRange = range ?? (0, _letpeoplework_lighthouse_client.getDefaultMetricsDateRange)();
|
|
1684
|
+
return answerMetric(metricLabels("team", "percentilesOverTime"), client.getTeamPercentilesOverTime(id, range, getPercentilesOverTimeMetricType(argumentsPayload), getHorizonArgument(argumentsPayload)), readMetricsWording(client, "team", id), summarisePercentilesOverTime(summaryRange, argumentsPayload));
|
|
1685
|
+
}
|
|
1686
|
+
if (name === "lighthouse_portfolio_metrics_percentilesOverTime") {
|
|
1687
|
+
const id = getNumericId(argumentsPayload);
|
|
1688
|
+
if (id === null) return getErrorToolResult("portfolio metrics: invalid id");
|
|
1689
|
+
const range = getDateRange(argumentsPayload);
|
|
1690
|
+
const summaryRange = range ?? (0, _letpeoplework_lighthouse_client.getDefaultMetricsDateRange)();
|
|
1691
|
+
return answerMetric(metricLabels("portfolio", "percentilesOverTime"), client.getPortfolioPercentilesOverTime(id, range, getPercentilesOverTimeMetricType(argumentsPayload), getHorizonArgument(argumentsPayload)), readMetricsWording(client, "portfolio", id), summarisePercentilesOverTime(summaryRange, argumentsPayload));
|
|
1692
|
+
}
|
|
1693
|
+
if (name === "lighthouse_team_metrics_processBehaviorOverTime") {
|
|
1694
|
+
const id = getNumericId(argumentsPayload);
|
|
1695
|
+
if (id === null) return getErrorToolResult("team metrics: invalid id");
|
|
1696
|
+
const range = getDateRange(argumentsPayload);
|
|
1697
|
+
const summaryRange = range ?? (0, _letpeoplework_lighthouse_client.getDefaultMetricsDateRange)();
|
|
1698
|
+
return answerMetric(metricLabels("team", "processBehaviorOverTime"), client.getTeamProcessBehaviorOverTime(id, range, getProcessBehaviorMetricType(argumentsPayload)), readMetricsWording(client, "team", id), summariseProcessBehaviorOverTime(summaryRange, argumentsPayload));
|
|
1699
|
+
}
|
|
1700
|
+
if (name === "lighthouse_portfolio_metrics_processBehaviorOverTime") {
|
|
1701
|
+
const id = getNumericId(argumentsPayload);
|
|
1702
|
+
if (id === null) return getErrorToolResult("portfolio metrics: invalid id");
|
|
1703
|
+
const range = getDateRange(argumentsPayload);
|
|
1704
|
+
const summaryRange = range ?? (0, _letpeoplework_lighthouse_client.getDefaultMetricsDateRange)();
|
|
1705
|
+
return answerMetric(metricLabels("portfolio", "processBehaviorOverTime"), client.getPortfolioProcessBehaviorOverTime(id, range, getProcessBehaviorMetricType(argumentsPayload)), readMetricsWording(client, "portfolio", id), summariseProcessBehaviorOverTime(summaryRange, argumentsPayload));
|
|
1706
|
+
}
|
|
1707
|
+
if (name === "lighthouse_team_metrics_cumulativeStateTime") {
|
|
1708
|
+
const id = getNumericId(argumentsPayload);
|
|
1709
|
+
if (id === null) return getErrorToolResult("team metrics: invalid id");
|
|
1710
|
+
const range = getDateRange(argumentsPayload);
|
|
1711
|
+
return answerMetric(metricLabels("team", "cumulativeStateTime"), client.getTeamCumulativeStateTime(id, range, getItemIdsArgument(argumentsPayload)), readMetricsWording(client, "team", id), summariseTimeInState("team", range ?? (0, _letpeoplework_lighthouse_client.getDefaultMetricsDateRange)()));
|
|
1712
|
+
}
|
|
1713
|
+
if (name === "lighthouse_team_metrics_cumulativeStateTimeItems") {
|
|
1714
|
+
const id = getNumericId(argumentsPayload);
|
|
1715
|
+
if (id === null) return getErrorToolResult("team metrics: invalid id");
|
|
1716
|
+
const state = getStringArgument(argumentsPayload, "state");
|
|
1717
|
+
if (state === void 0) return getErrorToolResult("team metrics: missing state");
|
|
1718
|
+
const range = getDateRange(argumentsPayload);
|
|
1719
|
+
return answerMetric(metricLabels("team", "cumulativeStateTimeItems"), client.getTeamCumulativeStateTimeItems(id, state, range, getItemIdsArgument(argumentsPayload)), readMetricsWording(client, "team", id), summariseTimeInStateContributors("team", range ?? (0, _letpeoplework_lighthouse_client.getDefaultMetricsDateRange)()));
|
|
1720
|
+
}
|
|
1721
|
+
if (name === "lighthouse_team_metrics_cumulativeStateTimeCandidates") {
|
|
1722
|
+
const id = getNumericId(argumentsPayload);
|
|
1723
|
+
if (id === null) return getErrorToolResult("team metrics: invalid id");
|
|
1724
|
+
const result = await client.getTeamCumulativeStateTimeCandidates(id, getDateRange(argumentsPayload));
|
|
1725
|
+
if (result.ok) return getSuccessToolResult(`team cumulativeStateTimeCandidates: ${encodePayload(result.value)}`);
|
|
1726
|
+
return getErrorToolResult(`team metrics: ${result.error.category} (${result.error.reason})`);
|
|
1727
|
+
}
|
|
1728
|
+
if (name === "lighthouse_portfolio_metrics_cumulativeStateTime") {
|
|
1729
|
+
const id = getNumericId(argumentsPayload);
|
|
1730
|
+
if (id === null) return getErrorToolResult("portfolio metrics: invalid id");
|
|
1731
|
+
const range = getDateRange(argumentsPayload);
|
|
1732
|
+
return answerMetric(metricLabels("portfolio", "cumulativeStateTime"), client.getPortfolioCumulativeStateTime(id, range, getItemIdsArgument(argumentsPayload)), readMetricsWording(client, "portfolio", id), summariseTimeInState("portfolio", range ?? (0, _letpeoplework_lighthouse_client.getDefaultMetricsDateRange)()));
|
|
1733
|
+
}
|
|
1734
|
+
if (name === "lighthouse_portfolio_metrics_cumulativeStateTimeItems") {
|
|
1735
|
+
const id = getNumericId(argumentsPayload);
|
|
1736
|
+
if (id === null) return getErrorToolResult("portfolio metrics: invalid id");
|
|
1737
|
+
const state = getStringArgument(argumentsPayload, "state");
|
|
1738
|
+
if (state === void 0) return getErrorToolResult("portfolio metrics: missing state");
|
|
1739
|
+
const range = getDateRange(argumentsPayload);
|
|
1740
|
+
return answerMetric(metricLabels("portfolio", "cumulativeStateTimeItems"), client.getPortfolioCumulativeStateTimeItems(id, state, range, getItemIdsArgument(argumentsPayload)), readMetricsWording(client, "portfolio", id), summariseTimeInStateContributors("portfolio", range ?? (0, _letpeoplework_lighthouse_client.getDefaultMetricsDateRange)()));
|
|
1741
|
+
}
|
|
1742
|
+
if (name === "lighthouse_portfolio_metrics_cumulativeStateTimeCandidates") {
|
|
1743
|
+
const id = getNumericId(argumentsPayload);
|
|
1744
|
+
if (id === null) return getErrorToolResult("portfolio metrics: invalid id");
|
|
1745
|
+
const result = await client.getPortfolioCumulativeStateTimeCandidates(id, getDateRange(argumentsPayload));
|
|
1746
|
+
if (result.ok) return getSuccessToolResult(`portfolio cumulativeStateTimeCandidates: ${encodePayload(result.value)}`);
|
|
1747
|
+
return getErrorToolResult(`portfolio metrics: ${result.error.category} (${result.error.reason})`);
|
|
1748
|
+
}
|
|
1749
|
+
if (name === "lighthouse_portfolio_metrics_throughput") {
|
|
1750
|
+
const id = getNumericId(argumentsPayload);
|
|
1751
|
+
if (id === null) return getErrorToolResult("portfolio metrics: invalid id");
|
|
1752
|
+
const range = getDateRange(argumentsPayload);
|
|
1753
|
+
const summaryRange = range ?? (0, _letpeoplework_lighthouse_client.getDefaultMetricsDateRange)();
|
|
1754
|
+
return answerMetric(metricLabels("portfolio", "throughput"), client.getPortfolioThroughput(id, range), readMetricsWording(client, "portfolio", id), summariseThroughput("portfolio", summaryRange));
|
|
1755
|
+
}
|
|
1756
|
+
if (name === "lighthouse_team_metrics_workItemAge") {
|
|
1757
|
+
const id = getNumericId(argumentsPayload);
|
|
1758
|
+
if (id === null) return getErrorToolResult("team metrics: invalid id");
|
|
1759
|
+
const range = getDateRange(argumentsPayload);
|
|
1760
|
+
return answerMetric(metricLabels("team", "workItemAge"), client.getTeamWorkItemAgeOverTime(id, range), Promise.all([readMetricsWording(client, "team", id), readForSummary(() => client.getTeamWorkItemAgePercentiles(id, range))]).then(([wording, percentiles]) => ({
|
|
1761
|
+
wording,
|
|
1762
|
+
percentiles: answeredValue(percentiles)
|
|
1763
|
+
})), summariseWorkItemAge("team"));
|
|
1764
|
+
}
|
|
1765
|
+
if (name === "lighthouse_team_metrics_totalWorkItemAge") {
|
|
1766
|
+
const id = getNumericId(argumentsPayload);
|
|
1767
|
+
if (id === null) return getErrorToolResult("team metrics: invalid id");
|
|
1768
|
+
const range = getDateRange(argumentsPayload);
|
|
1769
|
+
return answerMetric(metricLabels("team", "totalWorkItemAge"), client.getTeamTotalWorkItemAgeOverTime(id, range), readMetricsWording(client, "team", id), summariseTotalWorkItemAge("team"));
|
|
1770
|
+
}
|
|
1771
|
+
if (name === "lighthouse_portfolio_metrics_workItemAge") {
|
|
1772
|
+
const id = getNumericId(argumentsPayload);
|
|
1773
|
+
if (id === null) return getErrorToolResult("portfolio metrics: invalid id");
|
|
1774
|
+
const range = getDateRange(argumentsPayload);
|
|
1775
|
+
return answerMetric(metricLabels("portfolio", "workItemAge"), client.getPortfolioWorkItemAgeOverTime(id, range), Promise.all([readMetricsWording(client, "portfolio", id), readForSummary(() => client.getPortfolioWorkItemAgePercentiles(id, range))]).then(([wording, percentiles]) => ({
|
|
1776
|
+
wording,
|
|
1777
|
+
percentiles: answeredValue(percentiles)
|
|
1778
|
+
})), summariseWorkItemAge("portfolio"));
|
|
1779
|
+
}
|
|
1780
|
+
if (name === "lighthouse_portfolio_metrics_totalWorkItemAge") {
|
|
1781
|
+
const id = getNumericId(argumentsPayload);
|
|
1782
|
+
if (id === null) return getErrorToolResult("portfolio metrics: invalid id");
|
|
1783
|
+
const range = getDateRange(argumentsPayload);
|
|
1784
|
+
return answerMetric(metricLabels("portfolio", "totalWorkItemAge"), client.getPortfolioTotalWorkItemAgeOverTime(id, range), readMetricsWording(client, "portfolio", id), summariseTotalWorkItemAge("portfolio"));
|
|
1785
|
+
}
|
|
1786
|
+
if (name === "lighthouse_feature_get") {
|
|
1787
|
+
const payload = isObjectRecord(argumentsPayload) ? argumentsPayload : {};
|
|
1788
|
+
const idsValue = payload.ids;
|
|
1789
|
+
const refsValue = payload.refs;
|
|
1790
|
+
if (Array.isArray(idsValue) && idsValue.length > 0) {
|
|
1791
|
+
const ids = idsValue.filter((v) => typeof v === "number");
|
|
1792
|
+
return answerFeatures(client, client.getFeaturesByIds(ids));
|
|
1793
|
+
}
|
|
1794
|
+
if (Array.isArray(refsValue) && refsValue.length > 0) {
|
|
1795
|
+
const refs = refsValue.filter((v) => typeof v === "string");
|
|
1796
|
+
return answerFeatures(client, client.getFeaturesByReferences(refs));
|
|
1797
|
+
}
|
|
1798
|
+
return getErrorToolResult("features: provide ids (array of numbers) or refs (array of strings)");
|
|
1799
|
+
}
|
|
1800
|
+
if (name === "lighthouse_feature_workitems") {
|
|
1801
|
+
const id = getNumericId(argumentsPayload);
|
|
1802
|
+
if (id === null) return getErrorToolResult("feature workitems: invalid id");
|
|
1803
|
+
const [result, wording] = await Promise.all([client.getFeatureWorkItems(id), (0, _letpeoplework_lighthouse_client.readFeatureWording)(client, id)]);
|
|
1804
|
+
if (!result.ok) return getErrorToolResult(`feature workitems: ${result.error.category} (${result.error.reason})`);
|
|
1805
|
+
return withSummary("feature workitems", result.value, summaryOrNull(() => {
|
|
1806
|
+
const items = (0, _letpeoplework_lighthouse_client.readFeatureWorkItems)(result.value);
|
|
1807
|
+
return items === null ? null : (0, _letpeoplework_lighthouse_client.describeFeatureWorkItemsHeading)(wording.name, items.length, wording.terms);
|
|
1808
|
+
}));
|
|
1809
|
+
}
|
|
1810
|
+
if (name === "lighthouse_delivery_list") {
|
|
1811
|
+
const id = getNumericId(argumentsPayload);
|
|
1812
|
+
if (id === null) return getErrorToolResult("delivery: invalid id (portfolio id required)");
|
|
1813
|
+
const [result, terms] = await Promise.all([client.listDeliveries(id), (0, _letpeoplework_lighthouse_client.readTerms)(client)]);
|
|
1814
|
+
if (!result.ok) return getErrorToolResult(`delivery: ${result.error.category} (${result.error.reason})`);
|
|
1815
|
+
return withSummary("deliveries", result.value, countSummary(result.value, _letpeoplework_lighthouse_client.readDeliveryList, (count) => (0, _letpeoplework_lighthouse_client.describeDeliveryCount)(count, terms)));
|
|
1816
|
+
}
|
|
1817
|
+
if (name === "lighthouse_delivery_metrics") {
|
|
1818
|
+
const id = getNumericId(argumentsPayload);
|
|
1819
|
+
if (id === null) return getErrorToolResult("delivery metrics: invalid id (delivery id required)");
|
|
1820
|
+
const wantsEpics = argumentsPayload?.detail === "epics";
|
|
1821
|
+
const [result, terms] = await Promise.all([client.getDeliveryMetricsHistory(id), (0, _letpeoplework_lighthouse_client.readTerms)(client)]);
|
|
1822
|
+
if (!result.ok) return getErrorToolResult(`delivery metrics: ${result.error.category} (${result.error.reason})`);
|
|
1823
|
+
const payload = wantsEpics ? result.value : (0, _letpeoplework_lighthouse_client.summariseDeliveryMetricsHistory)(result.value);
|
|
1824
|
+
return withSummary("delivery metrics", payload, summaryOrNull(() => {
|
|
1825
|
+
const history = (0, _letpeoplework_lighthouse_client.readDeliveryMetricsHistory)(result.value);
|
|
1826
|
+
return history === null ? null : (0, _letpeoplework_lighthouse_client.describeDeliveryMetricsHeading)(history, id, terms);
|
|
1827
|
+
}));
|
|
1828
|
+
}
|
|
1829
|
+
if (name === "lighthouse_blackout_list") {
|
|
1830
|
+
const result = await client.getRecurringBlackoutRules();
|
|
1831
|
+
if (result.ok) return withSummary("recurringBlackoutRules", result.value, countSummary(result.value, _letpeoplework_lighthouse_client.readBlackoutRules, _letpeoplework_lighthouse_client.describeBlackoutRuleCount));
|
|
1832
|
+
return getErrorToolResult(`blackout: ${result.error.category} (${result.error.reason})`);
|
|
1833
|
+
}
|
|
1834
|
+
if (name === "lighthouse_blackout_create") {
|
|
1835
|
+
const payload = isObjectRecord(argumentsPayload) ? argumentsPayload : {};
|
|
1836
|
+
return answerBlackoutRuleWrite("Created", client.createRecurringBlackoutRule(payload));
|
|
1837
|
+
}
|
|
1838
|
+
if (name === "lighthouse_blackout_update") {
|
|
1839
|
+
const id = getNumericId(argumentsPayload);
|
|
1840
|
+
if (id === null) return getErrorToolResult("blackout: invalid id (rule id required)");
|
|
1841
|
+
const { id: _ignoredId, ...rulePayload } = isObjectRecord(argumentsPayload) ? argumentsPayload : {};
|
|
1842
|
+
return answerBlackoutRuleWrite("Updated", client.updateRecurringBlackoutRule(id, rulePayload));
|
|
1843
|
+
}
|
|
1844
|
+
if (name === "lighthouse_blackout_delete") {
|
|
1845
|
+
const id = getNumericId(argumentsPayload);
|
|
1846
|
+
if (id === null) return getErrorToolResult("blackout: invalid id (rule id required)");
|
|
1847
|
+
const result = await client.deleteRecurringBlackoutRule(id);
|
|
1848
|
+
if (!result.ok) return getErrorToolResult(`blackout: ${result.error.category} (${result.error.reason})`);
|
|
1849
|
+
return withConfirmation(`recurringBlackoutRule deleted: ${id}`, () => (0, _letpeoplework_lighthouse_client.describeBlackoutRuleWriteConfirmation)("Deleted", { id }));
|
|
1850
|
+
}
|
|
1851
|
+
if (name === "lighthouse_forecast_manual") {
|
|
1852
|
+
const id = getNumericId(argumentsPayload);
|
|
1853
|
+
if (id === null) return getErrorToolResult("forecast: invalid id (team id required)");
|
|
1854
|
+
const payload = isObjectRecord(argumentsPayload) ? argumentsPayload : {};
|
|
1855
|
+
const remainingItems = typeof payload.remainingItems === "number" ? payload.remainingItems : void 0;
|
|
1856
|
+
const targetDate = typeof payload.targetDate === "string" ? payload.targetDate : void 0;
|
|
1857
|
+
const applyFilterOverride = getApplyFilterOverride(argumentsPayload);
|
|
1858
|
+
const [result, wording] = await Promise.all([client.runManualForecast(id, {
|
|
1859
|
+
remainingItems,
|
|
1860
|
+
targetDate,
|
|
1861
|
+
applyFilterOverride
|
|
1862
|
+
}), readTeamWording(client, id)]);
|
|
1863
|
+
if (result.ok) return withSummary("forecast", result.value, summaryOrNull(() => describeManualForecastAnswer(result.value, wording)));
|
|
1864
|
+
return getErrorToolResult(`forecast: ${result.error.category} (${result.error.reason})`);
|
|
1865
|
+
}
|
|
1866
|
+
if (name === "lighthouse_forecast_backtest") {
|
|
1867
|
+
const id = getNumericId(argumentsPayload);
|
|
1868
|
+
if (id === null) return getErrorToolResult("backtest: invalid id (team id required)");
|
|
1869
|
+
const payload = isObjectRecord(argumentsPayload) ? argumentsPayload : {};
|
|
1870
|
+
const startDate = typeof payload.startDate === "string" ? payload.startDate : void 0;
|
|
1871
|
+
const endDate = typeof payload.endDate === "string" ? payload.endDate : void 0;
|
|
1872
|
+
const historicalStartDate = typeof payload.historicalStartDate === "string" ? payload.historicalStartDate : void 0;
|
|
1873
|
+
const historicalEndDate = typeof payload.historicalEndDate === "string" ? payload.historicalEndDate : void 0;
|
|
1874
|
+
if (!startDate || !endDate || !historicalStartDate || !historicalEndDate) return getErrorToolResult("backtest: startDate, endDate, historicalStartDate, and historicalEndDate are required");
|
|
1875
|
+
const applyFilterOverride = getApplyFilterOverride(argumentsPayload);
|
|
1876
|
+
const [result, wording] = await Promise.all([client.runBacktest(id, {
|
|
1877
|
+
startDate,
|
|
1878
|
+
endDate,
|
|
1879
|
+
historicalStartDate,
|
|
1880
|
+
historicalEndDate,
|
|
1881
|
+
applyFilterOverride
|
|
1882
|
+
}), readTeamWording(client, id)]);
|
|
1883
|
+
if (result.ok) return withSummary("backtest", result.value, summaryOrNull(() => describeBacktestAnswer(result.value, wording)));
|
|
1884
|
+
return getErrorToolResult(`backtest: ${result.error.category} (${result.error.reason})`);
|
|
1885
|
+
}
|
|
1886
|
+
return getErrorToolResult(`Unknown tool: ${name}`);
|
|
1887
|
+
};
|
|
1888
|
+
const countedOf = (name, answered) => isToolResult(answered) ? countedToolResult(answered, usageDataOccurrencesOf(name)) : answered;
|
|
1889
|
+
const createMcpCoreRuntime = (dependencies) => {
|
|
1890
|
+
const answer = answerToolCall(dependencies);
|
|
1891
|
+
const callCountedTool = async (name, argumentsPayload) => countedOf(name, await answer(name, argumentsPayload));
|
|
1892
|
+
return {
|
|
1893
|
+
listTools: () => toolDefinitions,
|
|
1894
|
+
callTool: async (name, argumentsPayload) => (await callCountedTool(name, argumentsPayload)).result,
|
|
1895
|
+
callCountedTool
|
|
1896
|
+
};
|
|
1897
|
+
};
|
|
1898
|
+
const canElicit = (server) => server.server?.getClientCapabilities()?.elicitation !== void 0;
|
|
1899
|
+
const registerMcpTools = (server, dependencies) => {
|
|
1900
|
+
const runtime = createMcpCoreRuntime(dependencies);
|
|
1901
|
+
for (const tool of toolDefinitions) server.registerTool(tool.name, {
|
|
1902
|
+
description: tool.description,
|
|
1903
|
+
inputSchema: toolInputSchemas[tool.name],
|
|
1904
|
+
annotations: {
|
|
1905
|
+
readOnlyHint: isReadOnlyTool(tool.name),
|
|
1906
|
+
idempotentHint: isReadOnlyTool(tool.name),
|
|
1907
|
+
openWorldHint: false
|
|
1908
|
+
}
|
|
1909
|
+
}, async (argumentsPayload, extra) => {
|
|
1910
|
+
const { result, occurrences } = await runtime.callCountedTool(tool.name, argumentsPayload);
|
|
1911
|
+
await dependencies.usageData?.({
|
|
1912
|
+
reached: !result.isError,
|
|
1913
|
+
occurrences,
|
|
1914
|
+
ask: canElicit(server) ? askThroughTheAssistant((params, options) => extra.sendRequest({
|
|
1915
|
+
method: "elicitation/create",
|
|
1916
|
+
params
|
|
1917
|
+
}, _modelcontextprotocol_sdk_types_js.ElicitResultSchema, {
|
|
1918
|
+
...options,
|
|
1919
|
+
signal: extra.signal
|
|
1920
|
+
})) : void 0
|
|
1921
|
+
});
|
|
1922
|
+
return {
|
|
1923
|
+
...result,
|
|
1924
|
+
content: [...result.content]
|
|
1925
|
+
};
|
|
1926
|
+
});
|
|
1927
|
+
};
|
|
1928
|
+
//#endregion
|
|
1929
|
+
exports.USAGE_DATA_ELICITATION_MESSAGE = USAGE_DATA_ELICITATION_MESSAGE;
|
|
1930
|
+
exports.USAGE_DATA_QUESTION_TIMEOUT_MS = USAGE_DATA_QUESTION_TIMEOUT_MS;
|
|
1931
|
+
exports.askThroughTheAssistant = askThroughTheAssistant;
|
|
1932
|
+
exports.askingOnceInThisProcess = askingOnceInThisProcess;
|
|
1933
|
+
exports.countedToolResult = countedToolResult;
|
|
1934
|
+
exports.createMcpCoreRuntime = createMcpCoreRuntime;
|
|
1935
|
+
exports.getMcpCorePackageContract = getMcpCorePackageContract;
|
|
1936
|
+
exports.registerMcpTools = registerMcpTools;
|
|
1937
|
+
exports.usageDataOccurrencesOf = usageDataOccurrencesOf;
|
|
1938
|
+
exports.usageDataOccurrencesOfARead = usageDataOccurrencesOfARead;
|
|
1939
|
+
exports.usageDataOccurrencesOfAVote = usageDataOccurrencesOfAVote;
|