@basein/runner 0.3.20 → 0.3.22

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.
Files changed (51) hide show
  1. package/README.md +6 -5
  2. package/dist/bin/bir-hooks.d.ts +17 -19
  3. package/dist/bin/bir-hooks.js +17 -19
  4. package/dist/bin/bir-scenario.js +1 -1
  5. package/dist/bin/bir.js +1 -21
  6. package/dist/bin/investigate.d.ts +0 -9
  7. package/dist/bin/investigate.js +15 -43
  8. package/dist/bin/scenario-edit.js +13 -44
  9. package/dist/control/recorder-main.d.ts +0 -15
  10. package/dist/control/recorder-main.js +22 -42
  11. package/dist/control/server.d.ts +24 -137
  12. package/dist/control/server.js +107 -1001
  13. package/dist/record/recorder.d.ts +11 -142
  14. package/dist/record/recorder.js +0 -3
  15. package/dist/record/remote-recorder.d.ts +1 -9
  16. package/dist/record/remote-recorder.js +3 -49
  17. package/dist/record/switchable-recorder.js +0 -2
  18. package/dist/replay/builtins.d.ts +45 -9
  19. package/dist/replay/builtins.js +131 -59
  20. package/dist/replay/bundle.d.ts +2 -2
  21. package/dist/replay/bundle.js +3 -3
  22. package/dist/replay/controller.d.ts +34 -125
  23. package/dist/replay/controller.js +171 -528
  24. package/dist/replay/derive.d.ts +0 -10
  25. package/dist/replay/derive.js +0 -3
  26. package/dist/replay/handover.d.ts +2 -37
  27. package/dist/replay/handover.js +38 -106
  28. package/dist/replay/logic.d.ts +0 -11
  29. package/dist/replay/logic.js +0 -24
  30. package/dist/replay/plan.d.ts +43 -163
  31. package/dist/replay/plan.js +144 -556
  32. package/dist/replay/safety.d.ts +4 -5
  33. package/dist/replay/safety.js +7 -7
  34. package/dist/replay/source-run.d.ts +15 -24
  35. package/dist/replay/source-run.js +25 -58
  36. package/dist/replay/targets.d.ts +11 -21
  37. package/dist/replay/targets.js +30 -69
  38. package/dist/replay/types.d.ts +9 -96
  39. package/dist/replay/types.js +3 -16
  40. package/dist/util/service-headers.d.ts +1 -2
  41. package/dist/util/service-headers.js +1 -2
  42. package/docs/calculatedReplay.md +30 -81
  43. package/docs/calculatedReplayGuide.md +17 -34
  44. package/package.json +1 -1
  45. package/production.md +7 -36
  46. package/dist/replay/condition-words.d.ts +0 -28
  47. package/dist/replay/condition-words.js +0 -59
  48. package/dist/replay/flatten.d.ts +0 -161
  49. package/dist/replay/flatten.js +0 -222
  50. package/dist/replay/reads-only.d.ts +0 -29
  51. package/dist/replay/reads-only.js +0 -261
@@ -1,261 +0,0 @@
1
- /**
2
- * Whether a tool call may change something, judged by its name alone — the
3
- * runner's copy of the service's own rule (BaseIn src/scenarios/correctionCheck.ts,
4
- * `readsOnly`, `commandReadsOnly`, `callMayChange`), kept word for word so the
5
- * two never disagree about the same call.
6
- *
7
- * Used where a call after a plan's decision is the agent starting a way of its
8
- * own (the service's offer1.md O7), and where a plan started after a call
9
- * would make it a second time (O8). When in doubt, a call is a change: that
10
- * only ends a set of scenarios early or keeps a plan from starting, never lets
11
- * a second write through.
12
- */
13
- /** Built-in tools that only read (Claude Code's). */
14
- const READ_TOOLS = new Set([
15
- "Read",
16
- "Grep",
17
- "Glob",
18
- "LS",
19
- "WebFetch",
20
- "WebSearch",
21
- "NotebookRead",
22
- "TodoWrite",
23
- "TaskOutput",
24
- "BashOutput",
25
- ]);
26
- /** Built-in tools that change files or run commands (Claude Code's). */
27
- const CHANGING_BUILTINS = new Set([
28
- "Write",
29
- "Edit",
30
- "MultiEdit",
31
- "NotebookEdit",
32
- "Bash",
33
- "KillShell",
34
- ]);
35
- // Not `query`, `select` or `check`: a database query, a selected option, a
36
- // check-in can change something.
37
- const READ_WORDS = new Set([
38
- "list",
39
- "get",
40
- "search",
41
- "find",
42
- "read",
43
- "fetch",
44
- "lookup",
45
- "count",
46
- "view",
47
- "show",
48
- "describe",
49
- "retrieve",
50
- "browse",
51
- "peek",
52
- "inspect",
53
- "snapshot",
54
- ]);
55
- /**
56
- * A word that may change something: a name holding one writes, whatever else
57
- * it says (`get_or_create_contact`, `find_and_replace`).
58
- */
59
- const WRITE_WORDS = new Set([
60
- "create",
61
- "add",
62
- "set",
63
- "update",
64
- "upsert",
65
- "insert",
66
- "put",
67
- "post",
68
- "send",
69
- "delete",
70
- "remove",
71
- "mark",
72
- "replace",
73
- "archive",
74
- "move",
75
- "assign",
76
- "book",
77
- "cancel",
78
- "write",
79
- "edit",
80
- "modify",
81
- "save",
82
- "submit",
83
- "approve",
84
- "reject",
85
- "close",
86
- "open",
87
- "merge",
88
- "push",
89
- "publish",
90
- "upload",
91
- "invite",
92
- "schedule",
93
- "reply",
94
- "forward",
95
- "transfer",
96
- "pay",
97
- "refund",
98
- "notify",
99
- "run",
100
- "execute",
101
- "exec",
102
- "apply",
103
- "reset",
104
- "start",
105
- "stop",
106
- "kill",
107
- "enable",
108
- "disable",
109
- "grant",
110
- "revoke",
111
- "rename",
112
- "tag",
113
- "label",
114
- "comment",
115
- ]);
116
- /** A tool name's words: `getJiraIssue` → get, jira, issue; `calendar_search_events` → calendar, search, events. */
117
- function nameWords(name) {
118
- return name
119
- .replace(/([a-z\d])([A-Z])/g, "$1 $2")
120
- .replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2")
121
- .toLowerCase()
122
- .split(/[^a-z\d]+/)
123
- .filter(Boolean);
124
- }
125
- /**
126
- * A tool that only reads: Claude Code's read-only tools, then the name — a
127
- * reading word and no writing word (`calendar_search_events`, `getJiraIssue`;
128
- * `run_sql` no: `run` writes). A name with both (`get_or_create_contact`)
129
- * changes something.
130
- */
131
- export function readsOnly(toolName) {
132
- if (READ_TOOLS.has(toolName))
133
- return true;
134
- if (CHANGING_BUILTINS.has(toolName))
135
- return false;
136
- const words = nameWords(toolName.replace(/^mcp__.+?__/, ""));
137
- if (words.some((w) => WRITE_WORDS.has(w)))
138
- return false;
139
- return words.some((w) => READ_WORDS.has(w));
140
- }
141
- /** Commands that only look (`ls`, `git status`, `grep …`). */
142
- const READ_COMMANDS = new Set([
143
- "ls",
144
- "dir",
145
- "cat",
146
- "type",
147
- "head",
148
- "tail",
149
- "less",
150
- "more",
151
- "grep",
152
- "rg",
153
- "egrep",
154
- "fgrep",
155
- "find",
156
- "wc",
157
- "pwd",
158
- "echo",
159
- "printf",
160
- "date",
161
- "whoami",
162
- "which",
163
- "where",
164
- "env",
165
- "printenv",
166
- "stat",
167
- "file",
168
- "du",
169
- "df",
170
- "tree",
171
- "jq",
172
- "sort",
173
- "uniq",
174
- "cut",
175
- "awk",
176
- "diff",
177
- "cmp",
178
- "basename",
179
- "dirname",
180
- "realpath",
181
- "readlink",
182
- "true",
183
- "false",
184
- "test",
185
- "sleep",
186
- "ps",
187
- "uname",
188
- "hostname",
189
- "id",
190
- "nproc",
191
- "free",
192
- "uptime",
193
- "node --version",
194
- "npm --version",
195
- ]);
196
- const READ_GIT = new Set([
197
- "status",
198
- "log",
199
- "diff",
200
- "show",
201
- "branch",
202
- "rev-parse",
203
- "ls-files",
204
- "blame",
205
- "remote",
206
- "describe",
207
- "config --get",
208
- "grep",
209
- "shortlog",
210
- "tag --list",
211
- ]);
212
- /** Whether a shell command only looks: every part of it is a looking command, and nothing is written to a file. */
213
- export function commandReadsOnly(command) {
214
- const text = command.trim();
215
- if (!text)
216
- return true;
217
- // A redirect into a file (not into /dev/null, not 2>&1), tee, or an in-place edit changes something.
218
- if (/(^|[^0-9&])>{1,2}\s*(?!&|\/dev\/null)\S/.test(text) || /\btee\b/.test(text) || /\bsed\b[^|;&]*\s-i\b/.test(text)) {
219
- return false;
220
- }
221
- if (/\bfind\b[^|;&]*\s-(delete|exec|execdir|ok)\b/.test(text))
222
- return false;
223
- const parts = text
224
- .split(/\|\||&&|[|;\n]/)
225
- .map((p) => p.trim())
226
- .filter(Boolean);
227
- return parts.every((part) => {
228
- const words = part.replace(/^(\w+=\S+\s+)+/, "").split(/\s+/);
229
- const cmd = (words[0] ?? "").replace(/^.*[\\/]/, "");
230
- if (cmd === "git")
231
- return READ_GIT.has(words[1] ?? "") || READ_GIT.has(`${words[1] ?? ""} ${words[2] ?? ""}`);
232
- if (cmd === "sed" || cmd === "awk")
233
- return !/\s-i\b/.test(part);
234
- return READ_COMMANDS.has(cmd) || READ_COMMANDS.has(`${cmd} ${words[1] ?? ""}`);
235
- });
236
- }
237
- /**
238
- * Whether one call may change something. A Bash call changes nothing only
239
- * when its command is there and only looks; any other tool is a change unless
240
- * {@link readsOnly} says it only reads — a tool it cannot tell about counts as
241
- * a change. `input` is the call's arguments, as an object or as JSON text.
242
- */
243
- export function callMayChange(toolName, input) {
244
- if (toolName === "Bash") {
245
- let value = input;
246
- if (typeof value === "string") {
247
- try {
248
- value = JSON.parse(value);
249
- }
250
- catch {
251
- value = undefined;
252
- }
253
- }
254
- const command = value && typeof value === "object" && typeof value.command === "string"
255
- ? value.command
256
- : "";
257
- return command.trim() === "" || !commandReadsOnly(command);
258
- }
259
- return !readsOnly(toolName);
260
- }
261
- //# sourceMappingURL=reads-only.js.map