@dotsetlabs/bellwether 2.1.0 → 2.1.2
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/CHANGELOG.md +35 -0
- package/README.md +48 -31
- package/dist/cli/commands/check.js +49 -6
- package/dist/cli/commands/dashboard.d.ts +3 -0
- package/dist/cli/commands/dashboard.js +69 -0
- package/dist/cli/commands/discover.js +24 -2
- package/dist/cli/commands/explore.js +49 -6
- package/dist/cli/commands/watch.js +12 -1
- package/dist/cli/index.js +27 -34
- package/dist/cli/utils/headers.d.ts +12 -0
- package/dist/cli/utils/headers.js +63 -0
- package/dist/config/defaults.d.ts +2 -0
- package/dist/config/defaults.js +2 -0
- package/dist/config/template.js +12 -0
- package/dist/config/validator.d.ts +38 -18
- package/dist/config/validator.js +10 -0
- package/dist/constants/core.d.ts +4 -2
- package/dist/constants/core.js +13 -2
- package/dist/dashboard/index.d.ts +3 -0
- package/dist/dashboard/index.js +6 -0
- package/dist/dashboard/runtime/artifact-index.d.ts +45 -0
- package/dist/dashboard/runtime/artifact-index.js +238 -0
- package/dist/dashboard/runtime/command-profiles.d.ts +764 -0
- package/dist/dashboard/runtime/command-profiles.js +691 -0
- package/dist/dashboard/runtime/config-service.d.ts +21 -0
- package/dist/dashboard/runtime/config-service.js +73 -0
- package/dist/dashboard/runtime/job-runner.d.ts +26 -0
- package/dist/dashboard/runtime/job-runner.js +292 -0
- package/dist/dashboard/security/input-validation.d.ts +3 -0
- package/dist/dashboard/security/input-validation.js +27 -0
- package/dist/dashboard/security/localhost-guard.d.ts +5 -0
- package/dist/dashboard/security/localhost-guard.js +52 -0
- package/dist/dashboard/server.d.ts +14 -0
- package/dist/dashboard/server.js +293 -0
- package/dist/dashboard/types.d.ts +55 -0
- package/dist/dashboard/types.js +2 -0
- package/dist/dashboard/ui.d.ts +2 -0
- package/dist/dashboard/ui.js +2264 -0
- package/dist/discovery/discovery.js +20 -1
- package/dist/discovery/types.d.ts +1 -1
- package/dist/docs/contract.js +7 -1
- package/dist/errors/retry.js +15 -1
- package/dist/errors/types.d.ts +10 -0
- package/dist/errors/types.js +28 -0
- package/dist/logging/logger.js +5 -2
- package/dist/transport/env-filter.d.ts +6 -0
- package/dist/transport/env-filter.js +76 -0
- package/dist/transport/http-transport.js +10 -0
- package/dist/transport/mcp-client.d.ts +16 -9
- package/dist/transport/mcp-client.js +119 -88
- package/dist/transport/sse-transport.js +19 -0
- package/dist/version.js +2 -2
- package/package.json +5 -15
- package/man/bellwether.1 +0 -204
- package/man/bellwether.1.md +0 -148
|
@@ -0,0 +1,691 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
const dashboardProfiles = [
|
|
3
|
+
{
|
|
4
|
+
id: 'check',
|
|
5
|
+
label: 'Check',
|
|
6
|
+
description: 'Run deterministic schema drift detection',
|
|
7
|
+
requiresServerCommand: true,
|
|
8
|
+
category: 'core',
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
id: 'explore',
|
|
12
|
+
label: 'Explore',
|
|
13
|
+
description: 'Run LLM-powered behavioral exploration',
|
|
14
|
+
requiresServerCommand: true,
|
|
15
|
+
category: 'core',
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
id: 'validate-config',
|
|
19
|
+
label: 'Validate Config',
|
|
20
|
+
description: 'Validate bellwether.yaml without running tests',
|
|
21
|
+
requiresServerCommand: false,
|
|
22
|
+
category: 'core',
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
id: 'discover',
|
|
26
|
+
label: 'Discover',
|
|
27
|
+
description: 'Discover tools, prompts, and resources',
|
|
28
|
+
requiresServerCommand: true,
|
|
29
|
+
category: 'advanced',
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
id: 'watch',
|
|
33
|
+
label: 'Watch',
|
|
34
|
+
description: 'Start watch mode for automatic check runs',
|
|
35
|
+
requiresServerCommand: false,
|
|
36
|
+
category: 'advanced',
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
id: 'baseline.save',
|
|
40
|
+
label: 'Baseline Save',
|
|
41
|
+
description: 'Save check report as baseline',
|
|
42
|
+
requiresServerCommand: false,
|
|
43
|
+
category: 'baseline',
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
id: 'baseline.compare',
|
|
47
|
+
label: 'Baseline Compare',
|
|
48
|
+
description: 'Compare current check report with baseline',
|
|
49
|
+
requiresServerCommand: false,
|
|
50
|
+
category: 'baseline',
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
id: 'baseline.show',
|
|
54
|
+
label: 'Baseline Show',
|
|
55
|
+
description: 'Inspect baseline contents',
|
|
56
|
+
requiresServerCommand: false,
|
|
57
|
+
category: 'baseline',
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
id: 'baseline.diff',
|
|
61
|
+
label: 'Baseline Diff',
|
|
62
|
+
description: 'Compare two baseline files',
|
|
63
|
+
requiresServerCommand: false,
|
|
64
|
+
category: 'baseline',
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
id: 'baseline.accept',
|
|
68
|
+
label: 'Baseline Accept',
|
|
69
|
+
description: 'Accept current drift and update baseline',
|
|
70
|
+
requiresServerCommand: false,
|
|
71
|
+
category: 'baseline',
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
id: 'registry.search',
|
|
75
|
+
label: 'Registry Search',
|
|
76
|
+
description: 'Search MCP Registry servers',
|
|
77
|
+
requiresServerCommand: false,
|
|
78
|
+
category: 'advanced',
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
id: 'contract.validate',
|
|
82
|
+
label: 'Contract Validate',
|
|
83
|
+
description: 'Validate server behavior against a contract',
|
|
84
|
+
requiresServerCommand: true,
|
|
85
|
+
category: 'advanced',
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
id: 'contract.generate',
|
|
89
|
+
label: 'Contract Generate',
|
|
90
|
+
description: 'Generate contract from current server behavior',
|
|
91
|
+
requiresServerCommand: true,
|
|
92
|
+
category: 'advanced',
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
id: 'contract.show',
|
|
96
|
+
label: 'Contract Show',
|
|
97
|
+
description: 'Display contract file contents',
|
|
98
|
+
requiresServerCommand: false,
|
|
99
|
+
category: 'advanced',
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
id: 'golden.save',
|
|
103
|
+
label: 'Golden Save',
|
|
104
|
+
description: 'Capture current tool output as golden reference',
|
|
105
|
+
requiresServerCommand: false,
|
|
106
|
+
category: 'advanced',
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
id: 'golden.compare',
|
|
110
|
+
label: 'Golden Compare',
|
|
111
|
+
description: 'Compare live outputs against saved goldens',
|
|
112
|
+
requiresServerCommand: false,
|
|
113
|
+
category: 'advanced',
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
id: 'golden.list',
|
|
117
|
+
label: 'Golden List',
|
|
118
|
+
description: 'List captured golden outputs',
|
|
119
|
+
requiresServerCommand: false,
|
|
120
|
+
category: 'advanced',
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
id: 'golden.delete',
|
|
124
|
+
label: 'Golden Delete',
|
|
125
|
+
description: 'Delete captured golden outputs for a tool',
|
|
126
|
+
requiresServerCommand: false,
|
|
127
|
+
category: 'advanced',
|
|
128
|
+
},
|
|
129
|
+
];
|
|
130
|
+
const nonEmptyString = z.string().transform((value) => value.trim()).optional();
|
|
131
|
+
const optionalBoolean = z.boolean().optional();
|
|
132
|
+
const optionalPositiveInteger = z.preprocess((value) => {
|
|
133
|
+
if (value === undefined || value === null || value === '') {
|
|
134
|
+
return undefined;
|
|
135
|
+
}
|
|
136
|
+
if (typeof value === 'string') {
|
|
137
|
+
const parsed = Number.parseInt(value, 10);
|
|
138
|
+
return Number.isNaN(parsed) ? value : parsed;
|
|
139
|
+
}
|
|
140
|
+
return value;
|
|
141
|
+
}, z.number().int().min(1).optional());
|
|
142
|
+
const serverCommandArgsSchema = z
|
|
143
|
+
.object({
|
|
144
|
+
configPath: nonEmptyString,
|
|
145
|
+
serverCommand: nonEmptyString,
|
|
146
|
+
serverArgs: z.array(z.string()).optional(),
|
|
147
|
+
})
|
|
148
|
+
.strict();
|
|
149
|
+
const validateConfigArgsSchema = z
|
|
150
|
+
.object({
|
|
151
|
+
configPath: nonEmptyString,
|
|
152
|
+
})
|
|
153
|
+
.strict();
|
|
154
|
+
const discoverArgsSchema = z
|
|
155
|
+
.object({
|
|
156
|
+
configPath: nonEmptyString,
|
|
157
|
+
serverCommand: nonEmptyString,
|
|
158
|
+
serverArgs: z.array(z.string()).optional(),
|
|
159
|
+
json: optionalBoolean,
|
|
160
|
+
timeout: optionalPositiveInteger,
|
|
161
|
+
transport: z.enum(['stdio', 'sse', 'streamable-http']).optional(),
|
|
162
|
+
url: nonEmptyString,
|
|
163
|
+
sessionId: nonEmptyString,
|
|
164
|
+
})
|
|
165
|
+
.strict()
|
|
166
|
+
.superRefine((value, ctx) => {
|
|
167
|
+
const transport = value.transport ?? 'stdio';
|
|
168
|
+
const isRemoteTransport = transport === 'sse' || transport === 'streamable-http';
|
|
169
|
+
if (!isRemoteTransport && !value.serverCommand?.trim()) {
|
|
170
|
+
ctx.addIssue({
|
|
171
|
+
code: z.ZodIssueCode.custom,
|
|
172
|
+
message: 'serverCommand is required for stdio transport',
|
|
173
|
+
path: ['serverCommand'],
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
if (isRemoteTransport && !value.url?.trim()) {
|
|
177
|
+
ctx.addIssue({
|
|
178
|
+
code: z.ZodIssueCode.custom,
|
|
179
|
+
message: 'url is required for remote transport',
|
|
180
|
+
path: ['url'],
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
if (!isRemoteTransport && value.url?.trim()) {
|
|
184
|
+
ctx.addIssue({
|
|
185
|
+
code: z.ZodIssueCode.custom,
|
|
186
|
+
message: 'url requires transport sse or streamable-http',
|
|
187
|
+
path: ['url'],
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
const watchArgsSchema = z
|
|
192
|
+
.object({
|
|
193
|
+
configPath: nonEmptyString,
|
|
194
|
+
serverCommand: nonEmptyString,
|
|
195
|
+
serverArgs: z.array(z.string()).optional(),
|
|
196
|
+
})
|
|
197
|
+
.strict();
|
|
198
|
+
const baselineSaveArgsSchema = z
|
|
199
|
+
.object({
|
|
200
|
+
configPath: nonEmptyString,
|
|
201
|
+
baselinePath: nonEmptyString,
|
|
202
|
+
reportPath: nonEmptyString,
|
|
203
|
+
force: optionalBoolean,
|
|
204
|
+
})
|
|
205
|
+
.strict();
|
|
206
|
+
const baselineCompareArgsSchema = z
|
|
207
|
+
.object({
|
|
208
|
+
configPath: nonEmptyString,
|
|
209
|
+
baselinePath: nonEmptyString,
|
|
210
|
+
reportPath: nonEmptyString,
|
|
211
|
+
format: z.enum(['text', 'json', 'markdown', 'compact']).optional(),
|
|
212
|
+
failOnDrift: optionalBoolean,
|
|
213
|
+
ignoreVersionMismatch: optionalBoolean,
|
|
214
|
+
})
|
|
215
|
+
.strict();
|
|
216
|
+
const baselineShowArgsSchema = z
|
|
217
|
+
.object({
|
|
218
|
+
configPath: nonEmptyString,
|
|
219
|
+
baselinePath: nonEmptyString,
|
|
220
|
+
json: optionalBoolean,
|
|
221
|
+
tools: optionalBoolean,
|
|
222
|
+
assertions: optionalBoolean,
|
|
223
|
+
})
|
|
224
|
+
.strict();
|
|
225
|
+
const baselineDiffArgsSchema = z
|
|
226
|
+
.object({
|
|
227
|
+
configPath: nonEmptyString,
|
|
228
|
+
path1: z.string().transform((value) => value.trim()),
|
|
229
|
+
path2: z.string().transform((value) => value.trim()),
|
|
230
|
+
format: z.enum(['text', 'json', 'markdown', 'compact']).optional(),
|
|
231
|
+
ignoreVersionMismatch: optionalBoolean,
|
|
232
|
+
})
|
|
233
|
+
.strict()
|
|
234
|
+
.superRefine((value, ctx) => {
|
|
235
|
+
if (!value.path1) {
|
|
236
|
+
ctx.addIssue({
|
|
237
|
+
code: z.ZodIssueCode.custom,
|
|
238
|
+
message: 'path1 is required',
|
|
239
|
+
path: ['path1'],
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
if (!value.path2) {
|
|
243
|
+
ctx.addIssue({
|
|
244
|
+
code: z.ZodIssueCode.custom,
|
|
245
|
+
message: 'path2 is required',
|
|
246
|
+
path: ['path2'],
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
const baselineAcceptArgsSchema = z
|
|
251
|
+
.object({
|
|
252
|
+
configPath: nonEmptyString,
|
|
253
|
+
reportPath: nonEmptyString,
|
|
254
|
+
baselinePath: nonEmptyString,
|
|
255
|
+
reason: nonEmptyString,
|
|
256
|
+
acceptedBy: nonEmptyString,
|
|
257
|
+
dryRun: optionalBoolean,
|
|
258
|
+
force: optionalBoolean,
|
|
259
|
+
})
|
|
260
|
+
.strict();
|
|
261
|
+
const registrySearchArgsSchema = z
|
|
262
|
+
.object({
|
|
263
|
+
configPath: nonEmptyString,
|
|
264
|
+
query: nonEmptyString,
|
|
265
|
+
limit: optionalPositiveInteger,
|
|
266
|
+
json: optionalBoolean,
|
|
267
|
+
})
|
|
268
|
+
.strict();
|
|
269
|
+
const contractValidateArgsSchema = z
|
|
270
|
+
.object({
|
|
271
|
+
configPath: nonEmptyString,
|
|
272
|
+
serverCommand: z.string().transform((value) => value.trim()),
|
|
273
|
+
serverArgs: z.array(z.string()).optional(),
|
|
274
|
+
contractPath: nonEmptyString,
|
|
275
|
+
mode: z.enum(['strict', 'lenient', 'report']).optional(),
|
|
276
|
+
failOnViolation: optionalBoolean,
|
|
277
|
+
format: z.enum(['text', 'json', 'markdown']).optional(),
|
|
278
|
+
timeout: optionalPositiveInteger,
|
|
279
|
+
})
|
|
280
|
+
.strict()
|
|
281
|
+
.superRefine((value, ctx) => {
|
|
282
|
+
if (!value.serverCommand) {
|
|
283
|
+
ctx.addIssue({
|
|
284
|
+
code: z.ZodIssueCode.custom,
|
|
285
|
+
message: 'serverCommand is required',
|
|
286
|
+
path: ['serverCommand'],
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
const contractGenerateArgsSchema = z
|
|
291
|
+
.object({
|
|
292
|
+
configPath: nonEmptyString,
|
|
293
|
+
serverCommand: z.string().transform((value) => value.trim()),
|
|
294
|
+
serverArgs: z.array(z.string()).optional(),
|
|
295
|
+
outputPath: nonEmptyString,
|
|
296
|
+
timeout: optionalPositiveInteger,
|
|
297
|
+
force: optionalBoolean,
|
|
298
|
+
})
|
|
299
|
+
.strict()
|
|
300
|
+
.superRefine((value, ctx) => {
|
|
301
|
+
if (!value.serverCommand) {
|
|
302
|
+
ctx.addIssue({
|
|
303
|
+
code: z.ZodIssueCode.custom,
|
|
304
|
+
message: 'serverCommand is required',
|
|
305
|
+
path: ['serverCommand'],
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
const contractShowArgsSchema = z
|
|
310
|
+
.object({
|
|
311
|
+
configPath: nonEmptyString,
|
|
312
|
+
path: nonEmptyString,
|
|
313
|
+
json: optionalBoolean,
|
|
314
|
+
})
|
|
315
|
+
.strict();
|
|
316
|
+
const goldenSaveArgsSchema = z
|
|
317
|
+
.object({
|
|
318
|
+
configPath: nonEmptyString,
|
|
319
|
+
toolName: z.string().transform((value) => value.trim()),
|
|
320
|
+
argsJson: nonEmptyString,
|
|
321
|
+
mode: z.enum(['exact', 'structural', 'semantic']).optional(),
|
|
322
|
+
allowedDrift: nonEmptyString,
|
|
323
|
+
normalizeTimestamps: optionalBoolean,
|
|
324
|
+
normalizeUuids: optionalBoolean,
|
|
325
|
+
description: nonEmptyString,
|
|
326
|
+
})
|
|
327
|
+
.strict()
|
|
328
|
+
.superRefine((value, ctx) => {
|
|
329
|
+
if (!value.toolName) {
|
|
330
|
+
ctx.addIssue({
|
|
331
|
+
code: z.ZodIssueCode.custom,
|
|
332
|
+
message: 'toolName is required',
|
|
333
|
+
path: ['toolName'],
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
const goldenCompareArgsSchema = z
|
|
338
|
+
.object({
|
|
339
|
+
configPath: nonEmptyString,
|
|
340
|
+
toolName: nonEmptyString,
|
|
341
|
+
failOnDrift: optionalBoolean,
|
|
342
|
+
format: z.enum(['text', 'json', 'markdown']).optional(),
|
|
343
|
+
})
|
|
344
|
+
.strict();
|
|
345
|
+
const goldenListArgsSchema = z
|
|
346
|
+
.object({
|
|
347
|
+
configPath: nonEmptyString,
|
|
348
|
+
format: z.enum(['text', 'json']).optional(),
|
|
349
|
+
})
|
|
350
|
+
.strict();
|
|
351
|
+
const goldenDeleteArgsSchema = z
|
|
352
|
+
.object({
|
|
353
|
+
configPath: nonEmptyString,
|
|
354
|
+
toolName: z.string().transform((value) => value.trim()),
|
|
355
|
+
all: optionalBoolean,
|
|
356
|
+
})
|
|
357
|
+
.strict()
|
|
358
|
+
.superRefine((value, ctx) => {
|
|
359
|
+
if (!value.toolName) {
|
|
360
|
+
ctx.addIssue({
|
|
361
|
+
code: z.ZodIssueCode.custom,
|
|
362
|
+
message: 'toolName is required',
|
|
363
|
+
path: ['toolName'],
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
});
|
|
367
|
+
const runRequestSchema = z.discriminatedUnion('profile', [
|
|
368
|
+
z.object({
|
|
369
|
+
profile: z.literal('check'),
|
|
370
|
+
args: serverCommandArgsSchema.optional().default({}),
|
|
371
|
+
}),
|
|
372
|
+
z.object({
|
|
373
|
+
profile: z.literal('explore'),
|
|
374
|
+
args: serverCommandArgsSchema.optional().default({}),
|
|
375
|
+
}),
|
|
376
|
+
z.object({
|
|
377
|
+
profile: z.literal('validate-config'),
|
|
378
|
+
args: validateConfigArgsSchema.optional().default({}),
|
|
379
|
+
}),
|
|
380
|
+
z.object({
|
|
381
|
+
profile: z.literal('discover'),
|
|
382
|
+
args: discoverArgsSchema.optional().default({}),
|
|
383
|
+
}),
|
|
384
|
+
z.object({
|
|
385
|
+
profile: z.literal('watch'),
|
|
386
|
+
args: watchArgsSchema.optional().default({}),
|
|
387
|
+
}),
|
|
388
|
+
z.object({
|
|
389
|
+
profile: z.literal('baseline.save'),
|
|
390
|
+
args: baselineSaveArgsSchema.optional().default({}),
|
|
391
|
+
}),
|
|
392
|
+
z.object({
|
|
393
|
+
profile: z.literal('baseline.compare'),
|
|
394
|
+
args: baselineCompareArgsSchema.optional().default({}),
|
|
395
|
+
}),
|
|
396
|
+
z.object({
|
|
397
|
+
profile: z.literal('baseline.show'),
|
|
398
|
+
args: baselineShowArgsSchema.optional().default({}),
|
|
399
|
+
}),
|
|
400
|
+
z.object({
|
|
401
|
+
profile: z.literal('baseline.diff'),
|
|
402
|
+
args: baselineDiffArgsSchema,
|
|
403
|
+
}),
|
|
404
|
+
z.object({
|
|
405
|
+
profile: z.literal('baseline.accept'),
|
|
406
|
+
args: baselineAcceptArgsSchema.optional().default({}),
|
|
407
|
+
}),
|
|
408
|
+
z.object({
|
|
409
|
+
profile: z.literal('registry.search'),
|
|
410
|
+
args: registrySearchArgsSchema.optional().default({}),
|
|
411
|
+
}),
|
|
412
|
+
z.object({
|
|
413
|
+
profile: z.literal('contract.validate'),
|
|
414
|
+
args: contractValidateArgsSchema,
|
|
415
|
+
}),
|
|
416
|
+
z.object({
|
|
417
|
+
profile: z.literal('contract.generate'),
|
|
418
|
+
args: contractGenerateArgsSchema,
|
|
419
|
+
}),
|
|
420
|
+
z.object({
|
|
421
|
+
profile: z.literal('contract.show'),
|
|
422
|
+
args: contractShowArgsSchema.optional().default({}),
|
|
423
|
+
}),
|
|
424
|
+
z.object({
|
|
425
|
+
profile: z.literal('golden.save'),
|
|
426
|
+
args: goldenSaveArgsSchema,
|
|
427
|
+
}),
|
|
428
|
+
z.object({
|
|
429
|
+
profile: z.literal('golden.compare'),
|
|
430
|
+
args: goldenCompareArgsSchema.optional().default({}),
|
|
431
|
+
}),
|
|
432
|
+
z.object({
|
|
433
|
+
profile: z.literal('golden.list'),
|
|
434
|
+
args: goldenListArgsSchema.optional().default({}),
|
|
435
|
+
}),
|
|
436
|
+
z.object({
|
|
437
|
+
profile: z.literal('golden.delete'),
|
|
438
|
+
args: goldenDeleteArgsSchema,
|
|
439
|
+
}),
|
|
440
|
+
]);
|
|
441
|
+
function normalizeString(value) {
|
|
442
|
+
const normalized = value?.trim();
|
|
443
|
+
if (!normalized) {
|
|
444
|
+
return undefined;
|
|
445
|
+
}
|
|
446
|
+
return normalized;
|
|
447
|
+
}
|
|
448
|
+
function normalizeServerArgs(args) {
|
|
449
|
+
if (!args) {
|
|
450
|
+
return [];
|
|
451
|
+
}
|
|
452
|
+
return args.map((arg) => arg.trim()).filter((arg) => arg.length > 0);
|
|
453
|
+
}
|
|
454
|
+
function pushOptionIfValue(args, option, value) {
|
|
455
|
+
if (value) {
|
|
456
|
+
args.push(option, value);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
function pushFlagIfTrue(args, enabled, option) {
|
|
460
|
+
if (enabled) {
|
|
461
|
+
args.push(option);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
function pushOptionIfNumber(args, option, value) {
|
|
465
|
+
if (typeof value === 'number') {
|
|
466
|
+
args.push(option, String(value));
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
function buildServerCommandArgs(commandName, args) {
|
|
470
|
+
const commandArgs = [commandName];
|
|
471
|
+
const configPath = normalizeString(args.configPath);
|
|
472
|
+
const serverCommand = normalizeString(args.serverCommand);
|
|
473
|
+
const serverArgs = normalizeServerArgs(args.serverArgs);
|
|
474
|
+
pushOptionIfValue(commandArgs, '--config', configPath);
|
|
475
|
+
if (serverCommand) {
|
|
476
|
+
commandArgs.push(serverCommand, ...serverArgs);
|
|
477
|
+
}
|
|
478
|
+
return commandArgs;
|
|
479
|
+
}
|
|
480
|
+
function buildValidateConfigArgs(args) {
|
|
481
|
+
const commandArgs = ['validate-config'];
|
|
482
|
+
pushOptionIfValue(commandArgs, '--config', normalizeString(args.configPath));
|
|
483
|
+
return commandArgs;
|
|
484
|
+
}
|
|
485
|
+
function buildDiscoverArgs(args) {
|
|
486
|
+
const value = args;
|
|
487
|
+
const commandArgs = ['discover'];
|
|
488
|
+
pushOptionIfValue(commandArgs, '--config', normalizeString(value.configPath));
|
|
489
|
+
pushFlagIfTrue(commandArgs, value.json, '--json');
|
|
490
|
+
pushOptionIfNumber(commandArgs, '--timeout', value.timeout);
|
|
491
|
+
pushOptionIfValue(commandArgs, '--transport', value.transport);
|
|
492
|
+
pushOptionIfValue(commandArgs, '--url', normalizeString(value.url));
|
|
493
|
+
pushOptionIfValue(commandArgs, '--session-id', normalizeString(value.sessionId));
|
|
494
|
+
const serverCommand = normalizeString(value.serverCommand);
|
|
495
|
+
if (serverCommand) {
|
|
496
|
+
commandArgs.push(serverCommand, ...normalizeServerArgs(value.serverArgs));
|
|
497
|
+
}
|
|
498
|
+
return commandArgs;
|
|
499
|
+
}
|
|
500
|
+
function buildBaselineSaveArgs(args) {
|
|
501
|
+
const commandArgs = ['baseline', 'save'];
|
|
502
|
+
const value = args;
|
|
503
|
+
const baselinePath = normalizeString(value.baselinePath);
|
|
504
|
+
if (baselinePath) {
|
|
505
|
+
commandArgs.push(baselinePath);
|
|
506
|
+
}
|
|
507
|
+
pushOptionIfValue(commandArgs, '--config', normalizeString(value.configPath));
|
|
508
|
+
pushOptionIfValue(commandArgs, '--report', normalizeString(value.reportPath));
|
|
509
|
+
pushFlagIfTrue(commandArgs, value.force, '--force');
|
|
510
|
+
return commandArgs;
|
|
511
|
+
}
|
|
512
|
+
function buildBaselineCompareArgs(args) {
|
|
513
|
+
const commandArgs = ['baseline', 'compare'];
|
|
514
|
+
const value = args;
|
|
515
|
+
const baselinePath = normalizeString(value.baselinePath);
|
|
516
|
+
if (baselinePath) {
|
|
517
|
+
commandArgs.push(baselinePath);
|
|
518
|
+
}
|
|
519
|
+
pushOptionIfValue(commandArgs, '--config', normalizeString(value.configPath));
|
|
520
|
+
pushOptionIfValue(commandArgs, '--report', normalizeString(value.reportPath));
|
|
521
|
+
pushOptionIfValue(commandArgs, '--format', value.format);
|
|
522
|
+
pushFlagIfTrue(commandArgs, value.failOnDrift, '--fail-on-drift');
|
|
523
|
+
pushFlagIfTrue(commandArgs, value.ignoreVersionMismatch, '--ignore-version-mismatch');
|
|
524
|
+
return commandArgs;
|
|
525
|
+
}
|
|
526
|
+
function buildBaselineShowArgs(args) {
|
|
527
|
+
const commandArgs = ['baseline', 'show'];
|
|
528
|
+
const value = args;
|
|
529
|
+
const baselinePath = normalizeString(value.baselinePath);
|
|
530
|
+
if (baselinePath) {
|
|
531
|
+
commandArgs.push(baselinePath);
|
|
532
|
+
}
|
|
533
|
+
pushOptionIfValue(commandArgs, '--config', normalizeString(value.configPath));
|
|
534
|
+
pushFlagIfTrue(commandArgs, value.json, '--json');
|
|
535
|
+
pushFlagIfTrue(commandArgs, value.tools, '--tools');
|
|
536
|
+
pushFlagIfTrue(commandArgs, value.assertions, '--assertions');
|
|
537
|
+
return commandArgs;
|
|
538
|
+
}
|
|
539
|
+
function buildBaselineDiffArgs(args) {
|
|
540
|
+
const value = args;
|
|
541
|
+
const commandArgs = ['baseline', 'diff', value.path1.trim(), value.path2.trim()];
|
|
542
|
+
pushOptionIfValue(commandArgs, '--config', normalizeString(value.configPath));
|
|
543
|
+
pushOptionIfValue(commandArgs, '--format', value.format);
|
|
544
|
+
pushFlagIfTrue(commandArgs, value.ignoreVersionMismatch, '--ignore-version-mismatch');
|
|
545
|
+
return commandArgs;
|
|
546
|
+
}
|
|
547
|
+
function buildBaselineAcceptArgs(args) {
|
|
548
|
+
const commandArgs = ['baseline', 'accept'];
|
|
549
|
+
const value = args;
|
|
550
|
+
pushOptionIfValue(commandArgs, '--config', normalizeString(value.configPath));
|
|
551
|
+
pushOptionIfValue(commandArgs, '--report', normalizeString(value.reportPath));
|
|
552
|
+
pushOptionIfValue(commandArgs, '--baseline', normalizeString(value.baselinePath));
|
|
553
|
+
pushOptionIfValue(commandArgs, '--reason', normalizeString(value.reason));
|
|
554
|
+
pushOptionIfValue(commandArgs, '--accepted-by', normalizeString(value.acceptedBy));
|
|
555
|
+
pushFlagIfTrue(commandArgs, value.dryRun, '--dry-run');
|
|
556
|
+
pushFlagIfTrue(commandArgs, value.force, '--force');
|
|
557
|
+
return commandArgs;
|
|
558
|
+
}
|
|
559
|
+
function buildRegistrySearchArgs(args) {
|
|
560
|
+
const commandArgs = ['registry'];
|
|
561
|
+
const value = args;
|
|
562
|
+
pushOptionIfValue(commandArgs, '--config', normalizeString(value.configPath));
|
|
563
|
+
pushOptionIfNumber(commandArgs, '--limit', value.limit);
|
|
564
|
+
pushFlagIfTrue(commandArgs, value.json, '--json');
|
|
565
|
+
const query = normalizeString(value.query);
|
|
566
|
+
if (query) {
|
|
567
|
+
commandArgs.push(query);
|
|
568
|
+
}
|
|
569
|
+
return commandArgs;
|
|
570
|
+
}
|
|
571
|
+
function buildContractValidateArgs(args) {
|
|
572
|
+
const commandArgs = ['contract', 'validate'];
|
|
573
|
+
const value = args;
|
|
574
|
+
pushOptionIfValue(commandArgs, '--config', normalizeString(value.configPath));
|
|
575
|
+
pushOptionIfValue(commandArgs, '--contract', normalizeString(value.contractPath));
|
|
576
|
+
pushOptionIfValue(commandArgs, '--mode', value.mode);
|
|
577
|
+
pushOptionIfValue(commandArgs, '--format', value.format);
|
|
578
|
+
pushOptionIfNumber(commandArgs, '--timeout', value.timeout);
|
|
579
|
+
pushFlagIfTrue(commandArgs, value.failOnViolation, '--fail-on-violation');
|
|
580
|
+
commandArgs.push(value.serverCommand, ...normalizeServerArgs(value.serverArgs));
|
|
581
|
+
return commandArgs;
|
|
582
|
+
}
|
|
583
|
+
function buildContractGenerateArgs(args) {
|
|
584
|
+
const commandArgs = ['contract', 'generate'];
|
|
585
|
+
const value = args;
|
|
586
|
+
pushOptionIfValue(commandArgs, '--config', normalizeString(value.configPath));
|
|
587
|
+
pushOptionIfValue(commandArgs, '--output', normalizeString(value.outputPath));
|
|
588
|
+
pushOptionIfNumber(commandArgs, '--timeout', value.timeout);
|
|
589
|
+
pushFlagIfTrue(commandArgs, value.force, '--force');
|
|
590
|
+
commandArgs.push(value.serverCommand, ...normalizeServerArgs(value.serverArgs));
|
|
591
|
+
return commandArgs;
|
|
592
|
+
}
|
|
593
|
+
function buildContractShowArgs(args) {
|
|
594
|
+
const commandArgs = ['contract', 'show'];
|
|
595
|
+
const value = args;
|
|
596
|
+
const path = normalizeString(value.path);
|
|
597
|
+
if (path) {
|
|
598
|
+
commandArgs.push(path);
|
|
599
|
+
}
|
|
600
|
+
pushOptionIfValue(commandArgs, '--config', normalizeString(value.configPath));
|
|
601
|
+
pushFlagIfTrue(commandArgs, value.json, '--json');
|
|
602
|
+
return commandArgs;
|
|
603
|
+
}
|
|
604
|
+
function buildGoldenSaveArgs(args) {
|
|
605
|
+
const commandArgs = ['golden', 'save'];
|
|
606
|
+
const value = args;
|
|
607
|
+
commandArgs.push('--tool', value.toolName);
|
|
608
|
+
pushOptionIfValue(commandArgs, '--config', normalizeString(value.configPath));
|
|
609
|
+
pushOptionIfValue(commandArgs, '--args', normalizeString(value.argsJson));
|
|
610
|
+
pushOptionIfValue(commandArgs, '--mode', value.mode);
|
|
611
|
+
pushOptionIfValue(commandArgs, '--allowed-drift', normalizeString(value.allowedDrift));
|
|
612
|
+
if (value.normalizeTimestamps === false) {
|
|
613
|
+
commandArgs.push('--no-normalize-timestamps');
|
|
614
|
+
}
|
|
615
|
+
if (value.normalizeUuids === false) {
|
|
616
|
+
commandArgs.push('--no-normalize-uuids');
|
|
617
|
+
}
|
|
618
|
+
pushOptionIfValue(commandArgs, '--description', normalizeString(value.description));
|
|
619
|
+
return commandArgs;
|
|
620
|
+
}
|
|
621
|
+
function buildGoldenCompareArgs(args) {
|
|
622
|
+
const commandArgs = ['golden', 'compare'];
|
|
623
|
+
const value = args;
|
|
624
|
+
pushOptionIfValue(commandArgs, '--config', normalizeString(value.configPath));
|
|
625
|
+
pushOptionIfValue(commandArgs, '--tool', normalizeString(value.toolName));
|
|
626
|
+
pushFlagIfTrue(commandArgs, value.failOnDrift, '--fail-on-drift');
|
|
627
|
+
pushOptionIfValue(commandArgs, '--format', value.format);
|
|
628
|
+
return commandArgs;
|
|
629
|
+
}
|
|
630
|
+
function buildGoldenListArgs(args) {
|
|
631
|
+
const commandArgs = ['golden', 'list'];
|
|
632
|
+
const value = args;
|
|
633
|
+
pushOptionIfValue(commandArgs, '--config', normalizeString(value.configPath));
|
|
634
|
+
pushOptionIfValue(commandArgs, '--format', value.format);
|
|
635
|
+
return commandArgs;
|
|
636
|
+
}
|
|
637
|
+
function buildGoldenDeleteArgs(args) {
|
|
638
|
+
const commandArgs = ['golden', 'delete'];
|
|
639
|
+
const value = args;
|
|
640
|
+
commandArgs.push('--tool', value.toolName);
|
|
641
|
+
pushOptionIfValue(commandArgs, '--config', normalizeString(value.configPath));
|
|
642
|
+
pushFlagIfTrue(commandArgs, value.all, '--all');
|
|
643
|
+
return commandArgs;
|
|
644
|
+
}
|
|
645
|
+
export function listDashboardProfiles() {
|
|
646
|
+
return dashboardProfiles.map((profile) => ({ ...profile }));
|
|
647
|
+
}
|
|
648
|
+
export function parseDashboardRunRequest(request) {
|
|
649
|
+
return runRequestSchema.parse(request);
|
|
650
|
+
}
|
|
651
|
+
export function buildBellwetherArgs(request) {
|
|
652
|
+
switch (request.profile) {
|
|
653
|
+
case 'check':
|
|
654
|
+
return buildServerCommandArgs('check', request.args);
|
|
655
|
+
case 'explore':
|
|
656
|
+
return buildServerCommandArgs('explore', request.args);
|
|
657
|
+
case 'validate-config':
|
|
658
|
+
return buildValidateConfigArgs(request.args);
|
|
659
|
+
case 'discover':
|
|
660
|
+
return buildDiscoverArgs(request.args);
|
|
661
|
+
case 'watch':
|
|
662
|
+
return buildServerCommandArgs('watch', request.args);
|
|
663
|
+
case 'baseline.save':
|
|
664
|
+
return buildBaselineSaveArgs(request.args);
|
|
665
|
+
case 'baseline.compare':
|
|
666
|
+
return buildBaselineCompareArgs(request.args);
|
|
667
|
+
case 'baseline.show':
|
|
668
|
+
return buildBaselineShowArgs(request.args);
|
|
669
|
+
case 'baseline.diff':
|
|
670
|
+
return buildBaselineDiffArgs(request.args);
|
|
671
|
+
case 'baseline.accept':
|
|
672
|
+
return buildBaselineAcceptArgs(request.args);
|
|
673
|
+
case 'registry.search':
|
|
674
|
+
return buildRegistrySearchArgs(request.args);
|
|
675
|
+
case 'contract.validate':
|
|
676
|
+
return buildContractValidateArgs(request.args);
|
|
677
|
+
case 'contract.generate':
|
|
678
|
+
return buildContractGenerateArgs(request.args);
|
|
679
|
+
case 'contract.show':
|
|
680
|
+
return buildContractShowArgs(request.args);
|
|
681
|
+
case 'golden.save':
|
|
682
|
+
return buildGoldenSaveArgs(request.args);
|
|
683
|
+
case 'golden.compare':
|
|
684
|
+
return buildGoldenCompareArgs(request.args);
|
|
685
|
+
case 'golden.list':
|
|
686
|
+
return buildGoldenListArgs(request.args);
|
|
687
|
+
case 'golden.delete':
|
|
688
|
+
return buildGoldenDeleteArgs(request.args);
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
//# sourceMappingURL=command-profiles.js.map
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type BellwetherConfig } from '../../config/validator.js';
|
|
2
|
+
export interface DashboardConfigDocument {
|
|
3
|
+
absolutePath: string;
|
|
4
|
+
workspacePath: string;
|
|
5
|
+
exists: boolean;
|
|
6
|
+
content: string;
|
|
7
|
+
}
|
|
8
|
+
export interface DashboardConfigValidationResult {
|
|
9
|
+
valid: boolean;
|
|
10
|
+
warnings: string[];
|
|
11
|
+
config: BellwetherConfig;
|
|
12
|
+
}
|
|
13
|
+
export declare function resolveWorkspacePath(cwd: string, targetPath: string): string;
|
|
14
|
+
export declare function resolveConfigPath(cwd: string, explicitPath?: string): string;
|
|
15
|
+
export declare function getConfigDocument(cwd: string, explicitPath?: string): DashboardConfigDocument;
|
|
16
|
+
export declare function saveConfigDocument(cwd: string, explicitPath: string | undefined, content: string): DashboardConfigDocument;
|
|
17
|
+
export declare function validateConfigSource(cwd: string, options: {
|
|
18
|
+
path?: string;
|
|
19
|
+
content?: string;
|
|
20
|
+
}): DashboardConfigValidationResult;
|
|
21
|
+
//# sourceMappingURL=config-service.d.ts.map
|