@dotsetlabs/bellwether 2.1.2 → 2.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +2 -2
  3. package/dist/baseline/golden-output.d.ts +0 -4
  4. package/dist/baseline/golden-output.js +2 -47
  5. package/dist/cli/commands/baseline-accept.js +14 -45
  6. package/dist/cli/commands/baseline.js +23 -78
  7. package/dist/cli/commands/check-formatters.d.ts +10 -0
  8. package/dist/cli/commands/check-formatters.js +160 -0
  9. package/dist/cli/commands/check.js +33 -241
  10. package/dist/cli/commands/contract.js +1 -13
  11. package/dist/cli/commands/explore.js +19 -66
  12. package/dist/cli/commands/watch.js +2 -3
  13. package/dist/cli/output.d.ts +0 -42
  14. package/dist/cli/output.js +73 -110
  15. package/dist/cli/utils/config-loader.d.ts +6 -0
  16. package/dist/cli/utils/config-loader.js +19 -0
  17. package/dist/cli/utils/error-hints.d.ts +9 -0
  18. package/dist/cli/utils/error-hints.js +128 -0
  19. package/dist/cli/utils/headers.js +2 -25
  20. package/dist/cli/utils/path-resolution.d.ts +10 -0
  21. package/dist/cli/utils/path-resolution.js +27 -0
  22. package/dist/cli/utils/report-loader.d.ts +9 -0
  23. package/dist/cli/utils/report-loader.js +31 -0
  24. package/dist/cli/utils/server-runtime.d.ts +16 -0
  25. package/dist/cli/utils/server-runtime.js +31 -0
  26. package/dist/config/defaults.d.ts +0 -1
  27. package/dist/config/defaults.js +0 -1
  28. package/dist/constants/core.d.ts +0 -42
  29. package/dist/constants/core.js +0 -50
  30. package/dist/contract/validator.js +2 -47
  31. package/dist/interview/question-category.d.ts +5 -0
  32. package/dist/interview/question-category.js +2 -0
  33. package/dist/interview/question-types.d.ts +80 -0
  34. package/dist/interview/question-types.js +2 -0
  35. package/dist/interview/schema-test-generator.d.ts +3 -29
  36. package/dist/interview/schema-test-generator.js +11 -286
  37. package/dist/interview/test-fixtures.d.ts +19 -0
  38. package/dist/interview/test-fixtures.js +2 -0
  39. package/dist/interview/types.d.ts +5 -80
  40. package/dist/persona/types.d.ts +3 -5
  41. package/dist/scenarios/types.d.ts +1 -1
  42. package/dist/transport/auth-errors.d.ts +15 -0
  43. package/dist/transport/auth-errors.js +22 -0
  44. package/dist/transport/http-transport.js +7 -9
  45. package/dist/transport/mcp-client.d.ts +0 -4
  46. package/dist/transport/mcp-client.js +13 -37
  47. package/dist/transport/sse-transport.d.ts +0 -1
  48. package/dist/transport/sse-transport.js +13 -28
  49. package/dist/utils/content-type.d.ts +14 -0
  50. package/dist/utils/content-type.js +37 -0
  51. package/dist/utils/http-headers.d.ts +9 -0
  52. package/dist/utils/http-headers.js +34 -0
  53. package/dist/utils/smart-truncate.js +2 -23
  54. package/package.json +2 -2
@@ -55,64 +55,103 @@ export function resetOutput() {
55
55
  export function isQuiet() {
56
56
  return globalConfig.quiet ?? false;
57
57
  }
58
+ function writeInfo(config, message) {
59
+ if (!config.quiet) {
60
+ console.log(message);
61
+ }
62
+ }
63
+ function writeWarn(message) {
64
+ console.warn(message);
65
+ }
66
+ function writeError(message) {
67
+ console.error(message);
68
+ }
69
+ function writeDebug(config, message, verbose) {
70
+ if (verbose && !config.quiet) {
71
+ console.log(message);
72
+ }
73
+ }
74
+ function writeNewline(config) {
75
+ if (!config.quiet) {
76
+ console.log('');
77
+ }
78
+ }
79
+ function writeLines(config, ...messages) {
80
+ if (!config.quiet) {
81
+ for (const msg of messages) {
82
+ console.log(msg);
83
+ }
84
+ }
85
+ }
86
+ function writeSection(config, title) {
87
+ if (!config.quiet) {
88
+ console.log(`\n--- ${title} ---`);
89
+ }
90
+ }
91
+ function writeKeyValue(config, key, value) {
92
+ if (!config.quiet && value !== undefined) {
93
+ console.log(`${key}: ${value}`);
94
+ }
95
+ }
96
+ function writeListItem(config, item, indent) {
97
+ if (!config.quiet) {
98
+ const prefix = `${' '.repeat(indent)}- `;
99
+ console.log(`${prefix}${item}`);
100
+ }
101
+ }
102
+ function writeNumberedList(config, items, startIndex) {
103
+ if (!config.quiet) {
104
+ items.forEach((item, i) => {
105
+ console.log(` ${startIndex + i}) ${item}`);
106
+ });
107
+ }
108
+ }
58
109
  /**
59
110
  * Standard information output.
60
111
  * Use for progress messages, status updates, and general information.
61
112
  */
62
113
  export function info(message) {
63
- if (!globalConfig.quiet) {
64
- console.log(message);
65
- }
114
+ writeInfo(globalConfig, message);
66
115
  }
67
116
  /**
68
117
  * Success message output.
69
118
  * Use for completion messages and positive confirmations.
70
119
  */
71
120
  export function success(message) {
72
- if (!globalConfig.quiet) {
73
- console.log(message);
74
- }
121
+ writeInfo(globalConfig, message);
75
122
  }
76
123
  /**
77
124
  * Warning message output.
78
125
  * Always shown (not suppressed by quiet mode) as warnings are important.
79
126
  */
80
127
  export function warn(message) {
81
- console.warn(message);
128
+ writeWarn(message);
82
129
  }
83
130
  /**
84
131
  * Error message output.
85
132
  * Always shown (not suppressed by quiet mode) as errors are critical.
86
133
  */
87
134
  export function error(message) {
88
- console.error(message);
135
+ writeError(message);
89
136
  }
90
137
  /**
91
138
  * Debug output (only shown in verbose mode).
92
139
  * For detailed information during development/troubleshooting.
93
140
  */
94
141
  export function debug(message, verbose = false) {
95
- if (verbose && !globalConfig.quiet) {
96
- console.log(message);
97
- }
142
+ writeDebug(globalConfig, message, verbose);
98
143
  }
99
144
  /**
100
145
  * Print a blank line for formatting.
101
146
  */
102
147
  export function newline() {
103
- if (!globalConfig.quiet) {
104
- console.log('');
105
- }
148
+ writeNewline(globalConfig);
106
149
  }
107
150
  /**
108
151
  * Print multiple lines.
109
152
  */
110
153
  export function lines(...messages) {
111
- if (!globalConfig.quiet) {
112
- for (const msg of messages) {
113
- console.log(msg);
114
- }
115
- }
154
+ writeLines(globalConfig, ...messages);
116
155
  }
117
156
  /**
118
157
  * Print formatted JSON output.
@@ -125,36 +164,25 @@ export function json(data) {
125
164
  * Print a section header.
126
165
  */
127
166
  export function section(title) {
128
- if (!globalConfig.quiet) {
129
- console.log(`\n--- ${title} ---`);
130
- }
167
+ writeSection(globalConfig, title);
131
168
  }
132
169
  /**
133
170
  * Print a key-value pair.
134
171
  */
135
172
  export function keyValue(key, value) {
136
- if (!globalConfig.quiet && value !== undefined) {
137
- console.log(`${key}: ${value}`);
138
- }
173
+ writeKeyValue(globalConfig, key, value);
139
174
  }
140
175
  /**
141
176
  * Print a list item.
142
177
  */
143
178
  export function listItem(item, indent = 0) {
144
- if (!globalConfig.quiet) {
145
- const prefix = `${' '.repeat(indent)}- `;
146
- console.log(`${prefix}${item}`);
147
- }
179
+ writeListItem(globalConfig, item, indent);
148
180
  }
149
181
  /**
150
182
  * Print numbered list items.
151
183
  */
152
184
  export function numberedList(items, startIndex = 1) {
153
- if (!globalConfig.quiet) {
154
- items.forEach((item, i) => {
155
- console.log(` ${startIndex + i}) ${item}`);
156
- });
157
- }
185
+ writeNumberedList(globalConfig, items, startIndex);
158
186
  }
159
187
  /**
160
188
  * Create a scoped output instance for a specific command.
@@ -172,63 +200,40 @@ export class Output {
172
200
  this.config = config;
173
201
  }
174
202
  info(message) {
175
- if (!this.config.quiet) {
176
- console.log(message);
177
- }
203
+ writeInfo(this.config, message);
178
204
  }
179
205
  success(message) {
180
- if (!this.config.quiet) {
181
- console.log(message);
182
- }
206
+ writeInfo(this.config, message);
183
207
  }
184
208
  warn(message) {
185
- console.warn(message);
209
+ writeWarn(message);
186
210
  }
187
211
  error(message) {
188
- console.error(message);
212
+ writeError(message);
189
213
  }
190
214
  debug(message, verbose = false) {
191
- if (verbose && !this.config.quiet) {
192
- console.log(message);
193
- }
215
+ writeDebug(this.config, message, verbose);
194
216
  }
195
217
  newline() {
196
- if (!this.config.quiet) {
197
- console.log('');
198
- }
218
+ writeNewline(this.config);
199
219
  }
200
220
  lines(...messages) {
201
- if (!this.config.quiet) {
202
- for (const msg of messages) {
203
- console.log(msg);
204
- }
205
- }
221
+ writeLines(this.config, ...messages);
206
222
  }
207
223
  json(data) {
208
224
  console.log(JSON.stringify(data, null, 2));
209
225
  }
210
226
  section(title) {
211
- if (!this.config.quiet) {
212
- console.log(`\n--- ${title} ---`);
213
- }
227
+ writeSection(this.config, title);
214
228
  }
215
229
  keyValue(key, value) {
216
- if (!this.config.quiet && value !== undefined) {
217
- console.log(`${key}: ${value}`);
218
- }
230
+ writeKeyValue(this.config, key, value);
219
231
  }
220
232
  listItem(item, indent = 0) {
221
- if (!this.config.quiet) {
222
- const prefix = `${' '.repeat(indent)}- `;
223
- console.log(`${prefix}${item}`);
224
- }
233
+ writeListItem(this.config, item, indent);
225
234
  }
226
235
  numberedList(items, startIndex = 1) {
227
- if (!this.config.quiet) {
228
- items.forEach((item, i) => {
229
- console.log(` ${startIndex + i}) ${item}`);
230
- });
231
- }
236
+ writeNumberedList(this.config, items, startIndex);
232
237
  }
233
238
  }
234
239
  /**
@@ -415,46 +420,4 @@ export function createStreamingCallback(prefix) {
415
420
  },
416
421
  };
417
422
  }
418
- /**
419
- * Label mapping for diff severity levels.
420
- */
421
- const SEVERITY_LABELS = {
422
- none: '[ok]',
423
- info: '[info]',
424
- warning: '[warn]',
425
- breaking: '[break]',
426
- };
427
- /**
428
- * Get the label for a severity level.
429
- */
430
- export function getSeverityIcon(severity) {
431
- return SEVERITY_LABELS[severity] ?? '?';
432
- }
433
- /**
434
- * Default export for convenient importing.
435
- */
436
- export default {
437
- configureOutput,
438
- getOutputConfig,
439
- resetOutput,
440
- isQuiet,
441
- info,
442
- success,
443
- warn,
444
- error,
445
- debug,
446
- newline,
447
- lines,
448
- json,
449
- section,
450
- keyValue,
451
- listItem,
452
- numberedList,
453
- createOutput,
454
- Output,
455
- StreamingDisplay,
456
- createStreamingDisplay,
457
- createStreamingCallback,
458
- getSeverityIcon,
459
- };
460
423
  //# sourceMappingURL=output.js.map
@@ -0,0 +1,6 @@
1
+ import { type BellwetherConfig } from '../../config/loader.js';
2
+ /**
3
+ * Load configuration and exit with a user-friendly message when missing.
4
+ */
5
+ export declare function loadConfigOrExit(configPath?: string): BellwetherConfig;
6
+ //# sourceMappingURL=config-loader.d.ts.map
@@ -0,0 +1,19 @@
1
+ import { loadConfig, ConfigNotFoundError } from '../../config/loader.js';
2
+ import { EXIT_CODES } from '../../constants.js';
3
+ import * as output from '../output.js';
4
+ /**
5
+ * Load configuration and exit with a user-friendly message when missing.
6
+ */
7
+ export function loadConfigOrExit(configPath) {
8
+ try {
9
+ return loadConfig(configPath);
10
+ }
11
+ catch (error) {
12
+ if (error instanceof ConfigNotFoundError) {
13
+ output.error(error.message);
14
+ process.exit(EXIT_CODES.ERROR);
15
+ }
16
+ throw error;
17
+ }
18
+ }
19
+ //# sourceMappingURL=config-loader.js.map
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Shared check-command transport/auth remediation hints.
3
+ */
4
+ export declare function printCheckErrorHints(error: unknown, transport: string): void;
5
+ /**
6
+ * Shared explore-command transport/auth remediation hints.
7
+ */
8
+ export declare function printExploreErrorHints(error: unknown, transport: string): void;
9
+ //# sourceMappingURL=error-hints.d.ts.map
@@ -0,0 +1,128 @@
1
+ import { ServerAuthError } from '../../errors/types.js';
2
+ import * as output from '../output.js';
3
+ function isAuthError(context) {
4
+ const { error, errorMessage } = context;
5
+ return (error instanceof ServerAuthError ||
6
+ errorMessage.includes('401') ||
7
+ errorMessage.includes('403') ||
8
+ errorMessage.includes('407') ||
9
+ /unauthorized|forbidden|authentication|authorization/i.test(errorMessage));
10
+ }
11
+ function isConnectionRefused(context) {
12
+ const { errorMessage } = context;
13
+ return errorMessage.includes('ECONNREFUSED') || errorMessage.includes('Connection refused');
14
+ }
15
+ function isRemoteNotFound(context) {
16
+ return context.isRemoteTransport && context.errorMessage.includes('HTTP 404');
17
+ }
18
+ function isTimeoutError(context) {
19
+ const { errorMessage } = context;
20
+ return errorMessage.includes('timeout') || errorMessage.includes('Timeout');
21
+ }
22
+ function isCommandNotFound(context) {
23
+ const { errorMessage, isRemoteTransport } = context;
24
+ return (!isRemoteTransport && (errorMessage.includes('ENOENT') || errorMessage.includes('not found')));
25
+ }
26
+ function isApiKeyError(context) {
27
+ const { errorMessage } = context;
28
+ return errorMessage.includes('API key') || errorMessage.includes('authentication');
29
+ }
30
+ /**
31
+ * Shared check-command transport/auth remediation hints.
32
+ */
33
+ export function printCheckErrorHints(error, transport) {
34
+ const context = {
35
+ error,
36
+ isRemoteTransport: transport !== 'stdio',
37
+ errorMessage: error instanceof Error ? error.message : String(error),
38
+ };
39
+ if (isAuthError(context)) {
40
+ output.error('\nAuthentication failed:');
41
+ output.error(' - Add server.headers.Authorization in bellwether.yaml');
42
+ output.error(' - Or pass --header "Authorization: Bearer $TOKEN"');
43
+ output.error(' - Verify credentials are valid and not expired');
44
+ return;
45
+ }
46
+ if (isConnectionRefused(context)) {
47
+ output.error('\nPossible causes:');
48
+ if (context.isRemoteTransport) {
49
+ output.error(' - The remote MCP server is not reachable');
50
+ output.error(' - The server URL/port is incorrect');
51
+ }
52
+ else {
53
+ output.error(' - The MCP server is not running');
54
+ output.error(' - The server address/port is incorrect');
55
+ }
56
+ return;
57
+ }
58
+ if (isRemoteNotFound(context)) {
59
+ output.error('\nPossible causes:');
60
+ output.error(' - The remote MCP URL is incorrect');
61
+ output.error(' - For SSE transport, verify the server exposes /sse');
62
+ return;
63
+ }
64
+ if (isTimeoutError(context)) {
65
+ output.error('\nPossible causes:');
66
+ output.error(' - The MCP server is taking too long to respond');
67
+ output.error(' - Increase server.timeout in bellwether.yaml');
68
+ return;
69
+ }
70
+ if (isCommandNotFound(context)) {
71
+ output.error('\nPossible causes:');
72
+ output.error(' - The server command was not found');
73
+ output.error(' - Check that the command is installed and in PATH');
74
+ }
75
+ }
76
+ /**
77
+ * Shared explore-command transport/auth remediation hints.
78
+ */
79
+ export function printExploreErrorHints(error, transport) {
80
+ const context = {
81
+ error,
82
+ isRemoteTransport: transport !== 'stdio',
83
+ errorMessage: error instanceof Error ? error.message : String(error),
84
+ };
85
+ if (isAuthError(context)) {
86
+ output.error('\nPossible causes:');
87
+ output.error(' - Missing or invalid remote MCP authentication headers');
88
+ output.error(' - Add server.headers.Authorization or pass --header "Authorization: Bearer $TOKEN"');
89
+ output.error(' - Verify token scopes/permissions');
90
+ return;
91
+ }
92
+ if (isConnectionRefused(context)) {
93
+ output.error('\nPossible causes:');
94
+ if (context.isRemoteTransport) {
95
+ output.error(' - The remote MCP server is not reachable');
96
+ output.error(' - The server URL/port is incorrect');
97
+ }
98
+ else {
99
+ output.error(' - The MCP server is not running');
100
+ output.error(' - The server address/port is incorrect');
101
+ }
102
+ return;
103
+ }
104
+ if (isRemoteNotFound(context)) {
105
+ output.error('\nPossible causes:');
106
+ output.error(' - The remote MCP URL is incorrect');
107
+ output.error(' - For SSE transport, verify the server exposes /sse');
108
+ return;
109
+ }
110
+ if (isTimeoutError(context)) {
111
+ output.error('\nPossible causes:');
112
+ output.error(' - The MCP server is taking too long to respond');
113
+ output.error(' - Increase server.timeout in bellwether.yaml');
114
+ return;
115
+ }
116
+ if (isCommandNotFound(context)) {
117
+ output.error('\nPossible causes:');
118
+ output.error(' - The server command was not found');
119
+ output.error(' - Check that the command is installed and in PATH');
120
+ return;
121
+ }
122
+ if (isApiKeyError(context)) {
123
+ output.error('\nPossible causes:');
124
+ output.error(' - Missing or invalid API key');
125
+ output.error(' - Run "bellwether auth" to configure API keys');
126
+ }
127
+ }
128
+ //# sourceMappingURL=error-hints.js.map
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * Utilities for parsing and merging HTTP headers from CLI/config.
3
3
  */
4
+ import { mergeHeaderMaps, setHeaderCaseInsensitive } from '../../utils/http-headers.js';
4
5
  const HEADER_NAME_PATTERN = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
5
6
  /**
6
7
  * Parse CLI --header values ("Name: value") into a validated header map.
@@ -34,30 +35,6 @@ export function parseCliHeaders(values) {
34
35
  * Merge two header maps case-insensitively, with override precedence.
35
36
  */
36
37
  export function mergeHeaders(base, override) {
37
- if (!base && !override) {
38
- return undefined;
39
- }
40
- const merged = {};
41
- if (base) {
42
- for (const [name, value] of Object.entries(base)) {
43
- setHeaderCaseInsensitive(merged, name, value);
44
- }
45
- }
46
- if (override) {
47
- for (const [name, value] of Object.entries(override)) {
48
- setHeaderCaseInsensitive(merged, name, value);
49
- }
50
- }
51
- return Object.keys(merged).length > 0 ? merged : undefined;
52
- }
53
- function setHeaderCaseInsensitive(headers, name, value) {
54
- const normalized = name.toLowerCase();
55
- for (const existing of Object.keys(headers)) {
56
- if (existing.toLowerCase() === normalized) {
57
- delete headers[existing];
58
- break;
59
- }
60
- }
61
- headers[name] = value;
38
+ return mergeHeaderMaps(base, override);
62
39
  }
63
40
  //# sourceMappingURL=headers.js.map
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Resolve a possibly relative path against the output directory.
3
+ */
4
+ export declare function resolvePathFromOutputDir(path: string, outputDir: string): string;
5
+ /**
6
+ * Resolve path using output dir first, then cwd fallback.
7
+ * Keeps existing baseline compare behavior for user-provided relative paths.
8
+ */
9
+ export declare function resolvePathFromOutputDirOrCwd(path: string, outputDir: string): string;
10
+ //# sourceMappingURL=path-resolution.d.ts.map
@@ -0,0 +1,27 @@
1
+ import { existsSync } from 'fs';
2
+ import { isAbsolute, join } from 'path';
3
+ /**
4
+ * Resolve a possibly relative path against the output directory.
5
+ */
6
+ export function resolvePathFromOutputDir(path, outputDir) {
7
+ return isAbsolute(path) ? path : join(outputDir, path);
8
+ }
9
+ /**
10
+ * Resolve path using output dir first, then cwd fallback.
11
+ * Keeps existing baseline compare behavior for user-provided relative paths.
12
+ */
13
+ export function resolvePathFromOutputDirOrCwd(path, outputDir) {
14
+ if (isAbsolute(path)) {
15
+ return path;
16
+ }
17
+ const outputDirPath = join(outputDir, path);
18
+ if (existsSync(outputDirPath)) {
19
+ return outputDirPath;
20
+ }
21
+ const cwdPath = join(process.cwd(), path);
22
+ if (existsSync(cwdPath)) {
23
+ return cwdPath;
24
+ }
25
+ return outputDirPath;
26
+ }
27
+ //# sourceMappingURL=path-resolution.js.map
@@ -0,0 +1,9 @@
1
+ import type { InterviewResult } from '../../interview/types.js';
2
+ /**
3
+ * Load a check-mode interview report from JSON.
4
+ */
5
+ export declare function loadCheckInterviewResult(reportPath: string, options?: {
6
+ missingReportMessage?: string;
7
+ invalidModeMessage?: (model: string | undefined) => string;
8
+ }): InterviewResult;
9
+ //# sourceMappingURL=report-loader.d.ts.map
@@ -0,0 +1,31 @@
1
+ import { existsSync, readFileSync } from 'fs';
2
+ const DEFAULT_MISSING_REPORT_MESSAGE = 'Run `bellwether check` first with JSON output enabled.\n' +
3
+ 'Configure in bellwether.yaml:\n' +
4
+ ' output:\n' +
5
+ ' format: json # or "both" for JSON + markdown';
6
+ /**
7
+ * Load a check-mode interview report from JSON.
8
+ */
9
+ export function loadCheckInterviewResult(reportPath, options) {
10
+ if (!existsSync(reportPath)) {
11
+ throw new Error(`Test report not found: ${reportPath}\n\n${options?.missingReportMessage ?? DEFAULT_MISSING_REPORT_MESSAGE}`);
12
+ }
13
+ const content = readFileSync(reportPath, 'utf-8');
14
+ let result;
15
+ try {
16
+ result = JSON.parse(content);
17
+ }
18
+ catch (error) {
19
+ throw new Error(`Invalid JSON in report file ${reportPath}: ${error instanceof Error ? error.message : 'Unknown error'}`);
20
+ }
21
+ if (result.metadata.model && result.metadata.model !== 'check') {
22
+ if (options?.invalidModeMessage) {
23
+ throw new Error(options.invalidModeMessage(result.metadata.model));
24
+ }
25
+ throw new Error(`Baseline operations only work with check mode results.\n\n` +
26
+ `The report at ${reportPath} was created with explore mode (model: ${result.metadata.model}).\n` +
27
+ 'Run `bellwether check` to generate a check mode report first.');
28
+ }
29
+ return result;
30
+ }
31
+ //# sourceMappingURL=report-loader.js.map
@@ -0,0 +1,16 @@
1
+ import { type BellwetherConfig } from '../../config/loader.js';
2
+ import type { TransportType } from '../../transport/base-transport.js';
3
+ export interface ResolvedServerRuntime {
4
+ serverCommand: string;
5
+ args: string[];
6
+ transport: TransportType;
7
+ remoteUrl?: string;
8
+ remoteSessionId?: string;
9
+ remoteHeaders?: Record<string, string>;
10
+ serverIdentifier: string;
11
+ }
12
+ /**
13
+ * Resolve server command, args, transport, and headers from config + CLI inputs.
14
+ */
15
+ export declare function resolveServerRuntime(config: BellwetherConfig, serverCommandArg: string | undefined, serverArgs: string[], headerValues?: string[]): ResolvedServerRuntime;
16
+ //# sourceMappingURL=server-runtime.d.ts.map
@@ -0,0 +1,31 @@
1
+ import { parseCommandString, } from '../../config/loader.js';
2
+ import { mergeHeaders, parseCliHeaders } from './headers.js';
3
+ /**
4
+ * Resolve server command, args, transport, and headers from config + CLI inputs.
5
+ */
6
+ export function resolveServerRuntime(config, serverCommandArg, serverArgs, headerValues) {
7
+ const serverConfig = config.server;
8
+ let serverCommand = serverCommandArg || serverConfig.command;
9
+ let args = serverArgs.length > 0 ? serverArgs : serverConfig.args;
10
+ if (!serverCommandArg && args.length === 0 && serverCommand.includes(' ')) {
11
+ const parsed = parseCommandString(serverCommand);
12
+ serverCommand = parsed.command;
13
+ args = parsed.args;
14
+ }
15
+ const transport = (serverConfig.transport ?? 'stdio');
16
+ const remoteUrl = serverConfig.url?.trim();
17
+ const remoteSessionId = serverConfig.sessionId?.trim();
18
+ const cliHeaders = parseCliHeaders(headerValues);
19
+ const remoteHeaders = mergeHeaders(serverConfig.headers, cliHeaders);
20
+ const serverIdentifier = transport === 'stdio' ? `${serverCommand} ${args.join(' ')}`.trim() : (remoteUrl ?? 'unknown');
21
+ return {
22
+ serverCommand,
23
+ args,
24
+ transport,
25
+ remoteUrl: remoteUrl || undefined,
26
+ remoteSessionId: remoteSessionId || undefined,
27
+ remoteHeaders,
28
+ serverIdentifier,
29
+ };
30
+ }
31
+ //# sourceMappingURL=server-runtime.js.map
@@ -101,7 +101,6 @@ export declare const CONFIG_DEFAULTS: {
101
101
  };
102
102
  readonly baseline: {
103
103
  readonly path: "bellwether-baseline.json";
104
- readonly savePath: ".bellwether/bellwether-baseline.json";
105
104
  readonly failOnDrift: false;
106
105
  readonly outputFormat: "text";
107
106
  readonly severity: {
@@ -110,7 +110,6 @@ export const CONFIG_DEFAULTS = {
110
110
  },
111
111
  baseline: {
112
112
  path: PATHS.DEFAULT_BASELINE_FILE,
113
- savePath: '.bellwether/bellwether-baseline.json',
114
113
  failOnDrift: false,
115
114
  outputFormat: 'text',
116
115
  severity: {