@basein/runner 0.3.24 → 0.3.26
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 +27 -26
- package/dist/auth/client.d.ts +4 -1
- package/dist/auth/client.js +83 -14
- package/dist/bin/bir-hooks.js +4 -2
- package/dist/bin/bir.js +153 -37
- package/dist/bin/investigate.js +5 -0
- package/dist/bin/scenario-edit.d.ts +5 -0
- package/dist/bin/scenario-edit.js +17 -1
- package/dist/config/adapters/claude-code.d.ts +51 -7
- package/dist/config/adapters/claude-code.js +105 -18
- package/dist/config/generate.d.ts +61 -13
- package/dist/config/generate.js +108 -20
- package/dist/config/resolve.d.ts +5 -0
- package/dist/config/resolve.js +7 -0
- package/dist/control/correlation.js +0 -0
- package/dist/control/daemon.d.ts +28 -0
- package/dist/control/daemon.js +62 -0
- package/dist/control/paths.d.ts +19 -1
- package/dist/control/paths.js +20 -2
- package/dist/control/pin-guard.js +8 -2
- package/dist/control/recorder-main.js +17 -5
- package/dist/control/server.d.ts +63 -9
- package/dist/control/server.js +350 -62
- package/dist/control/transcript.d.ts +64 -3
- package/dist/control/transcript.js +318 -37
- package/dist/jsonrpc/framing.d.ts +18 -3
- package/dist/jsonrpc/framing.js +57 -4
- package/dist/proxy/intercept.d.ts +4 -0
- package/dist/proxy/intercept.js +4 -0
- package/dist/proxy/relay.d.ts +13 -0
- package/dist/proxy/relay.js +12 -1
- package/dist/proxy/session.d.ts +8 -1
- package/dist/proxy/session.js +67 -10
- package/dist/record/recorder.d.ts +6 -1
- package/dist/record/redact.d.ts +18 -4
- package/dist/record/redact.js +538 -79
- package/dist/record/remote-recorder.d.ts +26 -5
- package/dist/record/remote-recorder.js +174 -18
- package/dist/record/truncate.js +3 -1
- package/dist/replay/bash-channel.d.ts +7 -1
- package/dist/replay/bash-channel.js +9 -3
- package/dist/replay/builtins.d.ts +14 -0
- package/dist/replay/builtins.js +460 -95
- package/dist/replay/bundle.d.ts +80 -0
- package/dist/replay/bundle.js +455 -24
- package/dist/replay/controller.d.ts +64 -1
- package/dist/replay/controller.js +238 -38
- package/dist/replay/derive.js +46 -4
- package/dist/replay/handover.d.ts +13 -0
- package/dist/replay/handover.js +18 -0
- package/dist/replay/plan.d.ts +15 -0
- package/dist/replay/plan.js +48 -30
- package/dist/replay/pricing.d.ts +61 -11
- package/dist/replay/pricing.js +135 -42
- package/dist/replay/safety.js +43 -5
- package/dist/upstream/http-client.d.ts +6 -3
- package/dist/upstream/http-client.js +54 -13
- package/dist/upstream/stdio-client.d.ts +7 -0
- package/dist/upstream/stdio-client.js +1 -1
- package/dist/util/atomic-write.d.ts +9 -1
- package/dist/util/atomic-write.js +9 -6
- package/dist/util/service-health.d.ts +7 -0
- package/dist/util/service-health.js +10 -3
- package/docs/calculatedReplay.md +32 -0
- package/package.json +1 -1
- package/production.md +2 -2
- package/scripts/install.ps1 +14 -2
package/dist/control/daemon.js
CHANGED
|
@@ -1117,6 +1117,12 @@ export function clearPortProblem(cwd) {
|
|
|
1117
1117
|
}
|
|
1118
1118
|
}
|
|
1119
1119
|
// ── the background recorder's own log ──────────────────────────────────────
|
|
1120
|
+
/** The longest a log's last lines may hold an exit back ({@link exitLogged}). */
|
|
1121
|
+
const LOG_CLOSE_MS = 1_000;
|
|
1122
|
+
/** The log this process pointed `console` at: the one an exit waits for. */
|
|
1123
|
+
let processLog;
|
|
1124
|
+
/** Set by the first {@link exitLogged}. */
|
|
1125
|
+
let exiting = false;
|
|
1120
1126
|
function silentConsole() {
|
|
1121
1127
|
const sink = new Writable({
|
|
1122
1128
|
write(_chunk, _encoding, callback) {
|
|
@@ -1166,6 +1172,7 @@ export class DaemonLog {
|
|
|
1166
1172
|
}
|
|
1167
1173
|
/** Open the file and point `console` (every `logLine`) at it. Never throws. */
|
|
1168
1174
|
open() {
|
|
1175
|
+
processLog = this;
|
|
1169
1176
|
try {
|
|
1170
1177
|
ensureDir(dirname(this.current));
|
|
1171
1178
|
}
|
|
@@ -1303,6 +1310,61 @@ export class DaemonLog {
|
|
|
1303
1310
|
close() {
|
|
1304
1311
|
this.stream?.end();
|
|
1305
1312
|
}
|
|
1313
|
+
/**
|
|
1314
|
+
* End the log for good, before an exit. `done` is called once: when every
|
|
1315
|
+
* line already logged is in the file, or when it cannot be — there is no
|
|
1316
|
+
* stream, it failed, or the file did not take them within
|
|
1317
|
+
* {@link LOG_CLOSE_MS}.
|
|
1318
|
+
*
|
|
1319
|
+
* Lines logged after this call are dropped. Written to the stream, one of
|
|
1320
|
+
* them would be a write after its end, which destroys the stream and the
|
|
1321
|
+
* lines it still held: a send failing in the background during a shutdown
|
|
1322
|
+
* would cost the log the very lines this waits for.
|
|
1323
|
+
*/
|
|
1324
|
+
end(done) {
|
|
1325
|
+
const stream = this.stream;
|
|
1326
|
+
this.stream = undefined;
|
|
1327
|
+
this.fd = undefined;
|
|
1328
|
+
globalThis.console = silentConsole();
|
|
1329
|
+
if (!stream) {
|
|
1330
|
+
done();
|
|
1331
|
+
return;
|
|
1332
|
+
}
|
|
1333
|
+
let called = false;
|
|
1334
|
+
const once = () => {
|
|
1335
|
+
if (called)
|
|
1336
|
+
return;
|
|
1337
|
+
called = true;
|
|
1338
|
+
clearTimeout(late);
|
|
1339
|
+
done();
|
|
1340
|
+
};
|
|
1341
|
+
// Not unref'd: `done` is an exit, and it must happen even when the write
|
|
1342
|
+
// it waits for never returns (a disk that hangs).
|
|
1343
|
+
const late = setTimeout(once, LOG_CLOSE_MS);
|
|
1344
|
+
stream.end(once);
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1347
|
+
/**
|
|
1348
|
+
* `process.exit(code)`, once the lines already logged are in the log file.
|
|
1349
|
+
*
|
|
1350
|
+
* A background recorder's log is a stream that writes in the background, and
|
|
1351
|
+
* a `process.exit()` right after a `logLine()` lost what the stream had not
|
|
1352
|
+
* written yet: a line logged right behind another, and every line while the
|
|
1353
|
+
* file was still being opened. Those are the lines that say why the recorder
|
|
1354
|
+
* is not running — its port is taken, and by whom; this project's recorder
|
|
1355
|
+
* already serves it; it was asked to stop. So the stream is ended first, and
|
|
1356
|
+
* the exit waits for it ({@link DaemonLog.end}, at most {@link LOG_CLOSE_MS}).
|
|
1357
|
+
* Without a log file of its own — `bir-hooks` in a terminal — the exit is at
|
|
1358
|
+
* once, as before; so is a second call, which means "now".
|
|
1359
|
+
*
|
|
1360
|
+
* It returns: whoever calls it must do nothing more.
|
|
1361
|
+
*/
|
|
1362
|
+
export function exitLogged(code) {
|
|
1363
|
+
const log = processLog;
|
|
1364
|
+
if (!log || exiting)
|
|
1365
|
+
process.exit(code);
|
|
1366
|
+
exiting = true;
|
|
1367
|
+
log.end(() => process.exit(code));
|
|
1306
1368
|
}
|
|
1307
1369
|
// ── the start lock ─────────────────────────────────────────────────────────
|
|
1308
1370
|
function lockPath(cwd) {
|
package/dist/control/paths.d.ts
CHANGED
|
@@ -7,8 +7,26 @@
|
|
|
7
7
|
* assumption is made about `$HOME` being set — Windows sets `USERPROFILE`
|
|
8
8
|
* instead, and `os.homedir()` already knows the difference.
|
|
9
9
|
*/
|
|
10
|
-
/**
|
|
10
|
+
/**
|
|
11
|
+
* Root of BaseInstRunner's state. `BIR_HOME` overrides it (tests, sandboxes).
|
|
12
|
+
*
|
|
13
|
+
* An empty `BIR_HOME` counts as unset (`||`, not `??`). Taken as a path it is
|
|
14
|
+
* the current directory: the sign-in, installed.json and the logs then land in
|
|
15
|
+
* whichever folder a command happens to run in, one copy per folder.
|
|
16
|
+
*/
|
|
11
17
|
export declare function configDir(): string;
|
|
18
|
+
/**
|
|
19
|
+
* The port `bir install` writes into the hook URLs, and the one `bir-hooks`
|
|
20
|
+
* prefers. Claude Code's `settings.json` needs a *static* URL, so the control
|
|
21
|
+
* server cannot be purely ephemeral: it asks for this port and falls back to an
|
|
22
|
+
* ephemeral one only if it is taken — in which case the installed hooks point at
|
|
23
|
+
* a port nobody is listening on, and both `bir-hooks` and `bir doctor` say so.
|
|
24
|
+
*
|
|
25
|
+
* Here rather than in control/server.ts so that `bir` can name it without
|
|
26
|
+
* loading the control server: that module and what it imports cost every
|
|
27
|
+
* `bir` command about 50 ms, and the `bir` MCP server starts one per call.
|
|
28
|
+
*/
|
|
29
|
+
export declare const DEFAULT_CONTROL_PORT = 53411;
|
|
12
30
|
/** Where control servers advertise themselves, one file per project cwd. */
|
|
13
31
|
export declare function controlDir(): string;
|
|
14
32
|
/** The sidecar holding original MCP entries so `bir uninstall` can restore them. */
|
package/dist/control/paths.js
CHANGED
|
@@ -11,10 +11,28 @@ import { homedir } from "node:os";
|
|
|
11
11
|
import { createHash } from "node:crypto";
|
|
12
12
|
import { join } from "node:path";
|
|
13
13
|
import { mkdirSync } from "node:fs";
|
|
14
|
-
/**
|
|
14
|
+
/**
|
|
15
|
+
* Root of BaseInstRunner's state. `BIR_HOME` overrides it (tests, sandboxes).
|
|
16
|
+
*
|
|
17
|
+
* An empty `BIR_HOME` counts as unset (`||`, not `??`). Taken as a path it is
|
|
18
|
+
* the current directory: the sign-in, installed.json and the logs then land in
|
|
19
|
+
* whichever folder a command happens to run in, one copy per folder.
|
|
20
|
+
*/
|
|
15
21
|
export function configDir() {
|
|
16
|
-
return process.env.BIR_HOME
|
|
22
|
+
return process.env.BIR_HOME || join(homedir(), ".baseinstrunner");
|
|
17
23
|
}
|
|
24
|
+
/**
|
|
25
|
+
* The port `bir install` writes into the hook URLs, and the one `bir-hooks`
|
|
26
|
+
* prefers. Claude Code's `settings.json` needs a *static* URL, so the control
|
|
27
|
+
* server cannot be purely ephemeral: it asks for this port and falls back to an
|
|
28
|
+
* ephemeral one only if it is taken — in which case the installed hooks point at
|
|
29
|
+
* a port nobody is listening on, and both `bir-hooks` and `bir doctor` say so.
|
|
30
|
+
*
|
|
31
|
+
* Here rather than in control/server.ts so that `bir` can name it without
|
|
32
|
+
* loading the control server: that module and what it imports cost every
|
|
33
|
+
* `bir` command about 50 ms, and the `bir` MCP server starts one per call.
|
|
34
|
+
*/
|
|
35
|
+
export const DEFAULT_CONTROL_PORT = 53411;
|
|
18
36
|
/** Where control servers advertise themselves, one file per project cwd. */
|
|
19
37
|
export function controlDir() {
|
|
20
38
|
return join(configDir(), "control");
|
|
@@ -352,7 +352,11 @@ function commandVerdict(mine, theirs, powershell = false) {
|
|
|
352
352
|
// No command at all: the model left it to the directive.
|
|
353
353
|
if (!mine)
|
|
354
354
|
return { ok: true };
|
|
355
|
-
|
|
355
|
+
// The same command, however its words are spaced. Spaces and tabs only: a
|
|
356
|
+
// new line chains (see the file comment), and with `\s` the step `ls` + new
|
|
357
|
+
// line + `rm -rf x` was "the same" as a call of `ls rm -rf x` — one command
|
|
358
|
+
// shown, two run — before the chains below were ever compared.
|
|
359
|
+
if (mine.replace(/[ \t]+/g, " ") === theirs.replace(/[ \t]+/g, " "))
|
|
356
360
|
return { ok: true };
|
|
357
361
|
// What a substitution runs is not in any head: only an exact copy is the step.
|
|
358
362
|
if ((powershell ? PS_SUBSTITUTION : SUBSTITUTION).test(theirs)) {
|
|
@@ -469,7 +473,9 @@ function statementVerdict(model, step) {
|
|
|
469
473
|
const mine = model[key];
|
|
470
474
|
if (typeof mine !== "string")
|
|
471
475
|
return { ok: false, why: `it does not supply the step's ${key}` };
|
|
472
|
-
|
|
476
|
+
// Spaces and tabs only, as in commandVerdict: a new line may chain here
|
|
477
|
+
// too. A query laid out on other lines still passes, by its verbs, below.
|
|
478
|
+
if (mine.replace(/[ \t]+/g, " ").trim() === theirs.replace(/[ \t]+/g, " ").trim())
|
|
473
479
|
continue;
|
|
474
480
|
// A shell command's substitution runs what no head shows (backticks are
|
|
475
481
|
// only an identifier quote in SQL, so SQL is not held to this).
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
import { hostname } from "node:os";
|
|
24
24
|
import { ControlServer, DEFAULT_CONTROL_PORT } from "./server.js";
|
|
25
25
|
import { DISCOVERY_CHECK_MS, HEARTBEAT_MS, pidAlive, readDiscovery, removeDiscoveryIfOwned, removeSupersededRecord, sweepStaleDiscovery, writeDiscovery, writeSupersededRecord, } from "./discovery.js";
|
|
26
|
-
import { DAEMON_CWD_ENV, DAEMON_ENV, DAEMON_LOG_ENV, DERIVE_KEY_ENV, DaemonLog, USE_API_KEY_ENV, clearPortProblem, compareVersions, probeHealth, projectEndpoint, rediscover, validPort, writePortProblem, } from "./daemon.js";
|
|
26
|
+
import { DAEMON_CWD_ENV, DAEMON_ENV, DAEMON_LOG_ENV, DERIVE_KEY_ENV, DaemonLog, USE_API_KEY_ENV, clearPortProblem, compareVersions, exitLogged, probeHealth, projectEndpoint, rediscover, validPort, writePortProblem, } from "./daemon.js";
|
|
27
27
|
import { configDir, normalizePath, supersededLogPath } from "./paths.js";
|
|
28
28
|
import { RecorderKeeper } from "./recorder-keeper.js";
|
|
29
29
|
import { FILE_BUILTINS, parseBashAllow, parseBuiltinTools, parsePathAllow } from "../replay/builtins.js";
|
|
@@ -34,6 +34,7 @@ import { resolveServers } from "../config/resolve.js";
|
|
|
34
34
|
import { isRecorderHealthReporter } from "../record/recorder.js";
|
|
35
35
|
import { errText, logLine, logOnce } from "../util/log.js";
|
|
36
36
|
import { openJournal } from "../util/journal.js";
|
|
37
|
+
import { MAX_TIMER_MS } from "../util/service-health.js";
|
|
37
38
|
import { packageVersion } from "../util/version.js";
|
|
38
39
|
/** How long `close()` may take on the way out: it flushes unfinished runs to the service. */
|
|
39
40
|
const SHUTDOWN_CLOSE_MS = 3_000;
|
|
@@ -57,9 +58,14 @@ const SWEEP_EVERY_MS = 24 * 60 * 60 * 1000;
|
|
|
57
58
|
* that had exited would turn every one of them into a hook error.
|
|
58
59
|
*/
|
|
59
60
|
const SUPERSEDED_EXIT_MS = 24 * 60 * 60 * 1000;
|
|
61
|
+
/**
|
|
62
|
+
* A positive whole number, held to what a timer takes ({@link MAX_TIMER_MS}):
|
|
63
|
+
* most of these become a delay, and `BIR_RECORDER_TICK_MS=3000000000` would
|
|
64
|
+
* otherwise run the minute check every millisecond.
|
|
65
|
+
*/
|
|
60
66
|
function positiveInt(value, fallback) {
|
|
61
67
|
const n = Number(value);
|
|
62
|
-
return Number.isFinite(n) && n > 0 ? Math.floor(n) : fallback;
|
|
68
|
+
return Number.isFinite(n) && n > 0 ? Math.min(Math.floor(n), MAX_TIMER_MS) : fallback;
|
|
63
69
|
}
|
|
64
70
|
/** Like {@link positiveInt}, but 0 is a meaningful setting rather than unset. */
|
|
65
71
|
function nonNegativeInt(value, fallback) {
|
|
@@ -454,7 +460,8 @@ export async function runRecorder() {
|
|
|
454
460
|
removeDiscoveryIfOwned(cwd, process.pid);
|
|
455
461
|
removeSupersededRecord(cwd, process.pid);
|
|
456
462
|
logLine(event, {});
|
|
457
|
-
process.exit(
|
|
463
|
+
// Not `process.exit()`: the line above is not in the log file yet.
|
|
464
|
+
exitLogged(exitCode);
|
|
458
465
|
};
|
|
459
466
|
const shutdown = async () => {
|
|
460
467
|
if (closing)
|
|
@@ -478,7 +485,7 @@ export async function runRecorder() {
|
|
|
478
485
|
// A second signal while stopping means "now": on POSIX it used to be
|
|
479
486
|
// swallowed, and a recorder stuck in its shutdown could not be stopped.
|
|
480
487
|
if (closing)
|
|
481
|
-
finish("control.stop_forced", 1);
|
|
488
|
+
return finish("control.stop_forced", 1);
|
|
482
489
|
void shutdown();
|
|
483
490
|
};
|
|
484
491
|
const options = {
|
|
@@ -529,7 +536,12 @@ export async function runRecorder() {
|
|
|
529
536
|
await sleep(500);
|
|
530
537
|
continue;
|
|
531
538
|
}
|
|
532
|
-
|
|
539
|
+
// `portBusy` has just logged why — who holds the port, or that this
|
|
540
|
+
// project's recorder already serves it. The log writes in the background,
|
|
541
|
+
// so a `process.exit()` here could lose that line, and the start-up lines
|
|
542
|
+
// before it with it.
|
|
543
|
+
exitLogged(verdict === "ours" ? 0 : 1);
|
|
544
|
+
return;
|
|
533
545
|
}
|
|
534
546
|
}
|
|
535
547
|
clearPortProblem(cwd);
|
package/dist/control/server.d.ts
CHANGED
|
@@ -282,6 +282,12 @@ export interface ControlServerOptions {
|
|
|
282
282
|
* failing. Unset or `BIR_INTENT_ARM=0` is off.
|
|
283
283
|
*/
|
|
284
284
|
intentArm?: boolean;
|
|
285
|
+
/**
|
|
286
|
+
* How long a turn's books wait after `Stop` for the turn's last message to
|
|
287
|
+
* reach the transcript, in ms (`sealRun`). Overrides `BIR_COST_SETTLE_MS`;
|
|
288
|
+
* 0 reads the cost at `Stop`, as every runner up to 0.3.25 did.
|
|
289
|
+
*/
|
|
290
|
+
costSettleMs?: number;
|
|
285
291
|
/**
|
|
286
292
|
* Whether the model's first call after a plan handed over asks the service
|
|
287
293
|
* for the plan of the work recorded after an earlier hand-over at that step,
|
|
@@ -351,6 +357,15 @@ export declare class ControlServer {
|
|
|
351
357
|
private readonly attention;
|
|
352
358
|
/** Plans a `/scenario/run` is executing right now: one run per plan. */
|
|
353
359
|
private readonly runningPlans;
|
|
360
|
+
/**
|
|
361
|
+
* Plans whose direct run its caller cancelled, by scenario id, and when
|
|
362
|
+
* ({@link declineAfterCancel}): the same plan is not armed again for
|
|
363
|
+
* {@link AFTER_CANCEL_MS} when the run sent a call, so its steps do not run
|
|
364
|
+
* twice. Here, not on the session: after `/clear` — a new session — or in a
|
|
365
|
+
* second window the same request armed the plan again, and ran every step
|
|
366
|
+
* a second time.
|
|
367
|
+
*/
|
|
368
|
+
private readonly cancelledScenarios;
|
|
354
369
|
/**
|
|
355
370
|
* Steer plans whose last pin the guard declined (control/pin-guard.ts): the
|
|
356
371
|
* model made the step's call its own way, so the plan is a step behind the
|
|
@@ -698,6 +713,34 @@ export declare class ControlServer {
|
|
|
698
713
|
* the service's own answer, not the one a hook may have been given at once.
|
|
699
714
|
*/
|
|
700
715
|
private noteDisabledMatch;
|
|
716
|
+
/**
|
|
717
|
+
* A plan whose caller cancelled it (Esc on `run_scenario`, or a timeout) a
|
|
718
|
+
* few minutes ago, after at least one of its steps had run, is not armed
|
|
719
|
+
* again when the same plan matches: the steps' side effects are in place
|
|
720
|
+
* already, and the model is told so by the note kept for it
|
|
721
|
+
* ({@link stashCancelledNote}). Armed, the plan would have run them a second
|
|
722
|
+
* time — a row added twice, a mail sent twice — and the model would have had
|
|
723
|
+
* the note and the instruction to run the plan in the same message.
|
|
724
|
+
*
|
|
725
|
+
* The mark is spent by the first match it is asked about, whichever way that
|
|
726
|
+
* goes: it holds back one arming, never a stream of them, and never on a
|
|
727
|
+
* plan that sent no call (there is nothing to repeat: a step left out, one
|
|
728
|
+
* whose logic broke, one that could not be sent), nor one that is long
|
|
729
|
+
* cancelled ({@link AFTER_CANCEL_MS}). A person who wants the plan again asks
|
|
730
|
+
* again. Except while the cancelled run is still going — Esc does not stop a
|
|
731
|
+
* step in flight, and the run ends after it: every match until then is held,
|
|
732
|
+
* and the first one after spends the mark.
|
|
733
|
+
*
|
|
734
|
+
* The mark is the recorder's, not the session's: after `/clear` or in a
|
|
735
|
+
* second window the same request arrives in another session. The note the
|
|
736
|
+
* cancelled run left goes with the decline, to the session it is declined
|
|
737
|
+
* in, when that note is still unread.
|
|
738
|
+
*
|
|
739
|
+
* Returns true when it declined.
|
|
740
|
+
*/
|
|
741
|
+
private declineAfterCancel;
|
|
742
|
+
/** Mark `state`'s scenario held after its caller cancelled it ({@link declineAfterCancel}). */
|
|
743
|
+
private holdAfterCancel;
|
|
701
744
|
/**
|
|
702
745
|
* A `direct` plan is announced as "call mcp__bir__run_scenario". In a project
|
|
703
746
|
* with no `bir` server that is a tool the model does not have: it would say
|
|
@@ -896,6 +939,19 @@ export declare class ControlServer {
|
|
|
896
939
|
* session of another host (see {@link CloseReason}).
|
|
897
940
|
*/
|
|
898
941
|
private sealRun;
|
|
942
|
+
/** How long a turn's books wait for its last message: `BIR_COST_SETTLE_MS`, 0 for no wait. */
|
|
943
|
+
private costSettleMs;
|
|
944
|
+
/**
|
|
945
|
+
* `work` joins what a drain of `run` waits for ({@link drainRun}). Never
|
|
946
|
+
* rejects: a seal's waits are best effort, and say so in the log themselves.
|
|
947
|
+
*/
|
|
948
|
+
private holdSeal;
|
|
949
|
+
/**
|
|
950
|
+
* The second half of {@link sealRun}: what the turn cost, its execution
|
|
951
|
+
* reports, and the finish of its recording. Run at the seal, or a moment
|
|
952
|
+
* after it, once the turn's last message is in the transcript.
|
|
953
|
+
*/
|
|
954
|
+
private closeBooks;
|
|
899
955
|
/**
|
|
900
956
|
* Report what a matched turn cost (docs/calculatedReplay.md §11).
|
|
901
957
|
*
|
|
@@ -925,7 +981,12 @@ export declare class ControlServer {
|
|
|
925
981
|
* one `run.unmeasured` line says which.
|
|
926
982
|
*/
|
|
927
983
|
private hostCost;
|
|
928
|
-
/**
|
|
984
|
+
/**
|
|
985
|
+
* Transcript cost since `mark`; unmeasured (and zero) without one, or with a
|
|
986
|
+
* model that has no price. Up to `until` — the mark of the session's next
|
|
987
|
+
* run — when the turn's books are closed after that run has opened, and up
|
|
988
|
+
* to now otherwise.
|
|
989
|
+
*/
|
|
929
990
|
private costSince;
|
|
930
991
|
private reportExecution;
|
|
931
992
|
/**
|
|
@@ -1566,12 +1627,5 @@ export declare class ControlServer {
|
|
|
1566
1627
|
*/
|
|
1567
1628
|
private record;
|
|
1568
1629
|
}
|
|
1569
|
-
|
|
1570
|
-
* The port `bir install` writes into the hook URLs, and the one `bir-hooks`
|
|
1571
|
-
* prefers. Claude Code's `settings.json` needs a *static* URL, so the control
|
|
1572
|
-
* server cannot be purely ephemeral: it asks for this port and falls back to an
|
|
1573
|
-
* ephemeral one only if it is taken — in which case the installed hooks point at
|
|
1574
|
-
* a port nobody is listening on, and both `bir-hooks` and `bir doctor` say so.
|
|
1575
|
-
*/
|
|
1576
|
-
export declare const DEFAULT_CONTROL_PORT = 53411;
|
|
1630
|
+
export { DEFAULT_CONTROL_PORT } from "./paths.js";
|
|
1577
1631
|
//# sourceMappingURL=server.d.ts.map
|