@agentguard-run/burn 0.1.0 → 0.2.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 +64 -0
- package/README.md +110 -1
- package/dist/src/adapters/codex.d.ts +48 -0
- package/dist/src/adapters/codex.js +194 -0
- package/dist/src/adapters/cursor.d.ts +35 -0
- package/dist/src/adapters/cursor.js +132 -0
- package/dist/src/adapters/raw-api.d.ts +76 -0
- package/dist/src/adapters/raw-api.js +130 -0
- package/dist/src/cli.d.ts +7 -3
- package/dist/src/cli.js +99 -10
- package/dist/src/conformance.d.ts +26 -0
- package/dist/src/conformance.js +261 -0
- package/dist/src/defaults.d.ts +11 -0
- package/dist/src/defaults.js +16 -1
- package/dist/src/detectors/local-compute.d.ts +19 -0
- package/dist/src/detectors/local-compute.js +66 -0
- package/dist/src/events.d.ts +94 -0
- package/dist/src/events.js +47 -0
- package/dist/src/gateway.d.ts +134 -0
- package/dist/src/gateway.js +522 -0
- package/dist/src/hook/pre-tool-use.js +5 -4
- package/dist/src/index.d.ts +15 -4
- package/dist/src/index.js +41 -1
- package/dist/src/proxy/server.d.ts +45 -0
- package/dist/src/proxy/server.js +169 -0
- package/dist/src/proxy/usage-observer.d.ts +40 -0
- package/dist/src/proxy/usage-observer.js +128 -0
- package/dist/src/receipt.d.ts +61 -0
- package/dist/src/receipt.js +98 -0
- package/dist/src/replay/render.d.ts +10 -3
- package/dist/src/replay/render.js +175 -44
- package/dist/src/replay/simulate.d.ts +4 -0
- package/dist/src/replay/simulate.js +24 -1
- package/dist/src/state/reservations.d.ts +115 -11
- package/dist/src/state/reservations.js +293 -59
- package/dist/src/state/session.d.ts +6 -0
- package/dist/src/state/session.js +17 -0
- package/dist/src/status.d.ts +11 -0
- package/dist/src/status.js +48 -0
- package/dist/src/types.d.ts +14 -1
- package/package.json +34 -7
|
@@ -0,0 +1,522 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* The gateway: one transaction boundary for every host.
|
|
4
|
+
*
|
|
5
|
+
* Adapters do not evaluate policy. They translate what they can see into
|
|
6
|
+
* AgentEvents and hand them here. The gateway folds events into per-session
|
|
7
|
+
* state, evaluates the same detectors the Claude hook uses, and returns a
|
|
8
|
+
* decision. Cursor, Codex, the Ollama proxy and raw middleware therefore
|
|
9
|
+
* cannot drift from each other, because there is nothing host-specific left
|
|
10
|
+
* to drift.
|
|
11
|
+
*
|
|
12
|
+
* Three properties are load-bearing:
|
|
13
|
+
*
|
|
14
|
+
* 1. A spawn is admitted inside the same machine-wide lock the Claude hook
|
|
15
|
+
* uses, as one transaction: fold, evaluate, reserve, sign. Ten parallel
|
|
16
|
+
* Cursor hooks racing a cap of 40 admit exactly 40, for exactly the
|
|
17
|
+
* reason ten Claude hooks do.
|
|
18
|
+
*
|
|
19
|
+
* 2. Usage is committed by call ID and *replaces* what was reserved under
|
|
20
|
+
* it. When middleware estimated 120K and the proxy later saw 87K for the
|
|
21
|
+
* same call, the session moves by 87K, not 207K. Double counting is the
|
|
22
|
+
* easiest way to make a cross-tool product lie, and it is ruled out here
|
|
23
|
+
* rather than in every adapter.
|
|
24
|
+
*
|
|
25
|
+
* 3. A STOP blocks the next expansion. It never truncates a request that is
|
|
26
|
+
* already streaming and never kills a running agent. Blocking is not
|
|
27
|
+
* killing, and the product does not pretend otherwise.
|
|
28
|
+
*
|
|
29
|
+
* Persisted state is content-free: counts, digests, verdicts.
|
|
30
|
+
*/
|
|
31
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
32
|
+
exports.Gateway = void 0;
|
|
33
|
+
exports.mergeCapabilities = mergeCapabilities;
|
|
34
|
+
const node_fs_1 = require("node:fs");
|
|
35
|
+
const node_path_1 = require("node:path");
|
|
36
|
+
const defaults_1 = require("./defaults");
|
|
37
|
+
const evaluate_1 = require("./detectors/evaluate");
|
|
38
|
+
const local_compute_1 = require("./detectors/local-compute");
|
|
39
|
+
const events_1 = require("./events");
|
|
40
|
+
const pre_tool_use_1 = require("./hook/pre-tool-use");
|
|
41
|
+
const receipt_1 = require("./receipt");
|
|
42
|
+
const reservations_1 = require("./state/reservations");
|
|
43
|
+
const session_1 = require("./state/session");
|
|
44
|
+
const MAX_SEEN_EVENTS = 4000;
|
|
45
|
+
const FILE_PREFIX = 'gw-';
|
|
46
|
+
function safeName(sessionId) {
|
|
47
|
+
return sessionId.replace(/[^a-zA-Z0-9_-]/g, '_').slice(0, 120) + '-' + (0, receipt_1.sha256)(sessionId).slice(0, 8);
|
|
48
|
+
}
|
|
49
|
+
class Gateway {
|
|
50
|
+
home;
|
|
51
|
+
store;
|
|
52
|
+
signer;
|
|
53
|
+
now;
|
|
54
|
+
sessionsDir;
|
|
55
|
+
constructor(home, opts = {}) {
|
|
56
|
+
this.home = home;
|
|
57
|
+
this.sessionsDir = (0, node_path_1.join)(home, 'sessions');
|
|
58
|
+
(0, node_fs_1.mkdirSync)(this.sessionsDir, { recursive: true, mode: 0o700 });
|
|
59
|
+
this.store = new reservations_1.ReservationStore(home);
|
|
60
|
+
this.signer = opts.sign === false ? null : receipt_1.ReceiptSigner.loadOrCreate(home);
|
|
61
|
+
this.now = opts.now ?? (() => Date.now());
|
|
62
|
+
}
|
|
63
|
+
// ---- persistence ----------------------------------------------------
|
|
64
|
+
file(sessionId) {
|
|
65
|
+
return (0, node_path_1.join)(this.sessionsDir, `${FILE_PREFIX}${safeName(sessionId)}.json`);
|
|
66
|
+
}
|
|
67
|
+
load(sessionId, host, at) {
|
|
68
|
+
try {
|
|
69
|
+
const raw = JSON.parse((0, node_fs_1.readFileSync)(this.file(sessionId), 'utf8'));
|
|
70
|
+
const state = inflate(raw.state);
|
|
71
|
+
if (!raw.hosts.includes(host)) {
|
|
72
|
+
raw.hosts.push(host);
|
|
73
|
+
raw.capabilities = mergeCapabilities(raw.hosts);
|
|
74
|
+
}
|
|
75
|
+
return { state, meta: raw };
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
const state = (0, session_1.newSessionState)(sessionId, at);
|
|
79
|
+
return {
|
|
80
|
+
state,
|
|
81
|
+
meta: {
|
|
82
|
+
hosts: [host],
|
|
83
|
+
capabilities: events_1.CAPABILITIES[host],
|
|
84
|
+
state: serialise(state),
|
|
85
|
+
calls: [],
|
|
86
|
+
liveSpawns: [],
|
|
87
|
+
seenEvents: [],
|
|
88
|
+
usage: { authoritative: 0, estimated: 0, missing: 0 },
|
|
89
|
+
decisions: 0,
|
|
90
|
+
wouldBlock: 0,
|
|
91
|
+
lastReceipt: null,
|
|
92
|
+
closedAt: null,
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
save(meta, state) {
|
|
98
|
+
// Only ever called inside a store transaction. If our lock instance was
|
|
99
|
+
// reclaimed while we worked, this throws and nothing is written.
|
|
100
|
+
this.store.assertHeld();
|
|
101
|
+
meta.state = serialise(state);
|
|
102
|
+
if (meta.seenEvents.length > MAX_SEEN_EVENTS)
|
|
103
|
+
meta.seenEvents = meta.seenEvents.slice(-MAX_SEEN_EVENTS);
|
|
104
|
+
const file = this.file(state.sessionId);
|
|
105
|
+
const tmp = `${file}.${process.pid}.tmp`;
|
|
106
|
+
(0, node_fs_1.writeFileSync)(tmp, JSON.stringify(meta), { mode: 0o600 });
|
|
107
|
+
(0, node_fs_1.renameSync)(tmp, file);
|
|
108
|
+
}
|
|
109
|
+
// ---- observations ---------------------------------------------------
|
|
110
|
+
/**
|
|
111
|
+
* Fold observations. Never decides, never blocks. Idempotent per eventId,
|
|
112
|
+
* so a retried hook or a replayed transcript line is a no-op.
|
|
113
|
+
*/
|
|
114
|
+
observe(events) {
|
|
115
|
+
if (events.length === 0)
|
|
116
|
+
return;
|
|
117
|
+
this.store.withLock((tx) => {
|
|
118
|
+
// Group by session so each session file is written once.
|
|
119
|
+
const bySession = new Map();
|
|
120
|
+
for (const e of events) {
|
|
121
|
+
const list = bySession.get(e.sessionId) ?? [];
|
|
122
|
+
list.push(e);
|
|
123
|
+
bySession.set(e.sessionId, list);
|
|
124
|
+
}
|
|
125
|
+
for (const [sessionId, list] of bySession) {
|
|
126
|
+
const first = list[0];
|
|
127
|
+
const { state, meta } = this.load(sessionId, first.host, first.at);
|
|
128
|
+
for (const event of list)
|
|
129
|
+
this.fold(event, state, meta, tx);
|
|
130
|
+
this.save(meta, state);
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
fold(event, state, meta, tx) {
|
|
135
|
+
if (meta.seenEvents.includes(event.eventId))
|
|
136
|
+
return;
|
|
137
|
+
meta.seenEvents.push(event.eventId);
|
|
138
|
+
const calls = new Map(meta.calls);
|
|
139
|
+
const live = new Map(meta.liveSpawns);
|
|
140
|
+
switch (event.kind) {
|
|
141
|
+
case 'session_opened':
|
|
142
|
+
meta.closedAt = null;
|
|
143
|
+
break;
|
|
144
|
+
case 'session_closed':
|
|
145
|
+
meta.closedAt = event.at;
|
|
146
|
+
break;
|
|
147
|
+
case 'model_usage': {
|
|
148
|
+
this.commitUsage(event, state, meta, calls);
|
|
149
|
+
if (event.callId)
|
|
150
|
+
tx.finishCall(event.callId, windowMs(), event.at);
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
153
|
+
case 'surface_read':
|
|
154
|
+
(0, session_1.applyEvent)(state, burnEvent(event.at, { surfaces: [event.surfaceDigest] }));
|
|
155
|
+
break;
|
|
156
|
+
case 'spawn_started': {
|
|
157
|
+
live.set(event.spawnId, event.depth);
|
|
158
|
+
const before = state.spawnCount;
|
|
159
|
+
(0, session_1.applyEvent)(state, burnEvent(event.at, { spawns: [{ description: '', issuerDepth: Math.max(0, event.depth - 1) }] }));
|
|
160
|
+
// The spawn is now observed; its reservation has done its job.
|
|
161
|
+
tx.reconcile(event.sessionId, state.spawnCount, before);
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
case 'spawn_finished':
|
|
165
|
+
live.delete(event.spawnId);
|
|
166
|
+
break;
|
|
167
|
+
case 'spawn_requested':
|
|
168
|
+
case 'call_requested':
|
|
169
|
+
// Decisions go through beforeSpawn / beforeCall. Folding one here
|
|
170
|
+
// would count it without admitting it.
|
|
171
|
+
break;
|
|
172
|
+
}
|
|
173
|
+
meta.calls = [...calls];
|
|
174
|
+
meta.liveSpawns = [...live];
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Replace-not-add by call ID. An estimate reserved by middleware is
|
|
178
|
+
* superseded by the proxy's authoritative count for the same call, up or
|
|
179
|
+
* down. Without a call ID the usage is simply added.
|
|
180
|
+
*/
|
|
181
|
+
applyUsage(callId, tokens, cacheRead, at, state, calls) {
|
|
182
|
+
const previous = callId ? calls.get(callId) : undefined;
|
|
183
|
+
if (callId)
|
|
184
|
+
calls.set(callId, { tokens, cacheRead });
|
|
185
|
+
if (!previous) {
|
|
186
|
+
(0, session_1.applyEvent)(state, burnEvent(at, { tokens, cacheRead }));
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
// Keep active-time accounting honest: the correction is not new activity.
|
|
190
|
+
(0, session_1.applyEvent)(state, burnEvent(at, {}));
|
|
191
|
+
(0, session_1.applyCorrection)(state, tokens - previous.tokens, cacheRead - previous.cacheRead);
|
|
192
|
+
}
|
|
193
|
+
commitUsage(event, state, meta, calls) {
|
|
194
|
+
this.applyUsage(event.callId, event.tokens, event.cacheRead, event.at, state, calls);
|
|
195
|
+
meta.usage[event.usageCoverage] += 1;
|
|
196
|
+
}
|
|
197
|
+
// ---- decisions ------------------------------------------------------
|
|
198
|
+
/**
|
|
199
|
+
* Admit or deny a spawn. One transaction under the machine lock: fold,
|
|
200
|
+
* evaluate the proposal, reserve, sign.
|
|
201
|
+
*/
|
|
202
|
+
beforeSpawn(event) {
|
|
203
|
+
const policy = (0, pre_tool_use_1.loadPolicy)(this.home);
|
|
204
|
+
try {
|
|
205
|
+
return this.store.withLock((tx) => {
|
|
206
|
+
const { state, meta } = this.load(event.sessionId, event.host, event.at);
|
|
207
|
+
if (meta.seenEvents.includes(event.eventId)) {
|
|
208
|
+
// Same request evaluated twice (host retry). Re-evaluate without
|
|
209
|
+
// reserving again; the store is idempotent on spawnId anyway.
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
meta.seenEvents.push(event.eventId);
|
|
213
|
+
}
|
|
214
|
+
const live = new Map(meta.liveSpawns);
|
|
215
|
+
const proposedDepth = event.proposedDepth ?? (event.issuerId !== undefined && live.has(event.issuerId) ? live.get(event.issuerId) + 1 : 1);
|
|
216
|
+
const report = (0, evaluate_1.evaluate)(state, policy.thresholds, proposedDepth);
|
|
217
|
+
const reservation = tx.reserve({
|
|
218
|
+
sessionId: event.sessionId,
|
|
219
|
+
toolUseId: event.spawnId,
|
|
220
|
+
observedSpawns: state.spawnCount,
|
|
221
|
+
ceiling: policy.thresholds.fanout.stop,
|
|
222
|
+
now: event.at,
|
|
223
|
+
});
|
|
224
|
+
const wouldBlock = report.verdict === 'STOP' || !reservation.allowed;
|
|
225
|
+
const verdict = wouldBlock ? 'STOP' : report.verdict;
|
|
226
|
+
// Session-scope STOPs need a session we trust. Fan-out is session scope.
|
|
227
|
+
const blocked = wouldBlock && policy.mode === 'enforce' && event.attribution === 'high';
|
|
228
|
+
const decision = this.finish({ action: 'spawn', host: event.host, sessionId: event.sessionId, at: event.at, proposedDepth, verdict, wouldBlock, blocked, report, effectiveSpawns: reservation.effectiveSpawns, compute: null }, policy, meta, state);
|
|
229
|
+
this.save(meta, state);
|
|
230
|
+
return decision;
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
catch (error) {
|
|
234
|
+
return this.failClosed('spawn', event, policy, error);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Admit or deny a model call. Reserves the caller's estimate under callId;
|
|
239
|
+
* completion replaces it. The local-compute plane is evaluated here and
|
|
240
|
+
* only here, because only calls occupy the machine.
|
|
241
|
+
*/
|
|
242
|
+
beforeCall(event) {
|
|
243
|
+
const policy = (0, pre_tool_use_1.loadPolicy)(this.home);
|
|
244
|
+
try {
|
|
245
|
+
return this.store.withLock((tx) => {
|
|
246
|
+
const { state, meta } = this.load(event.sessionId, event.host, event.at);
|
|
247
|
+
if (!meta.seenEvents.includes(event.eventId))
|
|
248
|
+
meta.seenEvents.push(event.eventId);
|
|
249
|
+
const calls = new Map(meta.calls);
|
|
250
|
+
const compute = tx.reserveCall({
|
|
251
|
+
sessionId: event.sessionId,
|
|
252
|
+
callId: event.callId,
|
|
253
|
+
host: event.host,
|
|
254
|
+
estimatedTokens: event.estimatedTokens,
|
|
255
|
+
ttlMs: defaults_1.CALL_RESERVATION_TTL_MS,
|
|
256
|
+
windowMs: windowMs(policy),
|
|
257
|
+
now: event.at,
|
|
258
|
+
});
|
|
259
|
+
// The estimate counts toward the session until the real number lands.
|
|
260
|
+
// It is a reservation, not an observation, so coverage is untouched.
|
|
261
|
+
if (event.estimatedTokens > 0 && !calls.has(event.callId)) {
|
|
262
|
+
this.applyUsage(event.callId, event.estimatedTokens, 0, event.at, state, calls);
|
|
263
|
+
}
|
|
264
|
+
meta.calls = [...calls];
|
|
265
|
+
const session = (0, evaluate_1.evaluate)(state, policy.thresholds, null);
|
|
266
|
+
const local = (0, local_compute_1.evaluateLocalCompute)(compute, policy.thresholds);
|
|
267
|
+
const report = merge(session, local.findings);
|
|
268
|
+
const wouldBlock = report.verdict === 'STOP';
|
|
269
|
+
// A low-confidence session (proxy without a session header) can be
|
|
270
|
+
// stopped only on machine-scope grounds. Its session count is a guess.
|
|
271
|
+
const machineStop = local.verdict === 'STOP';
|
|
272
|
+
const blocked = wouldBlock && policy.mode === 'enforce' && (event.attribution === 'high' || machineStop);
|
|
273
|
+
const decision = this.finish({ action: 'model_call', host: event.host, sessionId: event.sessionId, at: event.at, proposedDepth: null, verdict: report.verdict, wouldBlock, blocked, report, effectiveSpawns: state.spawnCount, compute }, policy, meta, state);
|
|
274
|
+
if (blocked) {
|
|
275
|
+
// A denied call neither occupies the machine nor spends tokens.
|
|
276
|
+
tx.finishCall(event.callId, windowMs(policy), event.at);
|
|
277
|
+
const released = new Map(meta.calls);
|
|
278
|
+
this.applyUsage(event.callId, 0, 0, event.at, state, released);
|
|
279
|
+
meta.calls = [...released];
|
|
280
|
+
}
|
|
281
|
+
this.save(meta, state);
|
|
282
|
+
return decision;
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
catch (error) {
|
|
286
|
+
return this.failClosed('model_call', event, policy, error);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
/** Real usage for a reserved call. Replaces the estimate; releases the slot. */
|
|
290
|
+
completeCall(args) {
|
|
291
|
+
this.observe([
|
|
292
|
+
{
|
|
293
|
+
schemaVersion: 1,
|
|
294
|
+
kind: 'model_usage',
|
|
295
|
+
// Per host: middleware and the proxy may both complete one call, and
|
|
296
|
+
// the later authoritative figure supersedes by callId.
|
|
297
|
+
eventId: `complete-${args.host}-${args.callId}`,
|
|
298
|
+
host: args.host,
|
|
299
|
+
sessionId: args.sessionId,
|
|
300
|
+
at: args.at ?? this.now(),
|
|
301
|
+
tokens: Math.max(0, args.tokens),
|
|
302
|
+
cacheRead: Math.max(0, args.cacheRead ?? 0),
|
|
303
|
+
usageCoverage: args.usageCoverage,
|
|
304
|
+
callId: args.callId,
|
|
305
|
+
},
|
|
306
|
+
]);
|
|
307
|
+
}
|
|
308
|
+
/** The call never produced usage. Releases the estimate and the slot. */
|
|
309
|
+
failCall(args) {
|
|
310
|
+
this.observe([
|
|
311
|
+
{
|
|
312
|
+
schemaVersion: 1,
|
|
313
|
+
kind: 'model_usage',
|
|
314
|
+
eventId: `fail-${args.host}-${args.callId}`,
|
|
315
|
+
host: args.host,
|
|
316
|
+
sessionId: args.sessionId,
|
|
317
|
+
at: args.at ?? this.now(),
|
|
318
|
+
tokens: 0,
|
|
319
|
+
cacheRead: 0,
|
|
320
|
+
usageCoverage: 'missing',
|
|
321
|
+
callId: args.callId,
|
|
322
|
+
},
|
|
323
|
+
]);
|
|
324
|
+
}
|
|
325
|
+
finish(d, policy, meta, state) {
|
|
326
|
+
meta.decisions += 1;
|
|
327
|
+
if (d.wouldBlock)
|
|
328
|
+
meta.wouldBlock += 1;
|
|
329
|
+
const decisionId = (0, events_1.eventId)();
|
|
330
|
+
// Sign what matters: every spawn admission, and any call that is not OK.
|
|
331
|
+
// Signing every OK call through a busy proxy would be thousands of
|
|
332
|
+
// receipts an hour saying nothing.
|
|
333
|
+
let receipt = null;
|
|
334
|
+
if (this.signer && (d.action === 'spawn' || d.verdict !== 'OK')) {
|
|
335
|
+
const payload = {
|
|
336
|
+
schema: 'agentguard.burn.decision.v1',
|
|
337
|
+
decisionId,
|
|
338
|
+
at: d.at,
|
|
339
|
+
host: d.host,
|
|
340
|
+
sessionDigest: (0, receipt_1.sha256)(d.sessionId),
|
|
341
|
+
action: d.action,
|
|
342
|
+
policy: { mode: policy.mode, digest: (0, receipt_1.sha256)((0, receipt_1.canonical)(policy)) },
|
|
343
|
+
measured: {
|
|
344
|
+
sessionTokens: state.totalTokens,
|
|
345
|
+
sessionSpawns: d.effectiveSpawns,
|
|
346
|
+
proposedDepth: d.proposedDepth,
|
|
347
|
+
inFlight: d.compute?.inFlight ?? 0,
|
|
348
|
+
occupiedMs: d.compute?.occupiedMs ?? 0,
|
|
349
|
+
},
|
|
350
|
+
coverage: meta.capabilities,
|
|
351
|
+
verdict: d.verdict,
|
|
352
|
+
blocked: d.blocked,
|
|
353
|
+
reasons: d.report.findings.map((f) => `${f.detector}:${f.verdict}`),
|
|
354
|
+
previous: meta.lastReceipt,
|
|
355
|
+
};
|
|
356
|
+
receipt = this.signer.sign(payload);
|
|
357
|
+
meta.lastReceipt = (0, receipt_1.receiptDigest)(receipt);
|
|
358
|
+
(0, node_fs_1.appendFileSync)((0, node_path_1.join)(this.home, 'receipts.ndjson'), `${JSON.stringify(receipt)}\n`, { mode: 0o600 });
|
|
359
|
+
}
|
|
360
|
+
// Same ledger the Claude hook writes, so `status` and shadow eligibility
|
|
361
|
+
// count every host.
|
|
362
|
+
(0, node_fs_1.appendFileSync)((0, node_path_1.join)(this.home, 'decisions.ndjson'), `${JSON.stringify({
|
|
363
|
+
at: d.at,
|
|
364
|
+
host: d.host,
|
|
365
|
+
action: d.action,
|
|
366
|
+
sessionId: d.sessionId,
|
|
367
|
+
verdict: d.verdict,
|
|
368
|
+
wouldDeny: d.wouldBlock,
|
|
369
|
+
enforced: d.blocked,
|
|
370
|
+
mode: policy.mode,
|
|
371
|
+
findings: d.report.findings.map((f) => ({ detector: f.detector, verdict: f.verdict, observed: f.observed, threshold: f.threshold })),
|
|
372
|
+
effectiveSpawns: d.effectiveSpawns,
|
|
373
|
+
totals: d.report.totals,
|
|
374
|
+
compute: d.compute,
|
|
375
|
+
coverage: meta.capabilities,
|
|
376
|
+
})}\n`, { mode: 0o600 });
|
|
377
|
+
return {
|
|
378
|
+
decisionId,
|
|
379
|
+
action: d.action,
|
|
380
|
+
verdict: d.verdict,
|
|
381
|
+
wouldBlock: d.wouldBlock,
|
|
382
|
+
blocked: d.blocked,
|
|
383
|
+
mode: policy.mode,
|
|
384
|
+
report: d.report,
|
|
385
|
+
capabilities: meta.capabilities,
|
|
386
|
+
effectiveSpawns: d.effectiveSpawns,
|
|
387
|
+
proposedDepth: d.proposedDepth,
|
|
388
|
+
compute: d.compute,
|
|
389
|
+
receipt,
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
failClosed(action, event, policy, error) {
|
|
393
|
+
const reason = `AgentGuard failed closed: ${error instanceof Error ? error.message : 'unknown error'}`;
|
|
394
|
+
(0, node_fs_1.mkdirSync)(this.home, { recursive: true, mode: 0o700 });
|
|
395
|
+
(0, node_fs_1.appendFileSync)((0, node_path_1.join)(this.home, 'decisions.ndjson'), `${JSON.stringify({ at: event.at, host: event.host, action, sessionId: event.sessionId, verdict: 'STOP', wouldDeny: true, enforced: policy.mode === 'enforce', mode: policy.mode, reason, failClosed: true })}\n`, { mode: 0o600 });
|
|
396
|
+
const report = {
|
|
397
|
+
sessionId: event.sessionId,
|
|
398
|
+
verdict: 'STOP',
|
|
399
|
+
findings: [{ detector: action === 'spawn' ? 'fanout' : 'local_compute', verdict: 'STOP', summary: reason, observed: 0, threshold: 0 }],
|
|
400
|
+
prescriptions: ['Another AgentGuard process holds the lock and is not releasing it. Check for a stuck hook, then retry.'],
|
|
401
|
+
cacheReadRatio: 0,
|
|
402
|
+
totals: { tokens: 0, spawns: 0, maxDepth: 0, activeMinutes: 0 },
|
|
403
|
+
};
|
|
404
|
+
return {
|
|
405
|
+
decisionId: (0, events_1.eventId)(),
|
|
406
|
+
action,
|
|
407
|
+
verdict: 'STOP',
|
|
408
|
+
wouldBlock: true,
|
|
409
|
+
blocked: policy.mode === 'enforce',
|
|
410
|
+
mode: policy.mode,
|
|
411
|
+
report,
|
|
412
|
+
capabilities: events_1.CAPABILITIES[event.host],
|
|
413
|
+
effectiveSpawns: 0,
|
|
414
|
+
proposedDepth: event.kind === 'spawn_requested' ? event.proposedDepth ?? 1 : null,
|
|
415
|
+
compute: null,
|
|
416
|
+
receipt: null,
|
|
417
|
+
failedClosed: reason,
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
// ---- read side ------------------------------------------------------
|
|
421
|
+
peek(sessionId) {
|
|
422
|
+
try {
|
|
423
|
+
const raw = JSON.parse((0, node_fs_1.readFileSync)(this.file(sessionId), 'utf8'));
|
|
424
|
+
return view(sessionId, raw);
|
|
425
|
+
}
|
|
426
|
+
catch {
|
|
427
|
+
return null;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
/** Every gateway session on this machine, newest activity first. */
|
|
431
|
+
sessions() {
|
|
432
|
+
const out = [];
|
|
433
|
+
let names = [];
|
|
434
|
+
try {
|
|
435
|
+
names = (0, node_fs_1.readdirSync)(this.sessionsDir).filter((n) => n.startsWith(FILE_PREFIX) && n.endsWith('.json'));
|
|
436
|
+
}
|
|
437
|
+
catch {
|
|
438
|
+
return out;
|
|
439
|
+
}
|
|
440
|
+
for (const name of names) {
|
|
441
|
+
try {
|
|
442
|
+
const raw = JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)(this.sessionsDir, name), 'utf8'));
|
|
443
|
+
out.push(view(raw.state.sessionId, raw));
|
|
444
|
+
}
|
|
445
|
+
catch {
|
|
446
|
+
/* half-written or foreign file: skip */
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
return out.sort((a, b) => b.state.lastEventAt - a.state.lastEventAt);
|
|
450
|
+
}
|
|
451
|
+
compute(sessionId = '') {
|
|
452
|
+
return this.store.computeSnapshot(sessionId, windowMs((0, pre_tool_use_1.loadPolicy)(this.home)), this.now());
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
exports.Gateway = Gateway;
|
|
456
|
+
// ---- helpers ------------------------------------------------------------
|
|
457
|
+
function windowMs(policy) {
|
|
458
|
+
return policy?.thresholds.localCompute?.windowMs ?? defaults_1.DEFAULT_LOCAL_COMPUTE.windowMs;
|
|
459
|
+
}
|
|
460
|
+
function burnEvent(at, partial) {
|
|
461
|
+
return { at, tokens: 0, cacheRead: 0, spawns: [], surfaces: [], sidechain: false, ...partial };
|
|
462
|
+
}
|
|
463
|
+
const RANK = { OK: 0, WARN: 1, STOP: 2 };
|
|
464
|
+
function merge(report, extra) {
|
|
465
|
+
if (extra.length === 0)
|
|
466
|
+
return report;
|
|
467
|
+
const findings = [...report.findings, ...extra];
|
|
468
|
+
let verdict = report.verdict;
|
|
469
|
+
for (const f of extra)
|
|
470
|
+
if (RANK[f.verdict] > RANK[verdict])
|
|
471
|
+
verdict = f.verdict;
|
|
472
|
+
const prescriptions = [...report.prescriptions.filter((p) => p !== 'Nothing pathological. Carry on.')];
|
|
473
|
+
if (extra.some((f) => f.verdict === 'STOP'))
|
|
474
|
+
prescriptions.unshift('Let the model calls already in flight finish before admitting more work.');
|
|
475
|
+
else if (extra.length)
|
|
476
|
+
prescriptions.push('Queue model calls instead of firing them in parallel; the machine is shared by every agent on it.');
|
|
477
|
+
return { ...report, verdict, findings, prescriptions };
|
|
478
|
+
}
|
|
479
|
+
const COVERAGE_RANK = { missing: 0, estimated: 1, authoritative: 2 };
|
|
480
|
+
/** A session fed by several hosts sees the best coverage any of them provides. */
|
|
481
|
+
function mergeCapabilities(hosts) {
|
|
482
|
+
const best = (k) => hosts.map((h) => events_1.CAPABILITIES[h][k]).reduce((a, b) => (COVERAGE_RANK[b] > COVERAGE_RANK[a] ? b : a), 'missing');
|
|
483
|
+
return { spawns: best('spawns'), depth: best('depth'), usage: best('usage') };
|
|
484
|
+
}
|
|
485
|
+
function serialise(state) {
|
|
486
|
+
return {
|
|
487
|
+
sessionId: state.sessionId,
|
|
488
|
+
startedAt: state.startedAt,
|
|
489
|
+
lastEventAt: state.lastEventAt,
|
|
490
|
+
totalTokens: state.totalTokens,
|
|
491
|
+
totalCacheRead: state.totalCacheRead,
|
|
492
|
+
spawnCount: state.spawnCount,
|
|
493
|
+
maxDepth: state.maxDepth,
|
|
494
|
+
activeMinutes: state.activeMinutes,
|
|
495
|
+
tokensByActiveMinute: [...state.tokensByActiveMinute],
|
|
496
|
+
spawnsByActiveMinute: [...state.spawnsByActiveMinute],
|
|
497
|
+
surfaceReaders: [...state.surfaceReaders].map(([k, v]) => [k, [...v]]),
|
|
498
|
+
burnDebt: state.burnDebt,
|
|
499
|
+
lastDebtEventAt: state.lastDebtEventAt,
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
function inflate(s) {
|
|
503
|
+
return {
|
|
504
|
+
...s,
|
|
505
|
+
tokensByActiveMinute: new Map(s.tokensByActiveMinute),
|
|
506
|
+
spawnsByActiveMinute: new Map(s.spawnsByActiveMinute),
|
|
507
|
+
surfaceReaders: new Map(s.surfaceReaders.map(([k, v]) => [k, new Set(v)])),
|
|
508
|
+
};
|
|
509
|
+
}
|
|
510
|
+
function view(sessionId, raw) {
|
|
511
|
+
return {
|
|
512
|
+
sessionId,
|
|
513
|
+
hosts: raw.hosts,
|
|
514
|
+
capabilities: raw.capabilities,
|
|
515
|
+
state: inflate(raw.state),
|
|
516
|
+
liveSpawns: raw.liveSpawns.length,
|
|
517
|
+
usage: raw.usage,
|
|
518
|
+
decisions: raw.decisions,
|
|
519
|
+
wouldBlock: raw.wouldBlock,
|
|
520
|
+
closedAt: raw.closedAt,
|
|
521
|
+
};
|
|
522
|
+
}
|
|
@@ -27,6 +27,7 @@ const claude_transcript_1 = require("../history/claude-transcript");
|
|
|
27
27
|
const reservations_1 = require("../state/reservations");
|
|
28
28
|
const session_1 = require("../state/session");
|
|
29
29
|
const defaults_1 = require("../defaults");
|
|
30
|
+
const render_1 = require("../replay/render");
|
|
30
31
|
const SPAWN_TOOLS = new Set(['Agent', 'Task']);
|
|
31
32
|
function sessionFile(home, sessionId) {
|
|
32
33
|
return (0, node_path_1.join)(home, 'sessions', `${sessionId.replace(/[^a-zA-Z0-9_-]/g, '_')}.json`);
|
|
@@ -145,10 +146,10 @@ function handlePreToolUse(input, home, now = Date.now()) {
|
|
|
145
146
|
}
|
|
146
147
|
return { continue: true, suppressOutput: true };
|
|
147
148
|
}
|
|
148
|
-
function buildDenyReason(report,
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
return
|
|
149
|
+
function buildDenyReason(report, _reservation) {
|
|
150
|
+
// Claude Code shows this reason to the user. A box reads as an alarm; a
|
|
151
|
+
// sentence reads as a log line. Colour is off: the host decides rendering.
|
|
152
|
+
return (0, render_1.renderStop)(report, { colour: false });
|
|
152
153
|
}
|
|
153
154
|
function deny(reason) {
|
|
154
155
|
return {
|
package/dist/src/index.d.ts
CHANGED
|
@@ -1,10 +1,21 @@
|
|
|
1
1
|
export * from './types';
|
|
2
|
-
export { DEFAULT_POLICY, DEFAULT_THRESHOLDS } from './defaults';
|
|
2
|
+
export { DEFAULT_POLICY, DEFAULT_THRESHOLDS, DEFAULT_LOCAL_COMPUTE, CALL_RESERVATION_TTL_MS } from './defaults';
|
|
3
3
|
export { evaluate, fmt } from './detectors/evaluate';
|
|
4
|
+
export { evaluateLocalCompute } from './detectors/local-compute';
|
|
4
5
|
export { readIncremental, readAll, newCursor, normaliseLine, type ReaderCursor } from './history/claude-transcript';
|
|
5
|
-
export { applyEvent, newSessionState, windowSum, medianCompletedMinute, cacheReadRatio } from './state/session';
|
|
6
|
-
export { ReservationStore, RESERVATION_TTL_MS } from './state/reservations';
|
|
6
|
+
export { applyEvent, applyCorrection, newSessionState, windowSum, medianCompletedMinute, cacheReadRatio } from './state/session';
|
|
7
|
+
export { ReservationStore, Transaction, RESERVATION_TTL_MS, type Reservation, type CallReservation, type ComputeSnapshot } from './state/reservations';
|
|
7
8
|
export { replayAll, replaySession, replayEvents, discoverTranscripts, type ReplaySummary, type SessionReplay } from './replay/simulate';
|
|
8
|
-
export { renderReplay } from './replay/render';
|
|
9
|
+
export { renderReplay, renderStop } from './replay/render';
|
|
9
10
|
export { calibrate, type CalibrationResult } from './calibrate';
|
|
10
11
|
export { handlePreToolUse, refreshSession, loadPolicy, settingsSnippet, type HookInput, type HookOutput } from './hook/pre-tool-use';
|
|
12
|
+
export * from './events';
|
|
13
|
+
export { Gateway, mergeCapabilities, type Decision, type GatewaySessionView, type UsageCoverage, type GatewayOptions } from './gateway';
|
|
14
|
+
export { ReceiptSigner, verifyReceipt, receiptDigest, canonical, sha256, type ReceiptPayload, type SignedReceipt } from './receipt';
|
|
15
|
+
export { createRawApiGuard, BurnStopError, type RawApiGuard, type RawGuardOptions } from './adapters/raw-api';
|
|
16
|
+
export { handleCursorHook, cursorHooksSnippet, type CursorHookOutput } from './adapters/cursor';
|
|
17
|
+
export { handleCodexHook, codexHooksSnippet, parseCodexTranscript, readCodexTranscriptUsage, CODEX_FORBIDDEN_FIELDS, type CodexHookOutput } from './adapters/codex';
|
|
18
|
+
export { startProxy, profileFor, type ProxyOptions, type ProxyHost, type RunningProxy } from './proxy/server';
|
|
19
|
+
export { UsageObserver, type ProxyProfile, type ObservedUsage } from './proxy/usage-observer';
|
|
20
|
+
export { renderMachineStatus } from './status';
|
|
21
|
+
export { runConformance, type ConformanceResult } from './conformance';
|
package/dist/src/index.js
CHANGED
|
@@ -14,14 +14,19 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.settingsSnippet = exports.loadPolicy = exports.refreshSession = exports.handlePreToolUse = exports.calibrate = exports.renderReplay = exports.discoverTranscripts = exports.replayEvents = exports.replaySession = exports.replayAll = exports.RESERVATION_TTL_MS = exports.ReservationStore = exports.cacheReadRatio = exports.medianCompletedMinute = exports.windowSum = exports.newSessionState = exports.applyEvent = exports.normaliseLine = exports.newCursor = exports.readAll = exports.readIncremental = exports.fmt = exports.evaluate = exports.DEFAULT_THRESHOLDS = exports.DEFAULT_POLICY = void 0;
|
|
17
|
+
exports.UsageObserver = exports.profileFor = exports.startProxy = exports.CODEX_FORBIDDEN_FIELDS = exports.readCodexTranscriptUsage = exports.parseCodexTranscript = exports.codexHooksSnippet = exports.handleCodexHook = exports.cursorHooksSnippet = exports.handleCursorHook = exports.BurnStopError = exports.createRawApiGuard = exports.sha256 = exports.canonical = exports.receiptDigest = exports.verifyReceipt = exports.ReceiptSigner = exports.mergeCapabilities = exports.Gateway = exports.settingsSnippet = exports.loadPolicy = exports.refreshSession = exports.handlePreToolUse = exports.calibrate = exports.renderStop = exports.renderReplay = exports.discoverTranscripts = exports.replayEvents = exports.replaySession = exports.replayAll = exports.RESERVATION_TTL_MS = exports.Transaction = exports.ReservationStore = exports.cacheReadRatio = exports.medianCompletedMinute = exports.windowSum = exports.newSessionState = exports.applyCorrection = exports.applyEvent = exports.normaliseLine = exports.newCursor = exports.readAll = exports.readIncremental = exports.evaluateLocalCompute = exports.fmt = exports.evaluate = exports.CALL_RESERVATION_TTL_MS = exports.DEFAULT_LOCAL_COMPUTE = exports.DEFAULT_THRESHOLDS = exports.DEFAULT_POLICY = void 0;
|
|
18
|
+
exports.runConformance = exports.renderMachineStatus = void 0;
|
|
18
19
|
__exportStar(require("./types"), exports);
|
|
19
20
|
var defaults_1 = require("./defaults");
|
|
20
21
|
Object.defineProperty(exports, "DEFAULT_POLICY", { enumerable: true, get: function () { return defaults_1.DEFAULT_POLICY; } });
|
|
21
22
|
Object.defineProperty(exports, "DEFAULT_THRESHOLDS", { enumerable: true, get: function () { return defaults_1.DEFAULT_THRESHOLDS; } });
|
|
23
|
+
Object.defineProperty(exports, "DEFAULT_LOCAL_COMPUTE", { enumerable: true, get: function () { return defaults_1.DEFAULT_LOCAL_COMPUTE; } });
|
|
24
|
+
Object.defineProperty(exports, "CALL_RESERVATION_TTL_MS", { enumerable: true, get: function () { return defaults_1.CALL_RESERVATION_TTL_MS; } });
|
|
22
25
|
var evaluate_1 = require("./detectors/evaluate");
|
|
23
26
|
Object.defineProperty(exports, "evaluate", { enumerable: true, get: function () { return evaluate_1.evaluate; } });
|
|
24
27
|
Object.defineProperty(exports, "fmt", { enumerable: true, get: function () { return evaluate_1.fmt; } });
|
|
28
|
+
var local_compute_1 = require("./detectors/local-compute");
|
|
29
|
+
Object.defineProperty(exports, "evaluateLocalCompute", { enumerable: true, get: function () { return local_compute_1.evaluateLocalCompute; } });
|
|
25
30
|
var claude_transcript_1 = require("./history/claude-transcript");
|
|
26
31
|
Object.defineProperty(exports, "readIncremental", { enumerable: true, get: function () { return claude_transcript_1.readIncremental; } });
|
|
27
32
|
Object.defineProperty(exports, "readAll", { enumerable: true, get: function () { return claude_transcript_1.readAll; } });
|
|
@@ -29,12 +34,14 @@ Object.defineProperty(exports, "newCursor", { enumerable: true, get: function ()
|
|
|
29
34
|
Object.defineProperty(exports, "normaliseLine", { enumerable: true, get: function () { return claude_transcript_1.normaliseLine; } });
|
|
30
35
|
var session_1 = require("./state/session");
|
|
31
36
|
Object.defineProperty(exports, "applyEvent", { enumerable: true, get: function () { return session_1.applyEvent; } });
|
|
37
|
+
Object.defineProperty(exports, "applyCorrection", { enumerable: true, get: function () { return session_1.applyCorrection; } });
|
|
32
38
|
Object.defineProperty(exports, "newSessionState", { enumerable: true, get: function () { return session_1.newSessionState; } });
|
|
33
39
|
Object.defineProperty(exports, "windowSum", { enumerable: true, get: function () { return session_1.windowSum; } });
|
|
34
40
|
Object.defineProperty(exports, "medianCompletedMinute", { enumerable: true, get: function () { return session_1.medianCompletedMinute; } });
|
|
35
41
|
Object.defineProperty(exports, "cacheReadRatio", { enumerable: true, get: function () { return session_1.cacheReadRatio; } });
|
|
36
42
|
var reservations_1 = require("./state/reservations");
|
|
37
43
|
Object.defineProperty(exports, "ReservationStore", { enumerable: true, get: function () { return reservations_1.ReservationStore; } });
|
|
44
|
+
Object.defineProperty(exports, "Transaction", { enumerable: true, get: function () { return reservations_1.Transaction; } });
|
|
38
45
|
Object.defineProperty(exports, "RESERVATION_TTL_MS", { enumerable: true, get: function () { return reservations_1.RESERVATION_TTL_MS; } });
|
|
39
46
|
var simulate_1 = require("./replay/simulate");
|
|
40
47
|
Object.defineProperty(exports, "replayAll", { enumerable: true, get: function () { return simulate_1.replayAll; } });
|
|
@@ -43,6 +50,7 @@ Object.defineProperty(exports, "replayEvents", { enumerable: true, get: function
|
|
|
43
50
|
Object.defineProperty(exports, "discoverTranscripts", { enumerable: true, get: function () { return simulate_1.discoverTranscripts; } });
|
|
44
51
|
var render_1 = require("./replay/render");
|
|
45
52
|
Object.defineProperty(exports, "renderReplay", { enumerable: true, get: function () { return render_1.renderReplay; } });
|
|
53
|
+
Object.defineProperty(exports, "renderStop", { enumerable: true, get: function () { return render_1.renderStop; } });
|
|
46
54
|
var calibrate_1 = require("./calibrate");
|
|
47
55
|
Object.defineProperty(exports, "calibrate", { enumerable: true, get: function () { return calibrate_1.calibrate; } });
|
|
48
56
|
var pre_tool_use_1 = require("./hook/pre-tool-use");
|
|
@@ -50,3 +58,35 @@ Object.defineProperty(exports, "handlePreToolUse", { enumerable: true, get: func
|
|
|
50
58
|
Object.defineProperty(exports, "refreshSession", { enumerable: true, get: function () { return pre_tool_use_1.refreshSession; } });
|
|
51
59
|
Object.defineProperty(exports, "loadPolicy", { enumerable: true, get: function () { return pre_tool_use_1.loadPolicy; } });
|
|
52
60
|
Object.defineProperty(exports, "settingsSnippet", { enumerable: true, get: function () { return pre_tool_use_1.settingsSnippet; } });
|
|
61
|
+
// Cross-tool layer (0.2.0)
|
|
62
|
+
__exportStar(require("./events"), exports);
|
|
63
|
+
var gateway_1 = require("./gateway");
|
|
64
|
+
Object.defineProperty(exports, "Gateway", { enumerable: true, get: function () { return gateway_1.Gateway; } });
|
|
65
|
+
Object.defineProperty(exports, "mergeCapabilities", { enumerable: true, get: function () { return gateway_1.mergeCapabilities; } });
|
|
66
|
+
var receipt_1 = require("./receipt");
|
|
67
|
+
Object.defineProperty(exports, "ReceiptSigner", { enumerable: true, get: function () { return receipt_1.ReceiptSigner; } });
|
|
68
|
+
Object.defineProperty(exports, "verifyReceipt", { enumerable: true, get: function () { return receipt_1.verifyReceipt; } });
|
|
69
|
+
Object.defineProperty(exports, "receiptDigest", { enumerable: true, get: function () { return receipt_1.receiptDigest; } });
|
|
70
|
+
Object.defineProperty(exports, "canonical", { enumerable: true, get: function () { return receipt_1.canonical; } });
|
|
71
|
+
Object.defineProperty(exports, "sha256", { enumerable: true, get: function () { return receipt_1.sha256; } });
|
|
72
|
+
var raw_api_1 = require("./adapters/raw-api");
|
|
73
|
+
Object.defineProperty(exports, "createRawApiGuard", { enumerable: true, get: function () { return raw_api_1.createRawApiGuard; } });
|
|
74
|
+
Object.defineProperty(exports, "BurnStopError", { enumerable: true, get: function () { return raw_api_1.BurnStopError; } });
|
|
75
|
+
var cursor_1 = require("./adapters/cursor");
|
|
76
|
+
Object.defineProperty(exports, "handleCursorHook", { enumerable: true, get: function () { return cursor_1.handleCursorHook; } });
|
|
77
|
+
Object.defineProperty(exports, "cursorHooksSnippet", { enumerable: true, get: function () { return cursor_1.cursorHooksSnippet; } });
|
|
78
|
+
var codex_1 = require("./adapters/codex");
|
|
79
|
+
Object.defineProperty(exports, "handleCodexHook", { enumerable: true, get: function () { return codex_1.handleCodexHook; } });
|
|
80
|
+
Object.defineProperty(exports, "codexHooksSnippet", { enumerable: true, get: function () { return codex_1.codexHooksSnippet; } });
|
|
81
|
+
Object.defineProperty(exports, "parseCodexTranscript", { enumerable: true, get: function () { return codex_1.parseCodexTranscript; } });
|
|
82
|
+
Object.defineProperty(exports, "readCodexTranscriptUsage", { enumerable: true, get: function () { return codex_1.readCodexTranscriptUsage; } });
|
|
83
|
+
Object.defineProperty(exports, "CODEX_FORBIDDEN_FIELDS", { enumerable: true, get: function () { return codex_1.CODEX_FORBIDDEN_FIELDS; } });
|
|
84
|
+
var server_1 = require("./proxy/server");
|
|
85
|
+
Object.defineProperty(exports, "startProxy", { enumerable: true, get: function () { return server_1.startProxy; } });
|
|
86
|
+
Object.defineProperty(exports, "profileFor", { enumerable: true, get: function () { return server_1.profileFor; } });
|
|
87
|
+
var usage_observer_1 = require("./proxy/usage-observer");
|
|
88
|
+
Object.defineProperty(exports, "UsageObserver", { enumerable: true, get: function () { return usage_observer_1.UsageObserver; } });
|
|
89
|
+
var status_1 = require("./status");
|
|
90
|
+
Object.defineProperty(exports, "renderMachineStatus", { enumerable: true, get: function () { return status_1.renderMachineStatus; } });
|
|
91
|
+
var conformance_1 = require("./conformance");
|
|
92
|
+
Object.defineProperty(exports, "runConformance", { enumerable: true, get: function () { return conformance_1.runConformance; } });
|