@verndale/ai-commit 2.5.2 → 2.5.3

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
@@ -47,7 +47,7 @@ pnpm exec ai-commit init
47
47
  | Husky | Runs **`npx husky@9 init`** at the **git root** if **`husky.sh`** is missing under the resolved hooks directory. |
48
48
  | Hooks directory | **`core.hooksPath`** relative to the git root when set; otherwise **`<git-root>/.husky`**. Falls back to **`.husky`** at the git root with a warning if the config path is invalid or outside the repo. |
49
49
  | `package.json` | Adds missing **`commit`**, **`prepare`**, **`husky`** entries when **`package.json`** exists at the package root. |
50
- | Hooks | Writes **`prepare-commit-msg`** and **`commit-msg`** in the hooks directory. If package root ≠ git root, each hook **`cd`s** into the package directory before **`pnpm exec ai-commit`** / **`npx`**. |
50
+ | Hooks | Writes **`prepare-commit-msg`** and **`commit-msg`** in the hooks directory. If package root ≠ git root, each hook **`cd`s** into the package directory before **`pnpm exec ai-commit`** / **`npx`**. Removes a **stock** **`.husky/pre-commit`** that is only **`npm`**/**`pnpm`**/**`yarn`** **`test`** (Husky’s **`init`** default) so that hook does not block commits; custom **pre-commit** files are kept. |
51
51
 
52
52
  If **`package.json`** changed, run **`pnpm install`** (or `npm install`) again.
53
53
 
@@ -171,6 +171,8 @@ pnpm exec ai-commit lint --edit "$1"
171
171
 
172
172
  Hooks from **`init`** use **`pnpm exec ai-commit`** when **`pnpm-lock.yaml`** exists in the **package root**; otherwise **`npx --no ai-commit`**. In a monorepo, generated hooks **`cd`** from the git root into that package directory first. Edit the files if you use another runner.
173
173
 
174
+ **`pre-commit`:** Husky’s **`init`** often adds **`.husky/pre-commit`** with only **`pnpm test`** (or **`npm test`** / **`yarn test`**). That can block **`git commit`** when tests fail. On each **`ai-commit init`**, **`init`** removes **only** that stock one-liner (or the same command behind a minimal **`husky.sh`** wrapper). If you add other lines (e.g. **lint-staged**), the file is left unchanged. Add your own **pre-commit** or rely on **CI** if you still want tests on every commit.
175
+
174
176
  **Already using Husky?** If **`.husky/_/husky.sh`** exists, **`init`** does not run **`npx husky@9 init`**. **`package.json`** is only amended for missing **`commit`**, **`prepare`**, or **`devDependencies.husky`**. Existing **`.husky/prepare-commit-msg`** and **`.husky/commit-msg`** are not overwritten unless you use **`ai-commit init --force`**.
175
177
 
176
178
  ---
package/bin/cli.js CHANGED
@@ -22,6 +22,7 @@ const {
22
22
  detectPackageExec,
23
23
  hookScript,
24
24
  runHuskyInit,
25
+ removeHuskyDefaultPreCommitIfPresent,
25
26
  mergePackageJsonForAiCommit,
26
27
  warnIfPrepareMissingHusky,
27
28
  } = require("../lib/init-workspace.js");
@@ -229,6 +230,13 @@ function cmdInit(argv) {
229
230
  fs.mkdirSync(huskyDir, { recursive: true });
230
231
  }
231
232
 
233
+ for (const abs of removeHuskyDefaultPreCommitIfPresent(gitRoot, huskyDir)) {
234
+ const rel = path.relative(cwd, abs) || path.basename(abs);
235
+ process.stdout.write(
236
+ `Removed Husky default pre-commit (${rel}); add your own .husky/pre-commit or use CI if you want tests on every commit.\n`,
237
+ );
238
+ }
239
+
232
240
  const execPrefix = detectPackageExec(packageRoot);
233
241
  const preparePath = path.join(huskyDir, "prepare-commit-msg");
234
242
  const commitMsgPath = path.join(huskyDir, "commit-msg");
@@ -61,6 +61,92 @@ function runHuskyInit(cwd) {
61
61
  return { ok: status === 0, status };
62
62
  }
63
63
 
64
+ /**
65
+ * Husky `init` writes `.husky/pre-commit` with only `(npm|pnpm|yarn) test` (see husky bin.js).
66
+ * That often breaks commits when tests fail or are slow. Match that template and optional
67
+ * minimal shebang + husky.sh wrapper so we do not delete custom hooks.
68
+ * @param {string} raw
69
+ * @returns {boolean}
70
+ */
71
+ function isHuskyDefaultPreCommitContent(raw) {
72
+ const text = raw.replace(/\r\n/g, "\n").trim();
73
+ const nonEmpty = text
74
+ .split("\n")
75
+ .map((l) => l.trim())
76
+ .filter((l) => {
77
+ if (l.length === 0) {
78
+ return false;
79
+ }
80
+ if (/^#!\//.test(l)) {
81
+ return true;
82
+ }
83
+ return !/^\s*#/.test(l);
84
+ });
85
+ if (nonEmpty.length === 0) {
86
+ return false;
87
+ }
88
+ if (nonEmpty.length === 1) {
89
+ return /^(npm|pnpm|yarn)\s+test$/i.test(nonEmpty[0]);
90
+ }
91
+ const last = nonEmpty[nonEmpty.length - 1];
92
+ if (!/^(npm|pnpm|yarn)\s+test$/i.test(last)) {
93
+ return false;
94
+ }
95
+ const head = nonEmpty.slice(0, -1);
96
+ const shebang = /^#!\/usr\/bin\/env\s+sh$/.test(head[0]);
97
+ const huskySource = head.some((l) => {
98
+ if (/\bhusky\.sh\b/.test(l)) {
99
+ return true;
100
+ }
101
+ if (l.includes("$(dirname") && (l.includes("_/husky.sh") || l.includes('_/h"'))) {
102
+ return true;
103
+ }
104
+ return false;
105
+ });
106
+ return shebang && huskySource && head.length <= 3;
107
+ }
108
+
109
+ /**
110
+ * Remove Husky’s stock `pre-commit` (e.g. `pnpm test`) from common paths. Custom hooks are kept.
111
+ * @param {string} gitRoot
112
+ * @param {string} huskyDir Resolved hooks directory (from `core.hooksPath` or `.husky`)
113
+ * @returns {string[]} Absolute paths of removed files
114
+ */
115
+ function removeHuskyDefaultPreCommitIfPresent(gitRoot, huskyDir) {
116
+ const candidates = [
117
+ path.join(huskyDir, "pre-commit"),
118
+ path.join(gitRoot, ".husky", "pre-commit"),
119
+ ];
120
+ const seen = new Set();
121
+ const removed = [];
122
+ for (const filePath of candidates) {
123
+ const abs = path.resolve(filePath);
124
+ if (seen.has(abs)) {
125
+ continue;
126
+ }
127
+ seen.add(abs);
128
+ if (!fs.existsSync(abs)) {
129
+ continue;
130
+ }
131
+ let raw;
132
+ try {
133
+ raw = fs.readFileSync(abs, "utf8");
134
+ } catch {
135
+ continue;
136
+ }
137
+ if (!isHuskyDefaultPreCommitContent(raw)) {
138
+ continue;
139
+ }
140
+ try {
141
+ fs.unlinkSync(abs);
142
+ removed.push(abs);
143
+ } catch {
144
+ // ignore
145
+ }
146
+ }
147
+ return removed;
148
+ }
149
+
64
150
  /**
65
151
  * Ensure `commit` script, `prepare` for husky, and `devDependencies.husky`. Does not remove existing scripts.
66
152
  * @param {string} packageJsonPath
@@ -117,6 +203,7 @@ module.exports = {
117
203
  detectPackageExec,
118
204
  hookScript,
119
205
  runHuskyInit,
206
+ removeHuskyDefaultPreCommitIfPresent,
120
207
  mergePackageJsonForAiCommit,
121
208
  warnIfPrepareMissingHusky,
122
209
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@verndale/ai-commit",
3
- "version": "2.5.2",
3
+ "version": "2.5.3",
4
4
  "description": "AI-assisted conventional commits with bundled commitlint — one install, aligned rules",
5
5
  "license": "MIT",
6
6
  "author": "Verndale",