@wrongstack/tools 1.0.9 → 1.0.10

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.
@@ -7,7 +7,9 @@
7
7
  * dangerous kill commands targeting protected PIDs.
8
8
  *
9
9
  * Handles:
10
- * - Direct kill commands: kill -9 12345
10
+ * - Direct kill commands: kill -9 12345, kill -- 12345, kill 111 12345 (every target)
11
+ * - Sequenced commands: `true; kill 12345`, `a && kill 12345`, `a || kill 12345`,
12
+ * `a & kill 12345`, newline-separated — each segment is checked on its own
11
13
  * - Shell -c wrapped: bash -c "kill -9 12345" (any shell path — see P2 #10)
12
14
  * - Full path kills: /bin/kill -9 12345
13
15
  * - Name-based kills: pkill, killall, pgrep
@@ -41,7 +43,10 @@
41
43
  * fast path for the common non-obfuscated forms.
42
44
  */
43
45
  export interface KillCommand {
46
+ /** First PID target (kept for single-target callers). */
44
47
  pid?: number;
48
+ /** Every PID target when the command names more than one (`kill 1 2 3`). */
49
+ pids?: number[];
45
50
  name?: string;
46
51
  signal?: string;
47
52
  isGroupKill: boolean;
@@ -52,9 +57,6 @@ export interface KillCheckResult {
52
57
  blocked: boolean;
53
58
  reason?: string;
54
59
  }
55
- /**
56
- * Parse a kill command string to extract PID and signal.
57
- */
58
60
  export declare function parseKillCommand(command: string): KillCommand | null;
59
61
  /**
60
62
  * Main entry point: Check if a bash command contains a kill operation targeting protected PIDs.
package/dist/bash.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  bashTool
3
- } from "./chunk-QA37PFYL.js";
3
+ } from "./chunk-FCSUBTUJ.js";
4
4
  import "./chunk-BTSFTGIL.js";
5
5
  import "./chunk-PVCB7RUZ.js";
6
6
  import "./chunk-SCMRM6NL.js";
package/dist/builtin.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  TIER2_TOOLS,
7
7
  TIER3_TOOLS,
8
8
  builtinTools
9
- } from "./chunk-OXO773CW.js";
9
+ } from "./chunk-6I6RXQFG.js";
10
10
  import "./chunk-BVHKBBGA.js";
11
11
  import "./chunk-ENE22I5W.js";
12
12
  import "./chunk-XRNN44QY.js";
@@ -36,7 +36,7 @@ import "./chunk-ON6ET5ER.js";
36
36
  import "./chunk-DLZCOEVG.js";
37
37
  import "./chunk-YJTXRH5Y.js";
38
38
  import "./chunk-ZBMANLYH.js";
39
- import "./chunk-QA37PFYL.js";
39
+ import "./chunk-FCSUBTUJ.js";
40
40
  import "./chunk-QAWI3RSK.js";
41
41
  import "./chunk-BTSFTGIL.js";
42
42
  import "./chunk-PVCB7RUZ.js";
@@ -89,7 +89,7 @@ import {
89
89
  checkAndBlockKillCommand,
90
90
  diagnoseBashism,
91
91
  shellArgs
92
- } from "./chunk-QA37PFYL.js";
92
+ } from "./chunk-FCSUBTUJ.js";
93
93
  import {
94
94
  detectDanger,
95
95
  execTool
@@ -1623,4 +1623,4 @@ export {
1623
1623
  TIER3_TOOLS,
1624
1624
  builtinTools
1625
1625
  };
1626
- //# sourceMappingURL=chunk-OXO773CW.js.map
1626
+ //# sourceMappingURL=chunk-6I6RXQFG.js.map
@@ -185,6 +185,34 @@ function isKillRelatedCommand(cmd) {
185
185
  if (SCRIPT_KILL_RE_POSIX.test(normalized)) return true;
186
186
  return false;
187
187
  }
188
+ function parsePosixKillTargets(normalized, command) {
189
+ const tokens = normalized.split(" ");
190
+ if (tokens[0]?.toLowerCase() !== "kill") return null;
191
+ let i = 1;
192
+ let signal = "TERM";
193
+ const first = tokens[i];
194
+ if (first !== void 0 && /^-[sn]$/i.test(first)) {
195
+ const value = tokens[i + 1];
196
+ if (!value || !/^[a-zA-Z0-9]+$/.test(value)) return null;
197
+ signal = value.toUpperCase();
198
+ i += 2;
199
+ } else if (first !== void 0 && first !== "--" && /^-[a-zA-Z0-9]+$/.test(first) && tokens.length - i >= 2) {
200
+ signal = first.slice(1).toUpperCase();
201
+ i += 1;
202
+ }
203
+ if (tokens[i] === "--") i += 1;
204
+ const targets = tokens.slice(i);
205
+ if (targets.length === 0 || !targets.every((t) => /^-?\d+$/.test(t))) return null;
206
+ const pids = targets.map((t) => Number.parseInt(t.replace(/^-/, ""), 10));
207
+ return {
208
+ pid: pids[0],
209
+ ...pids.length > 1 ? { pids } : {},
210
+ signal,
211
+ isGroupKill: targets.some((t) => t.startsWith("-")),
212
+ isAllKill: false,
213
+ originalCommand: command
214
+ };
215
+ }
188
216
  function parseKillCommand(command) {
189
217
  const normalized = command.replace(/\s+/g, " ").trim();
190
218
  if (isWin) {
@@ -241,27 +269,8 @@ function parseKillCommand(command) {
241
269
  originalCommand: command
242
270
  };
243
271
  }
244
- const killSignalOptionMatch = normalized.match(/^kill\s+-s\s+([a-zA-Z0-9]+)\s+(\d+)$/i);
245
- if (killSignalOptionMatch?.[1] && killSignalOptionMatch[2]) {
246
- return {
247
- pid: parseInt(killSignalOptionMatch[2], 10),
248
- signal: killSignalOptionMatch[1].toUpperCase(),
249
- isGroupKill: false,
250
- isAllKill: false,
251
- originalCommand: command
252
- };
253
- }
254
- const killPosixMatch = normalized.match(/^kill\s+(?:(-[a-zA-Z0-9]+)\s+)?(\d+)$/);
255
- if (killPosixMatch?.[2]) {
256
- const sig = killPosixMatch[1] ? killPosixMatch[1].slice(1).toUpperCase() : "TERM";
257
- return {
258
- pid: parseInt(killPosixMatch[2], 10),
259
- signal: sig,
260
- isGroupKill: false,
261
- isAllKill: false,
262
- originalCommand: command
263
- };
264
- }
272
+ const gitBashKill = parsePosixKillTargets(normalized, command);
273
+ if (gitBashKill) return gitBashKill;
265
274
  const stopProcNameMatch = normalized.match(
266
275
  /^(?:stop-process|kill)\s+-(?:name|n)\s+(?:['"]([a-zA-Z0-9_.-]+)['"]|([a-zA-Z0-9_.-]+))(?:\s|$)/i
267
276
  );
@@ -324,33 +333,8 @@ function parseKillCommand(command) {
324
333
  }
325
334
  return null;
326
335
  }
327
- const signalOptionMatch = normalized.match(/^kill\s+-s\s+([a-zA-Z0-9]+)\s+(\d+|-?\d+)$/i);
328
- if (signalOptionMatch?.[1] && signalOptionMatch[2]) {
329
- const pidOrGroup = signalOptionMatch[2];
330
- const isGroupKill = pidOrGroup.startsWith("-");
331
- return {
332
- pid: parseInt(isGroupKill ? pidOrGroup.slice(1) : pidOrGroup, 10),
333
- signal: signalOptionMatch[1].toUpperCase(),
334
- isGroupKill,
335
- isAllKill: false,
336
- originalCommand: command
337
- };
338
- }
339
- const simpleMatch = normalized.match(/^kill\s+(?:(-[a-zA-Z0-9]+)\s+)?(\d+|-?\d+)$/);
340
- if (simpleMatch) {
341
- const signal = simpleMatch[1] ?? "-TERM";
342
- const pidOrGroup = simpleMatch[2];
343
- if (!pidOrGroup) return null;
344
- const isGroupKill = pidOrGroup.startsWith("-");
345
- const pid = isGroupKill ? parseInt(pidOrGroup.slice(1), 10) : parseInt(pidOrGroup, 10);
346
- return {
347
- pid,
348
- signal: signal.slice(1),
349
- isGroupKill,
350
- isAllKill: false,
351
- originalCommand: command
352
- };
353
- }
336
+ const posixKill = parsePosixKillTargets(normalized, command);
337
+ if (posixKill) return posixKill;
354
338
  const pkillMatch = normalized.match(/^pkill\s+(?:(-[a-zA-Z]+)\s+)?(.+)$/);
355
339
  if (pkillMatch?.[2]) {
356
340
  const name = pkillMatch[2];
@@ -429,14 +413,60 @@ async function isKillProtected(kill) {
429
413
  const protectedPids = await registry.getAllProtectedPids();
430
414
  return protectedPids.length > 0;
431
415
  }
432
- if (kill.pid !== void 0) {
433
- if (await registry.shouldBlockKill(kill.pid)) return true;
434
- if (kill.pid === process.pid || kill.pid === process.ppid) return true;
435
- return false;
416
+ const targets = kill.pids ?? (kill.pid !== void 0 ? [kill.pid] : []);
417
+ for (const pid of targets) {
418
+ if (await registry.shouldBlockKill(pid)) return true;
419
+ if (pid === process.pid || pid === process.ppid) return true;
436
420
  }
437
421
  return false;
438
422
  }
439
423
  async function checkAndBlockKillCommand(command) {
424
+ const whole = await checkSingleCommand(command);
425
+ if (whole.blocked) return whole;
426
+ const segments = splitShellSequence(command);
427
+ if (segments.length > 1) {
428
+ for (const segment of segments) {
429
+ const result = await checkSingleCommand(segment);
430
+ if (result.blocked) return result;
431
+ }
432
+ }
433
+ return { blocked: false };
434
+ }
435
+ function splitShellSequence(command) {
436
+ const segments = [];
437
+ let current = "";
438
+ let quote = null;
439
+ for (let i = 0; i < command.length; i++) {
440
+ const ch = command[i];
441
+ const next = command[i + 1];
442
+ if (quote) {
443
+ if (ch === quote) quote = null;
444
+ current += ch;
445
+ continue;
446
+ }
447
+ if (ch === "\\" && next !== void 0) {
448
+ current += ch + next;
449
+ i++;
450
+ continue;
451
+ }
452
+ if (ch === '"' || ch === "'") {
453
+ quote = ch;
454
+ current += ch;
455
+ continue;
456
+ }
457
+ const isSeparator = ch === ";" || ch === "\n" || ch === "\r" || ch === "|" && next === "|" || ch === "&" && command[i - 1] !== ">" && next !== ">";
458
+ if (isSeparator) {
459
+ if ((ch === "|" || ch === "&") && next === ch) i++;
460
+ if (current.trim()) segments.push(current.trim());
461
+ current = "";
462
+ continue;
463
+ }
464
+ current += ch;
465
+ }
466
+ if (current.trim()) segments.push(current.trim());
467
+ return segments;
468
+ }
469
+ async function checkSingleCommand(command) {
440
470
  const normalized = command.replace(/\s+/g, " ").trim();
441
471
  const killCmd = extractKillCommand(normalized) || (isKillRelatedCommand(normalized) ? normalized : null);
442
472
  if (!killCmd) {
@@ -462,6 +492,8 @@ async function checkAndBlockKillCommand(command) {
462
492
  let target;
463
493
  if (parsed.name) {
464
494
  target = `process name "${parsed.name}"`;
495
+ } else if (parsed.pids && parsed.pids.length > 1) {
496
+ target = `PIDs ${parsed.pids.join(", ")}`;
465
497
  } else if (parsed.pid !== void 0) {
466
498
  target = `PID ${parsed.pid}`;
467
499
  } else {
@@ -1054,4 +1086,4 @@ export {
1054
1086
  checkAndBlockKillCommand,
1055
1087
  bashTool
1056
1088
  };
1057
- //# sourceMappingURL=chunk-QA37PFYL.js.map
1089
+ //# sourceMappingURL=chunk-FCSUBTUJ.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  builtinTools
3
- } from "./chunk-OXO773CW.js";
3
+ } from "./chunk-6I6RXQFG.js";
4
4
 
5
5
  // src/pack.ts
6
6
  var builtinToolsPack = {
@@ -12,4 +12,4 @@ var builtinToolsPack = {
12
12
  export {
13
13
  builtinToolsPack
14
14
  };
15
- //# sourceMappingURL=chunk-WEUEU53R.js.map
15
+ //# sourceMappingURL=chunk-FVSMTEO3.js.map
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  builtinToolsPack
3
- } from "./chunk-WEUEU53R.js";
3
+ } from "./chunk-FVSMTEO3.js";
4
4
  import {
5
5
  TIER1_TOOLS,
6
6
  TIER2_TOOLS
7
- } from "./chunk-OXO773CW.js";
7
+ } from "./chunk-6I6RXQFG.js";
8
8
 
9
9
  // src/tool-tier.ts
10
10
  function toolNameSet(tools) {
@@ -54,4 +54,4 @@ export {
54
54
  selectBuiltinToolsForTier,
55
55
  registerBuiltinToolTier
56
56
  };
57
- //# sourceMappingURL=chunk-HV7RWDCL.js.map
57
+ //# sourceMappingURL=chunk-V25Q6TQ7.js.map
package/dist/index.js CHANGED
@@ -46,10 +46,10 @@ import "./chunk-Z6DAKQ3U.js";
46
46
  import {
47
47
  registerBuiltinToolTier,
48
48
  selectBuiltinToolsForTier
49
- } from "./chunk-HV7RWDCL.js";
49
+ } from "./chunk-V25Q6TQ7.js";
50
50
  import {
51
51
  builtinToolsPack
52
- } from "./chunk-WEUEU53R.js";
52
+ } from "./chunk-FVSMTEO3.js";
53
53
  import {
54
54
  OFF_ONLY_TOOLS,
55
55
  OPTIONAL_TOOLS,
@@ -64,7 +64,7 @@ import {
64
64
  pwshTool,
65
65
  readUrlContentTool,
66
66
  securityAstScanTool
67
- } from "./chunk-OXO773CW.js";
67
+ } from "./chunk-6I6RXQFG.js";
68
68
  import {
69
69
  discoverE2EProjects,
70
70
  e2ePlanTool
@@ -192,7 +192,7 @@ import {
192
192
  import {
193
193
  bashTool,
194
194
  checkAndBlockKillCommand
195
- } from "./chunk-QA37PFYL.js";
195
+ } from "./chunk-FCSUBTUJ.js";
196
196
  import {
197
197
  checkExecKillCommand,
198
198
  configureDangerBypass,
package/dist/pack.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  builtinToolsPack
3
- } from "./chunk-WEUEU53R.js";
4
- import "./chunk-OXO773CW.js";
3
+ } from "./chunk-FVSMTEO3.js";
4
+ import "./chunk-6I6RXQFG.js";
5
5
  import "./chunk-BVHKBBGA.js";
6
6
  import "./chunk-ENE22I5W.js";
7
7
  import "./chunk-XRNN44QY.js";
@@ -31,7 +31,7 @@ import "./chunk-ON6ET5ER.js";
31
31
  import "./chunk-DLZCOEVG.js";
32
32
  import "./chunk-YJTXRH5Y.js";
33
33
  import "./chunk-ZBMANLYH.js";
34
- import "./chunk-QA37PFYL.js";
34
+ import "./chunk-FCSUBTUJ.js";
35
35
  import "./chunk-QAWI3RSK.js";
36
36
  import "./chunk-BTSFTGIL.js";
37
37
  import "./chunk-PVCB7RUZ.js";
package/dist/tool-tier.js CHANGED
@@ -2,9 +2,9 @@ import {
2
2
  BUILTIN_TIER_COUNTS,
3
3
  registerBuiltinToolTier,
4
4
  selectBuiltinToolsForTier
5
- } from "./chunk-HV7RWDCL.js";
6
- import "./chunk-WEUEU53R.js";
7
- import "./chunk-OXO773CW.js";
5
+ } from "./chunk-V25Q6TQ7.js";
6
+ import "./chunk-FVSMTEO3.js";
7
+ import "./chunk-6I6RXQFG.js";
8
8
  import "./chunk-BVHKBBGA.js";
9
9
  import "./chunk-ENE22I5W.js";
10
10
  import "./chunk-XRNN44QY.js";
@@ -34,7 +34,7 @@ import "./chunk-ON6ET5ER.js";
34
34
  import "./chunk-DLZCOEVG.js";
35
35
  import "./chunk-YJTXRH5Y.js";
36
36
  import "./chunk-ZBMANLYH.js";
37
- import "./chunk-QA37PFYL.js";
37
+ import "./chunk-FCSUBTUJ.js";
38
38
  import "./chunk-QAWI3RSK.js";
39
39
  import "./chunk-BTSFTGIL.js";
40
40
  import "./chunk-PVCB7RUZ.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wrongstack/tools",
3
- "version": "1.0.9",
3
+ "version": "1.0.10",
4
4
  "license": "MIT",
5
5
  "description": "WrongStack built-in tools: read/write/edit, bash/exec, grep/glob, git, fetch, test, lint, and more.",
6
6
  "repository": {
@@ -237,10 +237,10 @@
237
237
  "@msgpack/msgpack": "^3.1.3",
238
238
  "@playwright/test": "^1.63.0",
239
239
  "@typescript/typescript6": "^6.0.2",
240
- "@wrongstack/core": "1.0.9",
241
- "@wrongstack/kanban": "1.0.9",
242
- "@wrongstack/persistence": "1.0.9",
243
- "@wrongstack/primitives": "1.0.9",
240
+ "@wrongstack/core": "1.0.10",
241
+ "@wrongstack/kanban": "1.0.10",
242
+ "@wrongstack/persistence": "1.0.10",
243
+ "@wrongstack/primitives": "1.0.10",
244
244
  "tree-sitter-wasm": "1.1.8",
245
245
  "turndown": "^7.2.4",
246
246
  "undici": "^8.10.2",