@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.
- package/README.md +6 -5
- package/dist/bin/bir-hooks.d.ts +17 -19
- package/dist/bin/bir-hooks.js +17 -19
- package/dist/bin/bir-scenario.js +1 -1
- package/dist/bin/bir.js +1 -21
- package/dist/bin/investigate.d.ts +0 -9
- package/dist/bin/investigate.js +15 -43
- package/dist/bin/scenario-edit.js +13 -44
- package/dist/control/recorder-main.d.ts +0 -15
- package/dist/control/recorder-main.js +22 -42
- package/dist/control/server.d.ts +24 -137
- package/dist/control/server.js +107 -1001
- package/dist/record/recorder.d.ts +11 -142
- package/dist/record/recorder.js +0 -3
- package/dist/record/remote-recorder.d.ts +1 -9
- package/dist/record/remote-recorder.js +3 -49
- package/dist/record/switchable-recorder.js +0 -2
- package/dist/replay/builtins.d.ts +45 -9
- package/dist/replay/builtins.js +131 -59
- package/dist/replay/bundle.d.ts +2 -2
- package/dist/replay/bundle.js +3 -3
- package/dist/replay/controller.d.ts +34 -125
- package/dist/replay/controller.js +171 -528
- package/dist/replay/derive.d.ts +0 -10
- package/dist/replay/derive.js +0 -3
- package/dist/replay/handover.d.ts +2 -37
- package/dist/replay/handover.js +38 -106
- package/dist/replay/logic.d.ts +0 -11
- package/dist/replay/logic.js +0 -24
- package/dist/replay/plan.d.ts +43 -163
- package/dist/replay/plan.js +144 -556
- package/dist/replay/safety.d.ts +4 -5
- package/dist/replay/safety.js +7 -7
- package/dist/replay/source-run.d.ts +15 -24
- package/dist/replay/source-run.js +25 -58
- package/dist/replay/targets.d.ts +11 -21
- package/dist/replay/targets.js +30 -69
- package/dist/replay/types.d.ts +9 -96
- package/dist/replay/types.js +3 -16
- package/dist/util/service-headers.d.ts +1 -2
- package/dist/util/service-headers.js +1 -2
- package/docs/calculatedReplay.md +30 -81
- package/docs/calculatedReplayGuide.md +17 -34
- package/package.json +1 -1
- package/production.md +7 -36
- package/dist/replay/condition-words.d.ts +0 -28
- package/dist/replay/condition-words.js +0 -59
- package/dist/replay/flatten.d.ts +0 -161
- package/dist/replay/flatten.js +0 -222
- package/dist/replay/reads-only.d.ts +0 -29
- 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
|