cc-safety-net 0.7.0 → 0.7.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.
@@ -2305,7 +2305,23 @@ function analyzeGitWorktree(tokens) {
2305
2305
  // src/core/rules-rm.ts
2306
2306
  import { realpathSync } from "node:fs";
2307
2307
  import { homedir as homedir3, tmpdir } from "node:os";
2308
- import { normalize, resolve as resolve2 } from "node:path";
2308
+ import { normalize, resolve as resolve2, sep } from "node:path";
2309
+ var IS_WINDOWS = process.platform === "win32";
2310
+ function normalizePathForComparison(p) {
2311
+ let normalized = normalize(p);
2312
+ if (IS_WINDOWS) {
2313
+ normalized = normalized.replace(/\//g, "\\");
2314
+ normalized = normalized.toLowerCase();
2315
+ if (normalized.length > 3 && normalized.endsWith("\\")) {
2316
+ normalized = normalized.slice(0, -1);
2317
+ }
2318
+ } else {
2319
+ if (normalized.length > 1 && normalized.endsWith("/")) {
2320
+ normalized = normalized.slice(0, -1);
2321
+ }
2322
+ }
2323
+ return normalized;
2324
+ }
2309
2325
  var REASON_RM_RF = "rm -rf outside cwd is blocked. Use explicit paths within the current directory, or delete manually.";
2310
2326
  var REASON_RM_RF_ROOT_HOME = "rm -rf targeting root or home directory is extremely dangerous and always blocked.";
2311
2327
  function analyzeRm(tokens, options = {}) {
@@ -2430,7 +2446,9 @@ function isTempTarget(path, allowTmpdirVar) {
2430
2446
  return true;
2431
2447
  }
2432
2448
  const systemTmpdir = tmpdir();
2433
- if (normalized.startsWith(`${systemTmpdir}/`) || normalized === systemTmpdir) {
2449
+ const normalizedTmpdir = normalizePathForComparison(systemTmpdir);
2450
+ const pathToCompare = normalizePathForComparison(normalized);
2451
+ if (pathToCompare.startsWith(`${normalizedTmpdir}${sep}`) || pathToCompare === normalizedTmpdir) {
2434
2452
  return true;
2435
2453
  }
2436
2454
  if (allowTmpdirVar) {
@@ -2448,27 +2466,24 @@ function getHomeDirForRmPolicy() {
2448
2466
  }
2449
2467
  function isCwdHomeForRmPolicy(cwd, homeDir) {
2450
2468
  try {
2451
- const normalizedCwd = normalize(cwd);
2452
- const normalizedHome = normalize(homeDir);
2453
- return normalizedCwd === normalizedHome;
2469
+ return normalizePathForComparison(cwd) === normalizePathForComparison(homeDir);
2454
2470
  } catch {
2455
2471
  return false;
2456
2472
  }
2457
2473
  }
2458
2474
  function isCwdSelfTarget(target, cwd) {
2459
- if (target === "." || target === "./") {
2475
+ if (target === "." || target === "./" || target === ".\\") {
2460
2476
  return true;
2461
2477
  }
2462
2478
  try {
2463
2479
  const resolved = resolve2(cwd, target);
2464
2480
  const realCwd = realpathSync(cwd);
2465
2481
  const realResolved = realpathSync(resolved);
2466
- return realResolved === realCwd;
2482
+ return normalizePathForComparison(realResolved) === normalizePathForComparison(realCwd);
2467
2483
  } catch {
2468
2484
  try {
2469
2485
  const resolved = resolve2(cwd, target);
2470
- const normalizedCwd = normalize(cwd);
2471
- return resolved === normalizedCwd;
2486
+ return normalizePathForComparison(resolved) === normalizePathForComparison(cwd);
2472
2487
  } catch {
2473
2488
  return false;
2474
2489
  }
@@ -2482,20 +2497,21 @@ function isTargetWithinCwd(target, originalCwd, effectiveCwd) {
2482
2497
  if (target.includes("$") || target.includes("`")) {
2483
2498
  return false;
2484
2499
  }
2485
- if (target.startsWith("/")) {
2500
+ if (target.startsWith("/") || /^[A-Za-z]:[\\/]/.test(target)) {
2486
2501
  try {
2487
- const normalizedTarget = normalize(target);
2488
- const normalizedCwd = `${normalize(originalCwd)}/`;
2502
+ const normalizedTarget = normalizePathForComparison(target);
2503
+ const normalizedCwd = `${normalizePathForComparison(originalCwd)}${sep}`;
2489
2504
  return normalizedTarget.startsWith(normalizedCwd);
2490
2505
  } catch {
2491
2506
  return false;
2492
2507
  }
2493
2508
  }
2494
- if (target.startsWith("./") || !target.includes("/")) {
2509
+ if (target.startsWith("./") || target.startsWith(".\\") || !target.includes("/") && !target.includes("\\")) {
2495
2510
  try {
2496
2511
  const resolved = resolve2(resolveCwd, target);
2497
- const normalizedOriginalCwd = normalize(originalCwd);
2498
- return resolved.startsWith(`${normalizedOriginalCwd}/`) || resolved === normalizedOriginalCwd;
2512
+ const normalizedResolved = normalizePathForComparison(resolved);
2513
+ const normalizedOriginalCwd = normalizePathForComparison(originalCwd);
2514
+ return normalizedResolved.startsWith(`${normalizedOriginalCwd}${sep}`) || normalizedResolved === normalizedOriginalCwd;
2499
2515
  } catch {
2500
2516
  return false;
2501
2517
  }
@@ -2505,8 +2521,9 @@ function isTargetWithinCwd(target, originalCwd, effectiveCwd) {
2505
2521
  }
2506
2522
  try {
2507
2523
  const resolved = resolve2(resolveCwd, target);
2508
- const normalizedCwd = normalize(originalCwd);
2509
- return resolved.startsWith(`${normalizedCwd}/`) || resolved === normalizedCwd;
2524
+ const normalizedResolved = normalizePathForComparison(resolved);
2525
+ const normalizedCwd = normalizePathForComparison(originalCwd);
2526
+ return normalizedResolved.startsWith(`${normalizedCwd}${sep}`) || normalizedResolved === normalizedCwd;
2510
2527
  } catch {
2511
2528
  return false;
2512
2529
  }
@@ -2514,9 +2531,7 @@ function isTargetWithinCwd(target, originalCwd, effectiveCwd) {
2514
2531
  function isHomeDirectory(cwd) {
2515
2532
  const home = process.env.HOME ?? homedir3();
2516
2533
  try {
2517
- const normalizedCwd = normalize(cwd);
2518
- const normalizedHome = normalize(home);
2519
- return normalizedCwd === normalizedHome;
2534
+ return normalizePathForComparison(cwd) === normalizePathForComparison(home);
2520
2535
  } catch {
2521
2536
  return false;
2522
2537
  }
@@ -3439,7 +3454,7 @@ function detectAllHooks(cwd, options) {
3439
3454
 
3440
3455
  // src/bin/doctor/system-info.ts
3441
3456
  import { spawn } from "node:child_process";
3442
- var CURRENT_VERSION = "0.7.0";
3457
+ var CURRENT_VERSION = "0.7.1";
3443
3458
  function getPackageVersion() {
3444
3459
  return CURRENT_VERSION;
3445
3460
  }
@@ -3608,6 +3623,7 @@ function printReport(report) {
3608
3623
 
3609
3624
  // src/bin/explain/config.ts
3610
3625
  import { existsSync as existsSync5 } from "node:fs";
3626
+ import { resolve as resolve3 } from "node:path";
3611
3627
 
3612
3628
  // src/core/env.ts
3613
3629
  function envTruthy(name) {
@@ -3637,7 +3653,7 @@ function getConfigSource(options) {
3637
3653
  return { configSource: null, configValid: true };
3638
3654
  }
3639
3655
  function buildAnalyzeOptions(explainOptions) {
3640
- const cwd = explainOptions?.cwd ?? process.cwd();
3656
+ const cwd = resolve3(explainOptions?.cwd ?? process.cwd());
3641
3657
  const paranoidAll = envTruthy("SAFETY_NET_PARANOID");
3642
3658
  return {
3643
3659
  cwd,
@@ -4484,7 +4500,7 @@ function formatTraceJson(result) {
4484
4500
  return JSON.stringify(result, null, 2);
4485
4501
  }
4486
4502
  // src/bin/help.ts
4487
- var version = "0.7.0";
4503
+ var version = "0.7.1";
4488
4504
  var INDENT = " ";
4489
4505
  var PROGRAM_NAME = "cc-safety-net";
4490
4506
  function formatOptionFlags(option) {
@@ -4852,7 +4868,7 @@ async function readStdinAsync() {
4852
4868
  if (process.stdin.isTTY) {
4853
4869
  return null;
4854
4870
  }
4855
- return new Promise((resolve3) => {
4871
+ return new Promise((resolve4) => {
4856
4872
  let data = "";
4857
4873
  process.stdin.setEncoding("utf-8");
4858
4874
  process.stdin.on("data", (chunk) => {
@@ -4860,10 +4876,10 @@ async function readStdinAsync() {
4860
4876
  });
4861
4877
  process.stdin.on("end", () => {
4862
4878
  const trimmed = data.trim();
4863
- resolve3(trimmed || null);
4879
+ resolve4(trimmed || null);
4864
4880
  });
4865
4881
  process.stdin.on("error", () => {
4866
- resolve3(null);
4882
+ resolve4(null);
4867
4883
  });
4868
4884
  });
4869
4885
  }
@@ -4927,7 +4943,7 @@ async function printStatusline() {
4927
4943
 
4928
4944
  // src/bin/verify-config.ts
4929
4945
  import { existsSync as existsSync8, readFileSync as readFileSync6, writeFileSync } from "node:fs";
4930
- import { resolve as resolve3 } from "node:path";
4946
+ import { resolve as resolve4 } from "node:path";
4931
4947
  var HEADER = "Safety Net Config";
4932
4948
  var SEPARATOR = "═".repeat(HEADER.length);
4933
4949
  var SCHEMA_URL = "https://raw.githubusercontent.com/kenryu42/claude-code-safety-net/main/assets/cc-safety-net.schema.json";
@@ -4992,7 +5008,7 @@ function verifyConfig(options = {}) {
4992
5008
  const result = validateConfigFile(projectConfig);
4993
5009
  configsChecked.push({
4994
5010
  scope: "Project",
4995
- path: resolve3(projectConfig),
5011
+ path: resolve4(projectConfig),
4996
5012
  result
4997
5013
  });
4998
5014
  if (result.errors.length > 0) {
package/dist/index.js CHANGED
@@ -1166,7 +1166,23 @@ function analyzeGitWorktree(tokens) {
1166
1166
  // src/core/rules-rm.ts
1167
1167
  import { realpathSync } from "node:fs";
1168
1168
  import { homedir, tmpdir } from "node:os";
1169
- import { normalize, resolve } from "node:path";
1169
+ import { normalize, resolve, sep } from "node:path";
1170
+ var IS_WINDOWS = process.platform === "win32";
1171
+ function normalizePathForComparison(p) {
1172
+ let normalized = normalize(p);
1173
+ if (IS_WINDOWS) {
1174
+ normalized = normalized.replace(/\//g, "\\");
1175
+ normalized = normalized.toLowerCase();
1176
+ if (normalized.length > 3 && normalized.endsWith("\\")) {
1177
+ normalized = normalized.slice(0, -1);
1178
+ }
1179
+ } else {
1180
+ if (normalized.length > 1 && normalized.endsWith("/")) {
1181
+ normalized = normalized.slice(0, -1);
1182
+ }
1183
+ }
1184
+ return normalized;
1185
+ }
1170
1186
  var REASON_RM_RF = "rm -rf outside cwd is blocked. Use explicit paths within the current directory, or delete manually.";
1171
1187
  var REASON_RM_RF_ROOT_HOME = "rm -rf targeting root or home directory is extremely dangerous and always blocked.";
1172
1188
  function analyzeRm(tokens, options = {}) {
@@ -1291,7 +1307,9 @@ function isTempTarget(path, allowTmpdirVar) {
1291
1307
  return true;
1292
1308
  }
1293
1309
  const systemTmpdir = tmpdir();
1294
- if (normalized.startsWith(`${systemTmpdir}/`) || normalized === systemTmpdir) {
1310
+ const normalizedTmpdir = normalizePathForComparison(systemTmpdir);
1311
+ const pathToCompare = normalizePathForComparison(normalized);
1312
+ if (pathToCompare.startsWith(`${normalizedTmpdir}${sep}`) || pathToCompare === normalizedTmpdir) {
1295
1313
  return true;
1296
1314
  }
1297
1315
  if (allowTmpdirVar) {
@@ -1309,27 +1327,24 @@ function getHomeDirForRmPolicy() {
1309
1327
  }
1310
1328
  function isCwdHomeForRmPolicy(cwd, homeDir) {
1311
1329
  try {
1312
- const normalizedCwd = normalize(cwd);
1313
- const normalizedHome = normalize(homeDir);
1314
- return normalizedCwd === normalizedHome;
1330
+ return normalizePathForComparison(cwd) === normalizePathForComparison(homeDir);
1315
1331
  } catch {
1316
1332
  return false;
1317
1333
  }
1318
1334
  }
1319
1335
  function isCwdSelfTarget(target, cwd) {
1320
- if (target === "." || target === "./") {
1336
+ if (target === "." || target === "./" || target === ".\\") {
1321
1337
  return true;
1322
1338
  }
1323
1339
  try {
1324
1340
  const resolved = resolve(cwd, target);
1325
1341
  const realCwd = realpathSync(cwd);
1326
1342
  const realResolved = realpathSync(resolved);
1327
- return realResolved === realCwd;
1343
+ return normalizePathForComparison(realResolved) === normalizePathForComparison(realCwd);
1328
1344
  } catch {
1329
1345
  try {
1330
1346
  const resolved = resolve(cwd, target);
1331
- const normalizedCwd = normalize(cwd);
1332
- return resolved === normalizedCwd;
1347
+ return normalizePathForComparison(resolved) === normalizePathForComparison(cwd);
1333
1348
  } catch {
1334
1349
  return false;
1335
1350
  }
@@ -1343,20 +1358,21 @@ function isTargetWithinCwd(target, originalCwd, effectiveCwd) {
1343
1358
  if (target.includes("$") || target.includes("`")) {
1344
1359
  return false;
1345
1360
  }
1346
- if (target.startsWith("/")) {
1361
+ if (target.startsWith("/") || /^[A-Za-z]:[\\/]/.test(target)) {
1347
1362
  try {
1348
- const normalizedTarget = normalize(target);
1349
- const normalizedCwd = `${normalize(originalCwd)}/`;
1363
+ const normalizedTarget = normalizePathForComparison(target);
1364
+ const normalizedCwd = `${normalizePathForComparison(originalCwd)}${sep}`;
1350
1365
  return normalizedTarget.startsWith(normalizedCwd);
1351
1366
  } catch {
1352
1367
  return false;
1353
1368
  }
1354
1369
  }
1355
- if (target.startsWith("./") || !target.includes("/")) {
1370
+ if (target.startsWith("./") || target.startsWith(".\\") || !target.includes("/") && !target.includes("\\")) {
1356
1371
  try {
1357
1372
  const resolved = resolve(resolveCwd, target);
1358
- const normalizedOriginalCwd = normalize(originalCwd);
1359
- return resolved.startsWith(`${normalizedOriginalCwd}/`) || resolved === normalizedOriginalCwd;
1373
+ const normalizedResolved = normalizePathForComparison(resolved);
1374
+ const normalizedOriginalCwd = normalizePathForComparison(originalCwd);
1375
+ return normalizedResolved.startsWith(`${normalizedOriginalCwd}${sep}`) || normalizedResolved === normalizedOriginalCwd;
1360
1376
  } catch {
1361
1377
  return false;
1362
1378
  }
@@ -1366,8 +1382,9 @@ function isTargetWithinCwd(target, originalCwd, effectiveCwd) {
1366
1382
  }
1367
1383
  try {
1368
1384
  const resolved = resolve(resolveCwd, target);
1369
- const normalizedCwd = normalize(originalCwd);
1370
- return resolved.startsWith(`${normalizedCwd}/`) || resolved === normalizedCwd;
1385
+ const normalizedResolved = normalizePathForComparison(resolved);
1386
+ const normalizedCwd = normalizePathForComparison(originalCwd);
1387
+ return normalizedResolved.startsWith(`${normalizedCwd}${sep}`) || normalizedResolved === normalizedCwd;
1371
1388
  } catch {
1372
1389
  return false;
1373
1390
  }
@@ -1375,9 +1392,7 @@ function isTargetWithinCwd(target, originalCwd, effectiveCwd) {
1375
1392
  function isHomeDirectory(cwd) {
1376
1393
  const home = process.env.HOME ?? homedir();
1377
1394
  try {
1378
- const normalizedCwd = normalize(cwd);
1379
- const normalizedHome = normalize(home);
1380
- return normalizedCwd === normalizedHome;
1395
+ return normalizePathForComparison(cwd) === normalizePathForComparison(home);
1381
1396
  } catch {
1382
1397
  return false;
1383
1398
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cc-safety-net",
3
- "version": "0.7.0",
3
+ "version": "0.7.1",
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",