harness-dispatch 0.7.9 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1170 -1
- package/README.md +52 -6
- package/config.default.yaml +49 -5
- package/dist/auth.d.ts +29 -0
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +58 -5
- package/dist/auth.js.map +1 -1
- package/dist/billing.d.ts +24 -0
- package/dist/billing.d.ts.map +1 -1
- package/dist/billing.js +24 -0
- package/dist/billing.js.map +1 -1
- package/dist/bin.d.ts.map +1 -1
- package/dist/bin.js +529 -31
- package/dist/bin.js.map +1 -1
- package/dist/breaker-store.d.ts +25 -1
- package/dist/breaker-store.d.ts.map +1 -1
- package/dist/breaker-store.js +193 -25
- package/dist/breaker-store.js.map +1 -1
- package/dist/circuit-breaker.d.ts +9 -1
- package/dist/circuit-breaker.d.ts.map +1 -1
- package/dist/circuit-breaker.js +15 -1
- package/dist/circuit-breaker.js.map +1 -1
- package/dist/client-register.d.ts +157 -0
- package/dist/client-register.d.ts.map +1 -0
- package/dist/client-register.js +389 -0
- package/dist/client-register.js.map +1 -0
- package/dist/config/validation.d.ts +41 -0
- package/dist/config/validation.d.ts.map +1 -1
- package/dist/config/validation.js +215 -1
- package/dist/config/validation.js.map +1 -1
- package/dist/config.d.ts +4 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +143 -6
- package/dist/config.js.map +1 -1
- package/dist/configure-yaml.d.ts +2 -0
- package/dist/configure-yaml.d.ts.map +1 -1
- package/dist/configure-yaml.js +69 -3
- package/dist/configure-yaml.js.map +1 -1
- package/dist/dispatch-log.d.ts +14 -0
- package/dist/dispatch-log.d.ts.map +1 -1
- package/dist/dispatch-log.js +3 -0
- package/dist/dispatch-log.js.map +1 -1
- package/dist/dispatchers/generic-cli.d.ts.map +1 -1
- package/dist/dispatchers/generic-cli.js +92 -15
- package/dist/dispatchers/generic-cli.js.map +1 -1
- package/dist/dispatchers/openai-compatible.d.ts +20 -4
- package/dist/dispatchers/openai-compatible.d.ts.map +1 -1
- package/dist/dispatchers/openai-compatible.js +167 -19
- package/dist/dispatchers/openai-compatible.js.map +1 -1
- package/dist/dispatchers/shared/harness-login.d.ts +25 -0
- package/dist/dispatchers/shared/harness-login.d.ts.map +1 -0
- package/dist/dispatchers/shared/harness-login.js +68 -0
- package/dist/dispatchers/shared/harness-login.js.map +1 -0
- package/dist/dispatchers/shared/stream-subprocess.d.ts.map +1 -1
- package/dist/dispatchers/shared/stream-subprocess.js +70 -4
- package/dist/dispatchers/shared/stream-subprocess.js.map +1 -1
- package/dist/file-lock.d.ts +29 -1
- package/dist/file-lock.d.ts.map +1 -1
- package/dist/file-lock.js +22 -1
- package/dist/file-lock.js.map +1 -1
- package/dist/http/answer-stream.d.ts +52 -0
- package/dist/http/answer-stream.d.ts.map +1 -0
- package/dist/http/answer-stream.js +47 -0
- package/dist/http/answer-stream.js.map +1 -0
- package/dist/http/parse.d.ts.map +1 -1
- package/dist/http/parse.js +41 -0
- package/dist/http/parse.js.map +1 -1
- package/dist/http/server.d.ts +2 -0
- package/dist/http/server.d.ts.map +1 -1
- package/dist/http/server.js +281 -23
- package/dist/http/server.js.map +1 -1
- package/dist/jobs/context.d.ts +0 -7
- package/dist/jobs/context.d.ts.map +1 -1
- package/dist/jobs/context.js +95 -7
- package/dist/jobs/context.js.map +1 -1
- package/dist/jobs/store.d.ts.map +1 -1
- package/dist/jobs/store.js +45 -4
- package/dist/jobs/store.js.map +1 -1
- package/dist/jobs/types.d.ts +8 -1
- package/dist/jobs/types.d.ts.map +1 -1
- package/dist/jobs.d.ts +39 -0
- package/dist/jobs.d.ts.map +1 -1
- package/dist/jobs.js +207 -15
- package/dist/jobs.js.map +1 -1
- package/dist/leaderboard.d.ts.map +1 -1
- package/dist/leaderboard.js +39 -27
- package/dist/leaderboard.js.map +1 -1
- package/dist/mcp/config-hot-reload.d.ts +14 -3
- package/dist/mcp/config-hot-reload.d.ts.map +1 -1
- package/dist/mcp/config-hot-reload.js +33 -5
- package/dist/mcp/config-hot-reload.js.map +1 -1
- package/dist/mcp/dispatcher-factory.d.ts.map +1 -1
- package/dist/mcp/dispatcher-factory.js +14 -3
- package/dist/mcp/dispatcher-factory.js.map +1 -1
- package/dist/mcp/near-miss-guard.d.ts +45 -0
- package/dist/mcp/near-miss-guard.d.ts.map +1 -0
- package/dist/mcp/near-miss-guard.js +98 -0
- package/dist/mcp/near-miss-guard.js.map +1 -0
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +36 -0
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tool-schemas.d.ts +1 -1
- package/dist/mcp/tool-schemas.d.ts.map +1 -1
- package/dist/mcp/tool-schemas.js +27 -7
- package/dist/mcp/tool-schemas.js.map +1 -1
- package/dist/mcp/tools.d.ts +33 -4
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +85 -8
- package/dist/mcp/tools.js.map +1 -1
- package/dist/mcp-clients.d.ts +72 -0
- package/dist/mcp-clients.d.ts.map +1 -0
- package/dist/mcp-clients.js +121 -0
- package/dist/mcp-clients.js.map +1 -0
- package/dist/near-miss.d.ts +63 -0
- package/dist/near-miss.d.ts.map +1 -0
- package/dist/near-miss.js +132 -0
- package/dist/near-miss.js.map +1 -0
- package/dist/quota.d.ts +31 -1
- package/dist/quota.d.ts.map +1 -1
- package/dist/quota.js +84 -8
- package/dist/quota.js.map +1 -1
- package/dist/route-policy.d.ts +12 -1
- package/dist/route-policy.d.ts.map +1 -1
- package/dist/route-policy.js +74 -2
- package/dist/route-policy.js.map +1 -1
- package/dist/router.d.ts +61 -2
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +160 -29
- package/dist/router.js.map +1 -1
- package/dist/safety.d.ts.map +1 -1
- package/dist/safety.js +37 -1
- package/dist/safety.js.map +1 -1
- package/dist/state-dir.d.ts +10 -0
- package/dist/state-dir.d.ts.map +1 -1
- package/dist/state-dir.js +12 -0
- package/dist/state-dir.js.map +1 -1
- package/dist/status.d.ts +30 -21
- package/dist/status.d.ts.map +1 -1
- package/dist/status.js +152 -8
- package/dist/status.js.map +1 -1
- package/dist/types.d.ts +49 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/working-dir.d.ts.map +1 -1
- package/dist/working-dir.js +16 -0
- package/dist/working-dir.js.map +1 -1
- package/dist/workspace-resolve.d.ts.map +1 -1
- package/dist/workspace-resolve.js +196 -15
- package/dist/workspace-resolve.js.map +1 -1
- package/dist/workspaces.d.ts +98 -0
- package/dist/workspaces.d.ts.map +1 -1
- package/dist/workspaces.js +609 -20
- package/dist/workspaces.js.map +1 -1
- package/package.json +1 -1
|
@@ -68,6 +68,9 @@ export const FAIL_OPEN_ENUMS = {
|
|
|
68
68
|
*/
|
|
69
69
|
export const KNOWN_TOP_LEVEL_KEYS = new Set([
|
|
70
70
|
"version",
|
|
71
|
+
// Opt back into auto-detection when a config defines its own routes, or
|
|
72
|
+
// opt out when it does not. See loadConfig for the three cases.
|
|
73
|
+
"detect",
|
|
71
74
|
"clis",
|
|
72
75
|
"endpoints",
|
|
73
76
|
"services",
|
|
@@ -122,6 +125,203 @@ export function warnUnknownRouteKeys(entry, label, warnings) {
|
|
|
122
125
|
warnings.push(`${label}: unknown key "${key}" — IGNORED. If this was meant to be a ` +
|
|
123
126
|
`safety or workspace setting, it is NOT in effect; check the spelling.`);
|
|
124
127
|
}
|
|
128
|
+
warnMistypedRouteValues(entry, label, warnings);
|
|
129
|
+
}
|
|
130
|
+
/** Recognised keys whose value must be a number, and what they mean if lost. */
|
|
131
|
+
const NUMERIC_ROUTE_KEYS = new Set([
|
|
132
|
+
"tier",
|
|
133
|
+
"weight",
|
|
134
|
+
"cli_capability",
|
|
135
|
+
"max_output_tokens",
|
|
136
|
+
"max_input_tokens",
|
|
137
|
+
"timeout_ms",
|
|
138
|
+
]);
|
|
139
|
+
/**
|
|
140
|
+
* The smallest value each numeric route key can carry and still mean anything.
|
|
141
|
+
*
|
|
142
|
+
* Every one of these is positive-only, and being in range is not a style
|
|
143
|
+
* preference — the router multiplies three of them together
|
|
144
|
+
* (`quality * cli_capability * capability * quota * weight`) and orders by
|
|
145
|
+
* `tier` ASCENDING. A negative pair therefore does not degrade a route, it
|
|
146
|
+
* PROMOTES it: an acceptance pass measured `tier: -5, weight: -100,
|
|
147
|
+
* cli_capability: -3` scoring 299.8 against a normal route's 0.88, from a
|
|
148
|
+
* tier that sorts ahead of every real one — a route that wins every routing
|
|
149
|
+
* decision, silently, with no warning anywhere.
|
|
150
|
+
*
|
|
151
|
+
* `tier` starts at 1 because tier 1 is the frontier band and lower sorts
|
|
152
|
+
* first; 0 and below are ahead of a band that already means "best". The rest
|
|
153
|
+
* are exclusive of 0 (a zero weight or capability multiplies the score to
|
|
154
|
+
* nothing, and a zero timeout is not a timeout).
|
|
155
|
+
*
|
|
156
|
+
* No upper bounds. `cli_capability: 1.1` ships in this repo's own default
|
|
157
|
+
* config as deliberate tuning, so a cap would reject a documented value; the
|
|
158
|
+
* defect being fixed is sign, not magnitude.
|
|
159
|
+
*/
|
|
160
|
+
const NUMERIC_ROUTE_MINIMUMS = {
|
|
161
|
+
tier: { min: 1, exclusive: false },
|
|
162
|
+
weight: { min: 0, exclusive: true },
|
|
163
|
+
cli_capability: { min: 0, exclusive: true },
|
|
164
|
+
max_output_tokens: { min: 0, exclusive: true },
|
|
165
|
+
max_input_tokens: { min: 0, exclusive: true },
|
|
166
|
+
timeout_ms: { min: 0, exclusive: true },
|
|
167
|
+
};
|
|
168
|
+
/**
|
|
169
|
+
* Of those, the ones the router actually multiplies into a score.
|
|
170
|
+
*
|
|
171
|
+
* Only these three get the "PROMOTES the route" explanation. Giving that
|
|
172
|
+
* reason for `timeout_ms` or a token cap told the operator something untrue
|
|
173
|
+
* about their own config: routing multiplies neither.
|
|
174
|
+
*/
|
|
175
|
+
const ROUTING_SCORED_KEYS = new Set(["tier", "weight", "cli_capability"]);
|
|
176
|
+
/** Recognised keys whose value must be a boolean. */
|
|
177
|
+
const BOOLEAN_ROUTE_KEYS = new Set([
|
|
178
|
+
"enabled",
|
|
179
|
+
"paid_usage_possible",
|
|
180
|
+
"allow_paid_usage",
|
|
181
|
+
"stdin",
|
|
182
|
+
]);
|
|
183
|
+
/**
|
|
184
|
+
* Is this a value that reads as a USABLE number?
|
|
185
|
+
*
|
|
186
|
+
* Finite on both branches, and the string branch is the one that was wrong:
|
|
187
|
+
* `Number("1e999")` is `Infinity`, and `!Number.isNaN(Infinity)` is true, so a
|
|
188
|
+
* YAML `weight: 1e999` (which parses as a string, not a number) sailed through
|
|
189
|
+
* as "reads as a number", then sailed through the range check too — `Infinity`
|
|
190
|
+
* is not below any minimum. An acceptance pass measured it loading as
|
|
191
|
+
* `weight = Infinity` with NO warning of any kind.
|
|
192
|
+
*
|
|
193
|
+
* `Number.isFinite` on both branches closes that: `.inf`, `-.inf`, `.nan` and
|
|
194
|
+
* `1e999` are all unusable, whichever way YAML happened to type them.
|
|
195
|
+
*/
|
|
196
|
+
function readsAsNumber(v) {
|
|
197
|
+
if (typeof v === "number")
|
|
198
|
+
return Number.isFinite(v);
|
|
199
|
+
return typeof v === "string" && v !== "" && Number.isFinite(Number(v));
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* How to name the offending value back to the operator.
|
|
203
|
+
*
|
|
204
|
+
* `JSON.stringify` has no representation for the non-finite numbers and emits
|
|
205
|
+
* `null`, so a warning about YAML's `-.inf` read "tier is null" — naming a
|
|
206
|
+
* value that appears nowhere in the file the reader is being asked to fix.
|
|
207
|
+
*/
|
|
208
|
+
function describeValue(v) {
|
|
209
|
+
if (typeof v === "number" && !Number.isFinite(v))
|
|
210
|
+
return String(v);
|
|
211
|
+
return JSON.stringify(v);
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* A RECOGNISED key carrying the wrong TYPE of value.
|
|
215
|
+
*
|
|
216
|
+
* The unknown-key warner above covers a misspelled key. It does not cover a
|
|
217
|
+
* correctly-spelled one whose value cannot be read: the coercions in
|
|
218
|
+
* coercions.ts drop on mismatch and the caller supplies a default, silently.
|
|
219
|
+
* That file's own header names this gap and points at the unknown-key warning
|
|
220
|
+
* as the mitigation — which does not cover it, because the key is not unknown.
|
|
221
|
+
*
|
|
222
|
+
* Found live on the maintainer's machine by an acceptance pass: four routes
|
|
223
|
+
* carrying `tier: metered`, which is not a number, silently running at the
|
|
224
|
+
* default tier 3. Nothing had ever said so. `weight: very-high` becomes 1.0 the
|
|
225
|
+
* same way, and both feed routing decisions.
|
|
226
|
+
*
|
|
227
|
+
* Reports rather than rejects, like every other warning here: the config still
|
|
228
|
+
* loads, and `doctor` exits non-zero so the signal is not merely decorative.
|
|
229
|
+
*
|
|
230
|
+
* The one thing it does beyond reporting is DELETE an out-of-range numeric
|
|
231
|
+
* value from the entry, so the built-in default applies. That is not a second
|
|
232
|
+
* behaviour bolted on: a non-numeric `tier: metered` already ends up at the
|
|
233
|
+
* default, because `num()` cannot read it. `tier: -5` is different only in
|
|
234
|
+
* that the coercion CAN read it, which is exactly why it is dangerous — it
|
|
235
|
+
* reaches routing and wins. Deleting the key makes the two unusable cases
|
|
236
|
+
* behave the same way, which is what an operator reading either warning
|
|
237
|
+
* ("IGNORED, and the built-in default applies instead") is being told.
|
|
238
|
+
*
|
|
239
|
+
* Every caller warns before it parses the same object, so the deletion is
|
|
240
|
+
* visible to the parse that follows.
|
|
241
|
+
*/
|
|
242
|
+
export function warnMistypedRouteValues(entry, label, warnings) {
|
|
243
|
+
for (const [key, value] of Object.entries(entry)) {
|
|
244
|
+
if (value === null || value === undefined)
|
|
245
|
+
continue;
|
|
246
|
+
if (NUMERIC_ROUTE_KEYS.has(key) && !readsAsNumber(value)) {
|
|
247
|
+
// Per field, for the same reason the range branch varies its text: the
|
|
248
|
+
// routing sentence was emitted for all six keys, and routing does not
|
|
249
|
+
// read `timeout_ms` or the token caps. The very next acceptance pass
|
|
250
|
+
// found this branch still saying it after the other was fixed — the
|
|
251
|
+
// same defect one branch over, in one function.
|
|
252
|
+
warnings.push(`${label}: ${key} is ${describeValue(value)}, which is not a number — ` +
|
|
253
|
+
`IGNORED, and the built-in default applies instead. ` +
|
|
254
|
+
(ROUTING_SCORED_KEYS.has(key)
|
|
255
|
+
? `Routing reads this field, so the route is not behaving the way this ` +
|
|
256
|
+
`line says it does.`
|
|
257
|
+
: `The route runs with the built-in ${key}, not the one written here.`));
|
|
258
|
+
// This branch WARNED without neutralising, and for a plain unreadable
|
|
259
|
+
// value that was harmless — `num()` returns the default anyway, so the
|
|
260
|
+
// warning was true by accident. `.inf` and `.nan` are `typeof "number"`,
|
|
261
|
+
// so `num()` hands them straight back: the route loaded at
|
|
262
|
+
// `tier=-Infinity, weight=Infinity` — ahead of every tier and above
|
|
263
|
+
// every score — underneath a warning reading "IGNORED, and the built-in
|
|
264
|
+
// default applies instead". The message asserted the opposite of what
|
|
265
|
+
// happened, which is worse than the silence it replaced.
|
|
266
|
+
delete entry[key];
|
|
267
|
+
}
|
|
268
|
+
else if (NUMERIC_ROUTE_KEYS.has(key)) {
|
|
269
|
+
const bound = NUMERIC_ROUTE_MINIMUMS[key];
|
|
270
|
+
const n = Number(value);
|
|
271
|
+
if (bound !== undefined && (bound.exclusive ? n <= bound.min : n < bound.min)) {
|
|
272
|
+
// The consequence differs by field, and stating the routing one for
|
|
273
|
+
// all six was simply false: routing does not multiply `timeout_ms` or
|
|
274
|
+
// the token caps. A warning that explains the wrong mechanism teaches
|
|
275
|
+
// the reader something untrue about their own config.
|
|
276
|
+
const consequence = ROUTING_SCORED_KEYS.has(key)
|
|
277
|
+
? `Routing multiplies these fields and orders tiers ascending, so a ` +
|
|
278
|
+
`negative one PROMOTES the route over every other rather than demoting it.`
|
|
279
|
+
: `A value at or below ${bound.min} here does not mean "no limit"; it ` +
|
|
280
|
+
`describes a route that can never do any work.`;
|
|
281
|
+
warnings.push(`${label}: ${key} is ${describeValue(value)}, which is below the minimum ` +
|
|
282
|
+
`of ${bound.min}${bound.exclusive ? " (exclusive)" : ""} — IGNORED, and the ` +
|
|
283
|
+
`built-in default applies instead. ${consequence}`);
|
|
284
|
+
delete entry[key];
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
if (BOOLEAN_ROUTE_KEYS.has(key) && typeof value !== "boolean") {
|
|
288
|
+
// A quoted "true"/"false" is accepted by bool() and is not a mistake
|
|
289
|
+
// worth reporting; anything else selects the default silently.
|
|
290
|
+
if (value === "true" || value === "false")
|
|
291
|
+
continue;
|
|
292
|
+
warnings.push(`${label}: ${key} is ${describeValue(value)}, which is not true or false — ` +
|
|
293
|
+
`IGNORED, and the built-in default applies instead.`);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Two route entries sharing one name.
|
|
299
|
+
*
|
|
300
|
+
* The later entry wins outright, so everything the earlier one declared is
|
|
301
|
+
* gone. An acceptance pass measured the consequence: a first entry setting
|
|
302
|
+
* `safety_profile: read_only` and `workspace_policy: copy` was replaced by a
|
|
303
|
+
* second with neither, and the surviving route ran `workspace_edit` /
|
|
304
|
+
* `shared_locked` — silently LESS restrictive than what was written, with no
|
|
305
|
+
* warning on any surface.
|
|
306
|
+
*/
|
|
307
|
+
export function warnDuplicateRouteNames(names, block, warnings) {
|
|
308
|
+
const seen = new Set();
|
|
309
|
+
const reported = new Set();
|
|
310
|
+
for (const name of names) {
|
|
311
|
+
if (name === undefined || name === "")
|
|
312
|
+
continue;
|
|
313
|
+
if (!seen.has(name)) {
|
|
314
|
+
seen.add(name);
|
|
315
|
+
continue;
|
|
316
|
+
}
|
|
317
|
+
if (reported.has(name))
|
|
318
|
+
continue;
|
|
319
|
+
reported.add(name);
|
|
320
|
+
warnings.push(`${block}: "${name}" is declared more than once — only the LAST entry ` +
|
|
321
|
+
`survives, and every field the earlier one set is discarded, including ` +
|
|
322
|
+
`safety_profile and workspace_policy. If the earlier entry restricted ` +
|
|
323
|
+
`this route, that restriction is NOT in effect.`);
|
|
324
|
+
}
|
|
125
325
|
}
|
|
126
326
|
/**
|
|
127
327
|
* Keys the parser ACCEPTS and nothing reads.
|
|
@@ -133,8 +333,22 @@ export function warnUnknownRouteKeys(entry, label, warnings) {
|
|
|
133
333
|
*
|
|
134
334
|
* Verified read-nowhere in src/ at the time of writing; if one is implemented
|
|
135
335
|
* later, delete it from here and the warning goes away.
|
|
336
|
+
*
|
|
337
|
+
* `policy` and `workspace_policy` were added after an acceptance pass found
|
|
338
|
+
* them allow-listed at top level and read nowhere — top-level isolation
|
|
339
|
+
* controls that do nothing, the same shape as `default_safety_profile` above.
|
|
340
|
+
* Both names ARE real per-route keys (see KNOWN_ROUTE_KEYS), which is what
|
|
341
|
+
* makes the top-level spelling plausible enough to write by mistake: it looks
|
|
342
|
+
* like a global default for the per-route setting, and there is no such thing.
|
|
343
|
+
* Re-verified read-nowhere at top level on 2026-08-31 — `raw?.policy` in
|
|
344
|
+
* jobs.ts reads a JOB MANIFEST, not this config file.
|
|
136
345
|
*/
|
|
137
|
-
const ACCEPTED_BUT_UNIMPLEMENTED = new Set([
|
|
346
|
+
const ACCEPTED_BUT_UNIMPLEMENTED = new Set([
|
|
347
|
+
"protocols",
|
|
348
|
+
"default_safety_profile",
|
|
349
|
+
"policy",
|
|
350
|
+
"workspace_policy",
|
|
351
|
+
]);
|
|
138
352
|
export function warnUnknownTopLevelKeys(raw, warnings) {
|
|
139
353
|
for (const key of Object.keys(raw)) {
|
|
140
354
|
if (ACCEPTED_BUT_UNIMPLEMENTED.has(key)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validation.js","sourceRoot":"","sources":["../../src/config/validation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAKH;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,CAAC,MAAM,eAAe,GAAsC;IAChE,wEAAwE;IACxE,wEAAwE;IACxE,4EAA4E;IAC5E,yEAAyE;IACzE,sEAAsE;IACtE,6EAA6E;IAC7E,WAAW;IACX,YAAY,EAAE;QACZ,eAAe;QACf,qBAAqB;QACrB,qCAAqC;QACrC,uCAAuC;QACvC,+BAA+B;QAC/B,aAAa;QACb,YAAY;QACZ,SAAS;KACV;IACD,kBAAkB,EAAE,CAAC,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,CAAC;IACxE,cAAc,EAAE,CAAC,WAAW,EAAE,gBAAgB,EAAE,WAAW,CAAC;IAC5D,gBAAgB,EAAE,CAAC,WAAW,EAAE,gBAAgB,EAAE,WAAW,CAAC;IAC9D,gBAAgB,EAAE,CAAC,QAAQ,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,CAAC;CACtE,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAC;IAC1C,SAAS;IACT,MAAM;IACN,WAAW;IACX,UAAU;IACV,UAAU;IACV,WAAW;IACX,UAAU;IACV,WAAW;IACX,QAAQ;IACR,WAAW;IACX,WAAW;IACX,aAAa;IACb,qBAAqB;IACrB,wBAAwB;IACxB,kBAAkB;IAClB,UAAU;CACX,CAAC,CAAC;AAEH;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC;IACtC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY;IAChF,MAAM,EAAE,QAAQ,EAAE,gBAAgB,EAAE,cAAc,EAAE,YAAY;IAChE,kBAAkB,EAAE,mBAAmB,EAAE,gBAAgB;IACzD,mBAAmB,EAAE,gBAAgB,EAAE,aAAa,EAAE,iBAAiB;IACvE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ;IAC3C,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,cAAc,EAAE,oBAAoB;IAC1E,eAAe,EAAE,qBAAqB,EAAE,kBAAkB;IAC1D,gBAAgB,EAAE,kBAAkB,EAAE,kBAAkB;IACxD,eAAe,EAAE,mBAAmB,EAAE,eAAe;CACtD,CAAC,CAAC;AAEH,MAAM,UAAU,oBAAoB,CAClC,KAA8B,EAC9B,KAAa,EACb,QAAkB;IAElB,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACrC,IAAI,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,SAAS;QACxC,QAAQ,CAAC,IAAI,CACX,GAAG,KAAK,kBAAkB,GAAG,yCAAyC;YACpE,uEAAuE,CAC1E,CAAC;IACJ,CAAC;AACH,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"validation.js","sourceRoot":"","sources":["../../src/config/validation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAKH;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,CAAC,MAAM,eAAe,GAAsC;IAChE,wEAAwE;IACxE,wEAAwE;IACxE,4EAA4E;IAC5E,yEAAyE;IACzE,sEAAsE;IACtE,6EAA6E;IAC7E,WAAW;IACX,YAAY,EAAE;QACZ,eAAe;QACf,qBAAqB;QACrB,qCAAqC;QACrC,uCAAuC;QACvC,+BAA+B;QAC/B,aAAa;QACb,YAAY;QACZ,SAAS;KACV;IACD,kBAAkB,EAAE,CAAC,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,CAAC;IACxE,cAAc,EAAE,CAAC,WAAW,EAAE,gBAAgB,EAAE,WAAW,CAAC;IAC5D,gBAAgB,EAAE,CAAC,WAAW,EAAE,gBAAgB,EAAE,WAAW,CAAC;IAC9D,gBAAgB,EAAE,CAAC,QAAQ,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,CAAC;CACtE,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAC;IAC1C,SAAS;IACT,wEAAwE;IACxE,gEAAgE;IAChE,QAAQ;IACR,MAAM;IACN,WAAW;IACX,UAAU;IACV,UAAU;IACV,WAAW;IACX,UAAU;IACV,WAAW;IACX,QAAQ;IACR,WAAW;IACX,WAAW;IACX,aAAa;IACb,qBAAqB;IACrB,wBAAwB;IACxB,kBAAkB;IAClB,UAAU;CACX,CAAC,CAAC;AAEH;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC;IACtC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY;IAChF,MAAM,EAAE,QAAQ,EAAE,gBAAgB,EAAE,cAAc,EAAE,YAAY;IAChE,kBAAkB,EAAE,mBAAmB,EAAE,gBAAgB;IACzD,mBAAmB,EAAE,gBAAgB,EAAE,aAAa,EAAE,iBAAiB;IACvE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ;IAC3C,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,cAAc,EAAE,oBAAoB;IAC1E,eAAe,EAAE,qBAAqB,EAAE,kBAAkB;IAC1D,gBAAgB,EAAE,kBAAkB,EAAE,kBAAkB;IACxD,eAAe,EAAE,mBAAmB,EAAE,eAAe;CACtD,CAAC,CAAC;AAEH,MAAM,UAAU,oBAAoB,CAClC,KAA8B,EAC9B,KAAa,EACb,QAAkB;IAElB,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACrC,IAAI,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,SAAS;QACxC,QAAQ,CAAC,IAAI,CACX,GAAG,KAAK,kBAAkB,GAAG,yCAAyC;YACpE,uEAAuE,CAC1E,CAAC;IACJ,CAAC;IACD,uBAAuB,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC;AAClD,CAAC;AAED,gFAAgF;AAChF,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAC;IACjC,MAAM;IACN,QAAQ;IACR,gBAAgB;IAChB,mBAAmB;IACnB,kBAAkB;IAClB,YAAY;CACb,CAAC,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,sBAAsB,GAAwD;IAClF,IAAI,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE;IAClC,MAAM,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE;IACnC,cAAc,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE;IAC3C,iBAAiB,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE;IAC9C,gBAAgB,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE;IAC7C,UAAU,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE;CACxC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,gBAAgB,CAAC,CAAC,CAAC;AAE1E,qDAAqD;AACrD,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAC;IACjC,SAAS;IACT,qBAAqB;IACrB,kBAAkB;IAClB,OAAO;CACR,CAAC,CAAC;AAEH;;;;;;;;;;;;GAYG;AACH,SAAS,aAAa,CAAC,CAAU;IAC/B,IAAI,OAAO,CAAC,KAAK,QAAQ;QAAE,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IACrD,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,EAAE,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AACzE,CAAC;AAED;;;;;;GAMG;AACH,SAAS,aAAa,CAAC,CAAU;IAC/B,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;QAAE,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC;IACnE,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC3B,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,UAAU,uBAAuB,CACrC,KAA8B,EAC9B,KAAa,EACb,QAAkB;IAElB,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACjD,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS;YAAE,SAAS;QACpD,IAAI,kBAAkB,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;YACzD,uEAAuE;YACvE,sEAAsE;YACtE,qEAAqE;YACrE,oEAAoE;YACpE,gDAAgD;YAChD,QAAQ,CAAC,IAAI,CACX,GAAG,KAAK,KAAK,GAAG,OAAO,aAAa,CAAC,KAAK,CAAC,4BAA4B;gBACrE,qDAAqD;gBACrD,CAAC,mBAAmB,CAAC,GAAG,CAAC,GAAG,CAAC;oBAC3B,CAAC,CAAC,sEAAsE;wBACtE,oBAAoB;oBACtB,CAAC,CAAC,oCAAoC,GAAG,6BAA6B,CAAC,CAC5E,CAAC;YACF,sEAAsE;YACtE,uEAAuE;YACvE,yEAAyE;YACzE,2DAA2D;YAC3D,oEAAoE;YACpE,wEAAwE;YACxE,sEAAsE;YACtE,yDAAyD;YACzD,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC;QACpB,CAAC;aAAM,IAAI,kBAAkB,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YACvC,MAAM,KAAK,GAAG,sBAAsB,CAAC,GAAG,CAAC,CAAC;YAC1C,MAAM,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;YACxB,IAAI,KAAK,KAAK,SAAS,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC9E,oEAAoE;gBACpE,sEAAsE;gBACtE,sEAAsE;gBACtE,sDAAsD;gBACtD,MAAM,WAAW,GAAG,mBAAmB,CAAC,GAAG,CAAC,GAAG,CAAC;oBAC9C,CAAC,CAAC,mEAAmE;wBACnE,2EAA2E;oBAC7E,CAAC,CAAC,uBAAuB,KAAK,CAAC,GAAG,qCAAqC;wBACrE,+CAA+C,CAAC;gBACpD,QAAQ,CAAC,IAAI,CACX,GAAG,KAAK,KAAK,GAAG,OAAO,aAAa,CAAC,KAAK,CAAC,+BAA+B;oBACxE,MAAM,KAAK,CAAC,GAAG,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,sBAAsB;oBAC7E,qCAAqC,WAAW,EAAE,CACrD,CAAC;gBACF,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC;YACpB,CAAC;QACH,CAAC;QACD,IAAI,kBAAkB,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,OAAO,KAAK,KAAK,SAAS,EAAE,CAAC;YAC9D,qEAAqE;YACrE,+DAA+D;YAC/D,IAAI,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,OAAO;gBAAE,SAAS;YACpD,QAAQ,CAAC,IAAI,CACX,GAAG,KAAK,KAAK,GAAG,OAAO,aAAa,CAAC,KAAK,CAAC,iCAAiC;gBAC1E,oDAAoD,CACvD,CAAC;QACJ,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,uBAAuB,CACrC,KAAgC,EAChC,KAAa,EACb,QAAkB;IAElB,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAC;IACnC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,EAAE;YAAE,SAAS;QAChD,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACpB,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACf,SAAS;QACX,CAAC;QACD,IAAI,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,SAAS;QACjC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACnB,QAAQ,CAAC,IAAI,CACX,GAAG,KAAK,MAAM,IAAI,qDAAqD;YACrE,wEAAwE;YACxE,uEAAuE;YACvE,gDAAgD,CACnD,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,0BAA0B,GAAG,IAAI,GAAG,CAAC;IACzC,WAAW;IACX,wBAAwB;IACxB,QAAQ;IACR,kBAAkB;CACnB,CAAC,CAAC;AAEH,MAAM,UAAU,uBAAuB,CAAC,GAA4B,EAAE,QAAkB;IACtF,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACnC,IAAI,0BAA0B,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YACxC,QAAQ,CAAC,IAAI,CACX,GAAG,GAAG,+DAA+D;gBACnE,gDAAgD,CACnD,CAAC;YACF,SAAS;QACX,CAAC;QACD,IAAI,oBAAoB,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,SAAS;QAC5C,IAAI,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC;YAAE,SAAS,CAAC,iCAAiC;QACzE,QAAQ,CAAC,IAAI,CACX,iCAAiC,GAAG,yCAAyC;YAC3E,wBAAwB,CAAC,GAAG,oBAAoB,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CACpF,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,IAAa,EAAE,QAAkB,EAAE,KAAK,GAAG,EAAE;IAClF,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QACxB,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE;YAAE,sBAAsB,CAAC,CAAC,EAAE,QAAQ,EAAE,GAAG,KAAK,IAAI,CAAC,GAAG,CAAC,CAAC;QAC3F,OAAO;IACT,CAAC;IACD,IAAI,IAAI,KAAK,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO;IACtD,MAAM,GAAG,GAAG,IAA+B,CAAC;IAC5C,MAAM,KAAK,GACT,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,IAAI,GAAG,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,QAAQ,CAAC;IACzF,KAAK,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,eAAe,CAAC,EAAE,CAAC;QAC7D,MAAM,KAAK,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;QACvB,IAAI,KAAK,KAAK,SAAS;YAAE,SAAS;QAClC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC;YAAE,SAAS;QACnE,uEAAuE;QACvE,sEAAsE;QACtE,oCAAoC;QACpC,IAAI,GAAG,KAAK,kBAAkB,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACvG,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,KAAgC,CAAC,CAAC;YACjE,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM,CACxB,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAClF,CAAC;YACF,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;gBAAE,SAAS;YAC/B,QAAQ,CAAC,IAAI,CACX,GAAG,KAAK,uBAAuB,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;gBAC5F,YAAY,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,qCAAqC,CACrE,CAAC;YACF,SAAS;QACX,CAAC;QACD,QAAQ,CAAC,IAAI,CACX,GAAG,KAAK,KAAK,GAAG,KAAK,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,kBAAkB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK;YACjF,gFAAgF;YAChF,qDAAqD,CACxD,CAAC;IACJ,CAAC;IACD,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACzC,sBAAsB,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACnE,CAAC;AACH,CAAC"}
|
package/dist/config.d.ts
CHANGED
|
@@ -49,8 +49,10 @@ export interface LoadConfigOptions {
|
|
|
49
49
|
*/
|
|
50
50
|
/**
|
|
51
51
|
* The config file a process should load: an explicit `--config`, else
|
|
52
|
-
* `HARNESS_DISPATCH_CONFIG`, else `./config.yaml` if it exists, else
|
|
53
|
-
* (
|
|
52
|
+
* `HARNESS_DISPATCH_CONFIG`, else `./config.yaml` if it exists, else the
|
|
53
|
+
* state directory's `config.yaml` (where `configure` writes) if it exists,
|
|
54
|
+
* else nothing (auto-detect). The current directory stays ahead of the user
|
|
55
|
+
* file so a per-project config still wins when one is present.
|
|
54
56
|
*
|
|
55
57
|
* ONE function because there used to be two, and they disagreed. job-runner.ts
|
|
56
58
|
* read the environment variable and bin.ts did not, while job-runner's own
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAgCH,2EAA2E;AAC3E,MAAM,MAAM,OAAO,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;AA+B9D,OAAO,KAAK,EAOV,iBAAiB,EAGjB,YAAY,EAOb,MAAM,YAAY,CAAC;AAsEpB,iKAAiK;AACjK,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAI9D,CAAC;AAQF;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAKvD,CAAC;AAooBF,MAAM,WAAW,iBAAiB;IAChC,0EAA0E;IAC1E,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;;;;;;;GAQG;AACH;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAOvE;AAED,wBAAsB,UAAU,CAC9B,IAAI,CAAC,EAAE,MAAM,EACb,IAAI,GAAE,iBAAsB,GAC3B,OAAO,CAAC,YAAY,CAAC,CAuNvB;AAMD,MAAM,WAAW,aAAa;IAC5B,IAAI,IAAI,IAAI,CAAC;CACd;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,CAAC,CAAC,EAAE,YAAY,KAAK,IAAI,EACnC,IAAI,GAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAO,GACpD,aAAa,CAkCf"}
|
package/dist/config.js
CHANGED
|
@@ -13,13 +13,14 @@
|
|
|
13
13
|
* the corresponding environment variable.
|
|
14
14
|
*/
|
|
15
15
|
import { existsSync, readFileSync, promises as fs } from "node:fs";
|
|
16
|
+
import { userConfigPath } from "./state-dir.js";
|
|
16
17
|
import path from "node:path";
|
|
17
18
|
import { fileURLToPath } from "node:url";
|
|
18
19
|
import yaml from "js-yaml";
|
|
19
20
|
import which from "which";
|
|
20
21
|
import { inferredPaidUsagePossible } from "./billing.js";
|
|
21
22
|
import { authSourceFrom, billingKindFrom, bool, endpointModeFrom, endpointProviderFrom, inferEndpointProvider, int, num, providerFrom, str, surfaceFrom, wireProtocolFrom, } from "./config/coercions.js";
|
|
22
|
-
import { warnUnknownRouteKeys, warnUnknownSafetyEnums, warnUnknownTopLevelKeys, } from "./config/validation.js";
|
|
23
|
+
import { warnDuplicateRouteNames, warnMistypedRouteValues, warnUnknownRouteKeys, warnUnknownSafetyEnums, warnUnknownTopLevelKeys, } from "./config/validation.js";
|
|
23
24
|
import { parseProtocolFields, protocolFrom, stringArrayFrom } from "./config/protocol.js";
|
|
24
25
|
import { effectiveSafetyFrom, resolveSharedRouteFields, } from "./config/route-fields.js";
|
|
25
26
|
import { ENV_VAR_RE, interpolateTree } from "./config/env-interpolation.js";
|
|
@@ -237,6 +238,31 @@ function buildLegacyConfig(raw) {
|
|
|
237
238
|
const services = {};
|
|
238
239
|
const rawServices = (raw.services ?? {});
|
|
239
240
|
const warnings = [];
|
|
241
|
+
// `services:` must be a MAP of route id -> settings, but `typeof [] ===
|
|
242
|
+
// "object"`, so a list slips through and Object.entries turns it into routes
|
|
243
|
+
// called "0", "1", … with each item's `name:` silently ignored. Everything
|
|
244
|
+
// then looks healthy — doctor reports the routes, status lists them — right
|
|
245
|
+
// up until `--service my_route` answers "Unknown service".
|
|
246
|
+
//
|
|
247
|
+
// The mistake is a natural one rather than carelessness: the sibling
|
|
248
|
+
// top-level keys `clis:` and `endpoints:` ARE lists, and their items DO
|
|
249
|
+
// carry `name:`. Found by an acceptance pass; it predates the work that pass
|
|
250
|
+
// was reviewing.
|
|
251
|
+
if (Array.isArray(raw.services)) {
|
|
252
|
+
const intended = raw.services
|
|
253
|
+
.map((e) => (e !== null && typeof e === "object" ? e.name : undefined))
|
|
254
|
+
.filter((n) => typeof n === "string" && n !== "");
|
|
255
|
+
const got = Object.keys(rawServices);
|
|
256
|
+
warnings.push(`services: is a LIST, but it must be a map of route id to settings. Its ` +
|
|
257
|
+
`${got.length} entr${got.length === 1 ? "y" : "ies"} became route id${got.length === 1 ? "" : "s"} ` +
|
|
258
|
+
`${got.join(", ")}` +
|
|
259
|
+
(intended.length > 0
|
|
260
|
+
? `, and each item's name: (${intended.join(", ")}) was ignored — so anything ` +
|
|
261
|
+
`referring to a route by name will not find it`
|
|
262
|
+
: "") +
|
|
263
|
+
`. Write it as \`services:\` then \` <id>:\` per route (unlike clis: and ` +
|
|
264
|
+
`endpoints:, which ARE lists).`);
|
|
265
|
+
}
|
|
240
266
|
// A top-level `services:` key selects the legacy parser entirely — it
|
|
241
267
|
// never looks at clis:/endpoints:/overrides:, so any of those sitting
|
|
242
268
|
// alongside it are silently dropped unless we say so here. The likely
|
|
@@ -251,6 +277,18 @@ function buildLegacyConfig(raw) {
|
|
|
251
277
|
`clis:/endpoints:/overrides: exclusively (see the shipped config.default.yaml).`);
|
|
252
278
|
}
|
|
253
279
|
for (const [name, svc] of Object.entries(rawServices)) {
|
|
280
|
+
// The legacy shape gets the same value checks as `clis:` and `endpoints:`.
|
|
281
|
+
//
|
|
282
|
+
// It got neither: both validators were wired into the two modern loops and
|
|
283
|
+
// not this one, so a `services:` config — still supported, still what an
|
|
284
|
+
// older `configure` wrote — reported one warning where the modern shape
|
|
285
|
+
// reports four. A delegate audit found the asymmetry.
|
|
286
|
+
//
|
|
287
|
+
// Deliberately only the VALUE checks. The unknown-KEY warner is not called
|
|
288
|
+
// here because the legacy shape accepts a wider set of keys than
|
|
289
|
+
// KNOWN_ROUTE_KEYS lists, and reporting those as typos would be worse than
|
|
290
|
+
// the silence it replaces.
|
|
291
|
+
warnMistypedRouteValues(svc, `services."${name}"`, warnings);
|
|
254
292
|
const type = (str(svc.type) ?? "cli");
|
|
255
293
|
// Computed once and reused below for both max-tokens fallback and the
|
|
256
294
|
// billing/safety/model-hint inheritance IIFE — legacy-format entries
|
|
@@ -448,6 +486,7 @@ async function detectServices(disabled, apiKeys, overrides, whichFn) {
|
|
|
448
486
|
*/
|
|
449
487
|
function addClis(services, raw, apiKeys, warnings) {
|
|
450
488
|
const clis = Array.isArray(raw.clis) ? raw.clis : [];
|
|
489
|
+
warnDuplicateRouteNames(clis.map((e) => str(e.name)), "clis", warnings);
|
|
451
490
|
for (const [index, entry] of clis.entries()) {
|
|
452
491
|
const name = str(entry.name);
|
|
453
492
|
const harness = str(entry.harness);
|
|
@@ -558,6 +597,7 @@ function addEndpoints(services, raw, apiKeys, warnings = []) {
|
|
|
558
597
|
const endpoints = Array.isArray(raw.endpoints)
|
|
559
598
|
? raw.endpoints
|
|
560
599
|
: [];
|
|
600
|
+
warnDuplicateRouteNames(endpoints.map((e) => str(e.name)), "endpoints", warnings);
|
|
561
601
|
for (const [index, ep] of endpoints.entries()) {
|
|
562
602
|
const name = str(ep.name);
|
|
563
603
|
warnUnknownRouteKeys(ep, `endpoints[${index}] "${name ?? "?"}"`, warnings);
|
|
@@ -633,8 +673,10 @@ function addEndpoints(services, raw, apiKeys, warnings = []) {
|
|
|
633
673
|
*/
|
|
634
674
|
/**
|
|
635
675
|
* The config file a process should load: an explicit `--config`, else
|
|
636
|
-
* `HARNESS_DISPATCH_CONFIG`, else `./config.yaml` if it exists, else
|
|
637
|
-
* (
|
|
676
|
+
* `HARNESS_DISPATCH_CONFIG`, else `./config.yaml` if it exists, else the
|
|
677
|
+
* state directory's `config.yaml` (where `configure` writes) if it exists,
|
|
678
|
+
* else nothing (auto-detect). The current directory stays ahead of the user
|
|
679
|
+
* file so a per-project config still wins when one is present.
|
|
638
680
|
*
|
|
639
681
|
* ONE function because there used to be two, and they disagreed. job-runner.ts
|
|
640
682
|
* read the environment variable and bin.ts did not, while job-runner's own
|
|
@@ -656,7 +698,10 @@ export function resolveConfigPath(explicit) {
|
|
|
656
698
|
const fromEnv = process.env["HARNESS_DISPATCH_CONFIG"];
|
|
657
699
|
if (fromEnv !== undefined && fromEnv !== "")
|
|
658
700
|
return fromEnv;
|
|
659
|
-
|
|
701
|
+
if (existsSync("config.yaml"))
|
|
702
|
+
return "config.yaml";
|
|
703
|
+
const user = userConfigPath();
|
|
704
|
+
return existsSync(user) ? user : undefined;
|
|
660
705
|
}
|
|
661
706
|
export async function loadConfig(path, opts = {}) {
|
|
662
707
|
const whichFn = opts.whichFn ?? defaultWhich;
|
|
@@ -715,6 +760,12 @@ export async function loadConfig(path, opts = {}) {
|
|
|
715
760
|
const legacyCfg = buildLegacyConfig(raw);
|
|
716
761
|
const enumWarnings = [];
|
|
717
762
|
warnUnknownSafetyEnums(raw, enumWarnings);
|
|
763
|
+
// The legacy shape returns before the modern path's top-level key check
|
|
764
|
+
// ever runs, so the same `policy: copy` that warns twice in a `clis:`
|
|
765
|
+
// config warned about nothing here. An acceptance pass reproduced the two
|
|
766
|
+
// shapes side by side. The check is about the top level of the FILE, which
|
|
767
|
+
// both shapes have; only route-entry validation is format-specific.
|
|
768
|
+
warnUnknownTopLevelKeys(raw, enumWarnings);
|
|
718
769
|
if (enumWarnings.length > 0) {
|
|
719
770
|
legacyCfg.configWarnings = [...(legacyCfg.configWarnings ?? []), ...enumWarnings];
|
|
720
771
|
}
|
|
@@ -741,14 +792,95 @@ export async function loadConfig(path, opts = {}) {
|
|
|
741
792
|
`before a route rename, the route it used to refer to is no longer disabled.`);
|
|
742
793
|
}
|
|
743
794
|
}
|
|
744
|
-
for (const name of Object.
|
|
795
|
+
for (const [name, entry] of Object.entries(overrides)) {
|
|
745
796
|
if (!knownAutoDetectNames.has(name)) {
|
|
746
797
|
warnings.push(`overrides.${name}: doesn't match any auto-detected route (expected one of: ` +
|
|
747
798
|
`${[...knownAutoDetectNames].join(", ")}) — ignored, none of these settings were applied.`);
|
|
799
|
+
continue;
|
|
800
|
+
}
|
|
801
|
+
// `overrides:` gets the same value checks as the three route shapes.
|
|
802
|
+
//
|
|
803
|
+
// It was left out when they were added, and it is the block most likely to
|
|
804
|
+
// carry exactly the fields the check exists for: config.default.yaml
|
|
805
|
+
// presents `overrides:` as the way to "tweak auto-detected service defaults
|
|
806
|
+
// without writing a full config", naming tier and weight. An acceptance
|
|
807
|
+
// pass measured `overrides: { claude_code_cli: { tier: metered, weight:
|
|
808
|
+
// very-high, enabled: yes-please } }` producing ZERO warnings while none of
|
|
809
|
+
// it applied. The enum walk already reached here; only the numeric,
|
|
810
|
+
// boolean and unknown-key checks stopped at the block boundary.
|
|
811
|
+
if (entry !== null && typeof entry === "object") {
|
|
812
|
+
warnUnknownRouteKeys(entry, `overrides.${name}`, warnings);
|
|
748
813
|
}
|
|
749
814
|
}
|
|
750
815
|
const apiKeys = collectApiKeys(raw);
|
|
751
|
-
|
|
816
|
+
// A CONFIG FILE THAT DEFINES ROUTES IS AUTHORITATIVE about them.
|
|
817
|
+
//
|
|
818
|
+
// Detection used to run unconditionally, so `clis: []` did NOT isolate a
|
|
819
|
+
// config from the harnesses installed on the machine — the file added to
|
|
820
|
+
// auto-detection rather than replacing it, and only `disabled:` (naming
|
|
821
|
+
// every route, including ones you might not know existed) subtracted. That
|
|
822
|
+
// default caught three acceptance passes in a row DESPITE explicit warnings,
|
|
823
|
+
// and caught this project's own test suite: one boundary test dispatched to
|
|
824
|
+
// the real Claude Code CLI on every `npm test` and every CI run, measured at
|
|
825
|
+
// 6.4s and 47k input tokens, under a comment asserting it could not reach a
|
|
826
|
+
// route. When a default surprises the maintainer, the reviewers, and the
|
|
827
|
+
// product's own tests, it is a least-surprise violation rather than a
|
|
828
|
+
// convenience.
|
|
829
|
+
//
|
|
830
|
+
// It also decayed: a future release adding a fifth supported harness would
|
|
831
|
+
// auto-add it to every existing config, so a `disabled:` list written today
|
|
832
|
+
// silently stops isolating tomorrow.
|
|
833
|
+
//
|
|
834
|
+
// The legacy `services:` format has ALWAYS been authoritative (it returns
|
|
835
|
+
// above without calling detection), so this makes the two shapes agree
|
|
836
|
+
// rather than inventing a rule.
|
|
837
|
+
//
|
|
838
|
+
// Three cases, and the third is what keeps the migration safe:
|
|
839
|
+
// detect: true/false — explicit, always wins.
|
|
840
|
+
// file defines routes — authoritative; detection off.
|
|
841
|
+
// file defines NO routes — detection ON, with a warning. A file carrying
|
|
842
|
+
// only `overrides:`/`disabled:`/settings exists to TUNE detection; it
|
|
843
|
+
// cannot be authoritative about routes it does not describe, and
|
|
844
|
+
// switching detection off for it would leave such a user with nothing.
|
|
845
|
+
// PRESENCE of the key, not a non-empty list. `clis: []` is someone writing
|
|
846
|
+
// down "no CLI routes" — an opinion about routes, and the most explicit one
|
|
847
|
+
// available. Requiring a non-empty array meant `clis: []` still loaded every
|
|
848
|
+
// harness on the machine, which is the precise failure the comment above
|
|
849
|
+
// describes in the past tense. An acceptance pass caught the contradiction:
|
|
850
|
+
// `clis: []` returned all four real CLIs, so the fix did not cover its own
|
|
851
|
+
// motivating example, and this project's test suite still leans on
|
|
852
|
+
// `disabled:` naming every route to stay off them.
|
|
853
|
+
const definesRoutes = Array.isArray(raw.clis) || Array.isArray(raw.endpoints);
|
|
854
|
+
// A `clis:` written as a MAPPING rather than a list is the same silent-drop
|
|
855
|
+
// class this module exists to prevent, and it fails in the worst direction:
|
|
856
|
+
// the entries vanish, `definesRoutes` is false, detection runs, and the user
|
|
857
|
+
// who was trying to name their own routes gets every installed paid harness
|
|
858
|
+
// instead — under a warning telling them their config "defines no routes",
|
|
859
|
+
// which contradicts the file in front of them.
|
|
860
|
+
for (const key of ["clis", "endpoints"]) {
|
|
861
|
+
const value = raw[key];
|
|
862
|
+
if (value !== undefined && value !== null && !Array.isArray(value)) {
|
|
863
|
+
warnings.push(`${key}: must be a LIST, but this config has ${typeof value === "object" ? "a mapping" : `a ${typeof value}`} — every entry under it was IGNORED. Write it as \`${key}:\` followed by ` +
|
|
864
|
+
`\` - name: ...\` items. As written this config defines no ${key} at all.`);
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
const detectRequested = typeof raw.detect === "boolean" ? raw.detect : undefined;
|
|
868
|
+
const detect = detectRequested ?? !definesRoutes;
|
|
869
|
+
if (detectRequested === undefined && !definesRoutes && Object.keys(raw).length > 0) {
|
|
870
|
+
warnings.push("this config defines no routes of its own (no `clis:` or `endpoints:` entries), so " +
|
|
871
|
+
"installed harness CLIs are still auto-detected and added. That is the old default " +
|
|
872
|
+
"and it still applies here; a config that DOES define routes is now authoritative " +
|
|
873
|
+
"and detection is off for it. Say `detect: true` to keep this explicit, or " +
|
|
874
|
+
"`detect: false` to run with no routes at all.");
|
|
875
|
+
}
|
|
876
|
+
const services = detect
|
|
877
|
+
? await detectServices(disabled, apiKeys, overrides, whichFn)
|
|
878
|
+
: {};
|
|
879
|
+
if (!detect && (disabled.length > 0 || Object.keys(overrides).length > 0)) {
|
|
880
|
+
warnings.push("`disabled:` and `overrides:` apply to AUTO-DETECTED routes, and this config is " +
|
|
881
|
+
"authoritative (it defines its own routes), so detection is off and neither had any " +
|
|
882
|
+
"effect. Remove them, or add `detect: true` if you also want detected routes.");
|
|
883
|
+
}
|
|
752
884
|
addClis(services, raw, apiKeys, warnings);
|
|
753
885
|
addEndpoints(services, raw, apiKeys, warnings);
|
|
754
886
|
warnUnknownSafetyEnums(raw, warnings);
|
|
@@ -758,6 +890,11 @@ export async function loadConfig(path, opts = {}) {
|
|
|
758
890
|
const cfg = {
|
|
759
891
|
services,
|
|
760
892
|
disabled,
|
|
893
|
+
// Only when the file SAID so. Carrying the resolved value instead would
|
|
894
|
+
// make `configure` write `detect: true` into every config that merely
|
|
895
|
+
// omitted it, turning a default into a permanent declaration.
|
|
896
|
+
...(detectRequested !== undefined ? { detect: detectRequested } : {}),
|
|
897
|
+
detectionRan: detect,
|
|
761
898
|
...topLevelSettings(raw, warnings),
|
|
762
899
|
...(envRefs.size > 0 ? { envRefs } : {}),
|
|
763
900
|
...(apiKeyRefs.size > 0 ? { apiKeyRefs } : {}),
|