@basein/runner 0.2.11 → 0.2.12
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 +33 -14
- package/dist/bin/bir-scenario.d.ts +11 -0
- package/dist/bin/bir-scenario.js +132 -34
- package/dist/bin/bir.d.ts +2 -2
- package/dist/bin/bir.js +11 -8
- package/dist/bin/investigate.js +1 -1
- package/dist/bin/scenario-edit.d.ts +36 -9
- package/dist/bin/scenario-edit.js +240 -61
- package/dist/control/server.js +18 -5
- package/dist/record/housekeeping.d.ts +71 -0
- package/dist/record/housekeeping.js +417 -0
- package/dist/replay/controller.d.ts +3 -1
- package/dist/replay/controller.js +17 -12
- package/docs/calculatedReplay.md +89 -29
- package/docs/calculatedReplayGuide.md +294 -86
- package/docs/quickstart.md +42 -2
- package/package.json +1 -1
package/docs/calculatedReplay.md
CHANGED
|
@@ -176,7 +176,7 @@ Three additions to the v1 topology, and nothing else moves:
|
|
|
176
176
|
|---|---|---|
|
|
177
177
|
| `bir-hooks` control server | extended | Holds the `ScenarioReplayPlan` on `RunState`. Arms it, pins inputs, threads outputs, dispatches direct steps, redeems the ticket |
|
|
178
178
|
| `bir-proxy` | extended | Long-polls for work; executes a `tools/call` on the upstream it already owns |
|
|
179
|
-
| `bir-scenario` | **new**, ~120 lines | A stdio MCP server exposing one tool, `run_scenario`. The delivery channel for direct mode (§6) |
|
|
179
|
+
| `bir-scenario` | **new**, ~120 lines | A stdio MCP server exposing one tool, `run_scenario`. The delivery channel for direct mode (§6). It later gained the scenario tools of §16.5 |
|
|
180
180
|
|
|
181
181
|
---
|
|
182
182
|
|
|
@@ -815,7 +815,7 @@ If that is not enough for a deployment, the mitigation is a real one and is out
|
|
|
815
815
|
evaluate the logic in a `node:vm` context with a frozen, minimal global. Filed as §20 question 3.
|
|
816
816
|
|
|
817
817
|
**A hand-edited step is the same code, and runs the same way.** Since 2026-09-25 (the service's
|
|
818
|
-
`editSteps.md
|
|
818
|
+
`editSteps.md`; built, not yet released) the owner — or Claude working for them — can change a step's
|
|
819
819
|
logic with `bir scenario edit`. The service checks the change against the recording before it saves
|
|
820
820
|
it, but that check is about *what the code computes*. Once saved, the step arrives in the same
|
|
821
821
|
payload and runs here unattended, with `new Function`, next to the same credentials, exactly like
|
|
@@ -823,13 +823,39 @@ calculated code. The provenance argument still holds: only the owner can edit, o
|
|
|
823
823
|
and anyone else — an admin included — gets `404`. What changes is that *"the model wrote it"* is no
|
|
824
824
|
longer always true.
|
|
825
825
|
|
|
826
|
-
The service
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
826
|
+
The service sandboxes its own evaluation of every logic body (built with the same service change;
|
|
827
|
+
not yet released). It had to: there, one account's code runs next to every account's data and the
|
|
828
|
+
service's secrets. How it is built:
|
|
829
|
+
|
|
830
|
+
- **A fresh `node:vm` context for each evaluation**, with a time limit (`LOGIC_TIMEOUT_MS`). Only
|
|
831
|
+
JavaScript's own built-ins are in it, less `ArrayBuffer`, `SharedArrayBuffer`, `DataView`, the
|
|
832
|
+
typed arrays, `Atomics`, `WebAssembly` and `FinalizationRegistry`; `Symbol.for` and
|
|
833
|
+
`Symbol.keyFor` are removed too. No `require`, `process`, `fetch`, `Buffer` or timers. Values go
|
|
834
|
+
in and come out as JSON text only.
|
|
835
|
+
- **That context lives in a separate evaluator process**, not in the service: an empty
|
|
836
|
+
environment, `--permission` (no files, no child processes), `--disallow-code-generation-from-strings`,
|
|
837
|
+
`--frozen-intrinsics`, and a heap of `LOGIC_MEMORY_MB`.
|
|
838
|
+
- **A relay worker thread of the service drives that process.** No logic runs in the relay. It
|
|
839
|
+
kills the evaluator when a body runs too long, and the next job starts a new one; a body that
|
|
840
|
+
runs out of memory takes down only the evaluator, and is run once more on a fresh one before it
|
|
841
|
+
is blamed. The relay also replaces the evaluator when its heap stays above half of
|
|
842
|
+
`LOGIC_MEMORY_MB` after a job, and after 2,000 jobs. A body that overran its time or memory, or
|
|
843
|
+
took the evaluator down twice, is refused at once, with the same message, for the next 10
|
|
844
|
+
minutes.
|
|
845
|
+
- **The hand-edit check runs in a check worker thread of its own**, with its own relay and
|
|
846
|
+
evaluator process, under a sandbox-time budget
|
|
847
|
+
(`EDIT_CHECK_BUDGET_MS`, 5000 ms by default; past it, *too costly to check*), so a slow check
|
|
848
|
+
never holds up the service's other requests.
|
|
849
|
+
|
|
850
|
+
**The runner still does not sandbox.** Here the code runs on the owner's machine, for the owner's
|
|
851
|
+
account, with `new Function`. One consequence to know: **the service's check only judges what a
|
|
852
|
+
body returns for the recording's values.** Code that calls `fetch`, `process` or a timer on that
|
|
853
|
+
path, and does not catch the error, throws in the check, so it cannot be saved without `--force`.
|
|
854
|
+
But a call behind a `typeof` guard (`if (typeof fetch === "function") …`), or on a branch the
|
|
855
|
+
recording's values never take, is never reached in the check; one inside a `try` fails there
|
|
856
|
+
quietly. Such code passes, it is saved like any other change, and here it runs with `fetch`,
|
|
857
|
+
`process` and timers all present. The service's sandbox protects the service; it proves
|
|
858
|
+
nothing about what a body does on the runner. Read every hand edit before it is saved.
|
|
833
859
|
|
|
834
860
|
### 13.2 Replay bypasses permission prompts
|
|
835
861
|
|
|
@@ -901,7 +927,7 @@ src/
|
|
|
901
927
|
│ ├─ source-run.ts # lazy GET /recordings/runs/:id → recorded outputs by tool (§8.1)
|
|
902
928
|
│ └─ types.ts # SerializedScenario, SerializedScenarioStep
|
|
903
929
|
├─ bin/
|
|
904
|
-
│ ├─ bir-scenario.ts ← new: the
|
|
930
|
+
│ ├─ bir-scenario.ts ← new: the `bir` MCP server — `run_scenario` (§6.3), later the scenario tools (§16.5)
|
|
905
931
|
│ └─ bir.ts # + `--replay`, `bir scenario …`, `bir replay` (§16.5)
|
|
906
932
|
├─ control/
|
|
907
933
|
│ ├─ server.ts # + arm / pin / thread / dispatch / report
|
|
@@ -1046,8 +1072,8 @@ and a session with no BaseIn credentials still replays (it just books nothing).
|
|
|
1046
1072
|
|
|
1047
1073
|
### 16.5 CLI surface
|
|
1048
1074
|
|
|
1049
|
-
`bir` gains one flag and one command group. Everything here is a thin client over
|
|
1050
|
-
|
|
1075
|
+
`bir` gains one flag and one command group. Everything here is a thin client over service
|
|
1076
|
+
endpoints, except `bir replay`, which drives §16.2's executor directly.
|
|
1051
1077
|
|
|
1052
1078
|
```
|
|
1053
1079
|
bir install --replay register the `bir` MCP server; raise the prompt-hook timeout to 15 s
|
|
@@ -1056,43 +1082,77 @@ bir uninstall --replay reverse exactly that, leaving the rest of the inst
|
|
|
1056
1082
|
bir scenario list GET /recordings/runs runs, iterations, scenario state
|
|
1057
1083
|
bir scenario show <runId> GET /recordings/runs/:id/scenario intent, params, steps, logic
|
|
1058
1084
|
bir scenario show <scnId> GET /scenarios/:id the same, by scenario id (segments too)
|
|
1059
|
-
[--step <n>: one step]
|
|
1085
|
+
[--step <n>: one step, with scenarioId and chainRevision first]
|
|
1060
1086
|
bir scenario calc <runId> POST /recordings/runs/:id/calculate [--force to re-derive in place]
|
|
1061
1087
|
[--force --discard-edits: re-derive a plan with hand edits]
|
|
1088
|
+
bir scenario calc <scnId> --force
|
|
1089
|
+
POST /scenarios/:id/recalculate recalculate in place (segments too)
|
|
1090
|
+
[--discard-edits: sends {discardEdits: true}]
|
|
1062
1091
|
bir scenario replay <scnId> --prompt "…" [--dry]
|
|
1063
1092
|
|
|
1064
1093
|
bir scenario check <id> --step <n> POST /scenarios/:id/steps/:n/check try a change; writes nothing
|
|
1065
1094
|
bir scenario edit <id> --step <n> PATCH /scenarios/:id/steps/:n the same check, then save
|
|
1066
1095
|
bir scenario edits <id> GET /scenarios/:id/edits the history, newest first
|
|
1067
|
-
bir scenario undo <id> [--edit <e>
|
|
1096
|
+
bir scenario undo <id> [--edit <e> | --step <n>]
|
|
1097
|
+
POST /scenarios/:id/edits/:e/revert take back the newest edit (of step n)
|
|
1068
1098
|
bir scenario editing on|off|status (no route) ~/.baseinstrunner/installed.json which `bir` MCP tools are offered
|
|
1069
1099
|
|
|
1070
1100
|
bir replay --scenario <scnId> --prompt "…" [--dry] alias; the Tier 2 / debugging path (§12.1)
|
|
1071
1101
|
```
|
|
1072
1102
|
|
|
1073
|
-
The second group, and `show <scnId>`, `--step` and `--discard-edits`, were added
|
|
1074
|
-
the service's `editSteps.md
|
|
1075
|
-
|
|
1103
|
+
The second group, and `show <scnId>`, `--step`, `calc <scnId>` and `--discard-edits`, were added
|
|
1104
|
+
on 2026-09-25 by the service's `editSteps.md`. They are built and tested, and not yet released in
|
|
1105
|
+
the form described here (version 0.2.11 on npm has an early form): they need the next
|
|
1106
|
+
`@basein/runner` version and a service deploy, because their routes are new on the service. They
|
|
1107
|
+
are where `bir` changes a scenario by hand, so the rules are strict:
|
|
1076
1108
|
|
|
1077
1109
|
- **Owner only.** Anyone else, an admin included, gets `404`, never `403`.
|
|
1078
1110
|
- **A change is saved only if it reproduces the recording and is not a copy**, or on purpose with
|
|
1079
|
-
`--force --note "<why>"`. `check` and `edit` run the same check; `check` never writes.
|
|
1111
|
+
`--force --note "<why>"`. `check` and `edit` run the same check; `check` never writes. When the
|
|
1112
|
+
check had any problem, a forced save is recorded as forced, and `bir investigate` keeps saying so.
|
|
1080
1113
|
- `<id>` is a `run_` id, resolved to its whole-run scenario with `GET /recordings/runs/:id/scenario`,
|
|
1081
|
-
or a `scn_` id, used as it is.
|
|
1082
|
-
|
|
1083
|
-
`--
|
|
1084
|
-
|
|
1085
|
-
the
|
|
1114
|
+
or a `scn_` id, used as it is. A sub-task scenario has only its `scn_` id; for a run with only
|
|
1115
|
+
sub-task scenarios, `bir` lists their `scn_` ids. Logic goes in with `--input-logic` /
|
|
1116
|
+
`--output-logic` from a file, or `-` for stdin — never inline, because shell quoting mangles
|
|
1117
|
+
JavaScript. `edit` also takes `--freeze`, `--unfreeze`, `--note` and `--revision <n>` (the
|
|
1118
|
+
`expectedRevision` of the body).
|
|
1119
|
+
- `show --step <n>` prints the step object with `scenarioId` and `chainRevision` first. The revision
|
|
1120
|
+
is the scenario's, and is what `--revision` takes.
|
|
1121
|
+
- **`undo` walks back.** Without `--edit` it takes back the newest edit (never an undo entry) that
|
|
1122
|
+
can be undone; with `--step <n>`, the newest edit of step `n`. Run again, it goes one further
|
|
1123
|
+
back. `--edit` and `--step` cannot be given together. To redo, undo the undo entry by its
|
|
1124
|
+
`sedit_` id; the undo prints that command. The service checks an undo like a save, for the later
|
|
1125
|
+
steps and the final answer (so only when it changes output logic), and answers
|
|
1126
|
+
`422 undo_refused` when it would break them, unless `--force --note "<why>"` is given. Every
|
|
1127
|
+
save and every undo bumps the scenario's `chainRevision`.
|
|
1128
|
+
- A save lifts a mark made by hand (`--freeze`, `by_hand`) only with `--unfreeze`; undoing the
|
|
1129
|
+
freeze, or `calc --force --discard-edits`, also removes it. A forced save lifts only a mark the
|
|
1130
|
+
calculation set.
|
|
1086
1131
|
- `calc --force` answers `409 scenario_has_edits` on a plan with hand edits, unless
|
|
1087
|
-
`--discard-edits` is given.
|
|
1132
|
+
`--discard-edits` is given. `calc <scnId>` without `--force` is a usage error: nothing is sent.
|
|
1133
|
+
- Answers `bir` puts in words: `400 nothing_to_change` (the code and mark asked for are the step's
|
|
1134
|
+
already), `413 payload_too_large`, `503 logic_sandbox_unavailable` (nothing was checked, saved or
|
|
1135
|
+
undone), and a check report with `noChange: true` (`check` then says nothing would change, and
|
|
1136
|
+
exits `0`).
|
|
1088
1137
|
- Exit codes: `0` checked OK, saved or undone; `1` refused, not found, or a service error; `2`
|
|
1089
1138
|
usage. `--json` prints the service's body unchanged.
|
|
1090
1139
|
|
|
1091
|
-
The same commands are tools on the `bir` MCP server. `scenario_show`, `
|
|
1092
|
-
`investigate` only read, and are always offered.
|
|
1093
|
-
`
|
|
1094
|
-
|
|
1095
|
-
|
|
1140
|
+
The same commands are tools on the `bir` MCP server. `scenario_show` (`target`, `step`),
|
|
1141
|
+
`scenario_edits` (`target`) and `investigate` (`id`) only read, and are always offered.
|
|
1142
|
+
`scenario_check` (`target`, `step`, `inputLogic`, `outputLogic`, `unfreeze`), `scenario_edit` (the
|
|
1143
|
+
same, plus `freeze`, `force`, `note`, `revision`) and `scenario_undo` (`target`, `edit` or `step`,
|
|
1144
|
+
`force`, `note`) are offered only in a project where `bir scenario editing on` was run, because that
|
|
1145
|
+
server runs in every session of every installed project. Each tool runs this package's own
|
|
1146
|
+
`bir … --json`, with logic bodies passed through temporary files; a refusal comes back as an MCP
|
|
1147
|
+
error result carrying the report. A call the host cancels, or leaves behind when it exits, has its
|
|
1148
|
+
`bir` stopped and its files removed.
|
|
1149
|
+
|
|
1150
|
+
**`bir`'s own calls are never recorded** (the service's `editSteps.md` D13; not yet released). The
|
|
1151
|
+
`bir` server's tools other than `run_scenario`, and a `Bash` or `PowerShell` command made only of
|
|
1152
|
+
`bir` invocations (and a plain `cd`), are host housekeeping, like `ToolSearch`
|
|
1153
|
+
([housekeeping.ts](../src/record/housekeeping.ts)). They are never recorded as steps, and never
|
|
1154
|
+
count as divergence from a plan. A session that fixes a plan must not become a plan that edits
|
|
1155
|
+
plans when it is replayed. The operator's walk-through is
|
|
1096
1156
|
[calculatedReplayGuide.md](calculatedReplayGuide.md) §9.2.
|
|
1097
1157
|
|
|
1098
1158
|
`--dry` maps to BaseIn's `POST /scenarios/:id/replay`, which evaluates the stored logic against the
|