claude-warden 2.10.0 → 2.10.1

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.
@@ -8,7 +8,7 @@
8
8
  {
9
9
  "name": "warden",
10
10
  "description": "Auto-approves safe commands, blocks dangerous ones, prompts for the rest",
11
- "version": "2.10.0",
11
+ "version": "2.10.1",
12
12
  "author": {
13
13
  "name": "banyudu"
14
14
  },
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "warden",
3
- "version": "2.10.0",
3
+ "version": "2.10.1",
4
4
  "description": "Smart command safety filter for Claude Code — parses shell pipelines and evaluates per-command safety rules to auto-approve safe commands and block dangerous ones",
5
5
  "author": {
6
6
  "name": "banyudu"
package/dist/cli.cjs CHANGED
@@ -18214,6 +18214,19 @@ function convertCommand(node) {
18214
18214
  const raw = rawParts.join(" ");
18215
18215
  return { command, originalCommand, args: args2, envPrefixes, raw };
18216
18216
  }
18217
+ function collectExpansionsFromWord(word, result) {
18218
+ if (!word?.expansion) return;
18219
+ for (const exp of word.expansion) {
18220
+ if (exp.type === "CommandExpansion" && exp.command) {
18221
+ result.hasSubshell = true;
18222
+ result.subshellCommands.push(exp.command);
18223
+ }
18224
+ }
18225
+ }
18226
+ function walkCompoundList(list, result) {
18227
+ if (!list?.commands) return;
18228
+ for (const cmd of list.commands) walkNode(cmd, result);
18229
+ }
18217
18230
  function collectCommandExpansions(node) {
18218
18231
  const commands = [];
18219
18232
  if (node.type === "Command") {
@@ -18288,15 +18301,47 @@ function walkNode(node, result) {
18288
18301
  }
18289
18302
  break;
18290
18303
  }
18291
- // Complex constructs flag as subshell for safety
18292
- case "If":
18293
- case "For":
18304
+ // Control constructs mirror the Subshell handler above: their bodies are
18305
+ // walked into result.commands so each inner command is evaluated normally.
18306
+ // hasSubshell stays false unless a head expression (`for f in $(...)`,
18307
+ // `case $(...) in ...`) introduces a real command substitution.
18308
+ case "For": {
18309
+ const f = node;
18310
+ if (f.wordlist) {
18311
+ for (const w of f.wordlist) collectExpansionsFromWord(w, result);
18312
+ }
18313
+ walkCompoundList(f.do, result);
18314
+ break;
18315
+ }
18294
18316
  case "While":
18295
- case "Until":
18296
- case "Case":
18297
- case "Function":
18298
- result.hasSubshell = true;
18317
+ case "Until": {
18318
+ const w = node;
18319
+ walkCompoundList(w.clause, result);
18320
+ walkCompoundList(w.do, result);
18299
18321
  break;
18322
+ }
18323
+ case "If": {
18324
+ const i = node;
18325
+ walkCompoundList(i.clause, result);
18326
+ walkCompoundList(i.then, result);
18327
+ if (i.else) {
18328
+ if (i.else.type === "If") walkNode(i.else, result);
18329
+ else walkCompoundList(i.else, result);
18330
+ }
18331
+ break;
18332
+ }
18333
+ case "Case": {
18334
+ const cs = node;
18335
+ collectExpansionsFromWord(cs.clause, result);
18336
+ if (cs.cases) {
18337
+ for (const item of cs.cases) walkCompoundList(item.body, result);
18338
+ }
18339
+ break;
18340
+ }
18341
+ case "Function": {
18342
+ walkCompoundList(node.body, result);
18343
+ break;
18344
+ }
18300
18345
  default:
18301
18346
  break;
18302
18347
  }
@@ -18218,6 +18218,19 @@ function convertCommand(node) {
18218
18218
  const raw = rawParts.join(" ");
18219
18219
  return { command, originalCommand, args: args2, envPrefixes, raw };
18220
18220
  }
18221
+ function collectExpansionsFromWord(word, result) {
18222
+ if (!word?.expansion) return;
18223
+ for (const exp of word.expansion) {
18224
+ if (exp.type === "CommandExpansion" && exp.command) {
18225
+ result.hasSubshell = true;
18226
+ result.subshellCommands.push(exp.command);
18227
+ }
18228
+ }
18229
+ }
18230
+ function walkCompoundList(list, result) {
18231
+ if (!list?.commands) return;
18232
+ for (const cmd of list.commands) walkNode(cmd, result);
18233
+ }
18221
18234
  function collectCommandExpansions(node) {
18222
18235
  const commands = [];
18223
18236
  if (node.type === "Command") {
@@ -18292,15 +18305,47 @@ function walkNode(node, result) {
18292
18305
  }
18293
18306
  break;
18294
18307
  }
18295
- // Complex constructs flag as subshell for safety
18296
- case "If":
18297
- case "For":
18308
+ // Control constructs mirror the Subshell handler above: their bodies are
18309
+ // walked into result.commands so each inner command is evaluated normally.
18310
+ // hasSubshell stays false unless a head expression (`for f in $(...)`,
18311
+ // `case $(...) in ...`) introduces a real command substitution.
18312
+ case "For": {
18313
+ const f = node;
18314
+ if (f.wordlist) {
18315
+ for (const w of f.wordlist) collectExpansionsFromWord(w, result);
18316
+ }
18317
+ walkCompoundList(f.do, result);
18318
+ break;
18319
+ }
18298
18320
  case "While":
18299
- case "Until":
18300
- case "Case":
18301
- case "Function":
18302
- result.hasSubshell = true;
18321
+ case "Until": {
18322
+ const w = node;
18323
+ walkCompoundList(w.clause, result);
18324
+ walkCompoundList(w.do, result);
18303
18325
  break;
18326
+ }
18327
+ case "If": {
18328
+ const i = node;
18329
+ walkCompoundList(i.clause, result);
18330
+ walkCompoundList(i.then, result);
18331
+ if (i.else) {
18332
+ if (i.else.type === "If") walkNode(i.else, result);
18333
+ else walkCompoundList(i.else, result);
18334
+ }
18335
+ break;
18336
+ }
18337
+ case "Case": {
18338
+ const cs = node;
18339
+ collectExpansionsFromWord(cs.clause, result);
18340
+ if (cs.cases) {
18341
+ for (const item of cs.cases) walkCompoundList(item.body, result);
18342
+ }
18343
+ break;
18344
+ }
18345
+ case "Function": {
18346
+ walkCompoundList(node.body, result);
18347
+ break;
18348
+ }
18304
18349
  default:
18305
18350
  break;
18306
18351
  }
package/dist/copilot.cjs CHANGED
@@ -18214,6 +18214,19 @@ function convertCommand(node) {
18214
18214
  const raw = rawParts.join(" ");
18215
18215
  return { command, originalCommand, args: args2, envPrefixes, raw };
18216
18216
  }
18217
+ function collectExpansionsFromWord(word, result) {
18218
+ if (!word?.expansion) return;
18219
+ for (const exp of word.expansion) {
18220
+ if (exp.type === "CommandExpansion" && exp.command) {
18221
+ result.hasSubshell = true;
18222
+ result.subshellCommands.push(exp.command);
18223
+ }
18224
+ }
18225
+ }
18226
+ function walkCompoundList(list, result) {
18227
+ if (!list?.commands) return;
18228
+ for (const cmd of list.commands) walkNode(cmd, result);
18229
+ }
18217
18230
  function collectCommandExpansions(node) {
18218
18231
  const commands = [];
18219
18232
  if (node.type === "Command") {
@@ -18288,15 +18301,47 @@ function walkNode(node, result) {
18288
18301
  }
18289
18302
  break;
18290
18303
  }
18291
- // Complex constructs flag as subshell for safety
18292
- case "If":
18293
- case "For":
18304
+ // Control constructs mirror the Subshell handler above: their bodies are
18305
+ // walked into result.commands so each inner command is evaluated normally.
18306
+ // hasSubshell stays false unless a head expression (`for f in $(...)`,
18307
+ // `case $(...) in ...`) introduces a real command substitution.
18308
+ case "For": {
18309
+ const f = node;
18310
+ if (f.wordlist) {
18311
+ for (const w of f.wordlist) collectExpansionsFromWord(w, result);
18312
+ }
18313
+ walkCompoundList(f.do, result);
18314
+ break;
18315
+ }
18294
18316
  case "While":
18295
- case "Until":
18296
- case "Case":
18297
- case "Function":
18298
- result.hasSubshell = true;
18317
+ case "Until": {
18318
+ const w = node;
18319
+ walkCompoundList(w.clause, result);
18320
+ walkCompoundList(w.do, result);
18299
18321
  break;
18322
+ }
18323
+ case "If": {
18324
+ const i = node;
18325
+ walkCompoundList(i.clause, result);
18326
+ walkCompoundList(i.then, result);
18327
+ if (i.else) {
18328
+ if (i.else.type === "If") walkNode(i.else, result);
18329
+ else walkCompoundList(i.else, result);
18330
+ }
18331
+ break;
18332
+ }
18333
+ case "Case": {
18334
+ const cs = node;
18335
+ collectExpansionsFromWord(cs.clause, result);
18336
+ if (cs.cases) {
18337
+ for (const item of cs.cases) walkCompoundList(item.body, result);
18338
+ }
18339
+ break;
18340
+ }
18341
+ case "Function": {
18342
+ walkCompoundList(node.body, result);
18343
+ break;
18344
+ }
18300
18345
  default:
18301
18346
  break;
18302
18347
  }
package/dist/index.cjs CHANGED
@@ -18214,6 +18214,19 @@ function convertCommand(node) {
18214
18214
  const raw = rawParts.join(" ");
18215
18215
  return { command, originalCommand, args: args2, envPrefixes, raw };
18216
18216
  }
18217
+ function collectExpansionsFromWord(word, result) {
18218
+ if (!word?.expansion) return;
18219
+ for (const exp of word.expansion) {
18220
+ if (exp.type === "CommandExpansion" && exp.command) {
18221
+ result.hasSubshell = true;
18222
+ result.subshellCommands.push(exp.command);
18223
+ }
18224
+ }
18225
+ }
18226
+ function walkCompoundList(list, result) {
18227
+ if (!list?.commands) return;
18228
+ for (const cmd of list.commands) walkNode(cmd, result);
18229
+ }
18217
18230
  function collectCommandExpansions(node) {
18218
18231
  const commands = [];
18219
18232
  if (node.type === "Command") {
@@ -18288,15 +18301,47 @@ function walkNode(node, result) {
18288
18301
  }
18289
18302
  break;
18290
18303
  }
18291
- // Complex constructs flag as subshell for safety
18292
- case "If":
18293
- case "For":
18304
+ // Control constructs mirror the Subshell handler above: their bodies are
18305
+ // walked into result.commands so each inner command is evaluated normally.
18306
+ // hasSubshell stays false unless a head expression (`for f in $(...)`,
18307
+ // `case $(...) in ...`) introduces a real command substitution.
18308
+ case "For": {
18309
+ const f = node;
18310
+ if (f.wordlist) {
18311
+ for (const w of f.wordlist) collectExpansionsFromWord(w, result);
18312
+ }
18313
+ walkCompoundList(f.do, result);
18314
+ break;
18315
+ }
18294
18316
  case "While":
18295
- case "Until":
18296
- case "Case":
18297
- case "Function":
18298
- result.hasSubshell = true;
18317
+ case "Until": {
18318
+ const w = node;
18319
+ walkCompoundList(w.clause, result);
18320
+ walkCompoundList(w.do, result);
18299
18321
  break;
18322
+ }
18323
+ case "If": {
18324
+ const i = node;
18325
+ walkCompoundList(i.clause, result);
18326
+ walkCompoundList(i.then, result);
18327
+ if (i.else) {
18328
+ if (i.else.type === "If") walkNode(i.else, result);
18329
+ else walkCompoundList(i.else, result);
18330
+ }
18331
+ break;
18332
+ }
18333
+ case "Case": {
18334
+ const cs = node;
18335
+ collectExpansionsFromWord(cs.clause, result);
18336
+ if (cs.cases) {
18337
+ for (const item of cs.cases) walkCompoundList(item.body, result);
18338
+ }
18339
+ break;
18340
+ }
18341
+ case "Function": {
18342
+ walkCompoundList(node.body, result);
18343
+ break;
18344
+ }
18300
18345
  default:
18301
18346
  break;
18302
18347
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-warden",
3
- "version": "2.10.0",
3
+ "version": "2.10.1",
4
4
  "description": "Smart command safety filter for Claude Code — auto-approves safe commands, blocks dangerous ones",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",