@verndale/ai-commit 2.4.1 → 2.4.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.
package/.env-example CHANGED
@@ -9,21 +9,30 @@ OPENAI_API_KEY=
9
9
  # Optional — default is gpt-4o-mini
10
10
  # COMMIT_AI_MODEL=
11
11
 
12
+
13
+ # ------------------------------------------------------------
14
+ # @verndale/ai-pr (pnpm open-pr) — GitHub PR create/update
15
+ # ------------------------------------------------------------
12
16
  # @verndale/ai-pr — GH_TOKEN: Set for local CLI runs; CI uses workflow env / secrets. Also reads GITHUB_TOKEN.
13
- GH_TOKEN=
17
+ #GH_TOKEN=
14
18
 
15
19
  # Optional — PR behavior
16
20
  # @verndale/ai-pr — PR_BASE_BRANCH: Base branch to merge into (default main).
17
21
  # PR_BASE_BRANCH=main
22
+
18
23
  # @verndale/ai-pr — PR_DRAFT: If true (default), new PRs are drafts.
19
24
  # PR_DRAFT=true
20
25
 
21
26
  # Optional — AI summary + labels (when PR_AI=true)
22
27
  # @verndale/ai-pr — PR_AI: Set true to enable AI summary and optional labels/checklist.
23
28
  # PR_AI=true
29
+
24
30
  # @verndale/ai-pr — PR_AI_ENDPOINT: AI API URL when PR_AI is true (e.g. OpenAI Responses endpoint).
25
31
  # PR_AI_ENDPOINT=https://api.openai.com/v1/responses
32
+
26
33
  # @verndale/ai-pr — PR_AI_API_KEY: Bearer token for the AI API when PR_AI is true.
27
34
  # PR_AI_API_KEY=
35
+
28
36
  # @verndale/ai-pr — PR_AI_MODEL: Model id (default string default).
29
37
  # PR_AI_MODEL=default
38
+
package/lib/init-env.js CHANGED
@@ -5,9 +5,11 @@ const fs = require("fs");
5
5
  /** Detect our doc line so we do not duplicate or replace other packages’ comments. */
6
6
  const MARKER_PREFIX = "# @verndale/ai-commit — ";
7
7
 
8
- const SECTION_DIVIDER = "# ------------------------------------------------------------";
9
- const SECTION_TITLE = "# @verndale/ai-commit (pnpm commit / ai-commit run)";
10
- const SECTION_HEADER = [SECTION_DIVIDER, SECTION_TITLE, SECTION_DIVIDER];
8
+ const HEADER_LINES = [
9
+ "# ------------------------------------------------------------",
10
+ "# @verndale/ai-commit (pnpm commit / ai-commit run)",
11
+ "# ------------------------------------------------------------",
12
+ ];
11
13
 
12
14
  const SUBSECTION_OPTIONAL_MODEL = "# Optional — default is gpt-4o-mini";
13
15
 
@@ -20,10 +22,7 @@ const DOC_OPENAI = [
20
22
  * @returns {boolean}
21
23
  */
22
24
  function hasAiCommitSectionHeader(text) {
23
- return (
24
- text.includes(SECTION_DIVIDER) &&
25
- text.includes("@verndale/ai-commit (pnpm commit / ai-commit run)")
26
- );
25
+ return text.includes(HEADER_LINES[0]) && text.includes(HEADER_LINES[1]);
27
26
  }
28
27
 
29
28
  /**
@@ -82,6 +81,25 @@ function hasOurDocForKey(lines, key) {
82
81
  return lines.some((line) => line.includes(needle));
83
82
  }
84
83
 
84
+ /**
85
+ * @param {string[]} lines mutable
86
+ * @param {RegExp} assignmentRegex
87
+ * @param {string[]} docLines
88
+ * @param {string} key
89
+ * @returns {boolean}
90
+ */
91
+ function injectDocBeforeAssignment(lines, assignmentRegex, docLines, key) {
92
+ if (hasOurDocForKey(lines, key)) {
93
+ return false;
94
+ }
95
+ const idx = lines.findIndex((line) => assignmentRegex.test(line));
96
+ if (idx === -1) {
97
+ return false;
98
+ }
99
+ lines.splice(idx, 0, ...docLines);
100
+ return true;
101
+ }
102
+
85
103
  /**
86
104
  * For keys already present (possibly with another package’s comments), add our doc line(s)
87
105
  * above the assignment if missing. Does not remove or edit existing comment lines.
@@ -93,12 +111,10 @@ function injectAiCommitDocsForExistingKeys(content) {
93
111
  let changed = false;
94
112
 
95
113
  if (!hasOurDocForKey(lines, "OPENAI_API_KEY")) {
96
- const idx = lines.findIndex((line) => /^\s*OPENAI_API_KEY\s*=/.test(line));
97
- if (idx !== -1) {
98
- const insert = hasAiCommitSectionHeader(lines.join("\n"))
99
- ? [DOC_OPENAI[0]]
100
- : [...SECTION_HEADER, DOC_OPENAI[0]];
101
- lines.splice(idx, 0, ...insert);
114
+ const docLines = hasAiCommitSectionHeader(lines.join("\n"))
115
+ ? [...DOC_OPENAI]
116
+ : [...HEADER_LINES, ...DOC_OPENAI];
117
+ if (injectDocBeforeAssignment(lines, /^\s*OPENAI_API_KEY\s*=/, docLines, "OPENAI_API_KEY")) {
102
118
  changed = true;
103
119
  }
104
120
  }
@@ -111,7 +127,7 @@ function injectAiCommitDocsForExistingKeys(content) {
111
127
  if (idx !== -1) {
112
128
  const insert = hasAiCommitSectionHeader(lines.join("\n"))
113
129
  ? [SUBSECTION_OPTIONAL_MODEL]
114
- : [...SECTION_HEADER, "", SUBSECTION_OPTIONAL_MODEL];
130
+ : [...HEADER_LINES, "", SUBSECTION_OPTIONAL_MODEL];
115
131
  lines.splice(idx, 0, ...insert);
116
132
  changed = true;
117
133
  }
@@ -140,35 +156,30 @@ function buildAiCommitEnvAppend(existing) {
140
156
  return null;
141
157
  }
142
158
 
159
+ const parts = [];
160
+
143
161
  if (needOpenai && needCommit) {
144
- return [
145
- ...SECTION_HEADER,
146
- DOC_OPENAI[0],
147
- "OPENAI_API_KEY=",
148
- "",
149
- SUBSECTION_OPTIONAL_MODEL,
150
- "# COMMIT_AI_MODEL=",
151
- "",
152
- "",
153
- ].join("\n");
154
- }
155
-
156
- if (needOpenai) {
157
- return [...SECTION_HEADER, DOC_OPENAI[0], "OPENAI_API_KEY=", ""].join("\n");
158
- }
159
-
160
- if (hasSection) {
161
- return [SUBSECTION_OPTIONAL_MODEL, "# COMMIT_AI_MODEL=", "", ""].join("\n");
162
- }
163
-
164
- return [
165
- ...SECTION_HEADER,
166
- "",
167
- SUBSECTION_OPTIONAL_MODEL,
168
- "# COMMIT_AI_MODEL=",
169
- "",
170
- "",
171
- ].join("\n");
162
+ parts.push(
163
+ `${HEADER_LINES.join("\n")}\n${DOC_OPENAI[0]}\nOPENAI_API_KEY=\n\n${SUBSECTION_OPTIONAL_MODEL}\n# COMMIT_AI_MODEL=\n\n\n`,
164
+ );
165
+ } else if (needOpenai) {
166
+ parts.push(
167
+ `${HEADER_LINES.join("\n")}\n${DOC_OPENAI[0]}\nOPENAI_API_KEY=\n\n`,
168
+ );
169
+ } else if (needCommit) {
170
+ if (hasSection) {
171
+ parts.push(`${SUBSECTION_OPTIONAL_MODEL}\n# COMMIT_AI_MODEL=\n\n\n`);
172
+ } else {
173
+ parts.push(
174
+ `${HEADER_LINES.join("\n")}\n\n${SUBSECTION_OPTIONAL_MODEL}\n# COMMIT_AI_MODEL=\n\n\n`,
175
+ );
176
+ }
177
+ }
178
+
179
+ if (parts.length === 0) {
180
+ return null;
181
+ }
182
+ return parts.join("");
172
183
  }
173
184
 
174
185
  /**
@@ -176,7 +187,7 @@ function buildAiCommitEnvAppend(existing) {
176
187
  * @param {string} destPath
177
188
  * @param {string} bundledPath
178
189
  * @param {{ force?: boolean }} [options]
179
- * @returns {{ kind: 'replaced' | 'wrote' | 'unchanged' }}
190
+ * @returns {{ kind: 'replaced' | 'wrote' | 'merged' | 'unchanged' }}
180
191
  */
181
192
  function mergeAiCommitEnvFile(destPath, bundledPath, options = {}) {
182
193
  const { force = false } = options;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@verndale/ai-commit",
3
- "version": "2.4.1",
3
+ "version": "2.4.2",
4
4
  "description": "AI-assisted conventional commits with bundled commitlint — one install, aligned rules",
5
5
  "license": "MIT",
6
6
  "author": "Verndale",
@@ -57,7 +57,7 @@
57
57
  "openai": "^6.33.0"
58
58
  },
59
59
  "devDependencies": {
60
- "@verndale/ai-pr": "^1.1.0",
60
+ "@verndale/ai-pr": "^1.1.2",
61
61
  "@semantic-release/changelog": "^6.0.3",
62
62
  "@semantic-release/commit-analyzer": "^13.0.1",
63
63
  "@semantic-release/git": "^10.0.1",