claude-code-token-saver 0.1.3 → 0.1.5

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.
package/README.md CHANGED
@@ -28,7 +28,7 @@ curl -fsSL https://raw.githubusercontent.com/NgTrgGiang/claude-code-token-saver/
28
28
  bash setup-claude-code.sh
29
29
  ```
30
30
 
31
- Cả 3 cách đều **không ghi đè** file đã tồn tại. Toàn bộ nội dung nằm trong `.claude/` (+ `CLAUDE.md` ở gốc), an toàn để commit chia sẻ cho cả team.
31
+ Cả 3 cách đều **không ghi đè** file đã tồn tại. Toàn bộ nội dung nằm trong `.claude/` (+ `CLAUDE.md` ở gốc). Đây là **đồ dùng local, tái tạo được** — cần đâu cài đó, nên tool tự thêm chúng vào `.gitignore` để repo dự án của bạn luôn sạch.
32
32
 
33
33
  > Mọi cách đều cần **bash** trên máy. Trên Windows: dùng Git Bash / WSL, hoặc cài [Git for Windows](https://git-scm.com/download/win).
34
34
 
@@ -67,12 +67,9 @@ Xong bước này, dự án của bạn sẽ mọc ra `CLAUDE.md` + thư mục `
67
67
 
68
68
  Mở `CLAUDE.md`, viết ngắn gọn phần **Architecture** (code nằm đâu), **Conventions** (quy ước riêng), và **lệnh dev/run**. Đây là phần Claude đọc mỗi lượt nên giữ thật gọn.
69
69
 
70
- ### Bước 3 — Commit cho cả team
70
+ ### Bước 3 — Không cần commit
71
71
 
72
- ```bash
73
- git add CLAUDE.md .claude/
74
- git commit -m "Add Claude Code rails"
75
- ```
72
+ Tool đã tự thêm `.claude/` và `CLAUDE.md` vào `.gitignore`, nên repo dự án của bạn vẫn sạch. Cần dùng ở máy/dự án khác thì **chạy lại installer** là có ngay — không phải commit hay chia sẻ gì cả.
76
73
 
77
74
  ### Bước 4 — Làm việc trong Claude Code
78
75
 
@@ -97,7 +94,7 @@ Trong lúc đó các hook tự chạy ngầm: chặn lệnh nguy hiểm, tự fo
97
94
  | Đường dẫn | Công dụng |
98
95
  |-----------|-----------|
99
96
  | `CLAUDE.md` | Bộ nhớ dự án gọn (< ~200 dòng): commands, kiến trúc, quy ước, gotchas, workflow |
100
- | `.claude/settings.json` | Hooks + danh sách chặn quyền (chặn đọc `.env`, `secrets/`) **nên commit** |
97
+ | `.claude/settings.json` | Hooks + danh sách chặn quyền (chặn đọc `.env`, `secrets/`) + status line |
101
98
  | `.claude/hooks/guard-bash.sh` | Chặn lệnh shell nguy hiểm (`rm -rf /`, fork bomb, `git push --force`, `chmod -R 777`, pipe script từ mạng vào shell) |
102
99
  | `.claude/hooks/format-file.sh` | Tự động format file sau khi Claude ghi (prettier / ruff / gofmt / rustfmt) |
103
100
  | `.claude/hooks/statusline.js` | Vẽ thanh usage 5 giờ ở đáy phiên (chỉ khi bật usage; xem mục bên dưới) |
package/bin/cli.js CHANGED
@@ -22,32 +22,42 @@ if (!fs.existsSync(script)) {
22
22
  process.exit(1);
23
23
  }
24
24
 
25
- // Candidate bash locations. First hit that runs wins.
25
+ // WSL's bash is often first on the Windows PATH, but it cannot open C:/... paths
26
+ // (it needs /mnt/c/...). So on Windows we prefer Git Bash (MSYS), which does
27
+ // understand C:/... paths, and only fall back to plain `bash` / WSL afterwards.
28
+ const WSL_BASH = "C:\\Windows\\System32\\bash.exe";
29
+
26
30
  function candidateBashes() {
27
- const list = ["bash"];
28
- if (process.platform === "win32") {
29
- const pf = process.env["ProgramFiles"] || "C:\\Program Files";
30
- const pf86 = process.env["ProgramFiles(x86)"] || "C:\\Program Files (x86)";
31
- const local = process.env["LOCALAPPDATA"] || "";
32
- list.push(
33
- path.join(pf, "Git", "bin", "bash.exe"),
34
- path.join(pf, "Git", "usr", "bin", "bash.exe"),
35
- path.join(pf86, "Git", "bin", "bash.exe"),
36
- local && path.join(local, "Programs", "Git", "bin", "bash.exe"),
37
- "C:\\Windows\\System32\\bash.exe" // WSL
38
- );
39
- }
40
- return list.filter(Boolean);
31
+ if (process.platform !== "win32") return ["bash"];
32
+ const pf = process.env["ProgramFiles"] || "C:\\Program Files";
33
+ const pf86 = process.env["ProgramFiles(x86)"] || "C:\\Program Files (x86)";
34
+ const local = process.env["LOCALAPPDATA"] || "";
35
+ return [
36
+ path.join(pf, "Git", "bin", "bash.exe"),
37
+ path.join(pf, "Git", "usr", "bin", "bash.exe"),
38
+ path.join(pf86, "Git", "bin", "bash.exe"),
39
+ local && path.join(local, "Programs", "Git", "bin", "bash.exe"),
40
+ "bash", // PATH (may be WSL; tried only if no Git Bash is present)
41
+ WSL_BASH, // WSL, last resort
42
+ ].filter(Boolean);
41
43
  }
42
44
 
43
45
  const args = process.argv.slice(2);
44
46
 
45
- // Pass a forward-slash path to bash. On Windows the script path uses
46
- // backslashes (C:\Users\...), which bash would treat as escape sequences and
47
- // mangle (C:UsersAdmin...). Git Bash / MSYS accept C:/Users/... just fine.
48
- const scriptArg = script.replace(/\\/g, "/");
47
+ // Pass a forward-slash path to bash. On Windows the script path uses backslashes
48
+ // (C:\Users\...), which bash would treat as escape sequences and mangle
49
+ // (C:UsersAdmin...). Git Bash / MSYS accept C:/Users/... just fine.
50
+ const scriptFwd = script.replace(/\\/g, "/");
51
+
52
+ // WSL needs a /mnt/<drive>/... path instead of C:/...
53
+ function toWslPath(p) {
54
+ return p.replace(/^([A-Za-z]):\//, function (_m, d) {
55
+ return "/mnt/" + d.toLowerCase() + "/";
56
+ });
57
+ }
49
58
 
50
59
  for (const bash of candidateBashes()) {
60
+ const scriptArg = bash === WSL_BASH ? toWslPath(scriptFwd) : scriptFwd;
51
61
  const res = spawnSync(bash, [scriptArg, ...args], {
52
62
  stdio: "inherit",
53
63
  cwd: process.cwd(),
@@ -55,6 +65,9 @@ for (const bash of candidateBashes()) {
55
65
  if (res.error && res.error.code === "ENOENT") {
56
66
  continue; // this bash isn't here, try the next candidate
57
67
  }
68
+ if (res.status === 127) {
69
+ continue; // bash ran but couldn't open the script (e.g. WSL + C:/ path) → next
70
+ }
58
71
  process.exit(res.status == null ? 1 : res.status);
59
72
  }
60
73
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-code-token-saver",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "One-shot installer that adds token-saving Claude Code rails (CLAUDE.md, hooks, subagents, slash commands, dev-docs) to any git repo.",
5
5
  "bin": {
6
6
  "claude-code-token-saver": "bin/cli.js",
@@ -10,8 +10,9 @@
10
10
  # bash setup-claude-code.sh
11
11
  #
12
12
  # It never overwrites existing files unless you pass --force.
13
- # Everything it writes lives under .claude/ (+ CLAUDE.md at the root),
14
- # so it is safe to commit to your repo and share with your team.
13
+ # Everything it writes lives under .claude/ (+ CLAUDE.md at the root) and is a
14
+ # local, regenerable scaffold the installer git-ignores it so your repo stays
15
+ # clean; just re-run it wherever you want the rails.
15
16
  # ---------------------------------------------------------------------------
16
17
 
17
18
  set -euo pipefail
@@ -144,7 +145,7 @@ EOF
144
145
 
145
146
  # ===========================================================================
146
147
  # 2. Hooks + permissions — .claude/settings.json
147
- # (safe to commit; secrets go in settings.local.json)
148
+ # (local scaffold, git-ignored; personal overrides go in settings.local.json)
148
149
  # ===========================================================================
149
150
  # Quality gate: block `git commit` unless tests pass.
150
151
  # Safety gate: block obviously destructive shell commands.
@@ -414,16 +415,18 @@ and compaction. Update with `/save`. Resume a session with:
414
415
  Files (per active task): plan.md, context.md, tasks.md, and SPEC.md (from /plan).
415
416
  EOF
416
417
 
417
- # Add ignore hints for personal/local settings, without clobbering an existing file.
418
+ # These rails are a local, regenerable scaffold (re-run this installer anytime to
419
+ # recreate them), so keep them out of the project's git. Add the ignore lines
420
+ # without clobbering an existing .gitignore.
418
421
  if [[ -f .gitignore ]]; then
419
- for line in ".claude/settings.local.json" ".claude/dev-docs/*.local.md"; do
422
+ for line in ".claude/" "CLAUDE.md"; do
420
423
  grep -qxF "$line" .gitignore 2>/dev/null || { echo "$line" >> .gitignore; ok ".gitignore += $line"; }
421
424
  done
422
425
  else
423
426
  write_file ".gitignore" <<'EOF'
424
- # Claude Code personal/local overrides (keep out of git)
425
- .claude/settings.local.json
426
- .claude/dev-docs/*.local.md
427
+ # Claude Code rails (installed by claude-code-token-saver; re-run to regenerate)
428
+ .claude/
429
+ CLAUDE.md
427
430
  EOF
428
431
  fi
429
432
 
@@ -435,7 +438,7 @@ info "Done. Here's what got installed:"
435
438
  cat <<EOF
436
439
 
437
440
  CLAUDE.md lean project memory (fill in the blanks)
438
- .claude/settings.json hooks + permission deny-list (commit this)
441
+ .claude/settings.json hooks + permission deny-list + status line
439
442
  .claude/hooks/guard-bash.sh blocks destructive shell commands
440
443
  .claude/hooks/format-file.sh auto-formats files Claude writes
441
444
  .claude/agents/explorer.md read-only investigator (own context)
@@ -448,7 +451,7 @@ cat <<EOF
448
451
 
449
452
  ${c_ylw}Next:${c_reset}
450
453
  1. Open CLAUDE.md and fill in Architecture / Conventions / dev command.
451
- 2. Commit .claude/ and CLAUDE.md so your team gets the same rails.
454
+ 2. These rails are git-ignored (local + regenerable) re-run this anytime.
452
455
  3. In Claude Code: run /hooks to confirm hooks are registered.
453
456
  4. Try the habits: /plan → /clear → build → /verify → /save.
454
457