claude-warden 1.1.0 → 1.1.4

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.
Files changed (3) hide show
  1. package/README.md +3 -3
  2. package/dist/index.cjs +55 -5
  3. package/package.json +10 -11
package/README.md CHANGED
@@ -15,7 +15,7 @@ Warden hooks into Claude Code's `PreToolUse` event and **parses every shell comm
15
15
  This AST-based approach enables:
16
16
 
17
17
  - **Pipe and chain decomposition**: `cat file | grep pattern | wc -l` is parsed into three commands, each evaluated separately. All safe → auto-allow. One dangerous → deny the whole pipeline.
18
- - **Argument-aware rules**: `git status` → allow, `git push --force` → prompt. `rm temp.txt` → allow, `rm -rf /` → deny. The evaluator matches against argument patterns, not just command names.
18
+ - **Argument-aware rules**: `git status` → allow, `git push --force` → prompt. `rm temp.txt` → allow, `rm -rf /` → prompt. The evaluator matches against argument patterns, not just command names.
19
19
  - **Recursive evaluation of remote commands**: `ssh devserver 'cat /etc/hosts'` → Warden extracts the remote command, parses it through the same pipeline, and allows it. `ssh devserver 'sudo rm -rf /'` → denied. Same for `docker exec`, `kubectl exec`, and `sprite exec`.
20
20
  - **Shell wrapper unwrapping**: `sh -c "npm run build && npm test"` → the inner command is extracted and recursively parsed/evaluated, not treated as an opaque string.
21
21
  - **Env prefix handling**: `NODE_ENV=production npm run build` → correctly evaluates `npm run build`, ignoring the env prefix.
@@ -32,7 +32,7 @@ The result: **100+ common dev commands auto-approved**, dangerous commands auto-
32
32
  | `cat file \| grep pattern \| wc -l` | Prompted | Auto-allowed (3 safe commands) |
33
33
  | `npm run build && npm test` | Prompted | Auto-allowed |
34
34
  | `git push --force origin main` | Prompted | Prompted (force push is risky) |
35
- | `sudo rm -rf /` | Prompted | Auto-denied |
35
+ | `sudo rm -rf /` | Prompted | Auto-denied (sudo is blocked) |
36
36
  | `ssh devserver cat /etc/hosts` | Prompted | Auto-allowed (trusted host + safe cmd) |
37
37
  | `ssh devserver sudo rm -rf /` | Prompted | Auto-denied (trusted host + dangerous cmd) |
38
38
 
@@ -147,7 +147,7 @@ File readers (`cat`, `head`, `tail`, `less`), search tools (`grep`, `rg`, `find`
147
147
  ### Conditional rules
148
148
  Commands like `node`, `npx`, `docker`, `ssh`, `git push --force`, `rm`, `chmod` have argument-aware rules. For example:
149
149
  - `git` is allowed but `git push --force` triggers a prompt
150
- - `rm temp.txt` is allowed but `rm -rf /` is denied
150
+ - `rm temp.txt` is allowed but `rm -rf /` is prompted
151
151
  - `chmod 644 file` prompts but `chmod -R 777 /var` is denied
152
152
 
153
153
  ### Trusted remote targets
package/dist/index.cjs CHANGED
@@ -18888,6 +18888,11 @@ var DEFAULT_CONFIG = {
18888
18888
  "fnm",
18889
18889
  "rbenv",
18890
18890
  "pyenv",
18891
+ // Terminal
18892
+ "stty",
18893
+ "tput",
18894
+ "reset",
18895
+ "clear",
18891
18896
  // Misc safe
18892
18897
  "cd",
18893
18898
  "pushd",
@@ -18931,6 +18936,36 @@ var DEFAULT_CONFIG = {
18931
18936
  "launchctl"
18932
18937
  ],
18933
18938
  rules: [
18939
+ // --- CLI tools ---
18940
+ {
18941
+ command: "claude",
18942
+ default: "ask",
18943
+ argPatterns: [
18944
+ { match: { anyArgMatches: ["^--(version|help)$", "^-[vh]$"] }, decision: "allow", description: "Version/help flags" }
18945
+ ]
18946
+ },
18947
+ // --- Shell interpreters ---
18948
+ {
18949
+ command: "bash",
18950
+ default: "ask",
18951
+ argPatterns: [
18952
+ { match: { anyArgMatches: ["^--(version|help)$"] }, decision: "allow", description: "Version/help flags" }
18953
+ ]
18954
+ },
18955
+ {
18956
+ command: "sh",
18957
+ default: "ask",
18958
+ argPatterns: [
18959
+ { match: { anyArgMatches: ["^--(version|help)$"] }, decision: "allow", description: "Version/help flags" }
18960
+ ]
18961
+ },
18962
+ {
18963
+ command: "zsh",
18964
+ default: "ask",
18965
+ argPatterns: [
18966
+ { match: { anyArgMatches: ["^--(version|help)$"] }, decision: "allow", description: "Version/help flags" }
18967
+ ]
18968
+ },
18934
18969
  // --- Node.js ecosystem ---
18935
18970
  {
18936
18971
  command: "node",
@@ -19075,7 +19110,7 @@ var DEFAULT_CONFIG = {
19075
19110
  command: "rm",
19076
19111
  default: "ask",
19077
19112
  argPatterns: [
19078
- { match: { argsMatch: ["-[^\\s]*r[^\\s]*f|-[^\\s]*f[^\\s]*r"] }, decision: "deny", reason: "Recursive force delete (rm -rf)" },
19113
+ { match: { argsMatch: ["-[^\\s]*r[^\\s]*f|-[^\\s]*f[^\\s]*r"] }, decision: "ask", reason: "Recursive force delete (rm -rf)" },
19079
19114
  { match: { argsMatch: ["-[^\\s]*r"] }, decision: "ask", reason: "Recursive delete" },
19080
19115
  { match: { argCount: { max: 3 }, not: false }, decision: "allow", description: "Deleting a small number of non-recursive files" }
19081
19116
  ]
@@ -19230,9 +19265,12 @@ function generateAllowSnippet(details) {
19230
19265
  return lines.join("\n");
19231
19266
  }
19232
19267
  function formatSystemMessage(decision, rawCommand, details) {
19233
- const header = decision === "deny" ? "[warden] Command blocked" : "[warden] Command flagged for review";
19234
- const lines = [header, ""];
19235
19268
  const relevant = details.filter((d) => d.decision !== "allow");
19269
+ if (decision === "ask") {
19270
+ const parts = relevant.map((d) => `\`${d.command}\`: ${d.reason}`);
19271
+ return `[warden] ${parts.join(" | ")} \u2014 To auto-allow, see /warden-allow`;
19272
+ }
19273
+ const lines = ["[warden] Command blocked", ""];
19236
19274
  if (relevant.length > 0) {
19237
19275
  for (const d of relevant) {
19238
19276
  lines.push(`- \`${d.command}\`: ${d.reason}`);
@@ -19291,14 +19329,26 @@ async function main() {
19291
19329
  }
19292
19330
  if (result.decision === "deny") {
19293
19331
  const msg2 = formatSystemMessage("deny", command, result.details);
19294
- const output2 = { systemMessage: msg2 };
19332
+ const output2 = {
19333
+ hookSpecificOutput: {
19334
+ hookEventName: "PreToolUse",
19335
+ permissionDecision: "deny",
19336
+ permissionDecisionReason: msg2
19337
+ }
19338
+ };
19295
19339
  process.stdout.write(JSON.stringify(output2));
19296
19340
  process.stderr.write(`[warden] Blocked: ${result.reason}
19297
19341
  `);
19298
19342
  process.exit(2);
19299
19343
  }
19300
19344
  const msg = formatSystemMessage("ask", command, result.details);
19301
- const output = { systemMessage: msg };
19345
+ const output = {
19346
+ hookSpecificOutput: {
19347
+ hookEventName: "PreToolUse",
19348
+ permissionDecision: "ask",
19349
+ permissionDecisionReason: msg
19350
+ }
19351
+ };
19302
19352
  process.stdout.write(JSON.stringify(output));
19303
19353
  process.exit(0);
19304
19354
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-warden",
3
- "version": "1.1.0",
3
+ "version": "1.1.4",
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",
@@ -28,15 +28,6 @@
28
28
  "README.md",
29
29
  "LICENSE"
30
30
  ],
31
- "scripts": {
32
- "build": "tsup",
33
- "dev": "tsup --watch",
34
- "test": "vitest run",
35
- "test:watch": "vitest",
36
- "typecheck": "tsc --noEmit",
37
- "eval": "node dist/index.cjs",
38
- "prepublishOnly": "pnpm run build && pnpm run test"
39
- },
40
31
  "devDependencies": {
41
32
  "@types/node": "^20.0.0",
42
33
  "bash-parser": "^0.5.0",
@@ -44,5 +35,13 @@
44
35
  "typescript": "^5.4.0",
45
36
  "vitest": "^1.6.0",
46
37
  "yaml": "^2.4.0"
38
+ },
39
+ "scripts": {
40
+ "build": "tsup",
41
+ "dev": "tsup --watch",
42
+ "test": "vitest run",
43
+ "test:watch": "vitest",
44
+ "typecheck": "tsc --noEmit",
45
+ "eval": "node dist/index.cjs"
47
46
  }
48
- }
47
+ }