claude-warden 1.1.6 → 1.1.8

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-warden",
3
- "version": "1.0.0",
3
+ "version": "1.1.8",
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/index.cjs CHANGED
@@ -18139,6 +18139,10 @@ var require_dist2 = __commonJS({
18139
18139
  var import_bash_parser = __toESM(require_src(), 1);
18140
18140
  var import_path = require("path");
18141
18141
  var HEREDOC_REGEX = /<<-?\s*['"]?\w+['"]?/;
18142
+ function preprocessCatHeredocs(input) {
18143
+ const regex = /\$\(cat\s+<<-?\s*['"]?(\w+)['"]?\n([\s\S]*?)\n\1\s*\)/g;
18144
+ return input.replace(regex, "__HEREDOC_TEXT__");
18145
+ }
18142
18146
  function convertCommand(node) {
18143
18147
  if (!node.name) return null;
18144
18148
  const command = node.name.text.includes("/") ? (0, import_path.basename)(node.name.text) : node.name.text;
@@ -18254,36 +18258,78 @@ function walkNode(node, result) {
18254
18258
  break;
18255
18259
  }
18256
18260
  }
18257
- function parseCommand(input) {
18258
- if (!input || !input.trim()) {
18259
- return { commands: [], hasSubshell: false, subshellCommands: [], parseError: false };
18260
- }
18261
- const hasHeredoc = HEREDOC_REGEX.test(input);
18262
- if (hasHeredoc) {
18263
- const firstLine = input.split("\n")[0];
18264
- const cmdPart = firstLine.replace(/<<-?\s*['"]?\w+['"]?.*$/, "").trim();
18265
- if (!cmdPart) {
18266
- return { commands: [], hasSubshell: false, subshellCommands: [], parseError: true };
18261
+ function hasHeredocRedirect(node) {
18262
+ if (!node.suffix) return false;
18263
+ return node.suffix.some((s) => s.type === "dless" || s.type === "dlessdash");
18264
+ }
18265
+ function astHasHeredoc(ast) {
18266
+ function check(node) {
18267
+ if (node.type === "Command") {
18268
+ if (hasHeredocRedirect(node)) return true;
18267
18269
  }
18268
- try {
18269
- const ast = (0, import_bash_parser.default)(cmdPart);
18270
- const result = { commands: [], hasSubshell: false, subshellCommands: [] };
18271
- for (const cmd of ast.commands) {
18272
- walkNode(cmd, result);
18270
+ for (const [key, value] of Object.entries(node)) {
18271
+ if (key === "commandAST" || key === "expansion") continue;
18272
+ if (Array.isArray(value)) {
18273
+ for (const child of value) {
18274
+ if (child && typeof child === "object" && "type" in child && check(child)) return true;
18275
+ }
18276
+ } else if (value && typeof value === "object" && "type" in value) {
18277
+ if (check(value)) return true;
18273
18278
  }
18274
- return { commands: result.commands, hasSubshell: true, subshellCommands: result.subshellCommands, parseError: false };
18275
- } catch {
18276
- return { commands: [], hasSubshell: true, subshellCommands: [], parseError: true };
18277
18279
  }
18280
+ return false;
18281
+ }
18282
+ for (const cmd of ast.commands) {
18283
+ if (check(cmd)) return true;
18284
+ }
18285
+ return false;
18286
+ }
18287
+ function parseCommand(input) {
18288
+ if (!input || !input.trim()) {
18289
+ return { commands: [], hasSubshell: false, subshellCommands: [], parseError: false };
18278
18290
  }
18291
+ input = preprocessCatHeredocs(input);
18279
18292
  try {
18280
18293
  const ast = (0, import_bash_parser.default)(input);
18281
18294
  const result = { commands: [], hasSubshell: false, subshellCommands: [] };
18295
+ if (astHasHeredoc(ast)) {
18296
+ const firstLine = input.split("\n")[0];
18297
+ const cmdPart = firstLine.replace(/<<-?\s*['"]?\w+['"]?.*$/, "").trim();
18298
+ if (!cmdPart) {
18299
+ return { commands: [], hasSubshell: false, subshellCommands: [], parseError: true };
18300
+ }
18301
+ try {
18302
+ const cmdAst = (0, import_bash_parser.default)(cmdPart);
18303
+ for (const cmd of cmdAst.commands) {
18304
+ walkNode(cmd, result);
18305
+ }
18306
+ return { commands: result.commands, hasSubshell: true, subshellCommands: result.subshellCommands, parseError: false };
18307
+ } catch {
18308
+ return { commands: [], hasSubshell: true, subshellCommands: [], parseError: true };
18309
+ }
18310
+ }
18282
18311
  for (const cmd of ast.commands) {
18283
18312
  walkNode(cmd, result);
18284
18313
  }
18285
18314
  return { commands: result.commands, hasSubshell: result.hasSubshell, subshellCommands: result.subshellCommands, parseError: false };
18286
18315
  } catch {
18316
+ if (HEREDOC_REGEX.test(input)) {
18317
+ const firstLine = input.split("\n")[0];
18318
+ const cmdPart = firstLine.replace(/<<-?\s*['"]?\w+['"]?.*$/, "").trim();
18319
+ if (!cmdPart) {
18320
+ return { commands: [], hasSubshell: true, subshellCommands: [], parseError: true };
18321
+ }
18322
+ try {
18323
+ const ast = (0, import_bash_parser.default)(cmdPart);
18324
+ const result = { commands: [], hasSubshell: false, subshellCommands: [] };
18325
+ for (const cmd of ast.commands) {
18326
+ walkNode(cmd, result);
18327
+ }
18328
+ return { commands: result.commands, hasSubshell: true, subshellCommands: result.subshellCommands, parseError: false };
18329
+ } catch {
18330
+ return { commands: [], hasSubshell: true, subshellCommands: [], parseError: true };
18331
+ }
18332
+ }
18287
18333
  return { commands: [], hasSubshell: false, subshellCommands: [], parseError: true };
18288
18334
  }
18289
18335
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-warden",
3
- "version": "1.1.6",
3
+ "version": "1.1.8",
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",
@@ -35,7 +35,9 @@
35
35
  "test:watch": "vitest",
36
36
  "typecheck": "tsc --noEmit",
37
37
  "eval": "node dist/index.cjs",
38
- "prepublishOnly": "pnpm run build && pnpm run test"
38
+ "sync-plugin-version": "node -e \"const p=require('./package.json'),fs=require('fs'),f='.claude-plugin/plugin.json',j=JSON.parse(fs.readFileSync(f));j.version=p.version;fs.writeFileSync(f,JSON.stringify(j,null,2)+'\\n')\"",
39
+ "prepublishOnly": "pnpm run sync-plugin-version && pnpm run build && pnpm run test",
40
+ "postpublish": "claude plugin update claude-warden@local 2>/dev/null; claude plugin update claude-warden@claude-warden 2>/dev/null; echo 'Plugin caches updated'"
39
41
  },
40
42
  "devDependencies": {
41
43
  "@types/node": "^20.0.0",