@gethelio/proxy 0.11.1 → 0.13.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/README.md +76 -45
- package/dist/cli.js +3878 -1786
- package/dist/dashboard-assets/assets/index-BUdEZ-VN.js +128 -0
- package/dist/dashboard-assets/assets/index-DtnT1Y9r.css +1 -0
- package/dist/dashboard-assets/index.html +2 -2
- package/dist/index.d.ts +744 -41
- package/dist/index.js +3405 -1568
- package/package.json +7 -7
- package/dist/dashboard-assets/assets/index-CPoQ6xns.css +0 -1
- package/dist/dashboard-assets/assets/index-D19fYKEH.js +0 -128
package/dist/index.d.ts
CHANGED
|
@@ -6,10 +6,18 @@ import { KnownBlock } from '@slack/web-api';
|
|
|
6
6
|
|
|
7
7
|
declare const VERSION: string;
|
|
8
8
|
|
|
9
|
+
declare const sessionIdentitySourceSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
10
|
+
source: z.ZodLiteral<"header">;
|
|
11
|
+
name: z.ZodPipe<z.ZodDefault<z.ZodString>, z.ZodTransform<string, string>>;
|
|
12
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
13
|
+
source: z.ZodLiteral<"meta">;
|
|
14
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
15
|
+
source: z.ZodLiteral<"legacy_header">;
|
|
16
|
+
}, z.core.$strict>], "source">;
|
|
9
17
|
declare const policiesSchema: z.ZodObject<{
|
|
10
18
|
default: z.ZodDefault<z.ZodEnum<{
|
|
11
|
-
allow: "allow";
|
|
12
19
|
deny: "deny";
|
|
20
|
+
allow: "allow";
|
|
13
21
|
}>>;
|
|
14
22
|
flag_destructive: z.ZodOptional<z.ZodEnum<{
|
|
15
23
|
require_approval: "require_approval";
|
|
@@ -43,10 +51,11 @@ declare const policiesSchema: z.ZodObject<{
|
|
|
43
51
|
contains: z.ZodOptional<z.ZodString>;
|
|
44
52
|
regex: z.ZodOptional<z.ZodString>;
|
|
45
53
|
}, z.core.$strict>]>>>;
|
|
54
|
+
upstreams: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
46
55
|
}, z.core.$strict>;
|
|
47
56
|
action: z.ZodEnum<{
|
|
48
|
-
allow: "allow";
|
|
49
57
|
deny: "deny";
|
|
58
|
+
allow: "allow";
|
|
50
59
|
require_approval: "require_approval";
|
|
51
60
|
rate_limit: "rate_limit";
|
|
52
61
|
spend_limit: "spend_limit";
|
|
@@ -92,8 +101,8 @@ declare const policiesSchema: z.ZodObject<{
|
|
|
92
101
|
}, z.core.$strict>>>;
|
|
93
102
|
install: z.ZodOptional<z.ZodObject<{
|
|
94
103
|
default: z.ZodDefault<z.ZodEnum<{
|
|
95
|
-
allow: "allow";
|
|
96
104
|
deny: "deny";
|
|
105
|
+
allow: "allow";
|
|
97
106
|
}>>;
|
|
98
107
|
rules: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
99
108
|
name: z.ZodOptional<z.ZodString>;
|
|
@@ -122,6 +131,11 @@ declare const policiesSchema: z.ZodObject<{
|
|
|
122
131
|
log: "log";
|
|
123
132
|
block: "block";
|
|
124
133
|
}>>;
|
|
134
|
+
tool_revalidation: z.ZodOptional<z.ZodObject<{
|
|
135
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
136
|
+
interval: z.ZodDefault<z.ZodString>;
|
|
137
|
+
max_advertised_ttl: z.ZodOptional<z.ZodString>;
|
|
138
|
+
}, z.core.$strict>>;
|
|
125
139
|
hot_reload: z.ZodOptional<z.ZodBoolean>;
|
|
126
140
|
}, z.core.$strict>;
|
|
127
141
|
declare const budgetSchema: z.ZodObject<{
|
|
@@ -158,6 +172,7 @@ declare const budgetSchema: z.ZodObject<{
|
|
|
158
172
|
contains: z.ZodOptional<z.ZodString>;
|
|
159
173
|
regex: z.ZodOptional<z.ZodString>;
|
|
160
174
|
}, z.core.$strict>>>;
|
|
175
|
+
upstreams: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
161
176
|
}, z.core.$strict>;
|
|
162
177
|
field: z.ZodString;
|
|
163
178
|
}, z.core.$strict>>>;
|
|
@@ -177,16 +192,247 @@ declare const approvalChannelSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
177
192
|
type: z.ZodLiteral<"dashboard">;
|
|
178
193
|
name: z.ZodOptional<z.ZodString>;
|
|
179
194
|
}, z.core.$strict>], "type">;
|
|
180
|
-
|
|
181
|
-
|
|
195
|
+
declare const singularConfigSchema: z.ZodObject<{
|
|
196
|
+
listen: z.ZodPrefault<z.ZodObject<{
|
|
197
|
+
port: z.ZodDefault<z.ZodNumber>;
|
|
198
|
+
host: z.ZodDefault<z.ZodString>;
|
|
199
|
+
allowed_origins: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
200
|
+
}, z.core.$strict>>;
|
|
201
|
+
environment: z.ZodOptional<z.ZodString>;
|
|
202
|
+
session: z.ZodPrefault<z.ZodObject<{
|
|
203
|
+
identity: z.ZodDefault<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
204
|
+
source: z.ZodLiteral<"header">;
|
|
205
|
+
name: z.ZodPipe<z.ZodDefault<z.ZodString>, z.ZodTransform<string, string>>;
|
|
206
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
207
|
+
source: z.ZodLiteral<"meta">;
|
|
208
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
209
|
+
source: z.ZodLiteral<"legacy_header">;
|
|
210
|
+
}, z.core.$strict>], "source">>>;
|
|
211
|
+
on_unresolved: z.ZodDefault<z.ZodEnum<{
|
|
212
|
+
deny: "deny";
|
|
213
|
+
anonymous: "anonymous";
|
|
214
|
+
}>>;
|
|
215
|
+
}, z.core.$strict>>;
|
|
216
|
+
policies: z.ZodPrefault<z.ZodObject<{
|
|
217
|
+
default: z.ZodDefault<z.ZodEnum<{
|
|
218
|
+
deny: "deny";
|
|
219
|
+
allow: "allow";
|
|
220
|
+
}>>;
|
|
221
|
+
flag_destructive: z.ZodOptional<z.ZodEnum<{
|
|
222
|
+
require_approval: "require_approval";
|
|
223
|
+
log: "log";
|
|
224
|
+
}>>;
|
|
225
|
+
dry_run: z.ZodDefault<z.ZodBoolean>;
|
|
226
|
+
rules: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
227
|
+
name: z.ZodOptional<z.ZodString>;
|
|
228
|
+
match: z.ZodObject<{
|
|
229
|
+
tool: z.ZodOptional<z.ZodString>;
|
|
230
|
+
annotations: z.ZodOptional<z.ZodObject<{
|
|
231
|
+
readOnlyHint: z.ZodOptional<z.ZodBoolean>;
|
|
232
|
+
destructiveHint: z.ZodOptional<z.ZodBoolean>;
|
|
233
|
+
idempotentHint: z.ZodOptional<z.ZodBoolean>;
|
|
234
|
+
openWorldHint: z.ZodOptional<z.ZodBoolean>;
|
|
235
|
+
}, z.core.$strict>>;
|
|
236
|
+
input: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
237
|
+
eq: z.ZodOptional<z.ZodUnknown>;
|
|
238
|
+
neq: z.ZodOptional<z.ZodUnknown>;
|
|
239
|
+
gt: z.ZodOptional<z.ZodNumber>;
|
|
240
|
+
gte: z.ZodOptional<z.ZodNumber>;
|
|
241
|
+
lt: z.ZodOptional<z.ZodNumber>;
|
|
242
|
+
lte: z.ZodOptional<z.ZodNumber>;
|
|
243
|
+
contains: z.ZodOptional<z.ZodString>;
|
|
244
|
+
regex: z.ZodOptional<z.ZodString>;
|
|
245
|
+
}, z.core.$strict>>>;
|
|
246
|
+
environment: z.ZodOptional<z.ZodString>;
|
|
247
|
+
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
248
|
+
eq: z.ZodOptional<z.ZodString>;
|
|
249
|
+
neq: z.ZodOptional<z.ZodString>;
|
|
250
|
+
contains: z.ZodOptional<z.ZodString>;
|
|
251
|
+
regex: z.ZodOptional<z.ZodString>;
|
|
252
|
+
}, z.core.$strict>]>>>;
|
|
253
|
+
upstreams: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
254
|
+
}, z.core.$strict>;
|
|
255
|
+
action: z.ZodEnum<{
|
|
256
|
+
deny: "deny";
|
|
257
|
+
allow: "allow";
|
|
258
|
+
require_approval: "require_approval";
|
|
259
|
+
rate_limit: "rate_limit";
|
|
260
|
+
spend_limit: "spend_limit";
|
|
261
|
+
dry_run: "dry_run";
|
|
262
|
+
}>;
|
|
263
|
+
approval: z.ZodOptional<z.ZodObject<{
|
|
264
|
+
channel: z.ZodString;
|
|
265
|
+
timeout: z.ZodOptional<z.ZodString>;
|
|
266
|
+
delegates: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
267
|
+
escalation_after: z.ZodOptional<z.ZodString>;
|
|
268
|
+
}, z.core.$strict>>;
|
|
269
|
+
evidence: z.ZodOptional<z.ZodObject<{
|
|
270
|
+
requires: z.ZodArray<z.ZodString>;
|
|
271
|
+
}, z.core.$strict>>;
|
|
272
|
+
requires: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
273
|
+
requires_success: z.ZodOptional<z.ZodBoolean>;
|
|
274
|
+
limits: z.ZodOptional<z.ZodObject<{
|
|
275
|
+
max_calls: z.ZodOptional<z.ZodNumber>;
|
|
276
|
+
window: z.ZodOptional<z.ZodString>;
|
|
277
|
+
key: z.ZodOptional<z.ZodEnum<{
|
|
278
|
+
tool: "tool";
|
|
279
|
+
agent: "agent";
|
|
280
|
+
session: "session";
|
|
281
|
+
sender_id: "sender_id";
|
|
282
|
+
}>>;
|
|
283
|
+
max_spend: z.ZodOptional<z.ZodObject<{
|
|
284
|
+
field: z.ZodString;
|
|
285
|
+
limit: z.ZodNumber;
|
|
286
|
+
currency: z.ZodString;
|
|
287
|
+
window: z.ZodString;
|
|
288
|
+
key: z.ZodOptional<z.ZodEnum<{
|
|
289
|
+
tool: "tool";
|
|
290
|
+
agent: "agent";
|
|
291
|
+
session: "session";
|
|
292
|
+
sender_id: "sender_id";
|
|
293
|
+
}>>;
|
|
294
|
+
}, z.core.$strict>>;
|
|
295
|
+
}, z.core.$strict>>;
|
|
296
|
+
feedback: z.ZodOptional<z.ZodObject<{
|
|
297
|
+
message: z.ZodString;
|
|
298
|
+
suggestion: z.ZodOptional<z.ZodString>;
|
|
299
|
+
}, z.core.$strict>>;
|
|
300
|
+
}, z.core.$strict>>>;
|
|
301
|
+
install: z.ZodOptional<z.ZodObject<{
|
|
302
|
+
default: z.ZodDefault<z.ZodEnum<{
|
|
303
|
+
deny: "deny";
|
|
304
|
+
allow: "allow";
|
|
305
|
+
}>>;
|
|
306
|
+
rules: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
307
|
+
name: z.ZodOptional<z.ZodString>;
|
|
308
|
+
match: z.ZodObject<{
|
|
309
|
+
name: z.ZodOptional<z.ZodString>;
|
|
310
|
+
source: z.ZodOptional<z.ZodString>;
|
|
311
|
+
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
312
|
+
eq: z.ZodOptional<z.ZodString>;
|
|
313
|
+
neq: z.ZodOptional<z.ZodString>;
|
|
314
|
+
contains: z.ZodOptional<z.ZodString>;
|
|
315
|
+
regex: z.ZodOptional<z.ZodString>;
|
|
316
|
+
}, z.core.$strict>]>>>;
|
|
317
|
+
}, z.core.$strict>;
|
|
318
|
+
action: z.ZodEnum<{
|
|
319
|
+
allow: "allow";
|
|
320
|
+
deny_install: "deny_install";
|
|
321
|
+
}>;
|
|
322
|
+
feedback: z.ZodOptional<z.ZodObject<{
|
|
323
|
+
message: z.ZodString;
|
|
324
|
+
suggestion: z.ZodOptional<z.ZodString>;
|
|
325
|
+
}, z.core.$strict>>;
|
|
326
|
+
}, z.core.$strict>>>;
|
|
327
|
+
}, z.core.$strict>>;
|
|
328
|
+
on_tool_drift: z.ZodOptional<z.ZodEnum<{
|
|
329
|
+
require_approval: "require_approval";
|
|
330
|
+
log: "log";
|
|
331
|
+
block: "block";
|
|
332
|
+
}>>;
|
|
333
|
+
tool_revalidation: z.ZodOptional<z.ZodObject<{
|
|
334
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
335
|
+
interval: z.ZodDefault<z.ZodString>;
|
|
336
|
+
max_advertised_ttl: z.ZodOptional<z.ZodString>;
|
|
337
|
+
}, z.core.$strict>>;
|
|
338
|
+
hot_reload: z.ZodOptional<z.ZodBoolean>;
|
|
339
|
+
}, z.core.$strict>>;
|
|
340
|
+
budgets: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
341
|
+
name: z.ZodString;
|
|
342
|
+
limit: z.ZodNumber;
|
|
343
|
+
currency: z.ZodString;
|
|
344
|
+
window: z.ZodUnion<readonly [z.ZodString, z.ZodLiteral<"session">]>;
|
|
345
|
+
key: z.ZodDefault<z.ZodEnum<{
|
|
346
|
+
session: "session";
|
|
347
|
+
sender_id: "sender_id";
|
|
348
|
+
global: "global";
|
|
349
|
+
}>>;
|
|
350
|
+
on_exceed: z.ZodDefault<z.ZodEnum<{
|
|
351
|
+
deny: "deny";
|
|
352
|
+
require_approval: "require_approval";
|
|
353
|
+
}>>;
|
|
354
|
+
approval: z.ZodOptional<z.ZodObject<{
|
|
355
|
+
channel: z.ZodString;
|
|
356
|
+
timeout: z.ZodOptional<z.ZodString>;
|
|
357
|
+
delegates: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
358
|
+
escalation_after: z.ZodOptional<z.ZodString>;
|
|
359
|
+
}, z.core.$strict>>;
|
|
360
|
+
idle_ttl: z.ZodOptional<z.ZodString>;
|
|
361
|
+
contributors: z.ZodArray<z.ZodPipe<z.ZodUnknown, z.ZodObject<{
|
|
362
|
+
match: z.ZodObject<{
|
|
363
|
+
tool: z.ZodString;
|
|
364
|
+
input: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
365
|
+
eq: z.ZodOptional<z.ZodUnknown>;
|
|
366
|
+
neq: z.ZodOptional<z.ZodUnknown>;
|
|
367
|
+
gt: z.ZodOptional<z.ZodNumber>;
|
|
368
|
+
gte: z.ZodOptional<z.ZodNumber>;
|
|
369
|
+
lt: z.ZodOptional<z.ZodNumber>;
|
|
370
|
+
lte: z.ZodOptional<z.ZodNumber>;
|
|
371
|
+
contains: z.ZodOptional<z.ZodString>;
|
|
372
|
+
regex: z.ZodOptional<z.ZodString>;
|
|
373
|
+
}, z.core.$strict>>>;
|
|
374
|
+
upstreams: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
375
|
+
}, z.core.$strict>;
|
|
376
|
+
field: z.ZodString;
|
|
377
|
+
}, z.core.$strict>>>;
|
|
378
|
+
}, z.core.$strict>>>;
|
|
379
|
+
approval: z.ZodPrefault<z.ZodObject<{
|
|
380
|
+
timeout: z.ZodDefault<z.ZodString>;
|
|
381
|
+
default_on_timeout: z.ZodDefault<z.ZodEnum<{
|
|
382
|
+
deny: "deny";
|
|
383
|
+
allow: "allow";
|
|
384
|
+
}>>;
|
|
385
|
+
channels: z.ZodDefault<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
386
|
+
type: z.ZodLiteral<"slack">;
|
|
387
|
+
name: z.ZodOptional<z.ZodString>;
|
|
388
|
+
bot_token: z.ZodString;
|
|
389
|
+
signing_secret: z.ZodString;
|
|
390
|
+
channel: z.ZodString;
|
|
391
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
392
|
+
type: z.ZodLiteral<"webhook">;
|
|
393
|
+
name: z.ZodOptional<z.ZodString>;
|
|
394
|
+
url: z.ZodString;
|
|
395
|
+
secret: z.ZodOptional<z.ZodString>;
|
|
396
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
397
|
+
type: z.ZodLiteral<"dashboard">;
|
|
398
|
+
name: z.ZodOptional<z.ZodString>;
|
|
399
|
+
}, z.core.$strict>], "type">>>;
|
|
400
|
+
}, z.core.$strict>>;
|
|
401
|
+
audit: z.ZodPrefault<z.ZodObject<{
|
|
402
|
+
storage: z.ZodDefault<z.ZodEnum<{
|
|
403
|
+
sqlite: "sqlite";
|
|
404
|
+
}>>;
|
|
405
|
+
path: z.ZodDefault<z.ZodString>;
|
|
406
|
+
retention: z.ZodDefault<z.ZodString>;
|
|
407
|
+
include_responses: z.ZodDefault<z.ZodBoolean>;
|
|
408
|
+
}, z.core.$strict>>;
|
|
409
|
+
dashboard: z.ZodPrefault<z.ZodObject<{
|
|
410
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
411
|
+
port: z.ZodDefault<z.ZodNumber>;
|
|
412
|
+
host: z.ZodDefault<z.ZodString>;
|
|
413
|
+
api_secret: z.ZodOptional<z.ZodString>;
|
|
414
|
+
allow_open_mode: z.ZodDefault<z.ZodBoolean>;
|
|
415
|
+
sse_heartbeat_interval: z.ZodDefault<z.ZodString>;
|
|
416
|
+
}, z.core.$strict>>;
|
|
417
|
+
sdk: z.ZodPrefault<z.ZodObject<{
|
|
418
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
419
|
+
port: z.ZodDefault<z.ZodNumber>;
|
|
420
|
+
host: z.ZodDefault<z.ZodString>;
|
|
421
|
+
evaluation_ttl: z.ZodDefault<z.ZodString>;
|
|
422
|
+
}, z.core.$strict>>;
|
|
182
423
|
version: z.ZodLiteral<"1">;
|
|
183
424
|
upstream: z.ZodObject<{
|
|
184
|
-
url: z.ZodString
|
|
425
|
+
url: z.ZodOptional<z.ZodString>;
|
|
185
426
|
transport: z.ZodDefault<z.ZodEnum<{
|
|
186
427
|
"streamable-http": "streamable-http";
|
|
187
428
|
sse: "sse";
|
|
188
429
|
stdio: "stdio";
|
|
189
430
|
}>>;
|
|
431
|
+
protocol_version: z.ZodDefault<z.ZodEnum<{
|
|
432
|
+
auto: "auto";
|
|
433
|
+
"2025-06-18": "2025-06-18";
|
|
434
|
+
"2026-07-28": "2026-07-28";
|
|
435
|
+
}>>;
|
|
190
436
|
command: z.ZodOptional<z.ZodString>;
|
|
191
437
|
args: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
192
438
|
connect_timeout: z.ZodDefault<z.ZodString>;
|
|
@@ -194,15 +440,32 @@ declare const helioConfigSchema: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.Z
|
|
|
194
440
|
forward_headers: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
195
441
|
headers: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
196
442
|
}, z.core.$strict>;
|
|
443
|
+
}, z.core.$strict>;
|
|
444
|
+
declare const namedConfigSchema: z.ZodObject<{
|
|
197
445
|
listen: z.ZodPrefault<z.ZodObject<{
|
|
198
446
|
port: z.ZodDefault<z.ZodNumber>;
|
|
199
447
|
host: z.ZodDefault<z.ZodString>;
|
|
448
|
+
allowed_origins: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
200
449
|
}, z.core.$strict>>;
|
|
201
450
|
environment: z.ZodOptional<z.ZodString>;
|
|
451
|
+
session: z.ZodPrefault<z.ZodObject<{
|
|
452
|
+
identity: z.ZodDefault<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
453
|
+
source: z.ZodLiteral<"header">;
|
|
454
|
+
name: z.ZodPipe<z.ZodDefault<z.ZodString>, z.ZodTransform<string, string>>;
|
|
455
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
456
|
+
source: z.ZodLiteral<"meta">;
|
|
457
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
458
|
+
source: z.ZodLiteral<"legacy_header">;
|
|
459
|
+
}, z.core.$strict>], "source">>>;
|
|
460
|
+
on_unresolved: z.ZodDefault<z.ZodEnum<{
|
|
461
|
+
deny: "deny";
|
|
462
|
+
anonymous: "anonymous";
|
|
463
|
+
}>>;
|
|
464
|
+
}, z.core.$strict>>;
|
|
202
465
|
policies: z.ZodPrefault<z.ZodObject<{
|
|
203
466
|
default: z.ZodDefault<z.ZodEnum<{
|
|
204
|
-
allow: "allow";
|
|
205
467
|
deny: "deny";
|
|
468
|
+
allow: "allow";
|
|
206
469
|
}>>;
|
|
207
470
|
flag_destructive: z.ZodOptional<z.ZodEnum<{
|
|
208
471
|
require_approval: "require_approval";
|
|
@@ -236,10 +499,11 @@ declare const helioConfigSchema: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.Z
|
|
|
236
499
|
contains: z.ZodOptional<z.ZodString>;
|
|
237
500
|
regex: z.ZodOptional<z.ZodString>;
|
|
238
501
|
}, z.core.$strict>]>>>;
|
|
502
|
+
upstreams: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
239
503
|
}, z.core.$strict>;
|
|
240
504
|
action: z.ZodEnum<{
|
|
241
|
-
allow: "allow";
|
|
242
505
|
deny: "deny";
|
|
506
|
+
allow: "allow";
|
|
243
507
|
require_approval: "require_approval";
|
|
244
508
|
rate_limit: "rate_limit";
|
|
245
509
|
spend_limit: "spend_limit";
|
|
@@ -285,8 +549,8 @@ declare const helioConfigSchema: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.Z
|
|
|
285
549
|
}, z.core.$strict>>>;
|
|
286
550
|
install: z.ZodOptional<z.ZodObject<{
|
|
287
551
|
default: z.ZodDefault<z.ZodEnum<{
|
|
288
|
-
allow: "allow";
|
|
289
552
|
deny: "deny";
|
|
553
|
+
allow: "allow";
|
|
290
554
|
}>>;
|
|
291
555
|
rules: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
292
556
|
name: z.ZodOptional<z.ZodString>;
|
|
@@ -315,6 +579,11 @@ declare const helioConfigSchema: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.Z
|
|
|
315
579
|
log: "log";
|
|
316
580
|
block: "block";
|
|
317
581
|
}>>;
|
|
582
|
+
tool_revalidation: z.ZodOptional<z.ZodObject<{
|
|
583
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
584
|
+
interval: z.ZodDefault<z.ZodString>;
|
|
585
|
+
max_advertised_ttl: z.ZodOptional<z.ZodString>;
|
|
586
|
+
}, z.core.$strict>>;
|
|
318
587
|
hot_reload: z.ZodOptional<z.ZodBoolean>;
|
|
319
588
|
}, z.core.$strict>>;
|
|
320
589
|
budgets: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
@@ -351,6 +620,7 @@ declare const helioConfigSchema: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.Z
|
|
|
351
620
|
contains: z.ZodOptional<z.ZodString>;
|
|
352
621
|
regex: z.ZodOptional<z.ZodString>;
|
|
353
622
|
}, z.core.$strict>>>;
|
|
623
|
+
upstreams: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
354
624
|
}, z.core.$strict>;
|
|
355
625
|
field: z.ZodString;
|
|
356
626
|
}, z.core.$strict>>>;
|
|
@@ -358,8 +628,8 @@ declare const helioConfigSchema: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.Z
|
|
|
358
628
|
approval: z.ZodPrefault<z.ZodObject<{
|
|
359
629
|
timeout: z.ZodDefault<z.ZodString>;
|
|
360
630
|
default_on_timeout: z.ZodDefault<z.ZodEnum<{
|
|
361
|
-
allow: "allow";
|
|
362
631
|
deny: "deny";
|
|
632
|
+
allow: "allow";
|
|
363
633
|
}>>;
|
|
364
634
|
channels: z.ZodDefault<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
365
635
|
type: z.ZodLiteral<"slack">;
|
|
@@ -399,13 +669,44 @@ declare const helioConfigSchema: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.Z
|
|
|
399
669
|
host: z.ZodDefault<z.ZodString>;
|
|
400
670
|
evaluation_ttl: z.ZodDefault<z.ZodString>;
|
|
401
671
|
}, z.core.$strict>>;
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
672
|
+
version: z.ZodLiteral<"1">;
|
|
673
|
+
upstreams: z.ZodArray<z.ZodObject<{
|
|
674
|
+
url: z.ZodOptional<z.ZodString>;
|
|
675
|
+
transport: z.ZodDefault<z.ZodEnum<{
|
|
676
|
+
"streamable-http": "streamable-http";
|
|
677
|
+
sse: "sse";
|
|
678
|
+
stdio: "stdio";
|
|
679
|
+
}>>;
|
|
680
|
+
protocol_version: z.ZodDefault<z.ZodEnum<{
|
|
681
|
+
auto: "auto";
|
|
682
|
+
"2025-06-18": "2025-06-18";
|
|
683
|
+
"2026-07-28": "2026-07-28";
|
|
684
|
+
}>>;
|
|
685
|
+
command: z.ZodOptional<z.ZodString>;
|
|
686
|
+
args: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
687
|
+
connect_timeout: z.ZodDefault<z.ZodString>;
|
|
688
|
+
request_timeout: z.ZodDefault<z.ZodString>;
|
|
689
|
+
forward_headers: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
690
|
+
headers: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
691
|
+
name: z.ZodString;
|
|
692
|
+
}, z.core.$strict>>;
|
|
693
|
+
}, z.core.$strict>;
|
|
694
|
+
/** A fully validated and defaulted singular-mode (`upstream:`) configuration. */
|
|
695
|
+
type SingularHelioConfig = z.output<typeof singularConfigSchema>;
|
|
696
|
+
/** A fully validated and defaulted named-mode (`upstreams:`) configuration. */
|
|
697
|
+
type NamedHelioConfig = z.output<typeof namedConfigSchema>;
|
|
698
|
+
/** Fully validated and defaulted Helio configuration — one of the two mode arms. */
|
|
699
|
+
type HelioConfig = SingularHelioConfig | NamedHelioConfig;
|
|
700
|
+
/** Narrow a parsed config to the singular-mode (`upstream:`) arm. */
|
|
701
|
+
declare function isSingularConfig(config: HelioConfig): config is SingularHelioConfig;
|
|
702
|
+
/** Narrow a parsed config to the named-mode (`upstreams:`) arm. */
|
|
703
|
+
declare function isNamedConfig(config: HelioConfig): config is NamedHelioConfig;
|
|
405
704
|
/** An approval channel configuration (slack, webhook, or dashboard). */
|
|
406
705
|
type ApprovalChannel$1 = z.infer<typeof approvalChannelSchema>;
|
|
407
706
|
/** The policies section of the config. */
|
|
408
707
|
type PoliciesConfig = z.infer<typeof policiesSchema>;
|
|
708
|
+
/** A single identity source from `session.identity`. */
|
|
709
|
+
type SessionIdentitySource = z.infer<typeof sessionIdentitySourceSchema>;
|
|
409
710
|
/** A single named budget from the `budgets` array (issue #14). */
|
|
410
711
|
type BudgetConfig = z.infer<typeof budgetSchema>;
|
|
411
712
|
/** The `budgets` section of the config. */
|
|
@@ -490,6 +791,8 @@ interface CompiledMatch {
|
|
|
490
791
|
readonly environment?: string;
|
|
491
792
|
/** Flattened list of metadata conditions (one entry per key+operator pair). */
|
|
492
793
|
readonly metadata?: readonly MetadataCondition[];
|
|
794
|
+
/** Configured upstream names the rule is scoped to, OR within the list (issue #293). */
|
|
795
|
+
readonly upstreams?: readonly string[];
|
|
493
796
|
}
|
|
494
797
|
/** Compiled approval configuration with durations as milliseconds. */
|
|
495
798
|
interface CompiledApproval {
|
|
@@ -513,6 +816,12 @@ interface CompiledLimits {
|
|
|
513
816
|
readonly key?: 'tool' | 'agent' | 'session' | 'sender_id';
|
|
514
817
|
readonly maxSpend?: CompiledSpendLimit;
|
|
515
818
|
}
|
|
819
|
+
/** Compiled tool revalidation settings with durations as milliseconds. */
|
|
820
|
+
interface CompiledToolRevalidation {
|
|
821
|
+
readonly enabled: boolean;
|
|
822
|
+
readonly intervalMs: number;
|
|
823
|
+
readonly maxAdvertisedTtlMs: number;
|
|
824
|
+
}
|
|
516
825
|
/** Policy action types. */
|
|
517
826
|
type PolicyAction = 'allow' | 'deny' | 'require_approval' | 'rate_limit' | 'spend_limit' | 'dry_run';
|
|
518
827
|
/** A fully compiled policy rule ready for engine evaluation. */
|
|
@@ -576,6 +885,8 @@ interface CompiledPolicy {
|
|
|
576
885
|
* at the use site — conservative by default.
|
|
577
886
|
*/
|
|
578
887
|
readonly onToolDrift?: 'block' | 'require_approval' | 'log';
|
|
888
|
+
/** Always set by compilePolicies; absent only in hand-built fixtures (treated as disabled). */
|
|
889
|
+
readonly toolRevalidation?: CompiledToolRevalidation;
|
|
579
890
|
readonly rules: readonly CompiledPolicyRule[];
|
|
580
891
|
/** Install-time policy (issue #13 — deny_install). Undefined ⇒ observational. */
|
|
581
892
|
readonly install?: CompiledInstallPolicy;
|
|
@@ -625,6 +936,12 @@ interface MatchContext {
|
|
|
625
936
|
* request column) is merged in by the decision pipeline, not stored here twice.
|
|
626
937
|
*/
|
|
627
938
|
readonly metadata?: Readonly<Record<string, unknown>>;
|
|
939
|
+
/**
|
|
940
|
+
* The governed door's configured upstream name (issue #295). A string only on
|
|
941
|
+
* the MCP path when a name is configured; undefined on the sideband and in
|
|
942
|
+
* singular mode, so upstream-scoped rules are inert there by construction.
|
|
943
|
+
*/
|
|
944
|
+
readonly upstream?: string;
|
|
628
945
|
}
|
|
629
946
|
|
|
630
947
|
/** One compiled contributor: which calls feed the budget, and from which field. */
|
|
@@ -634,6 +951,13 @@ interface CompiledBudgetContributor {
|
|
|
634
951
|
/** Flattened conditions (one per path+operator); absent when unconditioned. */
|
|
635
952
|
readonly input?: readonly InputCondition[];
|
|
636
953
|
};
|
|
954
|
+
/**
|
|
955
|
+
* Configured upstream names the contributor is scoped to (issue #293);
|
|
956
|
+
* absent means every door contributes. A scoped contributor never
|
|
957
|
+
* participates when the charge context carries no upstream (sideband,
|
|
958
|
+
* singular mode).
|
|
959
|
+
*/
|
|
960
|
+
readonly upstreams?: readonly string[];
|
|
637
961
|
/** Dot-path into the tool arguments (e.g. "$.amount"), resolved per call. */
|
|
638
962
|
readonly field: string;
|
|
639
963
|
}
|
|
@@ -679,15 +1003,63 @@ interface JsonRpcRequest {
|
|
|
679
1003
|
method: string;
|
|
680
1004
|
params?: unknown;
|
|
681
1005
|
}
|
|
1006
|
+
/** Resolved governance session identity (issue #218). */
|
|
1007
|
+
interface ResolvedSession {
|
|
1008
|
+
readonly id: string;
|
|
1009
|
+
/** Strategy that produced it — recorded in the audit trail. */
|
|
1010
|
+
readonly source: 'header' | 'meta' | 'legacy_header' | 'transport';
|
|
1011
|
+
}
|
|
682
1012
|
/** A parsed MCP request enriched with session context. */
|
|
683
1013
|
interface McpRequest extends JsonRpcRequest {
|
|
684
|
-
/**
|
|
685
|
-
|
|
1014
|
+
/** Proxy-resolved governance session identity (undefined when no strategy matched). */
|
|
1015
|
+
session?: ResolvedSession;
|
|
1016
|
+
/** Verbatim Mcp-Session-Id from the wire. Transport relay ONLY — never governance. */
|
|
1017
|
+
transportSessionId?: string;
|
|
1018
|
+
/**
|
|
1019
|
+
* The client's verbatim MCP-Protocol-Version wire claim (issue #219) —
|
|
1020
|
+
* captured raw, with no normalization, for the audit trail. It is the
|
|
1021
|
+
* CLIENT'S claim, not the upstream era. Since issue #226 the
|
|
1022
|
+
* streamable-http route validates header/body agreement before
|
|
1023
|
+
* forwarding, so on a FORWARDED request a claim of `2026-07-28` has
|
|
1024
|
+
* passed the agreement door; tier-2 claims (legacy, unknown, malformed)
|
|
1025
|
+
* and notification claims remain unvalidated as captured. Streamable
|
|
1026
|
+
* HTTP only: the header postdates the deprecated SSE transport, and
|
|
1027
|
+
* stdio has no headers, so both leave it unset.
|
|
1028
|
+
*/
|
|
1029
|
+
protocolVersion?: string;
|
|
686
1030
|
/** Per-request headers to forward to upstream (e.g. Authorization, X-* headers). */
|
|
687
1031
|
headers?: Record<string, string>;
|
|
688
1032
|
/** Abort signal tied to the downstream client request lifecycle. */
|
|
689
1033
|
signal?: AbortSignal;
|
|
690
1034
|
}
|
|
1035
|
+
/**
|
|
1036
|
+
* An inbound request rejected by the header/body agreement door (issue
|
|
1037
|
+
* #226), as protocol facts: what the body said, what the headers claimed,
|
|
1038
|
+
* and why they disagree. Deliberately camelCase and transport-free (no Hono
|
|
1039
|
+
* types, no audit field names) — the audit-record mapping lives solely in
|
|
1040
|
+
* `buildHeaderMismatchAuditRecord` on the audit side.
|
|
1041
|
+
*/
|
|
1042
|
+
interface HeaderMismatchRejection {
|
|
1043
|
+
/** Human-readable mismatch reason; echoed values are display-capped. */
|
|
1044
|
+
readonly reason: string;
|
|
1045
|
+
/** The body's JSON-RPC method. */
|
|
1046
|
+
readonly method: string;
|
|
1047
|
+
/** The body's params, verbatim as parsed. */
|
|
1048
|
+
readonly params?: unknown;
|
|
1049
|
+
/**
|
|
1050
|
+
* The body's name-bearing string field (`params.name` / `params.uri`),
|
|
1051
|
+
* when the method defines one and the body carries a string value.
|
|
1052
|
+
*/
|
|
1053
|
+
readonly bodyName?: string;
|
|
1054
|
+
/** The client's verbatim MCP-Protocol-Version wire claim, if any. */
|
|
1055
|
+
readonly protocolVersion?: string;
|
|
1056
|
+
/** The inbound marker headers that were present, verbatim as received. */
|
|
1057
|
+
readonly headers: Readonly<Record<string, string>>;
|
|
1058
|
+
/** Proxy-resolved governance session identity, when a strategy matched. */
|
|
1059
|
+
readonly session?: ResolvedSession;
|
|
1060
|
+
/** Time from route-handler entry to rejection, in milliseconds. */
|
|
1061
|
+
readonly durationMs: number;
|
|
1062
|
+
}
|
|
691
1063
|
/** The response returned by an MCP forwarder. */
|
|
692
1064
|
interface McpResponse {
|
|
693
1065
|
status: number;
|
|
@@ -724,6 +1096,13 @@ interface ServerHandle {
|
|
|
724
1096
|
interface CreateAppOptions {
|
|
725
1097
|
/** Slack interactive action handler (mounted at /slack/actions). */
|
|
726
1098
|
slackActionApp?: Hono;
|
|
1099
|
+
/**
|
|
1100
|
+
* Recorder for inbound header/body agreement rejections (issue #226) on
|
|
1101
|
+
* the streamable-http route. Enforcement does not depend on it — with no
|
|
1102
|
+
* recorder the request is still rejected and no record is written (the
|
|
1103
|
+
* library-embedding posture `missing_tool_name` also takes).
|
|
1104
|
+
*/
|
|
1105
|
+
onHeaderMismatch?: (rejection: HeaderMismatchRejection) => void;
|
|
727
1106
|
}
|
|
728
1107
|
/**
|
|
729
1108
|
* Create a Hono app configured with the MCP proxy routes.
|
|
@@ -733,6 +1112,47 @@ interface CreateAppOptions {
|
|
|
733
1112
|
* @param options - Optional sub-apps to mount.
|
|
734
1113
|
*/
|
|
735
1114
|
declare function createApp(config: HelioConfig, forwarder: McpForwarder, options?: CreateAppOptions): Hono;
|
|
1115
|
+
/**
|
|
1116
|
+
* Optional sub-apps and callbacks for the multi-upstream composition.
|
|
1117
|
+
* The main-port posture is `createApp`'s (see CreateAppOptions): only the
|
|
1118
|
+
* Slack webhook callback belongs beside the MCP doors.
|
|
1119
|
+
*/
|
|
1120
|
+
interface CreateMultiAppOptions {
|
|
1121
|
+
/** Slack interactive action handler (mounted at /slack/actions, global). */
|
|
1122
|
+
slackActionApp?: Hono;
|
|
1123
|
+
/**
|
|
1124
|
+
* Recorder for inbound header/body agreement rejections (issue #226),
|
|
1125
|
+
* called with the name of the door that rejected so the audit record can
|
|
1126
|
+
* attribute it. Enforcement does not depend on it.
|
|
1127
|
+
*/
|
|
1128
|
+
onHeaderMismatch?: (rejection: HeaderMismatchRejection, upstreamName: string) => void;
|
|
1129
|
+
/**
|
|
1130
|
+
* @internal Test seam for the per-door concurrent-session cap on the
|
|
1131
|
+
* `/sse/<name>` mounts (issue #232's cap, per-route by construction), so
|
|
1132
|
+
* tests need not mint 1024 real streams per door. The same value goes to
|
|
1133
|
+
* every door's route; the session maps stay per-route-instance. Not wired
|
|
1134
|
+
* to config — absent means the hardcoded 1024.
|
|
1135
|
+
*/
|
|
1136
|
+
sse?: {
|
|
1137
|
+
readonly maxConcurrentSessions?: number;
|
|
1138
|
+
};
|
|
1139
|
+
}
|
|
1140
|
+
/**
|
|
1141
|
+
* Create a Hono app serving every named upstream at its own pair of mounts,
|
|
1142
|
+
* `/mcp/<name>` and `/sse/<name>`, each a fresh route stack wrapping that
|
|
1143
|
+
* entry's forwarder. `/healthz` and `/slack/actions` stay global. There is
|
|
1144
|
+
* NO bare-path default: bare `/mcp`, `/sse`, and unknown names get an
|
|
1145
|
+
* explicit 404 catch-all whose JSON-RPC envelope states the path shape and
|
|
1146
|
+
* never enumerates configured names.
|
|
1147
|
+
*
|
|
1148
|
+
* @param config - The validated named-mode Helio configuration.
|
|
1149
|
+
* @param forwarders - One forwarder per configured entry, keyed by name.
|
|
1150
|
+
* Must cover the configured names exactly; missing or extra keys throw
|
|
1151
|
+
* (a missing key would silently mount a dead door, an extra one means the
|
|
1152
|
+
* record drifted from the config — fail at composition, not per request).
|
|
1153
|
+
* @param options - Optional sub-apps and callbacks.
|
|
1154
|
+
*/
|
|
1155
|
+
declare function createMultiApp(config: HelioConfig, forwarders: Record<string, McpForwarder>, options?: CreateMultiAppOptions): Hono;
|
|
736
1156
|
/**
|
|
737
1157
|
* Start the HTTP server on the configured host and port.
|
|
738
1158
|
*
|
|
@@ -748,6 +1168,12 @@ declare function startServer(app: Hono, config: HelioConfig): ServerHandle;
|
|
|
748
1168
|
*/
|
|
749
1169
|
declare function startSidebandServer(app: Hono, port: number, host?: string): ServerHandle;
|
|
750
1170
|
|
|
1171
|
+
/**
|
|
1172
|
+
* `upstream.protocol_version`: `auto` probes and caches; a dated pin is a
|
|
1173
|
+
* constant — never probed, never cached, never cleared.
|
|
1174
|
+
*/
|
|
1175
|
+
type UpstreamProtocolVersionPin = 'auto' | '2025-06-18' | '2026-07-28';
|
|
1176
|
+
|
|
751
1177
|
interface StreamableHttpForwarderOptions {
|
|
752
1178
|
/** The upstream MCP server URL (e.g. "http://localhost:8080/mcp"). */
|
|
753
1179
|
url: string;
|
|
@@ -755,6 +1181,13 @@ interface StreamableHttpForwarderOptions {
|
|
|
755
1181
|
headers?: Record<string, string>;
|
|
756
1182
|
/** Maximum time to wait for an upstream request before aborting. */
|
|
757
1183
|
requestTimeoutMs?: number;
|
|
1184
|
+
/** `upstream.protocol_version`: `auto` (default) probes; a dated pin skips it. */
|
|
1185
|
+
protocolVersion?: UpstreamProtocolVersionPin;
|
|
1186
|
+
/**
|
|
1187
|
+
* The operator-chosen upstream entry name (issue #295), threaded to the
|
|
1188
|
+
* session manager's era lifecycle lines. Unset in singular mode.
|
|
1189
|
+
*/
|
|
1190
|
+
upstreamName?: string;
|
|
758
1191
|
}
|
|
759
1192
|
/**
|
|
760
1193
|
* Spec-compliant upstream MCP Streamable HTTP client.
|
|
@@ -775,11 +1208,35 @@ declare class StreamableHttpForwarder implements McpForwarder {
|
|
|
775
1208
|
/** Lifecycle parity with sse/stdio. */
|
|
776
1209
|
close(): Promise<void>;
|
|
777
1210
|
forward(request: McpRequest): Promise<ForwardResult>;
|
|
1211
|
+
/**
|
|
1212
|
+
* The dual-era bridge (relay leg, modern era): a modern-only server
|
|
1213
|
+
* answers the retired `initialize` handshake with 404/-32601, so Helio
|
|
1214
|
+
* synthesizes the legacy InitializeResult locally from the upstream's own
|
|
1215
|
+
* probe-time DiscoverResult. No `mcp-session-id` response header — the
|
|
1216
|
+
* legacy spec permits sessionless servers, and the downstream stays
|
|
1217
|
+
* sessionless. The synthesized protocolVersion is always the current
|
|
1218
|
+
* legacy revision, even for a client that offered an older one.
|
|
1219
|
+
*/
|
|
1220
|
+
private synthesizeInitializeResult;
|
|
1221
|
+
/**
|
|
1222
|
+
* The modern upstream removed `notifications/initialized`; answer the
|
|
1223
|
+
* same minimal success envelope the SSE-notification path returns.
|
|
1224
|
+
*/
|
|
1225
|
+
private swallowInitializedNotification;
|
|
1226
|
+
/**
|
|
1227
|
+
* The relay-side era falsification door (issue #219): a legacy-leg relay whose answer only a
|
|
1228
|
+
* modern server gives clears the cached legacy era (the manager no-ops on
|
|
1229
|
+
* pins, uncached eras, and cached modern). The response still flows to the
|
|
1230
|
+
* client unchanged — no in-place retry.
|
|
1231
|
+
*/
|
|
1232
|
+
private inspectLegacyRelayOutcome;
|
|
778
1233
|
/**
|
|
779
1234
|
* Helio-internal execution path (startup prime / internal maintenance) that
|
|
780
1235
|
* may borrow the proxy-managed internal session.
|
|
781
1236
|
*/
|
|
782
1237
|
forwardInternal(request: McpRequest): Promise<ForwardResult>;
|
|
1238
|
+
/** Drop the managed internal session AND the cached era; next internal call re-probes. */
|
|
1239
|
+
resetInternalSession(): void;
|
|
783
1240
|
private send;
|
|
784
1241
|
}
|
|
785
1242
|
|
|
@@ -849,6 +1306,11 @@ interface StdioForwarderOptions {
|
|
|
849
1306
|
retryDelayMs?: number;
|
|
850
1307
|
/** Timeout in milliseconds for individual requests. */
|
|
851
1308
|
requestTimeoutMs?: number;
|
|
1309
|
+
/**
|
|
1310
|
+
* The operator-chosen upstream entry name (multi-upstream mode). Unset in
|
|
1311
|
+
* singular mode — the death line then keeps its bare `[helio]` tag.
|
|
1312
|
+
*/
|
|
1313
|
+
upstreamName?: string;
|
|
852
1314
|
}
|
|
853
1315
|
/**
|
|
854
1316
|
* Forward MCP requests to an upstream server via stdio.
|
|
@@ -862,6 +1324,7 @@ declare class StdioForwarder implements McpForwarder {
|
|
|
862
1324
|
private readonly maxRetries;
|
|
863
1325
|
private readonly retryDelayMs;
|
|
864
1326
|
private readonly pending;
|
|
1327
|
+
private readonly logTag;
|
|
865
1328
|
private child;
|
|
866
1329
|
private buffer;
|
|
867
1330
|
private retryCount;
|
|
@@ -939,8 +1402,14 @@ interface AuditRecord {
|
|
|
939
1402
|
readonly id: string;
|
|
940
1403
|
/** ISO 8601 timestamp of when the tool call was received by the proxy. */
|
|
941
1404
|
readonly timestamp: string;
|
|
942
|
-
/**
|
|
1405
|
+
/** Resolved governance session id, or the adapter-supplied id on sideband records. */
|
|
943
1406
|
readonly session_id: string | null;
|
|
1407
|
+
/**
|
|
1408
|
+
* Which identity strategy produced session_id (issue #218): `header`,
|
|
1409
|
+
* `meta`, `legacy_header`, or `transport` on the MCP door, `sideband` for
|
|
1410
|
+
* adapter-supplied ids. Null when no session resolved.
|
|
1411
|
+
*/
|
|
1412
|
+
readonly session_source: string | null;
|
|
944
1413
|
/** Agent identifier from config or request header, if present. */
|
|
945
1414
|
readonly agent_id: string | null;
|
|
946
1415
|
/** Runtime environment label configured on proxy startup, if set. */
|
|
@@ -1007,6 +1476,22 @@ interface AuditRecord {
|
|
|
1007
1476
|
* `match.metadata.*` (#13) and the dashboard metadata columns (#16).
|
|
1008
1477
|
*/
|
|
1009
1478
|
readonly metadata: Record<string, unknown> | null;
|
|
1479
|
+
/**
|
|
1480
|
+
* The client's verbatim MCP-Protocol-Version wire claim on the inbound
|
|
1481
|
+
* request (issue #219) — the CLIENT'S claim, not the upstream era, and not
|
|
1482
|
+
* a validated fact. Recorded uncapped: truncation would manufacture a
|
|
1483
|
+
* false claim in an audit record. Null when the request carried no header
|
|
1484
|
+
* and on records with no MCP wire (drift events, sideband records).
|
|
1485
|
+
*/
|
|
1486
|
+
readonly protocol_version: string | null;
|
|
1487
|
+
/**
|
|
1488
|
+
* Name of the upstream MCP server this record is attributed to (issue
|
|
1489
|
+
* #292). Null in singular mode (no named upstreams configured), on
|
|
1490
|
+
* sideband records (no MCP door), and on rows that predate the column.
|
|
1491
|
+
* Required-nullable like session_source/protocol_version: a producer that
|
|
1492
|
+
* could silently omit it would exempt that door from attribution.
|
|
1493
|
+
*/
|
|
1494
|
+
readonly upstream: string | null;
|
|
1010
1495
|
/** ISO 8601 timestamp of when the record was persisted. */
|
|
1011
1496
|
readonly created_at: string;
|
|
1012
1497
|
}
|
|
@@ -1022,6 +1507,18 @@ interface AuditQueryFilters {
|
|
|
1022
1507
|
readonly blocked?: boolean;
|
|
1023
1508
|
/** Filter by session ID (exact match). */
|
|
1024
1509
|
readonly session_id?: string;
|
|
1510
|
+
/**
|
|
1511
|
+
* Filter by session identity source (exact match — the five-value
|
|
1512
|
+
* `header` / `meta` / `legacy_header` / `transport` / `sideband`
|
|
1513
|
+
* vocabulary, issue #250). SQL equality: rows whose session_source is
|
|
1514
|
+
* NULL never match any filter value.
|
|
1515
|
+
*/
|
|
1516
|
+
readonly session_source?: string;
|
|
1517
|
+
/**
|
|
1518
|
+
* Filter by upstream name (exact match). SQL equality: rows whose
|
|
1519
|
+
* upstream is NULL never match any filter value.
|
|
1520
|
+
*/
|
|
1521
|
+
readonly upstream?: string;
|
|
1025
1522
|
/** Filter by agent ID (exact match). */
|
|
1026
1523
|
readonly agent_id?: string;
|
|
1027
1524
|
/** Include only records created at or after this ISO 8601 timestamp. */
|
|
@@ -1090,9 +1587,15 @@ interface AuditAggregateStats {
|
|
|
1090
1587
|
readonly reason: string;
|
|
1091
1588
|
readonly count: number;
|
|
1092
1589
|
}>;
|
|
1093
|
-
/**
|
|
1590
|
+
/**
|
|
1591
|
+
* Top tools by call count (max 10 rows). Each row is a (tool, upstream)
|
|
1592
|
+
* pair (issue #297): same-named tools on different upstreams stay
|
|
1593
|
+
* distinct. Upstream is null in singular mode, so all-null groups reduce
|
|
1594
|
+
* to exactly the pre-#297 per-tool rows.
|
|
1595
|
+
*/
|
|
1094
1596
|
readonly top_tools: ReadonlyArray<{
|
|
1095
1597
|
readonly tool_name: string;
|
|
1598
|
+
readonly upstream: string | null;
|
|
1096
1599
|
readonly count: number;
|
|
1097
1600
|
}>;
|
|
1098
1601
|
/** Approval rate (approved / total require_approval decisions), or null if none. */
|
|
@@ -1215,8 +1718,15 @@ declare class AuditStore {
|
|
|
1215
1718
|
private query;
|
|
1216
1719
|
/** Count records matching the given filters. */
|
|
1217
1720
|
count(filters?: AuditQueryFilters): number;
|
|
1218
|
-
/**
|
|
1219
|
-
|
|
1721
|
+
/**
|
|
1722
|
+
* Get aggregate statistics for a time range. The optional upstream filter
|
|
1723
|
+
* scopes EVERY sub-aggregate (totals, by_decision, by_block_reason,
|
|
1724
|
+
* top_tools, approval_rate, per_hour) — "analytics for this door", not one
|
|
1725
|
+
* filtered chart. Exact match: null-upstream rows never match any value.
|
|
1726
|
+
*/
|
|
1727
|
+
aggregate(from?: string, to?: string, filters?: {
|
|
1728
|
+
upstream?: string;
|
|
1729
|
+
}): AuditAggregateStats;
|
|
1220
1730
|
/** Delete records older than the retention period. Returns the count of deleted records. */
|
|
1221
1731
|
purgeExpired(): number;
|
|
1222
1732
|
private purgeBefore;
|
|
@@ -1504,6 +2014,18 @@ interface ApprovalTicket {
|
|
|
1504
2014
|
readonly rule_index: number | null;
|
|
1505
2015
|
readonly channel_name: string;
|
|
1506
2016
|
readonly session_id: string | null;
|
|
2017
|
+
/**
|
|
2018
|
+
* Which identity strategy produced session_id (issue #251): the MCP
|
|
2019
|
+
* resolver's vocabulary on proxy tickets, `sideband` on adapter tickets.
|
|
2020
|
+
* OPTIONAL-ABSENT, not nullable: the ticket is the wire object, and an
|
|
2021
|
+
* unattributed ticket omits the key rather than emitting null.
|
|
2022
|
+
*/
|
|
2023
|
+
readonly session_source?: string;
|
|
2024
|
+
/**
|
|
2025
|
+
* Upstream attribution (issue #292). Absent in singular mode and on
|
|
2026
|
+
* native (sideband) tickets — same wire-additive optional spelling.
|
|
2027
|
+
*/
|
|
2028
|
+
readonly upstream?: string;
|
|
1507
2029
|
readonly requested_at: string;
|
|
1508
2030
|
readonly timeout_at: string;
|
|
1509
2031
|
readonly timeout_ms: number;
|
|
@@ -1599,6 +2121,10 @@ declare class ApprovalQueue {
|
|
|
1599
2121
|
timeout_ms: number;
|
|
1600
2122
|
/** Breached budget context on break-glass / merged tickets (issue #14). */
|
|
1601
2123
|
breached_budgets?: readonly BudgetBreachContext[];
|
|
2124
|
+
/** Identity-strategy attribution for session_id (issue #251). */
|
|
2125
|
+
session_source?: string | null;
|
|
2126
|
+
/** Upstream attribution (issue #292); absent in singular mode. */
|
|
2127
|
+
upstream?: string | null;
|
|
1602
2128
|
}): ApprovalTicket;
|
|
1603
2129
|
/** Get a ticket by ID. Returns undefined if not found. */
|
|
1604
2130
|
get(id: string): ApprovalTicket | undefined;
|
|
@@ -1654,6 +2180,13 @@ interface ApprovalSubmitParams {
|
|
|
1654
2180
|
readonly tool_input: Record<string, unknown>;
|
|
1655
2181
|
readonly matched_rule: CompiledPolicyRule | undefined;
|
|
1656
2182
|
readonly session_id: string | null;
|
|
2183
|
+
/**
|
|
2184
|
+
* Identity-strategy attribution for session_id (issue #251).
|
|
2185
|
+
* Required-nullable so no submit site can silently forget it.
|
|
2186
|
+
*/
|
|
2187
|
+
readonly session_source: string | null;
|
|
2188
|
+
/** Upstream attribution (issue #292); null in singular mode. */
|
|
2189
|
+
readonly upstream: string | null;
|
|
1657
2190
|
/** Breached budget context; marks the ticket as break-glass (issue #14). */
|
|
1658
2191
|
readonly breached_budgets?: readonly BudgetBreachContext[];
|
|
1659
2192
|
/**
|
|
@@ -1861,12 +2394,21 @@ declare class RateLimiter {
|
|
|
1861
2394
|
* Reconcile bucket state against a new policy's limit configuration.
|
|
1862
2395
|
*
|
|
1863
2396
|
* Walks every existing bucket and checks whether its last-seen
|
|
1864
|
-
* `{ maxCalls, windowMs }` tuple still appears
|
|
2397
|
+
* `{ maxCalls, windowMs }` tuple still appears in `validConfigs`.
|
|
1865
2398
|
* Buckets whose config is still present are left untouched — counters and
|
|
1866
2399
|
* elapsed-window progress are preserved across hot-reloads. Buckets whose
|
|
1867
2400
|
* config is gone (rule changed or removed) are evicted so the next check
|
|
1868
2401
|
* lazy-creates a fresh bucket under the new config.
|
|
1869
2402
|
*
|
|
2403
|
+
* Keys built by `ruleBucketKey` (bucket-key.ts) carry the owning rule's
|
|
2404
|
+
* index, and for those the tuple must match at THAT index
|
|
2405
|
+
* (`config.ruleIndex`): a reorder that shifts a rate rule's index evicts
|
|
2406
|
+
* its old-index bucket instead of leaving an orphan no rule reads again —
|
|
2407
|
+
* or worse, letting whatever rule now sits at that index adopt another
|
|
2408
|
+
* rule's accrued calls. Un-suffixed keys keep the tuple-anywhere match,
|
|
2409
|
+
* but only against index-less configs — a caller that passes only indexed
|
|
2410
|
+
* configs (as the proxy does) evicts every un-suffixed bucket, fail-closed.
|
|
2411
|
+
*
|
|
1870
2412
|
* This is the compare-and-evict semantic that replaces the old `reset()`
|
|
1871
2413
|
* call on every hot-reload, which wiped all state even when the matching
|
|
1872
2414
|
* rule was unchanged.
|
|
@@ -1874,6 +2416,7 @@ declare class RateLimiter {
|
|
|
1874
2416
|
reconcile(validConfigs: Iterable<{
|
|
1875
2417
|
maxCalls: number;
|
|
1876
2418
|
windowMs: number;
|
|
2419
|
+
ruleIndex?: number;
|
|
1877
2420
|
}>): void;
|
|
1878
2421
|
/** Stop the cleanup timer and mark as closed. */
|
|
1879
2422
|
/**
|
|
@@ -2002,12 +2545,14 @@ declare class SpendLimiter {
|
|
|
2002
2545
|
* whose config is gone (rule changed or removed) are evicted so the next
|
|
2003
2546
|
* check lazy-creates a fresh bucket under the new config.
|
|
2004
2547
|
*
|
|
2005
|
-
* Keys built by
|
|
2006
|
-
* for those the tuple must match at THAT index (`config.ruleIndex`): a
|
|
2548
|
+
* Keys built by `ruleBucketKey` (bucket-key.ts) carry the owning rule's
|
|
2549
|
+
* index, and for those the tuple must match at THAT index (`config.ruleIndex`): a
|
|
2007
2550
|
* reorder that shifts a spend rule's index evicts its old-index bucket
|
|
2008
2551
|
* instead of leaving an orphan no rule reads again — or worse, letting
|
|
2009
2552
|
* whatever rule now sits at that index adopt another rule's accrued spend.
|
|
2010
|
-
* Un-suffixed keys keep the tuple-anywhere match
|
|
2553
|
+
* Un-suffixed keys keep the tuple-anywhere match, but only against
|
|
2554
|
+
* index-less configs — a caller that passes only indexed configs (as the
|
|
2555
|
+
* proxy does) evicts every un-suffixed bucket, fail-closed.
|
|
2011
2556
|
*
|
|
2012
2557
|
* Currency is part of the tuple because a USD→EUR switch is a meaningful
|
|
2013
2558
|
* policy change — the same numeric limit buys a different amount of real
|
|
@@ -2032,13 +2577,37 @@ declare class SpendLimiter {
|
|
|
2032
2577
|
close(): void;
|
|
2033
2578
|
}
|
|
2034
2579
|
|
|
2580
|
+
declare const GATED_SESSION: unique symbol;
|
|
2581
|
+
/** A session bucket value that provably passed the identity gate. */
|
|
2582
|
+
type GatedSession = string & {
|
|
2583
|
+
readonly [GATED_SESSION]: true;
|
|
2584
|
+
};
|
|
2585
|
+
declare const GATED_CHARGES: unique symbol;
|
|
2586
|
+
/** Budget charges that provably passed the session engagement check. */
|
|
2587
|
+
type GatedCharges = readonly BudgetCharge[] & {
|
|
2588
|
+
readonly [GATED_CHARGES]: true;
|
|
2589
|
+
};
|
|
2590
|
+
|
|
2035
2591
|
/** Everything the engine needs about one tool call to resolve its charges. */
|
|
2036
2592
|
interface BudgetChargeContext {
|
|
2037
2593
|
readonly toolName: string;
|
|
2038
2594
|
readonly toolArguments: Record<string, unknown> | undefined;
|
|
2039
|
-
|
|
2595
|
+
/**
|
|
2596
|
+
* Gate-minted session bucket value (issue #218), or null when identity is
|
|
2597
|
+
* unresolved — `bucketKey` builds `session:unknown` from null, which is
|
|
2598
|
+
* legal ONLY because `gateBudgetCharges` denies unresolved session-keyed
|
|
2599
|
+
* engagement before `peekAll`/`recordAll` can run.
|
|
2600
|
+
*/
|
|
2601
|
+
readonly sessionId: GatedSession | null;
|
|
2040
2602
|
/** Adapter-supplied sender id (sideband only); null on the MCP path. */
|
|
2041
2603
|
readonly senderId: string | null;
|
|
2604
|
+
/**
|
|
2605
|
+
* The governed door's configured upstream name (issue #295); null on the
|
|
2606
|
+
* sideband and in singular mode. Required so every door states its
|
|
2607
|
+
* upstream: a silently-missing value would exempt that door's calls from
|
|
2608
|
+
* upstream-scoped contributors once those exist.
|
|
2609
|
+
*/
|
|
2610
|
+
readonly upstream: string | null;
|
|
2042
2611
|
}
|
|
2043
2612
|
/** One budget's share of a call: which bucket, how much. */
|
|
2044
2613
|
interface BudgetCharge {
|
|
@@ -2052,6 +2621,12 @@ interface BudgetCharge {
|
|
|
2052
2621
|
* NOT repopulate the new pot with old-config spend — recordAll skips it.
|
|
2053
2622
|
*/
|
|
2054
2623
|
readonly generation: number;
|
|
2624
|
+
/**
|
|
2625
|
+
* The charge context's upstream name, stamped only when the door set one
|
|
2626
|
+
* (issue #295). Optional is the honest type: `remintDeferredCharges`
|
|
2627
|
+
* rebuilds charges without it, so deferred commits snapshot null.
|
|
2628
|
+
*/
|
|
2629
|
+
readonly upstream?: string;
|
|
2055
2630
|
}
|
|
2056
2631
|
/** A budget whose contributor matched but whose amount was unusable. */
|
|
2057
2632
|
interface BudgetChargeFailure {
|
|
@@ -2076,6 +2651,11 @@ interface BudgetPeekEntry {
|
|
|
2076
2651
|
readonly remaining: number;
|
|
2077
2652
|
/** Epoch ms when the oldest entry ages out (duration); null for session pots. */
|
|
2078
2653
|
readonly resetAtMs: number | null;
|
|
2654
|
+
/**
|
|
2655
|
+
* The charge's upstream label, or null: sideband calls, singular mode, and
|
|
2656
|
+
* reminted deferred commits all snapshot null (issue #295).
|
|
2657
|
+
*/
|
|
2658
|
+
readonly upstream: string | null;
|
|
2079
2659
|
/**
|
|
2080
2660
|
* Set on recordAll snapshots for charges frozen before a tuple-changing
|
|
2081
2661
|
* reload: the executed spend was ledgered under its evaluate-time
|
|
@@ -2140,6 +2720,12 @@ interface BudgetCommitEvent {
|
|
|
2140
2720
|
readonly limit: number;
|
|
2141
2721
|
readonly currency: string;
|
|
2142
2722
|
readonly utilization: number;
|
|
2723
|
+
/**
|
|
2724
|
+
* Upstream attribution from the charge context (issue #292), or null.
|
|
2725
|
+
* Reminted frozen-plan charges drop the label by design, so deferred
|
|
2726
|
+
* sideband commits always emit null here.
|
|
2727
|
+
*/
|
|
2728
|
+
readonly upstream: string | null;
|
|
2143
2729
|
}
|
|
2144
2730
|
/**
|
|
2145
2731
|
* Payload for the per-budget breach callback (dashboard event bus). Fired
|
|
@@ -2156,6 +2742,8 @@ interface BudgetBreachEvent {
|
|
|
2156
2742
|
readonly spent: number;
|
|
2157
2743
|
readonly limit: number;
|
|
2158
2744
|
readonly currency: string;
|
|
2745
|
+
/** Upstream attribution from the peek entry's context (issue #292), or null. */
|
|
2746
|
+
readonly upstream: string | null;
|
|
2159
2747
|
}
|
|
2160
2748
|
/** Wire-ready bucket state for `GET /api/budgets` (snake_case DTO). */
|
|
2161
2749
|
interface BudgetBucketState {
|
|
@@ -2207,21 +2795,29 @@ declare class BudgetEngine {
|
|
|
2207
2795
|
/**
|
|
2208
2796
|
* Resolve which budgets a call feeds and how much it charges each.
|
|
2209
2797
|
*
|
|
2210
|
-
* A contributor participates when its
|
|
2211
|
-
*
|
|
2212
|
-
*
|
|
2213
|
-
*
|
|
2214
|
-
*
|
|
2215
|
-
*
|
|
2216
|
-
*
|
|
2217
|
-
*
|
|
2798
|
+
* A contributor participates when its upstream scope admits the call's
|
|
2799
|
+
* door (absent scope admits every door; a scoped contributor never
|
|
2800
|
+
* participates when `ctx.upstream` is null — sideband, singular mode) AND
|
|
2801
|
+
* its tool glob matches the tool name AND every `match.input` condition
|
|
2802
|
+
* holds (absent conditions means the glob alone decides); the FIRST
|
|
2803
|
+
* participating contributor (config order, over that combined predicate)
|
|
2804
|
+
* supplies the amount field. A call that matches the glob but not the
|
|
2805
|
+
* conditions or the scope simply does not feed the budget — no charge, no
|
|
2806
|
+
* failure — and a later contributor may still participate. Once a
|
|
2807
|
+
* contributor is selected, a missing, non-numeric, negative, or non-finite
|
|
2808
|
+
* amount fails closed as a `failures` entry — the caller must deny the
|
|
2809
|
+
* call.
|
|
2218
2810
|
*/
|
|
2219
2811
|
resolveCharges(ctx: BudgetChargeContext): {
|
|
2220
2812
|
charges: BudgetCharge[];
|
|
2221
2813
|
failures: BudgetChargeFailure[];
|
|
2222
2814
|
};
|
|
2223
|
-
/**
|
|
2224
|
-
|
|
2815
|
+
/**
|
|
2816
|
+
* Check every charge without mutating. All-or-nothing: one deny flips
|
|
2817
|
+
* `allowed`. Accepts only gate-branded charges (issue #218) — a caller
|
|
2818
|
+
* cannot peek budget state without having run the session engagement check.
|
|
2819
|
+
*/
|
|
2820
|
+
peekAll(charges: GatedCharges): {
|
|
2225
2821
|
allowed: boolean;
|
|
2226
2822
|
entries: BudgetPeekEntry[];
|
|
2227
2823
|
};
|
|
@@ -2232,7 +2828,7 @@ declare class BudgetEngine {
|
|
|
2232
2828
|
* Recording is unconditional past the sink (an approved overage
|
|
2233
2829
|
* legitimately pushes a bucket past its limit).
|
|
2234
2830
|
*/
|
|
2235
|
-
recordAll(charges:
|
|
2831
|
+
recordAll(charges: GatedCharges, meta: BudgetCommitMeta): BudgetPeekEntry[];
|
|
2236
2832
|
/**
|
|
2237
2833
|
* Fire one `onBreach` event per breached entry. Called by the doors at the
|
|
2238
2834
|
* moment a peek outcome actually denies the call or raises the composite
|
|
@@ -2329,6 +2925,18 @@ declare class BudgetEngine {
|
|
|
2329
2925
|
private snapshot;
|
|
2330
2926
|
}
|
|
2331
2927
|
|
|
2928
|
+
/** Compiled session config, wired into the route factories at startup. */
|
|
2929
|
+
interface CompiledSessionIdentity {
|
|
2930
|
+
/** The configured identity chain, in order; first match wins. */
|
|
2931
|
+
readonly sources: readonly SessionIdentitySource[];
|
|
2932
|
+
readonly onUnresolved: 'deny' | 'anonymous';
|
|
2933
|
+
/**
|
|
2934
|
+
* Human-readable strategy list (e.g. `header "x-helio-session-id",
|
|
2935
|
+
* legacy_header`) — deny messages name the strategies that were tried.
|
|
2936
|
+
*/
|
|
2937
|
+
readonly strategySummary: string;
|
|
2938
|
+
}
|
|
2939
|
+
|
|
2332
2940
|
/** Options for constructing a GovernedForwarder. */
|
|
2333
2941
|
interface GovernedForwarderOptions {
|
|
2334
2942
|
/** The current environment label (e.g. "production", "staging"). */
|
|
@@ -2345,6 +2953,19 @@ interface GovernedForwarderOptions {
|
|
|
2345
2953
|
spendLimiter?: SpendLimiter;
|
|
2346
2954
|
/** Budget engine for named cross-tool budgets (issue #14). */
|
|
2347
2955
|
budgetEngine?: BudgetEngine;
|
|
2956
|
+
/**
|
|
2957
|
+
* Compiled session identity config (issue #218): the `on_unresolved` mode
|
|
2958
|
+
* and the strategy summary deny messages name. Defaults to the schema
|
|
2959
|
+
* default chain (deny mode) for direct/library construction.
|
|
2960
|
+
*/
|
|
2961
|
+
session?: CompiledSessionIdentity;
|
|
2962
|
+
/**
|
|
2963
|
+
* The operator-chosen upstream entry name (issue #295, multi-upstream
|
|
2964
|
+
* substrate). Unset in singular mode — every governance surface then
|
|
2965
|
+
* behaves exactly as today. The multi-upstream composition loop (issue
|
|
2966
|
+
* #294) passes each entry's name.
|
|
2967
|
+
*/
|
|
2968
|
+
upstreamName?: string;
|
|
2348
2969
|
}
|
|
2349
2970
|
/** Result of attempting to prime the tool annotation cache. */
|
|
2350
2971
|
interface AnnotationCachePrimeResult {
|
|
@@ -2367,12 +2988,14 @@ declare class GovernedForwarder implements McpForwarder {
|
|
|
2367
2988
|
private readonly inner;
|
|
2368
2989
|
private policy;
|
|
2369
2990
|
private readonly environment;
|
|
2991
|
+
private readonly session;
|
|
2370
2992
|
private readonly auditWriter;
|
|
2371
2993
|
private readonly evidenceStore;
|
|
2372
2994
|
private readonly approvalRouter;
|
|
2373
2995
|
private readonly rateLimiter;
|
|
2374
2996
|
private readonly spendLimiter;
|
|
2375
2997
|
private readonly budgetEngine;
|
|
2998
|
+
private readonly upstreamName;
|
|
2376
2999
|
private readonly annotationCache;
|
|
2377
3000
|
private agentKeyWarned;
|
|
2378
3001
|
private senderKeyWarned;
|
|
@@ -2406,6 +3029,20 @@ declare class GovernedForwarder implements McpForwarder {
|
|
|
2406
3029
|
*/
|
|
2407
3030
|
primeAnnotationCache(): Promise<AnnotationCachePrimeResult>;
|
|
2408
3031
|
forward(request: McpRequest): Promise<ForwardResult>;
|
|
3032
|
+
/**
|
|
3033
|
+
* Clamp an over-long `result.ttlMs` on a `tools/list` response to
|
|
3034
|
+
* `policies.tool_revalidation.max_advertised_ttl` (issue #221, D7).
|
|
3035
|
+
*
|
|
3036
|
+
* Downward-only: a `ttlMs` at or below the cap is left untouched, and a
|
|
3037
|
+
* response with no `ttlMs` never gains one — Helio does not manufacture a
|
|
3038
|
+
* cache hint the upstream never advertised. Non-numeric values are left
|
|
3039
|
+
* alone rather than coerced. `cacheScope` passes through untouched: Helio
|
|
3040
|
+
* baselines and vouches for tool *definitions* only, and its own
|
|
3041
|
+
* `tools/list` view is not caller-varying, so it has no basis to alter a
|
|
3042
|
+
* scope hint the upstream set. No-op when tool revalidation is disabled
|
|
3043
|
+
* (including hand-built `CompiledPolicy` fixtures that omit the field).
|
|
3044
|
+
*/
|
|
3045
|
+
private clampCacheHints;
|
|
2409
3046
|
/**
|
|
2410
3047
|
* Apply a tools/list response to the definition cache and surface any
|
|
2411
3048
|
* drift: console warning + immediate audit record per event. Single entry
|
|
@@ -2469,14 +3106,22 @@ declare class GovernedForwarder implements McpForwarder {
|
|
|
2469
3106
|
* or consuming any resources. Returns an MCP-compliant synthetic response.
|
|
2470
3107
|
*/
|
|
2471
3108
|
private handleDryRun;
|
|
2472
|
-
/**
|
|
3109
|
+
/**
|
|
3110
|
+
* Construct a non-session limit bucket key. Tool-scope keys route through
|
|
3111
|
+
* the shared `toolLimitKey` leaf, which prefixes them with the configured
|
|
3112
|
+
* upstream name when one is set (issue #295). Session keys are deliberately
|
|
3113
|
+
* NOT built here: they come only from the gate module's `sessionLimitKey`,
|
|
3114
|
+
* whose `GatedSession` parameter makes skipping the identity gate a
|
|
3115
|
+
* compile error (issue #218) — call sites branch on `key === 'session'`.
|
|
3116
|
+
*/
|
|
2473
3117
|
private buildLimitKey;
|
|
2474
3118
|
/**
|
|
2475
|
-
*
|
|
2476
|
-
*
|
|
2477
|
-
*
|
|
3119
|
+
* Gate a session-keyed limit at its key-build site (issue #218). Returns
|
|
3120
|
+
* the bucket key, or null when identity is unresolved under deny mode —
|
|
3121
|
+
* the caller denies (enforce) or reports the marker (dry-run).
|
|
2478
3122
|
*/
|
|
2479
|
-
private
|
|
3123
|
+
private gateSessionLimitKey;
|
|
3124
|
+
private makeSessionUnresolvedResult;
|
|
2480
3125
|
private writeAuditRecord;
|
|
2481
3126
|
private makeDriftBlockResult;
|
|
2482
3127
|
private makeDenyResult;
|
|
@@ -2521,6 +3166,13 @@ interface BudgetEventRecord {
|
|
|
2521
3166
|
readonly timestamp: string;
|
|
2522
3167
|
readonly timestamp_ms: number;
|
|
2523
3168
|
readonly created_at: string;
|
|
3169
|
+
/**
|
|
3170
|
+
* Upstream attribution read from the referenced audit record via LEFT
|
|
3171
|
+
* JOIN (issue #292) — never a stored ledger column. Null on singular-mode
|
|
3172
|
+
* records, dangling or null `audit_record_id`, and rows predating the
|
|
3173
|
+
* audit column; a null renders as empty/absent, never a made-up label.
|
|
3174
|
+
*/
|
|
3175
|
+
readonly upstream: string | null;
|
|
2524
3176
|
}
|
|
2525
3177
|
/** One page of a budget's event history plus the unpaginated total. */
|
|
2526
3178
|
interface BudgetEventsPage {
|
|
@@ -2611,6 +3263,13 @@ interface GovernanceServiceOptions {
|
|
|
2611
3263
|
readonly spendLimiter?: SpendLimiter;
|
|
2612
3264
|
/** Budget engine for named cross-tool budgets (issue #14). */
|
|
2613
3265
|
readonly budgetEngine?: BudgetEngine;
|
|
3266
|
+
/**
|
|
3267
|
+
* Compiled session identity config (issue #218): the sideband door gets
|
|
3268
|
+
* the SAME on_unresolved policy as the MCP door — an adapter omitting
|
|
3269
|
+
* session_id while a session-keyed control is engaged is denied under
|
|
3270
|
+
* `deny`, pools under `anonymous`. Defaults to the schema default chain.
|
|
3271
|
+
*/
|
|
3272
|
+
readonly session?: CompiledSessionIdentity;
|
|
2614
3273
|
readonly auditWriter?: AuditWriter;
|
|
2615
3274
|
/** Default approval timeout (ms) when a rule sets none. */
|
|
2616
3275
|
readonly approvalTimeoutMs?: number;
|
|
@@ -2630,6 +3289,7 @@ interface GovernanceServiceOptions {
|
|
|
2630
3289
|
declare class GovernanceService {
|
|
2631
3290
|
private policy;
|
|
2632
3291
|
private readonly environment;
|
|
3292
|
+
private readonly session;
|
|
2633
3293
|
private readonly evidenceStore;
|
|
2634
3294
|
private readonly approvalRouter;
|
|
2635
3295
|
private readonly rateLimiter;
|
|
@@ -2789,6 +3449,22 @@ declare class GovernanceConfigError extends Error {
|
|
|
2789
3449
|
constructor(message: string);
|
|
2790
3450
|
}
|
|
2791
3451
|
|
|
3452
|
+
/**
|
|
3453
|
+
* Map a header/body agreement rejection (issue #226) onto the audit record
|
|
3454
|
+
* shape, mirroring the `missing_tool_name` precedent: `policy_decision:
|
|
3455
|
+
* 'rejected'`, no rule evaluated, nothing forwarded, written by the caller
|
|
3456
|
+
* via `pushImmediate`. The snake_case mapping lives here alone — the
|
|
3457
|
+
* rejection payload itself stays camelCase protocol facts (`mcp/types.ts`).
|
|
3458
|
+
*
|
|
3459
|
+
* `record_kind` stays `'tool_call'` for the whole class, non-tool methods
|
|
3460
|
+
* included: it is the MCP-door request bucket, and `block_reason` is the
|
|
3461
|
+
* query key. `tool_name` carries the body's name-bearing field (the body
|
|
3462
|
+
* truth an investigator filters for) when the method has one, else the
|
|
3463
|
+
* reserved `'<header_mismatch>'` sentinel — either way `top_tools` already
|
|
3464
|
+
* excludes rejected records, so these rows never pollute tool rankings.
|
|
3465
|
+
*/
|
|
3466
|
+
declare function buildHeaderMismatchAuditRecord(rejection: HeaderMismatchRejection, environment?: string, upstream?: string): Omit<AuditRecord, 'id' | 'created_at'>;
|
|
3467
|
+
|
|
2792
3468
|
/** @internal Exported for testing only. */
|
|
2793
3469
|
declare class QueueChannel implements ApprovalChannel {
|
|
2794
3470
|
readonly type = "dashboard";
|
|
@@ -2915,6 +3591,10 @@ interface ActionEvent {
|
|
|
2915
3591
|
readonly block_reason: string | null;
|
|
2916
3592
|
readonly approval_status: string | null;
|
|
2917
3593
|
readonly session_id: string | null;
|
|
3594
|
+
/** Identity strategy that produced session_id (issue #218), or null. */
|
|
3595
|
+
readonly session_source: string | null;
|
|
3596
|
+
/** The client's verbatim MCP-Protocol-Version wire claim (issue #219), or null. */
|
|
3597
|
+
readonly protocol_version: string | null;
|
|
2918
3598
|
readonly agent_id: string | null;
|
|
2919
3599
|
readonly environment: string | null;
|
|
2920
3600
|
readonly timestamp: string;
|
|
@@ -2927,6 +3607,8 @@ interface ActionEvent {
|
|
|
2927
3607
|
readonly matched_rule_index: number | null;
|
|
2928
3608
|
readonly record_kind: AuditRecord['record_kind'];
|
|
2929
3609
|
readonly origin: string;
|
|
3610
|
+
/** Upstream attribution from the audit record (issue #292), or null. */
|
|
3611
|
+
readonly upstream: string | null;
|
|
2930
3612
|
}
|
|
2931
3613
|
/** Payload for an approval_requested event. */
|
|
2932
3614
|
interface ApprovalRequestedEvent {
|
|
@@ -2934,6 +3616,8 @@ interface ApprovalRequestedEvent {
|
|
|
2934
3616
|
readonly tool_name: string;
|
|
2935
3617
|
readonly channel: string;
|
|
2936
3618
|
readonly requested_at: string;
|
|
3619
|
+
/** Upstream attribution from the ticket (issue #292), or null. */
|
|
3620
|
+
readonly upstream: string | null;
|
|
2937
3621
|
}
|
|
2938
3622
|
/** Payload for an approval_resolved event. */
|
|
2939
3623
|
interface ApprovalResolvedEvent {
|
|
@@ -2949,6 +3633,11 @@ interface LimitWarningEvent {
|
|
|
2949
3633
|
readonly current: number;
|
|
2950
3634
|
readonly limit: number;
|
|
2951
3635
|
readonly utilization: number;
|
|
3636
|
+
/**
|
|
3637
|
+
* Upstream name parsed from a partitioned bucket key (issue #292), or
|
|
3638
|
+
* null — session keys, singular tool keys, and sideband keys have no door.
|
|
3639
|
+
*/
|
|
3640
|
+
readonly upstream: string | null;
|
|
2952
3641
|
}
|
|
2953
3642
|
/** Payload for approval notification delivery failures. */
|
|
2954
3643
|
interface ApprovalNotificationFailedEvent {
|
|
@@ -3052,6 +3741,20 @@ interface DashboardAppOptions {
|
|
|
3052
3741
|
readonly staticDir?: string;
|
|
3053
3742
|
/** SSE heartbeat interval in milliseconds. Defaults to 30 000 (30s). */
|
|
3054
3743
|
readonly sseHeartbeatMs?: number;
|
|
3744
|
+
/**
|
|
3745
|
+
* @internal Test seam for the concurrent-connection cap (issue #285), so
|
|
3746
|
+
* tests need not mint 256 real streams. Not wired to config — the cap is
|
|
3747
|
+
* a hardcoded invariant (see MAX_SSE_CONNECTIONS).
|
|
3748
|
+
*/
|
|
3749
|
+
readonly maxSseConnections?: number;
|
|
3750
|
+
/**
|
|
3751
|
+
* @internal Test seam for the stale-connection sweep cadence (issue
|
|
3752
|
+
* #327), so sweeper tests need not wait out the production floor. `0`
|
|
3753
|
+
* DISABLES the sweeper entirely (the repo-wide sweep-interval
|
|
3754
|
+
* convention). Not wired to config — the 10 s floor stays the
|
|
3755
|
+
* production default.
|
|
3756
|
+
*/
|
|
3757
|
+
readonly sweepIntervalMs?: number;
|
|
3055
3758
|
}
|
|
3056
3759
|
/**
|
|
3057
3760
|
* Create a Hono app for the dashboard REST + SSE API.
|
|
@@ -3061,4 +3764,4 @@ interface DashboardAppOptions {
|
|
|
3061
3764
|
*/
|
|
3062
3765
|
declare function createDashboardApp(deps: DashboardAppDeps, options?: DashboardAppOptions): Hono;
|
|
3063
3766
|
|
|
3064
|
-
export { type AdapterLivenessEntry, type ApprovalAppOptions, type ApprovalChannel, type ApprovalOutcome, ApprovalQueue, type ApprovalQueueOptions, ApprovalRouter, type ApprovalRouterOptions, type ApprovalStatus, type ApprovalTicket, type AuditAggregateStats, type AuditInput, type AuditListResult, type AuditPaginationOptions, type AuditQueryFilters, type AuditRecord, AuditStore, type AuditStoreOptions, type AuditTimeBucket, AuditWriter, type AuditWriterOptions, type BudgetBreachContext, type BudgetBreachEvent, type BudgetBucketState, type BudgetCommitEvent, BudgetEngine, type BudgetEventRecord, type BudgetEventsPage, type BudgetLedgerRow, type BudgetLedgerSink, BudgetParseError, type BudgetState, type CompilePoliciesResult, type CompiledBudget, type CompiledBudgetContributor, type CompiledBudgetWindow, type CompiledPolicy, type CompiledPolicyRule, ConfigError, type CreateAppOptions, type DashboardAppDeps, type DashboardAppOptions, DashboardEventBus, type DashboardEventType, type DashboardEvents, EXPORT_MAX_RECORDS, type EvaluateInput, type EvidenceEntry, EvidenceStore, type EvidenceStoreOptions, GovernanceConfigError, GovernanceService, type GovernanceServiceOptions, GovernedForwarder, type GovernedForwarderOptions, type HelioConfig, type InstallScanInput, LIST_MAX_PAGE_SIZE, type MatchContext, type PolicyDecision, PolicyParseError, QueueChannel, type RateLimitCheckParams, type RateLimitKeyState, type RateLimitResult, RateLimiter, type RateLimiterOptions, type ResolveApprovalInput, type ServerHandle, type SessionState, type SlackActionAppOptions, SlackChannel, type SlackChannelOptions, type SpendLimitCheckParams, type SpendLimitKeyState, type SpendLimitResult, SpendLimiter, type SpendLimiterOptions, SseUpstreamForwarder, type SseUpstreamForwarderOptions, StdioForwarder, type StdioForwarderOptions, StreamableHttpForwarder, type StreamableHttpForwarderOptions, UpstreamForwarder, type UpstreamForwarderOptions, VERSION, WebhookChannel, type WebhookChannelOptions, type WireDecision, compileBudgets, compilePolicies, createApp, createApprovalApp, createChannels, createDashboardApp, createSidebandApp, createSlackActionApp, evaluatePolicy, loadConfig, matchRule, startServer, startSidebandServer };
|
|
3767
|
+
export { type AdapterLivenessEntry, type ApprovalAppOptions, type ApprovalChannel, type ApprovalOutcome, ApprovalQueue, type ApprovalQueueOptions, ApprovalRouter, type ApprovalRouterOptions, type ApprovalStatus, type ApprovalTicket, type AuditAggregateStats, type AuditInput, type AuditListResult, type AuditPaginationOptions, type AuditQueryFilters, type AuditRecord, AuditStore, type AuditStoreOptions, type AuditTimeBucket, AuditWriter, type AuditWriterOptions, type BudgetBreachContext, type BudgetBreachEvent, type BudgetBucketState, type BudgetCommitEvent, BudgetEngine, type BudgetEventRecord, type BudgetEventsPage, type BudgetLedgerRow, type BudgetLedgerSink, BudgetParseError, type BudgetState, type CompilePoliciesResult, type CompiledBudget, type CompiledBudgetContributor, type CompiledBudgetWindow, type CompiledPolicy, type CompiledPolicyRule, ConfigError, type CreateAppOptions, type CreateMultiAppOptions, type DashboardAppDeps, type DashboardAppOptions, DashboardEventBus, type DashboardEventType, type DashboardEvents, EXPORT_MAX_RECORDS, type EvaluateInput, type EvidenceEntry, EvidenceStore, type EvidenceStoreOptions, GovernanceConfigError, GovernanceService, type GovernanceServiceOptions, GovernedForwarder, type GovernedForwarderOptions, type HeaderMismatchRejection, type HelioConfig, type InstallScanInput, LIST_MAX_PAGE_SIZE, type MatchContext, type NamedHelioConfig, type PolicyDecision, PolicyParseError, QueueChannel, type RateLimitCheckParams, type RateLimitKeyState, type RateLimitResult, RateLimiter, type RateLimiterOptions, type ResolveApprovalInput, type ServerHandle, type SessionState, type SingularHelioConfig, type SlackActionAppOptions, SlackChannel, type SlackChannelOptions, type SpendLimitCheckParams, type SpendLimitKeyState, type SpendLimitResult, SpendLimiter, type SpendLimiterOptions, SseUpstreamForwarder, type SseUpstreamForwarderOptions, StdioForwarder, type StdioForwarderOptions, StreamableHttpForwarder, type StreamableHttpForwarderOptions, UpstreamForwarder, type UpstreamForwarderOptions, VERSION, WebhookChannel, type WebhookChannelOptions, type WireDecision, buildHeaderMismatchAuditRecord, compileBudgets, compilePolicies, createApp, createApprovalApp, createChannels, createDashboardApp, createMultiApp, createSidebandApp, createSlackActionApp, evaluatePolicy, isNamedConfig, isSingularConfig, loadConfig, matchRule, startServer, startSidebandServer };
|