agy-worker-mcp 0.3.1
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 +141 -0
- package/LICENSE +21 -0
- package/README.md +309 -0
- package/commands/agy-ceiling.md +31 -0
- package/dist/broker/blockers.d.ts +86 -0
- package/dist/broker/blockers.d.ts.map +1 -0
- package/dist/broker/blockers.js +390 -0
- package/dist/broker/blockers.js.map +1 -0
- package/dist/broker/outcome.d.ts +85 -0
- package/dist/broker/outcome.d.ts.map +1 -0
- package/dist/broker/outcome.js +147 -0
- package/dist/broker/outcome.js.map +1 -0
- package/dist/broker/reconcile.d.ts +74 -0
- package/dist/broker/reconcile.d.ts.map +1 -0
- package/dist/broker/reconcile.js +415 -0
- package/dist/broker/reconcile.js.map +1 -0
- package/dist/broker/result.d.ts +88 -0
- package/dist/broker/result.d.ts.map +1 -0
- package/dist/broker/result.js +234 -0
- package/dist/broker/result.js.map +1 -0
- package/dist/broker/verify.d.ts +52 -0
- package/dist/broker/verify.d.ts.map +1 -0
- package/dist/broker/verify.js +174 -0
- package/dist/broker/verify.js.map +1 -0
- package/dist/contract/errors.d.ts +119 -0
- package/dist/contract/errors.d.ts.map +1 -0
- package/dist/contract/errors.js +99 -0
- package/dist/contract/errors.js.map +1 -0
- package/dist/contract/index.d.ts +10 -0
- package/dist/contract/index.d.ts.map +1 -0
- package/dist/contract/index.js +10 -0
- package/dist/contract/index.js.map +1 -0
- package/dist/contract/paths.d.ts +139 -0
- package/dist/contract/paths.d.ts.map +1 -0
- package/dist/contract/paths.js +359 -0
- package/dist/contract/paths.js.map +1 -0
- package/dist/contract/schema.sql +64 -0
- package/dist/contract/types.d.ts +1113 -0
- package/dist/contract/types.d.ts.map +1 -0
- package/dist/contract/types.js +114 -0
- package/dist/contract/types.js.map +1 -0
- package/dist/events/cursor.d.ts +65 -0
- package/dist/events/cursor.d.ts.map +1 -0
- package/dist/events/cursor.js +286 -0
- package/dist/events/cursor.js.map +1 -0
- package/dist/events/detect.d.ts +58 -0
- package/dist/events/detect.d.ts.map +1 -0
- package/dist/events/detect.js +183 -0
- package/dist/events/detect.js.map +1 -0
- package/dist/events/normalize.d.ts +30 -0
- package/dist/events/normalize.d.ts.map +1 -0
- package/dist/events/normalize.js +158 -0
- package/dist/events/normalize.js.map +1 -0
- package/dist/events/parse.d.ts +41 -0
- package/dist/events/parse.d.ts.map +1 -0
- package/dist/events/parse.js +89 -0
- package/dist/events/parse.js.map +1 -0
- package/dist/gate/bind.d.ts +28 -0
- package/dist/gate/bind.d.ts.map +1 -0
- package/dist/gate/bind.js +154 -0
- package/dist/gate/bind.js.map +1 -0
- package/dist/gate/gate.d.ts +139 -0
- package/dist/gate/gate.d.ts.map +1 -0
- package/dist/gate/gate.js +488 -0
- package/dist/gate/gate.js.map +1 -0
- package/dist/gate/hooks-file.d.ts +55 -0
- package/dist/gate/hooks-file.d.ts.map +1 -0
- package/dist/gate/hooks-file.js +104 -0
- package/dist/gate/hooks-file.js.map +1 -0
- package/dist/gate.d.ts +3 -0
- package/dist/gate.d.ts.map +1 -0
- package/dist/gate.js +20 -0
- package/dist/gate.js.map +1 -0
- package/dist/policy/ceiling-review.d.ts +22 -0
- package/dist/policy/ceiling-review.d.ts.map +1 -0
- package/dist/policy/ceiling-review.js +170 -0
- package/dist/policy/ceiling-review.js.map +1 -0
- package/dist/policy/ceiling.d.ts +128 -0
- package/dist/policy/ceiling.d.ts.map +1 -0
- package/dist/policy/ceiling.js +273 -0
- package/dist/policy/ceiling.js.map +1 -0
- package/dist/policy/containment.d.ts +100 -0
- package/dist/policy/containment.d.ts.map +1 -0
- package/dist/policy/containment.js +1071 -0
- package/dist/policy/containment.js.map +1 -0
- package/dist/policy/hard-deny.d.ts +28 -0
- package/dist/policy/hard-deny.d.ts.map +1 -0
- package/dist/policy/hard-deny.js +78 -0
- package/dist/policy/hard-deny.js.map +1 -0
- package/dist/policy/profiles.d.ts +82 -0
- package/dist/policy/profiles.d.ts.map +1 -0
- package/dist/policy/profiles.js +317 -0
- package/dist/policy/profiles.js.map +1 -0
- package/dist/policy/rules.d.ts +138 -0
- package/dist/policy/rules.d.ts.map +1 -0
- package/dist/policy/rules.js +1180 -0
- package/dist/policy/rules.js.map +1 -0
- package/dist/policy/seatbelt.d.ts +32 -0
- package/dist/policy/seatbelt.d.ts.map +1 -0
- package/dist/policy/seatbelt.js +59 -0
- package/dist/policy/seatbelt.js.map +1 -0
- package/dist/policy/tools.d.ts +36 -0
- package/dist/policy/tools.d.ts.map +1 -0
- package/dist/policy/tools.js +94 -0
- package/dist/policy/tools.js.map +1 -0
- package/dist/runner/gate-watchdog.d.ts +93 -0
- package/dist/runner/gate-watchdog.d.ts.map +1 -0
- package/dist/runner/gate-watchdog.js +153 -0
- package/dist/runner/gate-watchdog.js.map +1 -0
- package/dist/runner/idle.d.ts +51 -0
- package/dist/runner/idle.d.ts.map +1 -0
- package/dist/runner/idle.js +81 -0
- package/dist/runner/idle.js.map +1 -0
- package/dist/runner/inbox.d.ts +56 -0
- package/dist/runner/inbox.d.ts.map +1 -0
- package/dist/runner/inbox.js +134 -0
- package/dist/runner/inbox.js.map +1 -0
- package/dist/runner/reap.d.ts +65 -0
- package/dist/runner/reap.d.ts.map +1 -0
- package/dist/runner/reap.js +168 -0
- package/dist/runner/reap.js.map +1 -0
- package/dist/runner/runner.d.ts +51 -0
- package/dist/runner/runner.d.ts.map +1 -0
- package/dist/runner/runner.js +289 -0
- package/dist/runner/runner.js.map +1 -0
- package/dist/runner/spawn.d.ts +98 -0
- package/dist/runner/spawn.d.ts.map +1 -0
- package/dist/runner/spawn.js +230 -0
- package/dist/runner/spawn.js.map +1 -0
- package/dist/runner/verify.d.ts +24 -0
- package/dist/runner/verify.d.ts.map +1 -0
- package/dist/runner/verify.js +108 -0
- package/dist/runner/verify.js.map +1 -0
- package/dist/runner.d.ts +3 -0
- package/dist/runner.d.ts.map +1 -0
- package/dist/runner.js +15 -0
- package/dist/runner.js.map +1 -0
- package/dist/server/context.d.ts +41 -0
- package/dist/server/context.d.ts.map +1 -0
- package/dist/server/context.js +59 -0
- package/dist/server/context.js.map +1 -0
- package/dist/server/instructions.d.ts +13 -0
- package/dist/server/instructions.d.ts.map +1 -0
- package/dist/server/instructions.js +121 -0
- package/dist/server/instructions.js.map +1 -0
- package/dist/server/server.d.ts +20 -0
- package/dist/server/server.d.ts.map +1 -0
- package/dist/server/server.js +55 -0
- package/dist/server/server.js.map +1 -0
- package/dist/server/tools/cancel.d.ts +24 -0
- package/dist/server/tools/cancel.d.ts.map +1 -0
- package/dist/server/tools/cancel.js +59 -0
- package/dist/server/tools/cancel.js.map +1 -0
- package/dist/server/tools/capabilities.d.ts +36 -0
- package/dist/server/tools/capabilities.d.ts.map +1 -0
- package/dist/server/tools/capabilities.js +116 -0
- package/dist/server/tools/capabilities.js.map +1 -0
- package/dist/server/tools/ceiling.d.ts +31 -0
- package/dist/server/tools/ceiling.d.ts.map +1 -0
- package/dist/server/tools/ceiling.js +121 -0
- package/dist/server/tools/ceiling.js.map +1 -0
- package/dist/server/tools/index.d.ts +38 -0
- package/dist/server/tools/index.d.ts.map +1 -0
- package/dist/server/tools/index.js +115 -0
- package/dist/server/tools/index.js.map +1 -0
- package/dist/server/tools/listJobs.d.ts +30 -0
- package/dist/server/tools/listJobs.d.ts.map +1 -0
- package/dist/server/tools/listJobs.js +37 -0
- package/dist/server/tools/listJobs.js.map +1 -0
- package/dist/server/tools/logs.d.ts +31 -0
- package/dist/server/tools/logs.d.ts.map +1 -0
- package/dist/server/tools/logs.js +96 -0
- package/dist/server/tools/logs.js.map +1 -0
- package/dist/server/tools/result.d.ts +32 -0
- package/dist/server/tools/result.d.ts.map +1 -0
- package/dist/server/tools/result.js +95 -0
- package/dist/server/tools/result.js.map +1 -0
- package/dist/server/tools/send.d.ts +37 -0
- package/dist/server/tools/send.d.ts.map +1 -0
- package/dist/server/tools/send.js +71 -0
- package/dist/server/tools/send.js.map +1 -0
- package/dist/server/tools/sessions.d.ts +28 -0
- package/dist/server/tools/sessions.d.ts.map +1 -0
- package/dist/server/tools/sessions.js +54 -0
- package/dist/server/tools/sessions.js.map +1 -0
- package/dist/server/tools/start.d.ts +107 -0
- package/dist/server/tools/start.d.ts.map +1 -0
- package/dist/server/tools/start.js +482 -0
- package/dist/server/tools/start.js.map +1 -0
- package/dist/server/tools/wait.d.ts +29 -0
- package/dist/server/tools/wait.d.ts.map +1 -0
- package/dist/server/tools/wait.js +120 -0
- package/dist/server/tools/wait.js.map +1 -0
- package/dist/server.d.ts +3 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +17 -0
- package/dist/server.js.map +1 -0
- package/dist/setup/install.d.ts +52 -0
- package/dist/setup/install.d.ts.map +1 -0
- package/dist/setup/install.js +108 -0
- package/dist/setup/install.js.map +1 -0
- package/dist/setup.d.ts +3 -0
- package/dist/setup.d.ts.map +1 -0
- package/dist/setup.js +24 -0
- package/dist/setup.js.map +1 -0
- package/dist/store/db.d.ts +49 -0
- package/dist/store/db.d.ts.map +1 -0
- package/dist/store/db.js +101 -0
- package/dist/store/db.js.map +1 -0
- package/dist/store/jobs.d.ts +45 -0
- package/dist/store/jobs.d.ts.map +1 -0
- package/dist/store/jobs.js +150 -0
- package/dist/store/jobs.js.map +1 -0
- package/dist/store/locks.d.ts +60 -0
- package/dist/store/locks.d.ts.map +1 -0
- package/dist/store/locks.js +172 -0
- package/dist/store/locks.js.map +1 -0
- package/dist/store/sessions.d.ts +37 -0
- package/dist/store/sessions.d.ts.map +1 -0
- package/dist/store/sessions.js +117 -0
- package/dist/store/sessions.js.map +1 -0
- package/dist/trace/digest.d.ts +77 -0
- package/dist/trace/digest.d.ts.map +1 -0
- package/dist/trace/digest.js +481 -0
- package/dist/trace/digest.js.map +1 -0
- package/package.json +68 -0
- package/skills/agy-ceiling/SKILL.md +72 -0
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { ENVIRONMENT_BLOCK_SIGNATURES, GATE_DENIAL_MARKER, HOOK_DENIAL_PREFIX, } from '../contract/types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Detect the two ways a job gets stuck (see docs/permissions.md).
|
|
4
|
+
*
|
|
5
|
+
* Both are invisible in the obvious places: agy exits 0 and reports
|
|
6
|
+
* `status: "SUCCESS"` for a hook denial *and* for a sandboxed network block
|
|
7
|
+
* (see docs/permissions.md). Skipping this module means reporting failed work as success.
|
|
8
|
+
*/
|
|
9
|
+
function commandOf(toolInfo) {
|
|
10
|
+
const cmd = toolInfo?.parameters?.CommandLine;
|
|
11
|
+
return typeof cmd === 'string' ? cmd : null;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Class 1 — a structured refusal.
|
|
15
|
+
*
|
|
16
|
+
* Signal: `step_type === 'tool' && state === 'ERROR'`, message in
|
|
17
|
+
* `tool_info.error.message`. stderr stays empty and the exit code stays 0, so
|
|
18
|
+
* this event is the only trace.
|
|
19
|
+
*/
|
|
20
|
+
export function detectClass1(step) {
|
|
21
|
+
const su = step.step_update;
|
|
22
|
+
if (su.step_type !== 'tool' || su.state !== 'ERROR')
|
|
23
|
+
return null;
|
|
24
|
+
const message = su.tool_info?.error?.message ?? '';
|
|
25
|
+
const tool = su.tool_name ?? su.tool_info?.name ?? 'unknown';
|
|
26
|
+
const command = commandOf(su.tool_info);
|
|
27
|
+
const required_rule = extractRequiredRule(message);
|
|
28
|
+
const gatePayload = parseGateDenial(message);
|
|
29
|
+
let source = 'unknown';
|
|
30
|
+
if (message.startsWith(HOOK_DENIAL_PREFIX)) {
|
|
31
|
+
source = 'gate';
|
|
32
|
+
}
|
|
33
|
+
else if (su.tool_info?.error !== undefined) {
|
|
34
|
+
source = 'agy';
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
class: 1,
|
|
38
|
+
tool,
|
|
39
|
+
command,
|
|
40
|
+
required_rule,
|
|
41
|
+
policy: gatePayload?.policy ?? null,
|
|
42
|
+
source,
|
|
43
|
+
message,
|
|
44
|
+
step_idx: su.step_index ?? null,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/** The only tool agy's OS sandbox wraps; every other tool runs outside it. */
|
|
48
|
+
const SANDBOXED_TOOL = 'run_command';
|
|
49
|
+
/**
|
|
50
|
+
* Class 2 — a silent environment block.
|
|
51
|
+
*
|
|
52
|
+
* Signal: an ordinary successful `run_command` step whose `tool_info.output`
|
|
53
|
+
* matches one of `ENVIRONMENT_BLOCK_SIGNATURES`. There is no error event at all.
|
|
54
|
+
* This is the more dangerous class: an hour-long job can fail to install
|
|
55
|
+
* anything and still return SUCCESS.
|
|
56
|
+
*
|
|
57
|
+
* Only `run_command` is scanned: the sandbox wraps the shell and nothing else,
|
|
58
|
+
* and the output of `grep_search`/`view_file` over a source tree that merely
|
|
59
|
+
* *contains* the words "Operation not permitted" is not a block (measured
|
|
60
|
+
* 2026-09-03: a job grepping this very repository produced three false
|
|
61
|
+
* blockers that way).
|
|
62
|
+
*/
|
|
63
|
+
export function detectClass2(step) {
|
|
64
|
+
const su = step.step_update;
|
|
65
|
+
if (su.step_type !== 'tool')
|
|
66
|
+
return null;
|
|
67
|
+
const tool = su.tool_name ?? su.tool_info?.name ?? 'unknown';
|
|
68
|
+
if (tool !== SANDBOXED_TOOL)
|
|
69
|
+
return null;
|
|
70
|
+
const output = su.tool_info?.output;
|
|
71
|
+
if (typeof output !== 'string' || output.length === 0)
|
|
72
|
+
return null;
|
|
73
|
+
const signature = matchEnvironmentSignature(output);
|
|
74
|
+
if (signature === null)
|
|
75
|
+
return null;
|
|
76
|
+
const command = commandOf(su.tool_info);
|
|
77
|
+
// The match is case-insensitive, so locate the excerpt the same way.
|
|
78
|
+
const idx = output.toLowerCase().indexOf(signature.toLowerCase());
|
|
79
|
+
const CONTEXT = 60;
|
|
80
|
+
const start = Math.max(0, idx - CONTEXT);
|
|
81
|
+
const end = Math.min(output.length, idx + signature.length + CONTEXT);
|
|
82
|
+
const excerpt = output.slice(start, end).replace(/\s+/g, ' ').trim();
|
|
83
|
+
return {
|
|
84
|
+
class: 2,
|
|
85
|
+
tool,
|
|
86
|
+
command,
|
|
87
|
+
signature,
|
|
88
|
+
excerpt,
|
|
89
|
+
step_idx: su.step_index ?? null,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
/** Run both detectors over a whole event stream. */
|
|
93
|
+
export function scanDenials(events) {
|
|
94
|
+
const permission_denials = [];
|
|
95
|
+
const environment_blocks = [];
|
|
96
|
+
for (const e of events) {
|
|
97
|
+
if (e.event !== 'step_update')
|
|
98
|
+
continue;
|
|
99
|
+
const c1 = detectClass1(e);
|
|
100
|
+
if (c1 !== null)
|
|
101
|
+
permission_denials.push(c1);
|
|
102
|
+
const c2 = detectClass2(e);
|
|
103
|
+
if (c2 !== null)
|
|
104
|
+
environment_blocks.push(c2);
|
|
105
|
+
}
|
|
106
|
+
return { permission_denials, environment_blocks };
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Pull the machine payload our gate embedded after `GATE_DENIAL_MARKER`.
|
|
110
|
+
* Null when the refusal did not come from us.
|
|
111
|
+
*
|
|
112
|
+
* Format authored by the gate: `<guidance> [agy-worker-denial:{"...json..."}]`.
|
|
113
|
+
* The payload runs from right after the marker up to the closing `]` that wraps
|
|
114
|
+
* it, so a trailing `]` (if present) is stripped before parsing.
|
|
115
|
+
*/
|
|
116
|
+
export function parseGateDenial(message) {
|
|
117
|
+
const markerIdx = message.indexOf(GATE_DENIAL_MARKER);
|
|
118
|
+
if (markerIdx === -1)
|
|
119
|
+
return null;
|
|
120
|
+
let rest = message.slice(markerIdx + GATE_DENIAL_MARKER.length).trim();
|
|
121
|
+
if (rest.endsWith(']'))
|
|
122
|
+
rest = rest.slice(0, -1).trim();
|
|
123
|
+
try {
|
|
124
|
+
const payload = JSON.parse(rest);
|
|
125
|
+
if (typeof payload === 'object' && payload !== null) {
|
|
126
|
+
return payload;
|
|
127
|
+
}
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
// Greedy so a rule that itself contains parens — e.g. "command(echo x)" — keeps
|
|
135
|
+
// its own closing paren; only the outermost "(required rule: ...)" wrapper ends
|
|
136
|
+
// at the final ')' in the message.
|
|
137
|
+
const REQUIRED_RULE_PROSE = /\(required rule:\s*(.+)\)\s*$/;
|
|
138
|
+
/**
|
|
139
|
+
* Best-effort `required_rule` from a denial message.
|
|
140
|
+
*
|
|
141
|
+
* Prefers the embedded payload; falls back to the `(required rule: ...)` prose
|
|
142
|
+
* form that appears in the measured transcript. The caller pastes the result
|
|
143
|
+
* straight into the next `agy_start`'s `permissions.allow`, which is the whole
|
|
144
|
+
* recovery loop (see docs/permissions.md).
|
|
145
|
+
*/
|
|
146
|
+
export function extractRequiredRule(message) {
|
|
147
|
+
const gate = parseGateDenial(message);
|
|
148
|
+
if (gate !== null && typeof gate.required_rule === 'string' && gate.required_rule.length > 0) {
|
|
149
|
+
return gate.required_rule;
|
|
150
|
+
}
|
|
151
|
+
const match = message.match(REQUIRED_RULE_PROSE);
|
|
152
|
+
const rule = match?.[1];
|
|
153
|
+
return rule !== undefined ? rule.trim() : null;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Which signature, if any, a tool output contains. Case-insensitive: the same
|
|
157
|
+
* seatbelt refusal surfaces as `Operation not permitted` from coreutils
|
|
158
|
+
* (`mkdir: build: Operation not permitted`) and as `operation not permitted`
|
|
159
|
+
* from zsh's own redirection error (`zsh:1: operation not permitted: note.txt`,
|
|
160
|
+
* measured on agy 1.1.24), and as `sh: out.txt: Operation not permitted` — all
|
|
161
|
+
* single-line or final-line. The canonical (capitalised) signature is returned.
|
|
162
|
+
*
|
|
163
|
+
* 0.3.0 PR5: Only inspects the last 5 non-empty lines of the output.
|
|
164
|
+
* A real sandbox/network refusal is the failing command's final message;
|
|
165
|
+
* a signature buried mid-output inside a test report is not.
|
|
166
|
+
*/
|
|
167
|
+
export function matchEnvironmentSignature(output) {
|
|
168
|
+
const lines = output.split('\n');
|
|
169
|
+
const nonEmpty = [];
|
|
170
|
+
for (let i = lines.length - 1; i >= 0 && nonEmpty.length < 5; i--) {
|
|
171
|
+
const line = lines[i];
|
|
172
|
+
if (line !== undefined && line.trim().length > 0) {
|
|
173
|
+
nonEmpty.push(line);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
const tail = nonEmpty.reverse().join('\n').toLowerCase();
|
|
177
|
+
for (const sig of ENVIRONMENT_BLOCK_SIGNATURES) {
|
|
178
|
+
if (tail.includes(sig.toLowerCase()))
|
|
179
|
+
return sig;
|
|
180
|
+
}
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
183
|
+
//# sourceMappingURL=detect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detect.js","sourceRoot":"","sources":["../../src/events/detect.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { AgyEvent, NormalizedEvent } from '../contract/types.js';
|
|
2
|
+
import type { ParsedLine } from './parse.js';
|
|
3
|
+
/**
|
|
4
|
+
* Turn raw `step_update` traffic into a short human-readable trail.
|
|
5
|
+
*
|
|
6
|
+
* Keep: phase transitions, command start/end, errors and warnings, check
|
|
7
|
+
* PASS/FAIL, artifact creation, and the tail of the final response.
|
|
8
|
+
* Drop: repeated token deltas, blank text, and duplicates of the previous line.
|
|
9
|
+
*
|
|
10
|
+
* Normalization happens on read, in memory. Nothing is persisted — the raw
|
|
11
|
+
* NDJSON stays the only stored form.
|
|
12
|
+
*/
|
|
13
|
+
export interface NormalizeOptions {
|
|
14
|
+
/** Truncate each line to this many characters. */
|
|
15
|
+
maxLineChars?: number;
|
|
16
|
+
/** Collapse consecutive `agent_message` lines into one. */
|
|
17
|
+
collapseDeltas?: boolean;
|
|
18
|
+
}
|
|
19
|
+
/** Null when the event carries nothing worth a line. */
|
|
20
|
+
export declare function normalizeEvent(event: AgyEvent, opts?: NormalizeOptions): NormalizedEvent | null;
|
|
21
|
+
/** Batch form; also surfaces malformed lines as `kind: 'raw'`, severity `warning`. */
|
|
22
|
+
export declare function normalizeParsed(parsed: ParsedLine[], opts?: NormalizeOptions): NormalizedEvent[];
|
|
23
|
+
/** Render one normalized event as a single display line. */
|
|
24
|
+
export declare function formatNormalized(e: NormalizedEvent): string;
|
|
25
|
+
/**
|
|
26
|
+
* The last `maxLines` display lines, obeying a byte budget.
|
|
27
|
+
* This is what `agy_wait` returns as `log_tail`.
|
|
28
|
+
*/
|
|
29
|
+
export declare function tailSummary(events: NormalizedEvent[], maxLines: number, maxBytes?: number): string[];
|
|
30
|
+
//# sourceMappingURL=normalize.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"normalize.d.ts","sourceRoot":"","sources":["../../src/events/normalize.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAe,eAAe,EAAkB,MAAM,sBAAsB,CAAA;AAElG,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAE5C;;;;;;;;;GASG;AACH,MAAM,WAAW,gBAAgB;IAC/B,kDAAkD;IAClD,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,2DAA2D;IAC3D,cAAc,CAAC,EAAE,OAAO,CAAA;CACzB;AAuCD,wDAAwD;AACxD,wBAAgB,cAAc,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,CAAC,EAAE,gBAAgB,GAAG,eAAe,GAAG,IAAI,CA0G/F;AAED,sFAAsF;AACtF,wBAAgB,eAAe,CAAC,MAAM,EAAE,UAAU,EAAE,EAAE,IAAI,CAAC,EAAE,gBAAgB,GAAG,eAAe,EAAE,CAgChG;AAED,4DAA4D;AAC5D,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,eAAe,GAAG,MAAM,CAI3D;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,eAAe,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAYpG"}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { matchEnvironmentSignature } from './detect.js';
|
|
2
|
+
const DEFAULT_MAX_CHARS = 200;
|
|
3
|
+
function collapseWhitespace(text) {
|
|
4
|
+
return text.replace(/\s+/g, ' ').trim();
|
|
5
|
+
}
|
|
6
|
+
/** Head truncation: keep the start, ellipsis at the end. */
|
|
7
|
+
function truncateHead(text, maxChars) {
|
|
8
|
+
const collapsed = collapseWhitespace(text);
|
|
9
|
+
if (collapsed.length <= maxChars)
|
|
10
|
+
return collapsed;
|
|
11
|
+
if (maxChars <= 1)
|
|
12
|
+
return collapsed.slice(0, maxChars);
|
|
13
|
+
return collapsed.slice(0, maxChars - 1) + '…';
|
|
14
|
+
}
|
|
15
|
+
/** Tail truncation: keep the end (the part that matters for a final response). */
|
|
16
|
+
function truncateTail(text, maxChars) {
|
|
17
|
+
const collapsed = collapseWhitespace(text);
|
|
18
|
+
if (collapsed.length <= maxChars)
|
|
19
|
+
return collapsed;
|
|
20
|
+
if (maxChars <= 1)
|
|
21
|
+
return collapsed.slice(collapsed.length - maxChars);
|
|
22
|
+
return '…' + collapsed.slice(collapsed.length - (maxChars - 1));
|
|
23
|
+
}
|
|
24
|
+
function commandOf(toolInfo) {
|
|
25
|
+
const cmd = toolInfo?.parameters?.CommandLine;
|
|
26
|
+
return typeof cmd === 'string' ? cmd : undefined;
|
|
27
|
+
}
|
|
28
|
+
function make(kind, severity, stepIdx, text, extra) {
|
|
29
|
+
return { kind, severity, step_idx: stepIdx, text, ...extra };
|
|
30
|
+
}
|
|
31
|
+
/** Null when the event carries nothing worth a line. */
|
|
32
|
+
export function normalizeEvent(event, opts) {
|
|
33
|
+
const maxChars = opts?.maxLineChars ?? DEFAULT_MAX_CHARS;
|
|
34
|
+
if (event.event === 'init') {
|
|
35
|
+
const i = event.init;
|
|
36
|
+
return make('session_start', 'info', null, truncateHead(`session started model=${i.model} cwd=${i.cwd}`, maxChars));
|
|
37
|
+
}
|
|
38
|
+
if (event.event === 'result') {
|
|
39
|
+
const r = event.result;
|
|
40
|
+
if (r.status === 'SUCCESS') {
|
|
41
|
+
return make('final_response', 'info', null, truncateTail(r.response ?? '', maxChars), {
|
|
42
|
+
duration_seconds: r.duration_seconds,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
const text = r.error ?? r.response ?? 'turn ended with an error';
|
|
46
|
+
return make('final_response', 'error', null, truncateTail(text, maxChars), {
|
|
47
|
+
duration_seconds: r.duration_seconds,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
// step_update
|
|
51
|
+
const su = event.step_update;
|
|
52
|
+
const stepIdx = su.step_index ?? null;
|
|
53
|
+
const command = commandOf(su.tool_info);
|
|
54
|
+
if (su.step_type === 'tool') {
|
|
55
|
+
if (su.state === 'ERROR') {
|
|
56
|
+
const msg = su.tool_info?.error?.message ?? 'tool call failed';
|
|
57
|
+
return make('tool_error', 'error', stepIdx, truncateHead(`${su.tool_name ?? 'tool'} failed: ${msg}`, maxChars), { tool: su.tool_name, command, duration_seconds: su.duration_seconds });
|
|
58
|
+
}
|
|
59
|
+
if (su.state === 'ACTIVE') {
|
|
60
|
+
return make('command_start', 'info', stepIdx, truncateHead(`${su.tool_name ?? 'tool'} started${command ? `: ${command}` : ''}`, maxChars), { tool: su.tool_name, command });
|
|
61
|
+
}
|
|
62
|
+
if (su.state === 'DONE') {
|
|
63
|
+
const output = su.tool_info?.output;
|
|
64
|
+
// Same scope as `detectClass2`: only the shell runs inside the sandbox.
|
|
65
|
+
const sig = su.tool_name === 'run_command' && typeof output === 'string' ? matchEnvironmentSignature(output) : null;
|
|
66
|
+
if (sig !== null) {
|
|
67
|
+
return make('environment_block', 'warning', stepIdx, truncateHead(`${su.tool_name ?? 'tool'} output looks blocked by the environment (${sig})`, maxChars), { tool: su.tool_name, command, duration_seconds: su.duration_seconds });
|
|
68
|
+
}
|
|
69
|
+
return make('command_end', 'info', stepIdx, truncateHead(`${su.tool_name ?? 'tool'} finished${command ? `: ${command}` : ''}`, maxChars), { tool: su.tool_name, command, duration_seconds: su.duration_seconds });
|
|
70
|
+
}
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
if (su.step_type === 'user_input') {
|
|
74
|
+
if (su.state === 'DONE') {
|
|
75
|
+
return make('phase', 'info', stepIdx, 'turn started');
|
|
76
|
+
}
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
if (su.step_type === 'system_message') {
|
|
80
|
+
const text = su.text_delta;
|
|
81
|
+
if (!text || text.trim() === '')
|
|
82
|
+
return null;
|
|
83
|
+
return make('system', 'info', stepIdx, truncateHead(text, maxChars));
|
|
84
|
+
}
|
|
85
|
+
if (su.step_type === 'agent_response') {
|
|
86
|
+
if (su.state === 'ERROR') {
|
|
87
|
+
return make('tool_error', 'error', stepIdx, 'agent response ended in error');
|
|
88
|
+
}
|
|
89
|
+
// Streamed token deltas are dropped on purpose — the tail of the final
|
|
90
|
+
// response is already captured once, from the `result` event.
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
// Unrecognized step_type: still surface an error state, drop everything else.
|
|
94
|
+
if (su.state === 'ERROR') {
|
|
95
|
+
return make('tool_error', 'error', stepIdx, `step ${stepIdx ?? '?'} ended in error`);
|
|
96
|
+
}
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
/** Batch form; also surfaces malformed lines as `kind: 'raw'`, severity `warning`. */
|
|
100
|
+
export function normalizeParsed(parsed, opts) {
|
|
101
|
+
const maxChars = opts?.maxLineChars ?? DEFAULT_MAX_CHARS;
|
|
102
|
+
const out = [];
|
|
103
|
+
let prevKey = null;
|
|
104
|
+
for (const p of parsed) {
|
|
105
|
+
let ne;
|
|
106
|
+
if (!p.ok) {
|
|
107
|
+
ne = make('raw', 'warning', null, truncateHead(`malformed line: ${p.error}`, maxChars), {
|
|
108
|
+
offset: p.offset,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
else if ('unknown' in p) {
|
|
112
|
+
ne = make('raw', 'info', null, truncateHead(`unknown event: ${p.raw}`, maxChars), {
|
|
113
|
+
offset: p.offset,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
ne = normalizeEvent(p.event, opts);
|
|
118
|
+
if (ne !== null && p.offset !== undefined)
|
|
119
|
+
ne = { ...ne, offset: p.offset };
|
|
120
|
+
}
|
|
121
|
+
if (ne === null)
|
|
122
|
+
continue;
|
|
123
|
+
if (ne.text.trim() === '')
|
|
124
|
+
continue;
|
|
125
|
+
const key = `${ne.kind}|${ne.step_idx}|${ne.text}`;
|
|
126
|
+
if (key === prevKey)
|
|
127
|
+
continue; // duplicate of the immediately preceding line
|
|
128
|
+
out.push(ne);
|
|
129
|
+
prevKey = key;
|
|
130
|
+
}
|
|
131
|
+
return out;
|
|
132
|
+
}
|
|
133
|
+
/** Render one normalized event as a single display line. */
|
|
134
|
+
export function formatNormalized(e) {
|
|
135
|
+
const prefix = e.severity === 'error' ? '[ERROR]' : e.severity === 'warning' ? '[WARN]' : '';
|
|
136
|
+
const stepPart = e.step_idx !== null ? `#${e.step_idx}` : '';
|
|
137
|
+
return [prefix, stepPart, e.text].filter((s) => s.length > 0).join(' ');
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* The last `maxLines` display lines, obeying a byte budget.
|
|
141
|
+
* This is what `agy_wait` returns as `log_tail`.
|
|
142
|
+
*/
|
|
143
|
+
export function tailSummary(events, maxLines, maxBytes) {
|
|
144
|
+
if (maxLines <= 0)
|
|
145
|
+
return [];
|
|
146
|
+
const lines = events.slice(-maxLines).map(formatNormalized);
|
|
147
|
+
if (maxBytes === undefined)
|
|
148
|
+
return lines;
|
|
149
|
+
let total = lines.reduce((acc, l) => acc + Buffer.byteLength(l, 'utf8') + 1, 0);
|
|
150
|
+
while (lines.length > 0 && total > maxBytes) {
|
|
151
|
+
const removed = lines.shift();
|
|
152
|
+
if (removed === undefined)
|
|
153
|
+
break;
|
|
154
|
+
total -= Buffer.byteLength(removed, 'utf8') + 1;
|
|
155
|
+
}
|
|
156
|
+
return lines;
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=normalize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"normalize.js","sourceRoot":"","sources":["../../src/events/normalize.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { AgyEvent, AgyInitEvent, AgyResultEvent, AgyStepUpdateEvent, AgyUnknownEvent } from '../contract/types.js';
|
|
2
|
+
/**
|
|
3
|
+
* A parsed line. A malformed line is preserved as `ok: false` rather than dropped:
|
|
4
|
+
* losing bytes silently makes a truncated or interleaved stream indistinguishable
|
|
5
|
+
* from a clean one, and the malformed count feeds the broker's warnings.
|
|
6
|
+
*/
|
|
7
|
+
export type ParsedLine = {
|
|
8
|
+
ok: true;
|
|
9
|
+
event: AgyEvent;
|
|
10
|
+
raw: string;
|
|
11
|
+
offset?: number;
|
|
12
|
+
} | {
|
|
13
|
+
ok: true;
|
|
14
|
+
event: AgyUnknownEvent;
|
|
15
|
+
raw: string;
|
|
16
|
+
offset?: number;
|
|
17
|
+
unknown: true;
|
|
18
|
+
} | {
|
|
19
|
+
ok: false;
|
|
20
|
+
raw: string;
|
|
21
|
+
error: string;
|
|
22
|
+
offset?: number;
|
|
23
|
+
};
|
|
24
|
+
export declare function parseEventLine(raw: string, offset?: number): ParsedLine;
|
|
25
|
+
export declare function parseEventLines(lines: string[], startOffset?: number): ParsedLine[];
|
|
26
|
+
/** Narrowing helpers. The envelope key always equals the `event` value. */
|
|
27
|
+
export declare function isInit(e: AgyEvent | AgyUnknownEvent): e is AgyInitEvent;
|
|
28
|
+
export declare function isStepUpdate(e: AgyEvent | AgyUnknownEvent): e is AgyStepUpdateEvent;
|
|
29
|
+
export declare function isResult(e: AgyEvent | AgyUnknownEvent): e is AgyResultEvent;
|
|
30
|
+
/** All well-formed events out of a parse batch. */
|
|
31
|
+
export declare function okEvents(parsed: ParsedLine[]): AgyEvent[];
|
|
32
|
+
/**
|
|
33
|
+
* `conversation_id` from the first line of an events file, or null.
|
|
34
|
+
*
|
|
35
|
+
* Cheap by design — the gate calls it once per candidate job on every tool call.
|
|
36
|
+
* It is available before any tool runs because `init` is always line 1 (§4).
|
|
37
|
+
*/
|
|
38
|
+
export declare function extractConversationId(eventsPath: string): string | null;
|
|
39
|
+
/** The last `result` event, i.e. the final turn's self-report. */
|
|
40
|
+
export declare function lastResult(events: AgyEvent[]): AgyResultEvent | null;
|
|
41
|
+
//# sourceMappingURL=parse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../src/events/parse.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,QAAQ,EACR,YAAY,EACZ,cAAc,EACd,kBAAkB,EAClB,eAAe,EAChB,MAAM,sBAAsB,CAAA;AAG7B;;;;GAIG;AACH,MAAM,MAAM,UAAU,GAClB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,QAAQ,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAC3D;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,eAAe,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,IAAI,CAAA;CAAE,GACjF;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAA;AAM9D,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,UAAU,CA6BvE;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,WAAW,SAAI,GAAG,UAAU,EAAE,CAQ9E;AAED,2EAA2E;AAC3E,wBAAgB,MAAM,CAAC,CAAC,EAAE,QAAQ,GAAG,eAAe,GAAG,CAAC,IAAI,YAAY,CAEvE;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,QAAQ,GAAG,eAAe,GAAG,CAAC,IAAI,kBAAkB,CAEnF;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,QAAQ,GAAG,eAAe,GAAG,CAAC,IAAI,cAAc,CAE3E;AAED,mDAAmD;AACnD,wBAAgB,QAAQ,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,QAAQ,EAAE,CAQzD;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAOvE;AAED,kEAAkE;AAClE,wBAAgB,UAAU,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,cAAc,GAAG,IAAI,CAMpE"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { readFirstLine } from './cursor.js';
|
|
2
|
+
function isRecord(v) {
|
|
3
|
+
return typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
4
|
+
}
|
|
5
|
+
export function parseEventLine(raw, offset) {
|
|
6
|
+
let parsed;
|
|
7
|
+
try {
|
|
8
|
+
parsed = JSON.parse(raw);
|
|
9
|
+
}
|
|
10
|
+
catch (err) {
|
|
11
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
12
|
+
return { ok: false, raw, error: `invalid JSON: ${message}`, offset };
|
|
13
|
+
}
|
|
14
|
+
if (!isRecord(parsed)) {
|
|
15
|
+
return { ok: false, raw, error: 'not a JSON object', offset };
|
|
16
|
+
}
|
|
17
|
+
const eventName = parsed.event;
|
|
18
|
+
if (typeof eventName !== 'string' || eventName.length === 0) {
|
|
19
|
+
return { ok: false, raw, error: 'missing "event" field', offset };
|
|
20
|
+
}
|
|
21
|
+
if (eventName === 'init' && typeof parsed.conversation_id === 'string' && isRecord(parsed.init)) {
|
|
22
|
+
return { ok: true, event: parsed, raw, offset };
|
|
23
|
+
}
|
|
24
|
+
if (eventName === 'step_update' && isRecord(parsed.step_update)) {
|
|
25
|
+
return { ok: true, event: parsed, raw, offset };
|
|
26
|
+
}
|
|
27
|
+
if (eventName === 'result' && isRecord(parsed.result)) {
|
|
28
|
+
return { ok: true, event: parsed, raw, offset };
|
|
29
|
+
}
|
|
30
|
+
return { ok: true, event: parsed, raw, offset, unknown: true };
|
|
31
|
+
}
|
|
32
|
+
export function parseEventLines(lines, startOffset = 0) {
|
|
33
|
+
const out = [];
|
|
34
|
+
let offset = startOffset;
|
|
35
|
+
for (const line of lines) {
|
|
36
|
+
out.push(parseEventLine(line, offset));
|
|
37
|
+
offset += Buffer.byteLength(line, 'utf8') + 1;
|
|
38
|
+
}
|
|
39
|
+
return out;
|
|
40
|
+
}
|
|
41
|
+
/** Narrowing helpers. The envelope key always equals the `event` value. */
|
|
42
|
+
export function isInit(e) {
|
|
43
|
+
return e.event === 'init';
|
|
44
|
+
}
|
|
45
|
+
export function isStepUpdate(e) {
|
|
46
|
+
return e.event === 'step_update';
|
|
47
|
+
}
|
|
48
|
+
export function isResult(e) {
|
|
49
|
+
return e.event === 'result';
|
|
50
|
+
}
|
|
51
|
+
/** All well-formed events out of a parse batch. */
|
|
52
|
+
export function okEvents(parsed) {
|
|
53
|
+
const out = [];
|
|
54
|
+
for (const p of parsed) {
|
|
55
|
+
if (!p.ok)
|
|
56
|
+
continue;
|
|
57
|
+
if ('unknown' in p)
|
|
58
|
+
continue;
|
|
59
|
+
out.push(p.event);
|
|
60
|
+
}
|
|
61
|
+
return out;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* `conversation_id` from the first line of an events file, or null.
|
|
65
|
+
*
|
|
66
|
+
* Cheap by design — the gate calls it once per candidate job on every tool call.
|
|
67
|
+
* It is available before any tool runs because `init` is always line 1 (§4).
|
|
68
|
+
*/
|
|
69
|
+
export function extractConversationId(eventsPath) {
|
|
70
|
+
const first = readFirstLine(eventsPath);
|
|
71
|
+
if (first === null)
|
|
72
|
+
return null;
|
|
73
|
+
const parsed = parseEventLine(first);
|
|
74
|
+
if (!parsed.ok)
|
|
75
|
+
return null;
|
|
76
|
+
if (isInit(parsed.event))
|
|
77
|
+
return parsed.event.conversation_id;
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
/** The last `result` event, i.e. the final turn's self-report. */
|
|
81
|
+
export function lastResult(events) {
|
|
82
|
+
for (let i = events.length - 1; i >= 0; i--) {
|
|
83
|
+
const e = events[i];
|
|
84
|
+
if (e !== undefined && isResult(e))
|
|
85
|
+
return e;
|
|
86
|
+
}
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=parse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.js","sourceRoot":"","sources":["../../src/events/parse.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { EffectivePolicy, JobRow } from '../contract/types.js';
|
|
2
|
+
import type { Store } from '../store/db.js';
|
|
3
|
+
export interface BoundJob {
|
|
4
|
+
job: JobRow;
|
|
5
|
+
policy: EffectivePolicy;
|
|
6
|
+
conversationId: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Null means "not one of ours" — a user's own interactive agy session.
|
|
10
|
+
*
|
|
11
|
+
* ⚠ That case must produce `{"decision":"ask"}`, never `{}`. `{}` is a denial
|
|
12
|
+
* (§9) and would break every interactive session on the machine.
|
|
13
|
+
*/
|
|
14
|
+
export declare function bindConversation(store: Store, conversationId: string): BoundJob | null;
|
|
15
|
+
/**
|
|
16
|
+
* Persist the mapping so later calls skip the file scan. Also fills in
|
|
17
|
+
* `sessions.conversation_id` when it was still NULL.
|
|
18
|
+
*/
|
|
19
|
+
export declare function recordBinding(store: Store, jobId: string, conversationId: string): void;
|
|
20
|
+
/** Cached lookup for a conversation already bound in a previous hook invocation. */
|
|
21
|
+
export declare function lookupBoundJob(store: Store, conversationId: string): JobRow | null;
|
|
22
|
+
/**
|
|
23
|
+
* Load `jobs/<id>/policy.json`. Null when it is missing or unreadable.
|
|
24
|
+
*
|
|
25
|
+
* Defaults bypass_sandbox to false if missing (fail closed).
|
|
26
|
+
*/
|
|
27
|
+
export declare function loadJobPolicy(store: Store, jobId: string): EffectivePolicy | null;
|
|
28
|
+
//# sourceMappingURL=bind.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bind.d.ts","sourceRoot":"","sources":["../../src/gate/bind.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,EAAa,MAAM,sBAAsB,CAAA;AAC9E,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAA;AA0B3C,MAAM,WAAW,QAAQ;IACvB,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,EAAE,eAAe,CAAA;IACvB,cAAc,EAAE,MAAM,CAAA;CACvB;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,KAAK,EAAE,cAAc,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAqBtF;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,IAAI,CAQvF;AAED,oFAAoF;AACpF,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,EAAE,cAAc,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CASlF;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CA2BjF"}
|