cc-safety-net 0.8.1 → 0.8.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.
@@ -2865,6 +2865,7 @@ function normalizePathForComparison(p) {
2865
2865
  }
2866
2866
  var REASON_RM_RF = "rm -rf outside cwd is blocked. Use explicit paths within the current directory, or delete manually.";
2867
2867
  var REASON_RM_RF_ROOT_HOME = "rm -rf targeting root or home directory is extremely dangerous and always blocked.";
2868
+ var REASON_RM_HOME_CWD = "rm -rf in home directory is dangerous. Change to a project directory first.";
2868
2869
  function analyzeRm(tokens, options = {}) {
2869
2870
  const {
2870
2871
  cwd,
@@ -2921,18 +2922,16 @@ function classifyTarget(target, ctx) {
2921
2922
  if (isDangerousRootOrHomeTarget(target)) {
2922
2923
  return { kind: "root_or_home_target" };
2923
2924
  }
2924
- const anchoredCwd = ctx.anchoredCwd;
2925
- if (anchoredCwd) {
2926
- if (isCwdSelfTarget(target, anchoredCwd)) {
2927
- return { kind: "cwd_self_target" };
2928
- }
2929
- }
2930
2925
  if (isTempTarget(target, ctx.trustTmpdirVar)) {
2931
2926
  return { kind: "temp_target" };
2932
2927
  }
2928
+ const anchoredCwd = ctx.anchoredCwd;
2933
2929
  if (anchoredCwd) {
2934
2930
  if (isCwdHomeForRmPolicy(anchoredCwd, ctx.homeDir)) {
2935
- return { kind: "root_or_home_target" };
2931
+ return { kind: "home_cwd_target" };
2932
+ }
2933
+ if (isCwdSelfTarget(target, anchoredCwd)) {
2934
+ return { kind: "cwd_self_target" };
2936
2935
  }
2937
2936
  if (isTargetWithinCwd(target, anchoredCwd, ctx.resolvedCwd ?? anchoredCwd)) {
2938
2937
  return { kind: "within_anchored_cwd" };
@@ -2944,10 +2943,12 @@ function reasonForClassification(classification, ctx) {
2944
2943
  switch (classification.kind) {
2945
2944
  case "root_or_home_target":
2946
2945
  return REASON_RM_RF_ROOT_HOME;
2947
- case "cwd_self_target":
2948
- return REASON_RM_RF;
2949
2946
  case "temp_target":
2950
2947
  return null;
2948
+ case "home_cwd_target":
2949
+ return REASON_RM_HOME_CWD;
2950
+ case "cwd_self_target":
2951
+ return REASON_RM_RF;
2951
2952
  case "within_anchored_cwd":
2952
2953
  if (ctx.paranoid) {
2953
2954
  return `${REASON_RM_RF} (SAFETY_NET_PARANOID_RM enabled)`;
@@ -3069,14 +3070,6 @@ function isTargetWithinCwd(target, originalCwd, effectiveCwd) {
3069
3070
  return false;
3070
3071
  }
3071
3072
  }
3072
- function isHomeDirectory(cwd) {
3073
- const home = process.env.HOME ?? homedir3();
3074
- try {
3075
- return normalizePathForComparison(cwd) === normalizePathForComparison(home);
3076
- } catch {
3077
- return false;
3078
- }
3079
- }
3080
3073
 
3081
3074
  // src/core/analyze/parallel.ts
3082
3075
  var REASON_PARALLEL_RM = "parallel rm -rf with dynamic input is dangerous. Use explicit file list instead.";
@@ -3497,7 +3490,6 @@ function matchesBlockArgs(tokens, blockArgs, shortOpts) {
3497
3490
  // src/core/analyze/segment.ts
3498
3491
  var REASON_INTERPRETER_DANGEROUS = "Detected potentially dangerous command in interpreter code.";
3499
3492
  var REASON_INTERPRETER_BLOCKED = "Interpreter one-liners are blocked in paranoid mode.";
3500
- var REASON_RM_HOME_CWD = "rm -rf in home directory is dangerous. Change to a project directory first.";
3501
3493
  function deriveCwdContext(options) {
3502
3494
  const cwdUnknown = options.effectiveCwd === null;
3503
3495
  const cwdForRm = cwdUnknown ? undefined : options.effectiveCwd ?? options.cwd;
@@ -3561,11 +3553,6 @@ function analyzeSegment(tokens, depth, options) {
3561
3553
  }
3562
3554
  }
3563
3555
  if (isRm) {
3564
- if (cwdForRm && isHomeDirectory(cwdForRm)) {
3565
- if (hasRecursiveForceFlags(stripped)) {
3566
- return REASON_RM_HOME_CWD;
3567
- }
3568
- }
3569
3556
  const rmResult = analyzeRm(stripped, {
3570
3557
  cwd: cwdForRm,
3571
3558
  originalCwd,
@@ -4208,7 +4195,7 @@ function detectAllHooks(cwd, options) {
4208
4195
 
4209
4196
  // src/bin/doctor/system-info.ts
4210
4197
  import { spawn } from "node:child_process";
4211
- var CURRENT_VERSION = "0.8.1";
4198
+ var CURRENT_VERSION = "0.8.2";
4212
4199
  var VERSION_FETCH_TIMEOUT_MS = 2000;
4213
4200
  function getPackageVersion() {
4214
4201
  return CURRENT_VERSION;
@@ -4682,19 +4669,9 @@ function explainSegment(tokens, depth, options, steps) {
4682
4669
  return { reason };
4683
4670
  }
4684
4671
  if (isRm) {
4685
- if (effectiveCwd && isHomeDirectory(effectiveCwd) && hasRecursiveForceFlags(strippedTokens)) {
4686
- const reason2 = "rm -rf in home directory is dangerous. Change to a project directory first.";
4687
- steps.push({
4688
- type: "rule-check",
4689
- ruleModule: "rules-rm.ts",
4690
- ruleFunction: "isHomeDirectory",
4691
- matched: true,
4692
- reason: reason2
4693
- });
4694
- return { reason: reason2 };
4695
- }
4696
4672
  const reason = analyzeRm(strippedTokens, {
4697
- cwd: effectiveCwd ?? undefined,
4673
+ cwd: cwdForRm,
4674
+ originalCwd,
4698
4675
  paranoid: options.paranoidRm,
4699
4676
  allowTmpdirVar
4700
4677
  });
@@ -5291,7 +5268,7 @@ function formatTraceJson(result) {
5291
5268
  return JSON.stringify(result, null, 2);
5292
5269
  }
5293
5270
  // src/bin/help.ts
5294
- var version = "0.8.1";
5271
+ var version = "0.8.2";
5295
5272
  var INDENT = " ";
5296
5273
  var PROGRAM_NAME = "cc-safety-net";
5297
5274
  function formatOptionFlags(option) {
@@ -6,4 +6,5 @@ export interface AnalyzeRmOptions {
6
6
  tmpdirOverridden?: boolean;
7
7
  }
8
8
  export declare function analyzeRm(tokens: string[], options?: AnalyzeRmOptions): string | null;
9
+ /** @internal Exported for testing */
9
10
  export declare function isHomeDirectory(cwd: string): boolean;
package/dist/index.js CHANGED
@@ -1724,6 +1724,7 @@ function normalizePathForComparison(p) {
1724
1724
  }
1725
1725
  var REASON_RM_RF = "rm -rf outside cwd is blocked. Use explicit paths within the current directory, or delete manually.";
1726
1726
  var REASON_RM_RF_ROOT_HOME = "rm -rf targeting root or home directory is extremely dangerous and always blocked.";
1727
+ var REASON_RM_HOME_CWD = "rm -rf in home directory is dangerous. Change to a project directory first.";
1727
1728
  function analyzeRm(tokens, options = {}) {
1728
1729
  const {
1729
1730
  cwd,
@@ -1780,18 +1781,16 @@ function classifyTarget(target, ctx) {
1780
1781
  if (isDangerousRootOrHomeTarget(target)) {
1781
1782
  return { kind: "root_or_home_target" };
1782
1783
  }
1783
- const anchoredCwd = ctx.anchoredCwd;
1784
- if (anchoredCwd) {
1785
- if (isCwdSelfTarget(target, anchoredCwd)) {
1786
- return { kind: "cwd_self_target" };
1787
- }
1788
- }
1789
1784
  if (isTempTarget(target, ctx.trustTmpdirVar)) {
1790
1785
  return { kind: "temp_target" };
1791
1786
  }
1787
+ const anchoredCwd = ctx.anchoredCwd;
1792
1788
  if (anchoredCwd) {
1793
1789
  if (isCwdHomeForRmPolicy(anchoredCwd, ctx.homeDir)) {
1794
- return { kind: "root_or_home_target" };
1790
+ return { kind: "home_cwd_target" };
1791
+ }
1792
+ if (isCwdSelfTarget(target, anchoredCwd)) {
1793
+ return { kind: "cwd_self_target" };
1795
1794
  }
1796
1795
  if (isTargetWithinCwd(target, anchoredCwd, ctx.resolvedCwd ?? anchoredCwd)) {
1797
1796
  return { kind: "within_anchored_cwd" };
@@ -1803,10 +1802,12 @@ function reasonForClassification(classification, ctx) {
1803
1802
  switch (classification.kind) {
1804
1803
  case "root_or_home_target":
1805
1804
  return REASON_RM_RF_ROOT_HOME;
1806
- case "cwd_self_target":
1807
- return REASON_RM_RF;
1808
1805
  case "temp_target":
1809
1806
  return null;
1807
+ case "home_cwd_target":
1808
+ return REASON_RM_HOME_CWD;
1809
+ case "cwd_self_target":
1810
+ return REASON_RM_RF;
1810
1811
  case "within_anchored_cwd":
1811
1812
  if (ctx.paranoid) {
1812
1813
  return `${REASON_RM_RF} (SAFETY_NET_PARANOID_RM enabled)`;
@@ -1928,14 +1929,6 @@ function isTargetWithinCwd(target, originalCwd, effectiveCwd) {
1928
1929
  return false;
1929
1930
  }
1930
1931
  }
1931
- function isHomeDirectory(cwd) {
1932
- const home = process.env.HOME ?? homedir();
1933
- try {
1934
- return normalizePathForComparison(cwd) === normalizePathForComparison(home);
1935
- } catch {
1936
- return false;
1937
- }
1938
- }
1939
1932
 
1940
1933
  // src/core/analyze/parallel.ts
1941
1934
  var REASON_PARALLEL_RM = "parallel rm -rf with dynamic input is dangerous. Use explicit file list instead.";
@@ -2356,7 +2349,6 @@ function matchesBlockArgs(tokens, blockArgs, shortOpts) {
2356
2349
  // src/core/analyze/segment.ts
2357
2350
  var REASON_INTERPRETER_DANGEROUS = "Detected potentially dangerous command in interpreter code.";
2358
2351
  var REASON_INTERPRETER_BLOCKED = "Interpreter one-liners are blocked in paranoid mode.";
2359
- var REASON_RM_HOME_CWD = "rm -rf in home directory is dangerous. Change to a project directory first.";
2360
2352
  function deriveCwdContext(options) {
2361
2353
  const cwdUnknown = options.effectiveCwd === null;
2362
2354
  const cwdForRm = cwdUnknown ? undefined : options.effectiveCwd ?? options.cwd;
@@ -2420,11 +2412,6 @@ function analyzeSegment(tokens, depth, options) {
2420
2412
  }
2421
2413
  }
2422
2414
  if (isRm) {
2423
- if (cwdForRm && isHomeDirectory(cwdForRm)) {
2424
- if (hasRecursiveForceFlags(stripped)) {
2425
- return REASON_RM_HOME_CWD;
2426
- }
2427
- }
2428
2415
  const rmResult = analyzeRm(stripped, {
2429
2416
  cwd: cwdForRm,
2430
2417
  originalCwd,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cc-safety-net",
3
- "version": "0.8.1",
3
+ "version": "0.8.2",
4
4
  "description": "Claude Code / OpenCode plugin - block destructive git and filesystem commands before execution",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",