@basein/runner 0.2.12 → 0.3.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 +540 -369
- package/dist/auth/client.d.ts +65 -3
- package/dist/auth/client.js +305 -53
- package/dist/bin/bir-hooks.d.ts +72 -31
- package/dist/bin/bir-hooks.js +176 -284
- package/dist/bin/bir-proxy.d.ts +17 -2
- package/dist/bin/bir-proxy.js +222 -28
- package/dist/bin/bir-scenario.d.ts +61 -21
- package/dist/bin/bir-scenario.js +593 -122
- package/dist/bin/bir.d.ts +12 -6
- package/dist/bin/bir.js +2935 -489
- package/dist/bin/investigate.js +40 -15
- package/dist/bin/scenario-edit.d.ts +7 -1
- package/dist/bin/scenario-edit.js +43 -21
- package/dist/bin/scenario-liveness.d.ts +194 -0
- package/dist/bin/scenario-liveness.js +459 -0
- package/dist/bin/scenario-stderr.d.ts +43 -0
- package/dist/bin/scenario-stderr.js +76 -0
- package/dist/bin/service-read.d.ts +88 -0
- package/dist/bin/service-read.js +128 -0
- package/dist/bin/setup.d.ts +19 -0
- package/dist/bin/setup.js +146 -20
- package/dist/config/adapters/claude-code.d.ts +92 -14
- package/dist/config/adapters/claude-code.js +291 -101
- package/dist/config/adapters/generic.d.ts +4 -1
- package/dist/config/adapters/generic.js +13 -14
- package/dist/config/generate.d.ts +392 -14
- package/dist/config/generate.js +666 -19
- package/dist/config/mcp-approval.d.ts +76 -0
- package/dist/config/mcp-approval.js +210 -0
- package/dist/config/node-path.d.ts +42 -0
- package/dist/config/node-path.js +102 -0
- package/dist/config/overrides.d.ts +62 -0
- package/dist/config/overrides.js +136 -0
- package/dist/config/resolve.d.ts +70 -8
- package/dist/config/resolve.js +186 -15
- package/dist/control/client.d.ts +22 -0
- package/dist/control/client.js +26 -7
- package/dist/control/correlation.d.ts +23 -5
- package/dist/control/correlation.js +0 -0
- package/dist/control/daemon.d.ts +400 -18
- package/dist/control/daemon.js +1105 -102
- package/dist/control/discovery.d.ts +77 -5
- package/dist/control/discovery.js +186 -11
- package/dist/control/ensure-hook.d.ts +61 -0
- package/dist/control/ensure-hook.js +160 -8
- package/dist/control/paths.d.ts +26 -0
- package/dist/control/paths.js +34 -0
- package/dist/control/pin-guard.d.ts +83 -0
- package/dist/control/pin-guard.js +534 -0
- package/dist/control/recorder-keeper.d.ts +229 -0
- package/dist/control/recorder-keeper.js +721 -0
- package/dist/control/recorder-main.d.ts +73 -0
- package/dist/control/recorder-main.js +778 -0
- package/dist/control/server.d.ts +707 -31
- package/dist/control/server.js +2786 -302
- package/dist/control/transcript.d.ts +21 -1
- package/dist/control/transcript.js +378 -112
- package/dist/index.d.ts +5 -1
- package/dist/index.js +5 -1
- package/dist/jsonrpc/framing.d.ts +76 -12
- package/dist/jsonrpc/framing.js +216 -59
- package/dist/proxy/intercept.d.ts +49 -5
- package/dist/proxy/intercept.js +188 -59
- package/dist/proxy/relay.d.ts +16 -0
- package/dist/proxy/relay.js +77 -5
- package/dist/proxy/revive.d.ts +122 -0
- package/dist/proxy/revive.js +251 -0
- package/dist/proxy/session.d.ts +222 -14
- package/dist/proxy/session.js +708 -99
- package/dist/record/recorder.d.ts +51 -3
- package/dist/record/recorder.js +3 -0
- package/dist/record/redact.d.ts +103 -9
- package/dist/record/redact.js +659 -30
- package/dist/record/remote-recorder.d.ts +327 -32
- package/dist/record/remote-recorder.js +1517 -187
- package/dist/record/switchable-recorder.d.ts +126 -0
- package/dist/record/switchable-recorder.js +351 -0
- package/dist/record/truncate.d.ts +40 -1
- package/dist/record/truncate.js +111 -4
- package/dist/replay/bash-channel.d.ts +35 -0
- package/dist/replay/bash-channel.js +133 -0
- package/dist/replay/bundle.d.ts +10 -0
- package/dist/replay/bundle.js +10 -0
- package/dist/replay/controller.d.ts +369 -20
- package/dist/replay/controller.js +1176 -107
- package/dist/replay/derive.d.ts +1 -0
- package/dist/replay/derive.js +81 -24
- package/dist/replay/executor.d.ts +51 -16
- package/dist/replay/executor.js +114 -41
- package/dist/replay/handover.d.ts +54 -1
- package/dist/replay/handover.js +55 -5
- package/dist/replay/logic.d.ts +62 -10
- package/dist/replay/logic.js +140 -22
- package/dist/replay/plan.d.ts +201 -27
- package/dist/replay/plan.js +581 -141
- package/dist/replay/safety.d.ts +72 -0
- package/dist/replay/safety.js +303 -0
- package/dist/replay/source-run.d.ts +10 -0
- package/dist/replay/source-run.js +80 -35
- package/dist/replay/targets.d.ts +15 -1
- package/dist/replay/targets.js +62 -4
- package/dist/replay/tool-error.d.ts +15 -1
- package/dist/replay/tool-error.js +33 -1
- package/dist/replay/types.d.ts +7 -4
- package/dist/upstream/client.d.ts +56 -3
- package/dist/upstream/client.js +61 -4
- package/dist/upstream/headers.d.ts +43 -0
- package/dist/upstream/headers.js +90 -0
- package/dist/upstream/http-client.d.ts +213 -22
- package/dist/upstream/http-client.js +1034 -168
- package/dist/upstream/http-transport.d.ts +143 -0
- package/dist/upstream/http-transport.js +391 -0
- package/dist/upstream/lazy-client.d.ts +8 -0
- package/dist/upstream/lazy-client.js +29 -1
- package/dist/upstream/sse.d.ts +78 -0
- package/dist/upstream/sse.js +189 -0
- package/dist/upstream/stdio-client.d.ts +61 -1
- package/dist/upstream/stdio-client.js +356 -33
- package/dist/util/atomic-write.d.ts +29 -0
- package/dist/util/atomic-write.js +96 -0
- package/dist/util/journal.d.ts +15 -0
- package/dist/util/journal.js +48 -3
- package/dist/util/log.d.ts +10 -0
- package/dist/util/log.js +28 -1
- package/dist/util/off-switch.d.ts +46 -0
- package/dist/util/off-switch.js +91 -0
- package/dist/util/service-health.d.ts +133 -0
- package/dist/util/service-health.js +217 -0
- package/docs/BaseInstRunner.md +694 -621
- package/docs/calculatedReplay.md +1625 -1304
- package/docs/calculatedReplayGuide.md +1212 -1087
- package/docs/installRun.md +1013 -772
- package/docs/loginWeb.md +627 -607
- package/docs/mcpmark.md +49 -16
- package/docs/my-first-sample.md +569 -545
- package/docs/quickstart.md +384 -311
- package/docs/t-bench.md +406 -394
- package/package.json +58 -57
- package/production.md +1371 -0
- package/scripts/install.ps1 +97 -6
- package/scripts/install.sh +104 -7
package/dist/replay/logic.d.ts
CHANGED
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
* logic — the four stored-JS evaluators (docs/calculatedReplay.md §9).
|
|
3
3
|
*
|
|
4
4
|
* A calculated scenario carries JavaScript function *bodies*, one per hook
|
|
5
|
-
* point, each ending in `return { … }`. They are compiled
|
|
6
|
-
* and run here.
|
|
5
|
+
* point, each ending in `return { … }`. They are compiled and run here.
|
|
7
6
|
*
|
|
8
7
|
* PORTED FROM THE SERVICE, DELIBERATELY. BaseIn's `src/scenarios/logic.ts` is
|
|
9
8
|
* the copy the service itself evaluates in a dry replay, so it is the one that
|
|
@@ -12,18 +11,71 @@
|
|
|
12
11
|
* another way here — an untestable difference. Argument order and the
|
|
13
12
|
* plain-object guard both match the service exactly.
|
|
14
13
|
*
|
|
15
|
-
* THERE IS NO SANDBOX, and the doc says so plainly (§13.1). A
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
14
|
+
* THERE IS NO SANDBOX, and the doc says so plainly (§13.1). A body gets its
|
|
15
|
+
* declared arguments and the global scope: `require`/`import` are unreachable
|
|
16
|
+
* under ESM, but `fetch`, `process` and `globalThis` are not. What makes this
|
|
17
|
+
* acceptable is provenance, not containment — the payload arrives only in an
|
|
18
|
+
* authenticated response from the configured `BIR_AUTH_URL`, describing the
|
|
19
|
+
* caller's own recorded runs — and replay is opt-in for exactly this reason.
|
|
20
|
+
*
|
|
21
|
+
* THERE IS A CLOCK. Every body runs inside the one process that answers every
|
|
22
|
+
* hook of the project, on its only thread. The service ran the same body under
|
|
23
|
+
* a time limit — but on the *recording's* values, and a regex written against a
|
|
24
|
+
* 2 KB output can backtrack for minutes on a 2 MB one, or a hand edit saved with
|
|
25
|
+
* `--force` can loop. Without a limit that froze the event loop, and every
|
|
26
|
+
* `PreToolUse`, `PostToolUse` and prompt hook of every session in the project
|
|
27
|
+
* waited out its timeout on every call until someone killed `bir-hooks`.
|
|
28
|
+
*
|
|
29
|
+
* So each body runs through `vm.Script#runInThisContext` with a `timeout`
|
|
30
|
+
* ({@link logicTimeoutMs}). *This* context, not a new one: the body keeps the
|
|
31
|
+
* realm, the globals and the argument objects it always had — `instanceof
|
|
32
|
+
* Array` still holds for a value `JSON.parse` made outside, a body that writes
|
|
33
|
+
* into `respParams` still writes into the plan's own — so the only behaviour
|
|
34
|
+
* that changes is that a runaway body throws instead of hanging. That throw is
|
|
35
|
+
* an ordinary logic failure, and the plan hands over at that step. The limit
|
|
36
|
+
* covers synchronous work, which is all a body returning a plain object does;
|
|
37
|
+
* it does not bound memory.
|
|
38
|
+
*
|
|
39
|
+
* WHAT THE CLOCK DOES NOT COVER. `runInThisContext`'s timeout ends when the
|
|
40
|
+
* body returns. A continuation the body *queues* — `Promise.resolve().then(…)`,
|
|
41
|
+
* `queueMicrotask`, `setTimeout` — runs afterwards, outside it, on the same
|
|
42
|
+
* thread, and nothing here bounds it. A body that returns a promise is refused
|
|
43
|
+
* (it is no plain object, and it is the shape such work comes in); one that
|
|
44
|
+
* queues work and still returns a plain object is not caught. Bounding that
|
|
45
|
+
* would take a separate context (`microtaskMode: "afterEvaluate"`), which gives
|
|
46
|
+
* up the realm and the shared argument objects this relies on. The threat the
|
|
47
|
+
* clock answers — a backtracking regex, a loop saved with `--force` — is
|
|
48
|
+
* synchronous; a body written to get around it already has the process (see
|
|
49
|
+
* THERE IS NO SANDBOX above).
|
|
50
|
+
*/
|
|
51
|
+
/** How long one logic body may run before it is stopped. */
|
|
52
|
+
export declare const DEFAULT_LOGIC_TIMEOUT_MS = 1000;
|
|
53
|
+
/**
|
|
54
|
+
* The most `BIR_LOGIC_TIMEOUT_MS` may ask for. A body runs on the only thread
|
|
55
|
+
* of the process that answers every hook of the project, so each second it is
|
|
56
|
+
* allowed is a second every session's hooks can stand still; and a direct run
|
|
57
|
+
* adds a few of them past its own deadline (controller.ts, `clampDirectRun`).
|
|
22
58
|
*/
|
|
59
|
+
export declare const MAX_LOGIC_TIMEOUT_MS = 10000;
|
|
60
|
+
/** `BIR_LOGIC_TIMEOUT_MS` (at most {@link MAX_LOGIC_TIMEOUT_MS}), or {@link DEFAULT_LOGIC_TIMEOUT_MS}. */
|
|
61
|
+
export declare function logicTimeoutMs(): number;
|
|
62
|
+
/** A body stopped by its time limit — as opposed to one that threw on its own. */
|
|
63
|
+
export declare class LogicTimeoutError extends Error {
|
|
64
|
+
constructor(label: string, timeoutMs: number);
|
|
65
|
+
}
|
|
66
|
+
/** Per-call options for an evaluator. */
|
|
67
|
+
export interface LogicRunOptions {
|
|
68
|
+
/**
|
|
69
|
+
* A tighter limit than {@link logicTimeoutMs} for this one evaluation — for
|
|
70
|
+
* a look-ahead nobody waits on the answer of, such as the directive's
|
|
71
|
+
* preview of a step's arguments. Never raises the limit.
|
|
72
|
+
*/
|
|
73
|
+
timeoutMs?: number;
|
|
74
|
+
}
|
|
23
75
|
/** Transform the derived parameters once, before any step runs. */
|
|
24
76
|
export declare function evalParamsLogic(code: string, parameters: Record<string, unknown>, intent: string): Record<string, unknown>;
|
|
25
77
|
/** Derive one step's tool input from params, intent and the accumulated respParams. */
|
|
26
|
-
export declare function evalToolInputLogic(code: string, parameters: Record<string, unknown>, intent: string, respParams?: Record<string, unknown
|
|
78
|
+
export declare function evalToolInputLogic(code: string, parameters: Record<string, unknown>, intent: string, respParams?: Record<string, unknown>, opts?: LogicRunOptions): Record<string, unknown>;
|
|
27
79
|
/** Extract keys from a step's real output, to merge into respParams for later steps. */
|
|
28
80
|
export declare function evalToolOutputLogic(code: string, toolOutput: string, parameters: Record<string, unknown>, intent: string, respParams?: Record<string, unknown>): Record<string, unknown>;
|
|
29
81
|
/** Build the final response model from everything the steps accumulated. */
|
package/dist/replay/logic.js
CHANGED
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
* logic — the four stored-JS evaluators (docs/calculatedReplay.md §9).
|
|
3
3
|
*
|
|
4
4
|
* A calculated scenario carries JavaScript function *bodies*, one per hook
|
|
5
|
-
* point, each ending in `return { … }`. They are compiled
|
|
6
|
-
* and run here.
|
|
5
|
+
* point, each ending in `return { … }`. They are compiled and run here.
|
|
7
6
|
*
|
|
8
7
|
* PORTED FROM THE SERVICE, DELIBERATELY. BaseIn's `src/scenarios/logic.ts` is
|
|
9
8
|
* the copy the service itself evaluates in a dry replay, so it is the one that
|
|
@@ -12,40 +11,152 @@
|
|
|
12
11
|
* another way here — an untestable difference. Argument order and the
|
|
13
12
|
* plain-object guard both match the service exactly.
|
|
14
13
|
*
|
|
15
|
-
* THERE IS NO SANDBOX, and the doc says so plainly (§13.1). A
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
14
|
+
* THERE IS NO SANDBOX, and the doc says so plainly (§13.1). A body gets its
|
|
15
|
+
* declared arguments and the global scope: `require`/`import` are unreachable
|
|
16
|
+
* under ESM, but `fetch`, `process` and `globalThis` are not. What makes this
|
|
17
|
+
* acceptable is provenance, not containment — the payload arrives only in an
|
|
18
|
+
* authenticated response from the configured `BIR_AUTH_URL`, describing the
|
|
19
|
+
* caller's own recorded runs — and replay is opt-in for exactly this reason.
|
|
20
|
+
*
|
|
21
|
+
* THERE IS A CLOCK. Every body runs inside the one process that answers every
|
|
22
|
+
* hook of the project, on its only thread. The service ran the same body under
|
|
23
|
+
* a time limit — but on the *recording's* values, and a regex written against a
|
|
24
|
+
* 2 KB output can backtrack for minutes on a 2 MB one, or a hand edit saved with
|
|
25
|
+
* `--force` can loop. Without a limit that froze the event loop, and every
|
|
26
|
+
* `PreToolUse`, `PostToolUse` and prompt hook of every session in the project
|
|
27
|
+
* waited out its timeout on every call until someone killed `bir-hooks`.
|
|
28
|
+
*
|
|
29
|
+
* So each body runs through `vm.Script#runInThisContext` with a `timeout`
|
|
30
|
+
* ({@link logicTimeoutMs}). *This* context, not a new one: the body keeps the
|
|
31
|
+
* realm, the globals and the argument objects it always had — `instanceof
|
|
32
|
+
* Array` still holds for a value `JSON.parse` made outside, a body that writes
|
|
33
|
+
* into `respParams` still writes into the plan's own — so the only behaviour
|
|
34
|
+
* that changes is that a runaway body throws instead of hanging. That throw is
|
|
35
|
+
* an ordinary logic failure, and the plan hands over at that step. The limit
|
|
36
|
+
* covers synchronous work, which is all a body returning a plain object does;
|
|
37
|
+
* it does not bound memory.
|
|
38
|
+
*
|
|
39
|
+
* WHAT THE CLOCK DOES NOT COVER. `runInThisContext`'s timeout ends when the
|
|
40
|
+
* body returns. A continuation the body *queues* — `Promise.resolve().then(…)`,
|
|
41
|
+
* `queueMicrotask`, `setTimeout` — runs afterwards, outside it, on the same
|
|
42
|
+
* thread, and nothing here bounds it. A body that returns a promise is refused
|
|
43
|
+
* (it is no plain object, and it is the shape such work comes in); one that
|
|
44
|
+
* queues work and still returns a plain object is not caught. Bounding that
|
|
45
|
+
* would take a separate context (`microtaskMode: "afterEvaluate"`), which gives
|
|
46
|
+
* up the realm and the shared argument objects this relies on. The threat the
|
|
47
|
+
* clock answers — a backtracking regex, a loop saved with `--force` — is
|
|
48
|
+
* synchronous; a body written to get around it already has the process (see
|
|
49
|
+
* THERE IS NO SANDBOX above).
|
|
50
|
+
*/
|
|
51
|
+
import { Script } from "node:vm";
|
|
52
|
+
/** How long one logic body may run before it is stopped. */
|
|
53
|
+
export const DEFAULT_LOGIC_TIMEOUT_MS = 1_000;
|
|
54
|
+
/**
|
|
55
|
+
* The most `BIR_LOGIC_TIMEOUT_MS` may ask for. A body runs on the only thread
|
|
56
|
+
* of the process that answers every hook of the project, so each second it is
|
|
57
|
+
* allowed is a second every session's hooks can stand still; and a direct run
|
|
58
|
+
* adds a few of them past its own deadline (controller.ts, `clampDirectRun`).
|
|
59
|
+
*/
|
|
60
|
+
export const MAX_LOGIC_TIMEOUT_MS = 10_000;
|
|
61
|
+
/** `BIR_LOGIC_TIMEOUT_MS` (at most {@link MAX_LOGIC_TIMEOUT_MS}), or {@link DEFAULT_LOGIC_TIMEOUT_MS}. */
|
|
62
|
+
export function logicTimeoutMs() {
|
|
63
|
+
const n = Number(process.env.BIR_LOGIC_TIMEOUT_MS);
|
|
64
|
+
return Number.isFinite(n) && n > 0 ? Math.min(n, MAX_LOGIC_TIMEOUT_MS) : DEFAULT_LOGIC_TIMEOUT_MS;
|
|
65
|
+
}
|
|
66
|
+
/** A body stopped by its time limit — as opposed to one that threw on its own. */
|
|
67
|
+
export class LogicTimeoutError extends Error {
|
|
68
|
+
constructor(label, timeoutMs) {
|
|
69
|
+
super(`${label} ran longer than ${timeoutMs} ms and was stopped`);
|
|
70
|
+
this.name = "LogicTimeoutError";
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Where a call's arguments wait for the script to pick them up. Set and cleared
|
|
75
|
+
* around one synchronous evaluation, so no two calls can ever see each other's.
|
|
22
76
|
*/
|
|
77
|
+
const ARGS_SLOT = "__bir_logic_args__";
|
|
78
|
+
/** Compiled bodies, by argument list and source. A plan evaluates each many times. */
|
|
79
|
+
const compiled = new Map();
|
|
80
|
+
const MAX_COMPILED = 256;
|
|
81
|
+
function compile(argNames, code) {
|
|
82
|
+
const key = `${argNames.join(",")}\u0000${code}`;
|
|
83
|
+
const hit = compiled.get(key);
|
|
84
|
+
if (hit)
|
|
85
|
+
return hit;
|
|
86
|
+
// Parsed on its own first, exactly as it always was: a body that is not
|
|
87
|
+
// valid JavaScript fails with the same SyntaxError as before, and one that
|
|
88
|
+
// tries to close the wrapper below early cannot parse at all.
|
|
89
|
+
new Function(...argNames, code);
|
|
90
|
+
const script = new Script(`(function(){var __bir_a=globalThis[${JSON.stringify(ARGS_SLOT)}];` +
|
|
91
|
+
`return (function(${argNames.join(",")}){\n${code}\n}).apply(this,__bir_a);}).call(this)`, { filename: "bir-scenario-logic.js" });
|
|
92
|
+
if (compiled.size >= MAX_COMPILED)
|
|
93
|
+
compiled.clear();
|
|
94
|
+
compiled.set(key, script);
|
|
95
|
+
return script;
|
|
96
|
+
}
|
|
97
|
+
/** Run one body with `args`, under the time limit. Throws what the body throws. */
|
|
98
|
+
function run(label, argNames, code, args, opts = {}) {
|
|
99
|
+
const script = compile(argNames, code);
|
|
100
|
+
const slot = globalThis;
|
|
101
|
+
const previous = slot[ARGS_SLOT];
|
|
102
|
+
slot[ARGS_SLOT] = args;
|
|
103
|
+
const asked = opts.timeoutMs;
|
|
104
|
+
const timeout = typeof asked === "number" && Number.isFinite(asked) && asked > 0
|
|
105
|
+
? Math.max(1, Math.min(Math.floor(asked), logicTimeoutMs()))
|
|
106
|
+
: logicTimeoutMs();
|
|
107
|
+
try {
|
|
108
|
+
return script.runInThisContext({ timeout, displayErrors: false });
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
if (err?.code === "ERR_SCRIPT_EXECUTION_TIMEOUT") {
|
|
112
|
+
throw new LogicTimeoutError(label, timeout);
|
|
113
|
+
}
|
|
114
|
+
throw err;
|
|
115
|
+
}
|
|
116
|
+
finally {
|
|
117
|
+
if (previous === undefined)
|
|
118
|
+
delete slot[ARGS_SLOT];
|
|
119
|
+
else
|
|
120
|
+
slot[ARGS_SLOT] = previous;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
23
123
|
/** Every logic body must return a plain object; anything else is a bug upstream. */
|
|
24
124
|
function assertPlainObject(result, label) {
|
|
25
125
|
if (typeof result !== "object" || result === null || Array.isArray(result)) {
|
|
26
126
|
throw new Error(`${label} must return a plain object`);
|
|
27
127
|
}
|
|
128
|
+
// A promise is an object too, and used to pass. It is also the one shape of
|
|
129
|
+
// body whose work outlives its clock: what it queues runs after the time
|
|
130
|
+
// limit has stopped counting (see the file comment).
|
|
131
|
+
if (typeof result.then === "function") {
|
|
132
|
+
throw new Error(`${label} must return a plain object, not a promise`);
|
|
133
|
+
}
|
|
28
134
|
return result;
|
|
29
135
|
}
|
|
30
136
|
/** Transform the derived parameters once, before any step runs. */
|
|
31
137
|
export function evalParamsLogic(code, parameters, intent) {
|
|
32
|
-
|
|
33
|
-
return assertPlainObject(fn(parameters, intent), "paramsLogic");
|
|
138
|
+
return assertPlainObject(run("paramsLogic", ["parameters", "intent"], code, [parameters, intent]), "paramsLogic");
|
|
34
139
|
}
|
|
35
140
|
/** Derive one step's tool input from params, intent and the accumulated respParams. */
|
|
36
|
-
export function evalToolInputLogic(code, parameters, intent, respParams = {}) {
|
|
37
|
-
|
|
38
|
-
return assertPlainObject(fn(parameters, intent, respParams), "toolInputLogic");
|
|
141
|
+
export function evalToolInputLogic(code, parameters, intent, respParams = {}, opts) {
|
|
142
|
+
return assertPlainObject(run("toolInputLogic", ["parameters", "intent", "respParams"], code, [parameters, intent, respParams], opts), "toolInputLogic");
|
|
39
143
|
}
|
|
40
144
|
/** Extract keys from a step's real output, to merge into respParams for later steps. */
|
|
41
145
|
export function evalToolOutputLogic(code, toolOutput, parameters, intent, respParams = {}) {
|
|
42
|
-
|
|
43
|
-
|
|
146
|
+
return assertPlainObject(run("toolOutputLogic", ["toolOutput", "parameters", "intent", "respParams"], code, [
|
|
147
|
+
toolOutput,
|
|
148
|
+
parameters,
|
|
149
|
+
intent,
|
|
150
|
+
respParams,
|
|
151
|
+
]), "toolOutputLogic");
|
|
44
152
|
}
|
|
45
153
|
/** Build the final response model from everything the steps accumulated. */
|
|
46
154
|
export function evalResponseParamsLogic(code, respParams, parameters, intent) {
|
|
47
|
-
|
|
48
|
-
|
|
155
|
+
return assertPlainObject(run("responseParamsLogic", ["respParams", "parameters", "intent"], code, [
|
|
156
|
+
respParams,
|
|
157
|
+
parameters,
|
|
158
|
+
intent,
|
|
159
|
+
]), "responseParamsLogic");
|
|
49
160
|
}
|
|
50
161
|
/**
|
|
51
162
|
* The two mapping bodies of a call (segmented.md R-CALL-20).
|
|
@@ -57,11 +168,18 @@ export function evalResponseParamsLogic(code, respParams, parameters, intent) {
|
|
|
57
168
|
* two of them.
|
|
58
169
|
*/
|
|
59
170
|
export function evalParamMapLogic(code, parameters, intent, respParams = {}) {
|
|
60
|
-
|
|
61
|
-
|
|
171
|
+
return assertPlainObject(run("paramMapLogic", ["parameters", "intent", "respParams"], code, [
|
|
172
|
+
parameters,
|
|
173
|
+
intent,
|
|
174
|
+
respParams,
|
|
175
|
+
]), "paramMapLogic");
|
|
62
176
|
}
|
|
63
177
|
export function evalResultMapLogic(code, out, parameters, intent, respParams = {}) {
|
|
64
|
-
|
|
65
|
-
|
|
178
|
+
return assertPlainObject(run("resultMapLogic", ["out", "parameters", "intent", "respParams"], code, [
|
|
179
|
+
out,
|
|
180
|
+
parameters,
|
|
181
|
+
intent,
|
|
182
|
+
respParams,
|
|
183
|
+
]), "resultMapLogic");
|
|
66
184
|
}
|
|
67
185
|
//# sourceMappingURL=logic.js.map
|
package/dist/replay/plan.d.ts
CHANGED
|
@@ -22,15 +22,61 @@
|
|
|
22
22
|
*/
|
|
23
23
|
import { type FlatEntry } from "./flatten.js";
|
|
24
24
|
import type { ReplayMode } from "./coverage.js";
|
|
25
|
-
import type {
|
|
25
|
+
import type { HandoverStopReason } from "./handover.js";
|
|
26
|
+
import type { ExecutionStage, FallbackKind, ParamsSchema, SerializedScenario, SerializedScenarioStep } from "./types.js";
|
|
26
27
|
/**
|
|
27
28
|
* Runs one step's tool and returns its output as a string.
|
|
28
29
|
*
|
|
29
30
|
* Resolving with a failure message is a *result* — a tool that ran and failed.
|
|
30
|
-
* Rejecting means the step
|
|
31
|
-
*
|
|
31
|
+
* Rejecting means the step produced **no result here**: it could not be sent
|
|
32
|
+
* (`not_run`), it was sent and never answered (`uncertain`), or the upstream
|
|
33
|
+
* refused it (`failed`). Reject with a {@link StepRunError} to say which; any
|
|
34
|
+
* other rejection reads as `not_run`, the old contract.
|
|
32
35
|
*/
|
|
33
36
|
export type ExecuteStep = (step: SerializedScenarioStep, input: Record<string, unknown>) => Promise<string>;
|
|
37
|
+
/** Why a step's call produced no result. */
|
|
38
|
+
export type StepRejection = "not_run" | "uncertain" | "failed";
|
|
39
|
+
/** A rejection from an {@link ExecuteStep} that says what happened to the call. */
|
|
40
|
+
export declare class StepRunError extends Error {
|
|
41
|
+
readonly rejection: StepRejection;
|
|
42
|
+
constructor(message: string, rejection: StepRejection);
|
|
43
|
+
}
|
|
44
|
+
/** What a rejection means for the step — see {@link ExecuteStep}. */
|
|
45
|
+
export declare function rejectionOf(err: unknown): StepRejection;
|
|
46
|
+
/**
|
|
47
|
+
* How a plan driver treats the steps it cannot get a real result for.
|
|
48
|
+
*
|
|
49
|
+
* THE RULE: a result shown to the model is a result that happened, here, now.
|
|
50
|
+
* A step that could not run, did not answer or was refused is never replaced by
|
|
51
|
+
* the output recorded for it last week — "INSERT 0 1" under a header that says
|
|
52
|
+
* the work is done is how a user is told a write happened that did not. The run
|
|
53
|
+
* stops at that step, the steps before it are shown as they are, and the rest
|
|
54
|
+
* of the task is handed back with a note that names the step and what may be
|
|
55
|
+
* assumed about it (fallbk.md).
|
|
56
|
+
*/
|
|
57
|
+
export interface DriveOptions {
|
|
58
|
+
/**
|
|
59
|
+
* Stop at the first step that breaks — its logic throws, or its tool reports
|
|
60
|
+
* an error — instead of threading the error on (fallbk.md §Runner 3). A step
|
|
61
|
+
* after a failed one computes on a result that does not exist. Off keeps the
|
|
62
|
+
* old contract: a logic throw propagates, a tool error is threaded and
|
|
63
|
+
* counted. A step with *no* result stops the run either way.
|
|
64
|
+
*/
|
|
65
|
+
stopOnFailure?: boolean;
|
|
66
|
+
/**
|
|
67
|
+
* Serve the recorded output of a step whose tool could not be *sent* here
|
|
68
|
+
* (`not_run`: a built-in, a server with no proxy), labelled `(recorded)`.
|
|
69
|
+
* `BIR_REPLAY_RECORDED_OUTPUTS=1`, and `bir replay`. Never for a step that
|
|
70
|
+
* was sent and failed or did not answer.
|
|
71
|
+
*/
|
|
72
|
+
recordedFallback?: boolean;
|
|
73
|
+
/**
|
|
74
|
+
* The caller went away — `bir-scenario`'s request was cancelled or timed out
|
|
75
|
+
* (C4). No further step is *started*; one already sent runs to its own end,
|
|
76
|
+
* so what the run reports about it is the truth.
|
|
77
|
+
*/
|
|
78
|
+
signal?: AbortSignal;
|
|
79
|
+
}
|
|
34
80
|
/**
|
|
35
81
|
* Supplies a step's recorded output when its tool cannot run here (§8.1).
|
|
36
82
|
*
|
|
@@ -69,10 +115,30 @@ export interface StepInfo {
|
|
|
69
115
|
toolMissing?: boolean;
|
|
70
116
|
}
|
|
71
117
|
export type StepObserver = (info: StepInfo) => void;
|
|
118
|
+
/**
|
|
119
|
+
* One step's input logic, evaluated only to show its arguments, runs no longer
|
|
120
|
+
* than this (nor than `logicTimeoutMs()`).
|
|
121
|
+
*
|
|
122
|
+
* The limit is wall-clock time (a `vm` timeout), so it must tolerate a busy
|
|
123
|
+
* machine: with ten CPU-bound processes on eight cores, a trivial
|
|
124
|
+
* `return { command: 'ls ' + parameters.x }` took up to ~170 ms, and a 50 ms
|
|
125
|
+
* limit stopped more than half of them — ending the preview, and every
|
|
126
|
+
* argument with it, whenever the machine was loaded. At 250 ms none was
|
|
127
|
+
* stopped. A body stopped at this limit really is slow, and ends the preview.
|
|
128
|
+
*/
|
|
129
|
+
export declare const PREVIEW_LOGIC_MS = 250;
|
|
130
|
+
/**
|
|
131
|
+
* All of a directive's argument previews together: it is written inside the
|
|
132
|
+
* prompt hook, so this is the most the preview adds to it, a stopped body
|
|
133
|
+
* included — each body's limit is clipped to what is left of it. A caller with
|
|
134
|
+
* less time left passes less (`steeringDirective`'s `previewBudgetMs`).
|
|
135
|
+
*/
|
|
136
|
+
export declare const PREVIEW_BUDGET_MS = 500;
|
|
72
137
|
export interface ComposeResult {
|
|
73
138
|
text: string;
|
|
74
139
|
executed: number;
|
|
75
140
|
recorded: number;
|
|
141
|
+
/** Steps whose call produced no result. The run stopped at the first. */
|
|
76
142
|
skipped: number;
|
|
77
143
|
/**
|
|
78
144
|
* Of `executed`, how many tools ran and reported an error. Counted separately
|
|
@@ -80,6 +146,8 @@ export interface ComposeResult {
|
|
|
80
146
|
* and yet the work did not happen, and an outcome must not say it did.
|
|
81
147
|
*/
|
|
82
148
|
errored: number;
|
|
149
|
+
/** Where, and why, the run stopped short of its end, when it did. */
|
|
150
|
+
stopped?: PlanStop;
|
|
83
151
|
}
|
|
84
152
|
/** Where, and why, a run stopped short of the chain's end (fallbk.md). */
|
|
85
153
|
export interface PlanStop {
|
|
@@ -90,11 +158,28 @@ export interface PlanStop {
|
|
|
90
158
|
flatIndex?: number;
|
|
91
159
|
stage?: ExecutionStage;
|
|
92
160
|
error?: string;
|
|
161
|
+
/**
|
|
162
|
+
* For `step_failed`: what kind of stop — the step did not run, did not
|
|
163
|
+
* answer, was refused, or the budget or the caller ended the run before it.
|
|
164
|
+
* Absent means its logic threw or its tool reported an error.
|
|
165
|
+
*/
|
|
166
|
+
reason?: HandoverStopReason;
|
|
93
167
|
}
|
|
94
168
|
export interface PlanOptions {
|
|
95
169
|
scenario: SerializedScenario;
|
|
96
|
-
/**
|
|
170
|
+
/**
|
|
171
|
+
* Resolves with the derived parameters. A rejection settles them the way
|
|
172
|
+
* {@link ScenarioReplayPlan.useFallbackParams} does: settings at their
|
|
173
|
+
* recorded samples, targets `null` — never `{}`.
|
|
174
|
+
*/
|
|
97
175
|
params: Promise<Record<string, unknown>>;
|
|
176
|
+
/**
|
|
177
|
+
* What a *target* takes when the parameters settle without the derivation.
|
|
178
|
+
* `null` (the default) is the rule: a target is never guessed. `samples` is
|
|
179
|
+
* `bir replay`'s own contract — an operator named the scenario by id, so a
|
|
180
|
+
* recorded sample stands in (R-CALL-37).
|
|
181
|
+
*/
|
|
182
|
+
fallbackTargets?: "null" | "samples";
|
|
98
183
|
mode: ReplayMode;
|
|
99
184
|
respParamsInit?: Record<string, unknown>;
|
|
100
185
|
/**
|
|
@@ -127,6 +212,11 @@ export declare class ScenarioReplayPlan {
|
|
|
127
212
|
private readonly entries;
|
|
128
213
|
private readonly paramsPromise;
|
|
129
214
|
private params;
|
|
215
|
+
/** The derivation's own answer, before `paramsLogic`. What safety.ts judges. */
|
|
216
|
+
private derivedParams;
|
|
217
|
+
/** Set once the parameters are final — derived, or settled without the derivation. */
|
|
218
|
+
private paramsSettled;
|
|
219
|
+
private readonly fallbackTargets;
|
|
130
220
|
private respParams;
|
|
131
221
|
private stepIndex;
|
|
132
222
|
private readyPromise?;
|
|
@@ -158,11 +248,35 @@ export declare class ScenarioReplayPlan {
|
|
|
158
248
|
private leaveFrame;
|
|
159
249
|
/**
|
|
160
250
|
* Await the derivation, then apply `paramsLogic` — once, however many callers
|
|
161
|
-
* race here. A rejected derivation
|
|
162
|
-
*
|
|
163
|
-
*
|
|
251
|
+
* race here. A rejected derivation settles on the fallback values
|
|
252
|
+
* ({@link useFallbackParams}) rather than throwing.
|
|
253
|
+
*
|
|
254
|
+
* Rejects only when `paramsLogic` throws. That is real: the scenario's own
|
|
255
|
+
* logic is broken, and the caller must hand over rather than run steps on
|
|
256
|
+
* parameters nobody processed.
|
|
164
257
|
*/
|
|
165
258
|
ready(): Promise<void>;
|
|
259
|
+
/**
|
|
260
|
+
* Settle the parameters without waiting any longer for the derivation: every
|
|
261
|
+
* *setting* at its recorded sample, every *target* `null` (R-PARAM-3), then
|
|
262
|
+
* `paramsLogic`. What the caller does when the derivation's budget runs out.
|
|
263
|
+
*
|
|
264
|
+
* Never `{}`. Running on an empty object put `undefined` into every argument
|
|
265
|
+
* — `{"command":"query undefined"}` — and a steered step was auto-approved
|
|
266
|
+
* with it. A target stays null here exactly as it does when the derivation
|
|
267
|
+
* answers without one, and the caller decides whether the plan can run
|
|
268
|
+
* without it (targets.ts).
|
|
269
|
+
*
|
|
270
|
+
* A derivation that answers later is ignored. Throws what `paramsLogic`
|
|
271
|
+
* throws.
|
|
272
|
+
*/
|
|
273
|
+
useFallbackParams(): void;
|
|
274
|
+
/** Whether the parameters are final. */
|
|
275
|
+
get parametersSettled(): boolean;
|
|
276
|
+
/** The derivation's own values, before `paramsLogic`. Empty until settled. */
|
|
277
|
+
get derivedValues(): Readonly<Record<string, unknown>>;
|
|
278
|
+
private fallbackValues;
|
|
279
|
+
private settleParams;
|
|
166
280
|
/** 0-based index of the step awaiting execution (== completed step count). */
|
|
167
281
|
get currentStepIndex(): number;
|
|
168
282
|
/** Steps this plan will run — the chain up to the first known-bad step. */
|
|
@@ -185,6 +299,10 @@ export declare class ScenarioReplayPlan {
|
|
|
185
299
|
get parameters(): Readonly<Record<string, unknown>>;
|
|
186
300
|
/** Everything the steps have accumulated so far. */
|
|
187
301
|
get accumulated(): Readonly<Record<string, unknown>>;
|
|
302
|
+
/** The scenario's parameter schema — what the target and safety checks judge. */
|
|
303
|
+
get paramsSchema(): ParamsSchema | null;
|
|
304
|
+
/** The scenario's `paramsLogic`, which targets.ts reads as a consumer. */
|
|
305
|
+
get paramsLogic(): string | null;
|
|
188
306
|
/** The step awaiting execution, or undefined when the plan is done. */
|
|
189
307
|
currentStep(): SerializedScenarioStep | undefined;
|
|
190
308
|
/** The tool the current step expects, or undefined when done. */
|
|
@@ -220,6 +338,24 @@ export declare class ScenarioReplayPlan {
|
|
|
220
338
|
applyOutput(realOutput: string): string[];
|
|
221
339
|
/** Build the final response model from everything the steps accumulated. */
|
|
222
340
|
responseModel(): Record<string, unknown>;
|
|
341
|
+
/**
|
|
342
|
+
* The arguments each planned step will run with, where they are known before
|
|
343
|
+
* any step runs — for the steer directive (see {@link steeringDirective}).
|
|
344
|
+
*
|
|
345
|
+
* Known means: the parameters are settled, the step is the caller's own
|
|
346
|
+
* (a called segment's parameters are only built when it is entered), and
|
|
347
|
+
* its input logic neither reads nor passes on anything an earlier step
|
|
348
|
+
* accumulates — or it is the step at the cursor, whose accumulation is
|
|
349
|
+
* already final. Everything else is undefined, and the directive leaves
|
|
350
|
+
* those steps' arguments to the system.
|
|
351
|
+
*
|
|
352
|
+
* A look-ahead only: every body runs on copies, under a short limit, and a
|
|
353
|
+
* body that throws or runs long just leaves its step without arguments —
|
|
354
|
+
* the pin, not this, is what runs the step. The whole preview takes no more
|
|
355
|
+
* than `budgetMs` ({@link PREVIEW_BUDGET_MS}), a stopped body included; each
|
|
356
|
+
* body gets at most `bodyMs` ({@link PREVIEW_LOGIC_MS}) of it.
|
|
357
|
+
*/
|
|
358
|
+
private previewArguments;
|
|
223
359
|
/**
|
|
224
360
|
* The directive injected via `UserPromptSubmit`'s `additionalContext`.
|
|
225
361
|
*
|
|
@@ -227,9 +363,25 @@ export declare class ScenarioReplayPlan {
|
|
|
227
363
|
* whole sequence server-side. In `steer` mode it names the sequence so the
|
|
228
364
|
* model initiates the expected calls — the arguments are supplied by the
|
|
229
365
|
* system, so the model need not compute them.
|
|
366
|
+
*
|
|
367
|
+
* WHY A STEER DIRECTIVE SHOWS ARGUMENTS. The pin replaces the model's
|
|
368
|
+
* arguments with the step's only when the call is plausibly the step
|
|
369
|
+
* (control/pin-guard.ts): the same command head, the same file, an argument
|
|
370
|
+
* in common. Told merely that "the system supplies the arguments", a model
|
|
371
|
+
* writes a placeholder call — `ls`, `{"query":"..."}` — that the guard rightly
|
|
372
|
+
* declines, and the plan retires having run nothing. So where a step's
|
|
373
|
+
* arguments are already known they are shown under it, as data, so that the
|
|
374
|
+
* call the model writes, and the user sees, is the call that runs.
|
|
375
|
+
*
|
|
376
|
+
* `previewBudgetMs` / `previewBodyMs` bound that preview (default
|
|
377
|
+
* {@link PREVIEW_BUDGET_MS} / {@link PREVIEW_LOGIC_MS}): a caller with less
|
|
378
|
+
* of its hook's time left passes less, and under
|
|
379
|
+
* {@link MIN_PREVIEW_BODY_MS} there is no preview at all.
|
|
230
380
|
*/
|
|
231
381
|
steeringDirective(directToolName?: string, opts?: {
|
|
232
382
|
subTask?: boolean;
|
|
383
|
+
previewBudgetMs?: number;
|
|
384
|
+
previewBodyMs?: number;
|
|
233
385
|
}): string;
|
|
234
386
|
/**
|
|
235
387
|
* Execute every **remaining** step and lay the results out as one bundle.
|
|
@@ -238,16 +390,20 @@ export declare class ScenarioReplayPlan {
|
|
|
238
390
|
* live session already ran — with side effects — every step before the one it
|
|
239
391
|
* diverged on, so re-running them would be wrong.
|
|
240
392
|
*
|
|
241
|
-
*
|
|
242
|
-
*
|
|
243
|
-
*
|
|
244
|
-
*
|
|
245
|
-
*
|
|
246
|
-
*
|
|
247
|
-
*
|
|
393
|
+
* A step whose call produced no result ends the bundle there
|
|
394
|
+
* ({@link DriveOptions}): later steps would compute on a result that does not
|
|
395
|
+
* exist, and nothing may be shown in its place. The stop is returned, and the
|
|
396
|
+
* bundle says the task is not finished. With `stopOnFailure` a logic throw or
|
|
397
|
+
* a tool error ends it the same way; without it they keep their old contract
|
|
398
|
+
* (a throw propagates, an error is threaded and counted).
|
|
399
|
+
*
|
|
400
|
+
* `deadline` bounds the whole bundle: this runs inside a `PreToolUse` hook
|
|
401
|
+
* with a timeout of its own, and a step started after the host stopped
|
|
402
|
+
* waiting is a side effect nobody is told about.
|
|
248
403
|
*/
|
|
249
|
-
composeBundle(maxChars: number, execute: ExecuteStep, recordedOutputFor?: RecordedOutputFor, onStep?: StepObserver, opts?: {
|
|
404
|
+
composeBundle(maxChars: number, execute: ExecuteStep, recordedOutputFor?: RecordedOutputFor, onStep?: StepObserver, opts?: DriveOptions & {
|
|
250
405
|
handover?: boolean;
|
|
406
|
+
deadline?: number;
|
|
251
407
|
}): Promise<ComposeResult>;
|
|
252
408
|
/**
|
|
253
409
|
* Run the whole plan from the current cursor, advancing it as it goes.
|
|
@@ -255,26 +411,44 @@ export declare class ScenarioReplayPlan {
|
|
|
255
411
|
* This is `direct` mode's driver, and unlike {@link composeBundle} it mutates
|
|
256
412
|
* the plan — the steps really did run, so the cursor and `respParams` must say
|
|
257
413
|
* so, which is what lets the outcome be `steered_full` and `stepsPinned` be
|
|
258
|
-
* truthful.
|
|
259
|
-
*
|
|
414
|
+
* truthful.
|
|
415
|
+
*
|
|
416
|
+
* A step whose call produced no result stops the run there, with the cursor
|
|
417
|
+
* on it ({@link DriveOptions}). So does the deadline, checked before each
|
|
418
|
+
* step, and the caller's `signal`. A step already sent is never abandoned:
|
|
419
|
+
* its result arrives (or its own timeout does) and is reported as it is.
|
|
260
420
|
*
|
|
261
421
|
* `maxChars` caps the bundle exactly as a divergence bundle is capped. The
|
|
262
422
|
* direct path once passed `Number.MAX_SAFE_INTEGER` here — fine at 10 KB, and
|
|
263
423
|
* an unbounded payload into the model's context for a scenario whose tools
|
|
264
424
|
* answer in megabytes (docs/mcpmark.md §12).
|
|
265
425
|
*/
|
|
266
|
-
runToCompletion(execute: ExecuteStep, recordedOutputFor?: RecordedOutputFor, onStep?: StepObserver, deadline?: number, maxChars?: number, opts?: {
|
|
267
|
-
/**
|
|
268
|
-
* Stop at the first step that breaks — its logic throws, or its tool
|
|
269
|
-
* reports an error — instead of threading the error on (fallbk.md
|
|
270
|
-
* §Runner 3). A step after a failed one computes on a result that does not
|
|
271
|
-
* exist. Off keeps the old contract: a logic throw propagates, a tool
|
|
272
|
-
* error is threaded and counted.
|
|
273
|
-
*/
|
|
274
|
-
stopOnFailure?: boolean;
|
|
275
|
-
}): Promise<ComposeResult & {
|
|
426
|
+
runToCompletion(execute: ExecuteStep, recordedOutputFor?: RecordedOutputFor, onStep?: StepObserver, deadline?: number, maxChars?: number, opts?: DriveOptions): Promise<ComposeResult & {
|
|
276
427
|
partial: boolean;
|
|
277
428
|
stopped?: PlanStop;
|
|
429
|
+
aborted?: boolean;
|
|
278
430
|
}>;
|
|
431
|
+
/**
|
|
432
|
+
* A reason not to *start* the next step: the caller is gone, or the time is
|
|
433
|
+
* up. Undefined means go ahead.
|
|
434
|
+
*/
|
|
435
|
+
private stopBefore;
|
|
436
|
+
/**
|
|
437
|
+
* Call one step's tool. Resolves with its result, with the recorded output
|
|
438
|
+
* that may stand in for it (only under `recordedFallback`, only for a step
|
|
439
|
+
* that could not be sent), or with the stop a missing result means.
|
|
440
|
+
*/
|
|
441
|
+
private callStep;
|
|
442
|
+
/**
|
|
443
|
+
* A step's recorded output from the source run, waited on no longer than the
|
|
444
|
+
* driver's deadline.
|
|
445
|
+
*
|
|
446
|
+
* The lookup is a service fetch (source-run.ts) of up to its own timeout,
|
|
447
|
+
* and a divergence runs it inside a `PreToolUse` whose deadline the hook
|
|
448
|
+
* must keep (C1, C9): so it is a hot-path wait on the service, through the
|
|
449
|
+
* breaker, and a lookup that has not answered in time is no recorded output.
|
|
450
|
+
* A sliver of time left is not worth a request, nor a verdict on the service.
|
|
451
|
+
*/
|
|
452
|
+
private recordedWithin;
|
|
279
453
|
}
|
|
280
454
|
//# sourceMappingURL=plan.d.ts.map
|