@yusukeshib/pi-babysit 0.3.1 → 0.3.2
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 +7 -0
- package/index.ts +39 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -84,6 +84,13 @@ rg -n 'FAIL|ERROR' /path/to/output.log
|
|
|
84
84
|
`babysit_check { id, lines }` remains available as a convenient bounded tail.
|
|
85
85
|
Do not read a potentially large log file in full.
|
|
86
86
|
|
|
87
|
+
To enforce this policy, the extension blocks direct `bash` except for `pwd`,
|
|
88
|
+
short Git status/branch checks, and `head`/`tail`/`rg` reads of `.log` files that
|
|
89
|
+
are explicitly bounded to at most 100 lines. Broad searches, diffs, API calls,
|
|
90
|
+
multiple commands, redirects, and shell wrappers are redirected to
|
|
91
|
+
`babysit_run`. Set `PI_BABYSIT_ALLOW_BASH=1` only as an emergency escape hatch
|
|
92
|
+
to disable this gate.
|
|
93
|
+
|
|
87
94
|
## External worker death
|
|
88
95
|
|
|
89
96
|
If endpoint security or another external actor kills the babysit supervisor,
|
package/index.ts
CHANGED
|
@@ -1092,6 +1092,30 @@ function backgroundsItself(command: string): boolean {
|
|
|
1092
1092
|
return false;
|
|
1093
1093
|
}
|
|
1094
1094
|
|
|
1095
|
+
function boundedLineCount(command: string): number | null {
|
|
1096
|
+
const matches = [...command.matchAll(/(?:^|\|)\s*(?:head|tail)\s+(?:-n\s+|--lines(?:=|\s+)|-)(\d+)\b/g)];
|
|
1097
|
+
if (matches.length === 0) return null;
|
|
1098
|
+
return Math.max(...matches.map((m) => Number(m[1])));
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
/** Commands allowed to bypass babysit: tiny scalar observations and strictly
|
|
1102
|
+
* bounded reads of captured log files. This is deliberately conservative;
|
|
1103
|
+
* uncertain shell syntax belongs in babysit_run where output is capped. */
|
|
1104
|
+
export function isAllowedDirectBash(command: string): boolean {
|
|
1105
|
+
if (process.env.PI_BABYSIT_ALLOW_BASH === "1") return true;
|
|
1106
|
+
const s = command.trim();
|
|
1107
|
+
if (/^(pwd|git status --short|git branch --show-current)$/.test(s)) return true;
|
|
1108
|
+
if (!s || /[;&`\n\r]|\$\(|>|\b(?:bash|sh|zsh)\s+-c\b/.test(s)) return false;
|
|
1109
|
+
if (!/(?:output\.log|\/(?:tmp|var\/tmp)\/[^\s'\"]*\.log)\b/.test(s)) return false;
|
|
1110
|
+
if (/^wc\s+-(?:l|c)\s+/.test(s) && !s.includes("|")) return true;
|
|
1111
|
+
if (!/^(?:tail|head|rg)\b/.test(s)) return false;
|
|
1112
|
+
const limit = boundedLineCount(s);
|
|
1113
|
+
if (limit == null || limit > 100) return false;
|
|
1114
|
+
// rg must feed a bounded head/tail; direct head/tail is already bounded.
|
|
1115
|
+
if (/^rg\b/.test(s) && !/\|\s*(?:head|tail)\b/.test(s)) return false;
|
|
1116
|
+
return true;
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1095
1119
|
// ---------------------------------------------------------------------------
|
|
1096
1120
|
// extension
|
|
1097
1121
|
// ---------------------------------------------------------------------------
|
|
@@ -1228,17 +1252,27 @@ export default function (pi: ExtensionAPI) {
|
|
|
1228
1252
|
pollTimer = undefined;
|
|
1229
1253
|
});
|
|
1230
1254
|
|
|
1231
|
-
//
|
|
1232
|
-
//
|
|
1255
|
+
// Keep unpredictable command output out of model context. Direct bash is
|
|
1256
|
+
// reserved for tiny scalar observations and tightly bounded log inspection;
|
|
1257
|
+
// everything else belongs in babysit_run.
|
|
1233
1258
|
pi.on("tool_call", async (event) => {
|
|
1234
1259
|
if (event.toolName !== "bash") return;
|
|
1235
1260
|
const command = String((event.input as { command?: unknown }).command ?? "");
|
|
1236
|
-
if (
|
|
1261
|
+
if (backgroundsItself(command)) {
|
|
1262
|
+
return {
|
|
1263
|
+
block: true,
|
|
1264
|
+
reason:
|
|
1265
|
+
`This bash command tries to run in the background. Use babysit_run instead, e.g. ` +
|
|
1266
|
+
`babysit_run({ name: "background-process", command: ${JSON.stringify(command.replace(/\s*&\s*$/, ""))} })`,
|
|
1267
|
+
};
|
|
1268
|
+
}
|
|
1269
|
+
if (isAllowedDirectBash(command)) return;
|
|
1237
1270
|
return {
|
|
1238
1271
|
block: true,
|
|
1239
1272
|
reason:
|
|
1240
|
-
|
|
1241
|
-
|
|
1273
|
+
"Use babysit_run for this command so potentially large output is captured outside model context. " +
|
|
1274
|
+
"Direct bash is allowed only for pwd, short git status/branch checks, or log-file tail/rg commands explicitly bounded to at most 100 lines. " +
|
|
1275
|
+
`Retry as babysit_run({ command: ${JSON.stringify(command)} }).`,
|
|
1242
1276
|
};
|
|
1243
1277
|
});
|
|
1244
1278
|
|