From 6a581aacec6c38793b3f24c8726a71ac437e2c83 Mon Sep 17 00:00:00 2001 From: JFusco Date: Wed, 1 Apr 2026 13:28:34 -0400 Subject: [PATCH 1/5] feat(ai-commit): Add initial hello world file This commit introduces a new file containing a simple "hello world" message. The addition of this file serves as a foundational element for future development and testing. By including this basic output, we establish a clear starting point for further enhancements and functionality. This change will help new contributors understand the project's structure and purpose. --- asdasd | 1 + 1 file changed, 1 insertion(+) create mode 100644 asdasd diff --git a/asdasd b/asdasd new file mode 100644 index 0000000..95d09f2 --- /dev/null +++ b/asdasd @@ -0,0 +1 @@ +hello world \ No newline at end of file From da330178538d0f1901874459112cdb3a3e2c8e61 Mon Sep 17 00:00:00 2001 From: JFusco Date: Wed, 1 Apr 2026 21:36:28 -0400 Subject: [PATCH 2/5] chore(lib): Update environment documentation for ai-commit Enhance the documentation within the environment files to provide clearer instructions for users of the ai-commit tool. The changes include the addition of section headers and improved descriptions for the `OPENAI_API_KEY` and `COMMIT_AI_MODEL` variables. These updates aim to clarify the purpose of each variable and ensure that users understand the optional nature of the `COMMIT_AI_MODEL`. By improving the documentation, we enhance the user experience and reduce potential confusion when setting up the environment for ai-commit. --- .env-example | 5 +- lib/init-env.js | 132 ++++++++++++++++++++++++++++++++---------------- 2 files changed, 92 insertions(+), 45 deletions(-) diff --git a/.env-example b/.env-example index 9204b82..b714978 100644 --- a/.env-example +++ b/.env-example @@ -1,9 +1,12 @@ # Copy to .env and/or .env.local in your project root (do not commit secrets). +# ------------------------------------------------------------ +# @verndale/ai-commit (pnpm commit / ai-commit run) +# ------------------------------------------------------------ # @verndale/ai-commit — OPENAI_API_KEY: OpenAI API key for conventional commit messages (ai-commit run; optional for prepare-commit-msg with AI). OPENAI_API_KEY= -# @verndale/ai-commit — COMMIT_AI_MODEL: OpenAI model for commit messages (optional; default gpt-4o-mini). +# Optional — default is gpt-4o-mini # COMMIT_AI_MODEL= # @verndale/ai-pr — GH_TOKEN: Set for local CLI runs; CI uses workflow env / secrets. Also reads GITHUB_TOKEN. GH_TOKEN= diff --git a/lib/init-env.js b/lib/init-env.js index ef20941..bd4a911 100644 --- a/lib/init-env.js +++ b/lib/init-env.js @@ -5,13 +5,57 @@ const fs = require("fs"); /** Detect our doc line so we do not duplicate or replace other packages’ comments. */ const MARKER_PREFIX = "# @verndale/ai-commit — "; +const SECTION_DIVIDER = "# ------------------------------------------------------------"; +const SECTION_TITLE = "# @verndale/ai-commit (pnpm commit / ai-commit run)"; +const SECTION_HEADER = [SECTION_DIVIDER, SECTION_TITLE, SECTION_DIVIDER]; + +const SUBSECTION_OPTIONAL_MODEL = "# Optional — default is gpt-4o-mini"; + const DOC_OPENAI = [ `${MARKER_PREFIX}OPENAI_API_KEY: OpenAI API key for conventional commit messages (ai-commit run; optional for prepare-commit-msg with AI).`, ]; -const DOC_COMMIT_MODEL = [ - `${MARKER_PREFIX}COMMIT_AI_MODEL: OpenAI model for commit messages (optional; default gpt-4o-mini).`, -]; +/** + * @param {string} text + * @returns {boolean} + */ +function hasAiCommitSectionHeader(text) { + return ( + text.includes(SECTION_DIVIDER) && + text.includes("@verndale/ai-commit (pnpm commit / ai-commit run)") + ); +} + +/** + * True when COMMIT_AI_MODEL is already documented (long marker, subsection, or legacy block). + * @param {string[]} lines + * @returns {boolean} + */ +function hasCommitModelNotes(lines) { + if (hasOurDocForKey(lines, "COMMIT_AI_MODEL")) { + return true; + } + const commitIdx = lines.findIndex( + (line) => + /^\s*COMMIT_AI_MODEL\s*=/.test(line) || /^\s*#\s*COMMIT_AI_MODEL\s*=/.test(line), + ); + if (commitIdx === -1) { + return false; + } + for (let i = commitIdx - 1; i >= 0 && i >= commitIdx - 12; i--) { + const t = lines[i].trim(); + if (t === "") { + continue; + } + if (t === SUBSECTION_OPTIONAL_MODEL.trim()) { + return true; + } + if (lines[i].includes(`${MARKER_PREFIX}COMMIT_AI_MODEL:`)) { + return true; + } + } + return false; +} /** * Keys assigned on non-comment lines (`KEY=value` or `export KEY=value`). @@ -38,27 +82,6 @@ function hasOurDocForKey(lines, key) { return lines.some((line) => line.includes(needle)); } -/** - * Insert ai-commit doc lines immediately before an assignment line, without changing - * existing comments above that line (we insert after those lines, before the key line). - * @param {string[]} lines mutable - * @param {RegExp} assignmentRegex - * @param {string[]} docLines - * @param {string} key for marker check - * @returns {boolean} whether lines were mutated - */ -function injectDocBeforeAssignment(lines, assignmentRegex, docLines, key) { - if (hasOurDocForKey(lines, key)) { - return false; - } - const idx = lines.findIndex((line) => assignmentRegex.test(line)); - if (idx === -1) { - return false; - } - lines.splice(idx, 0, ...docLines); - return true; -} - /** * For keys already present (possibly with another package’s comments), add our doc line(s) * above the assignment if missing. Does not remove or edit existing comment lines. @@ -69,24 +92,27 @@ function injectAiCommitDocsForExistingKeys(content) { const lines = content.split(/\r?\n/); let changed = false; - if ( - injectDocBeforeAssignment( - lines, - /^\s*OPENAI_API_KEY\s*=/, - DOC_OPENAI, - "OPENAI_API_KEY", - ) - ) { - changed = true; + if (!hasOurDocForKey(lines, "OPENAI_API_KEY")) { + const idx = lines.findIndex((line) => /^\s*OPENAI_API_KEY\s*=/.test(line)); + if (idx !== -1) { + const insert = hasAiCommitSectionHeader(lines.join("\n")) + ? [DOC_OPENAI[0]] + : [...SECTION_HEADER, DOC_OPENAI[0]]; + lines.splice(idx, 0, ...insert); + changed = true; + } } - if (!hasOurDocForKey(lines, "COMMIT_AI_MODEL")) { + if (!hasCommitModelNotes(lines)) { let idx = lines.findIndex((line) => /^\s*COMMIT_AI_MODEL\s*=/.test(line)); if (idx === -1) { idx = lines.findIndex((line) => /^\s*#\s*COMMIT_AI_MODEL\s*=/.test(line)); } if (idx !== -1) { - lines.splice(idx, 0, ...DOC_COMMIT_MODEL); + const insert = hasAiCommitSectionHeader(lines.join("\n")) + ? [SUBSECTION_OPTIONAL_MODEL] + : [...SECTION_HEADER, "", SUBSECTION_OPTIONAL_MODEL]; + lines.splice(idx, 0, ...insert); changed = true; } } @@ -106,17 +132,35 @@ function buildAiCommitEnvAppend(existing) { keys.has("COMMIT_AI_MODEL") || /^\s*#\s*COMMIT_AI_MODEL\s*=/m.test(existing) || /^\s*COMMIT_AI_MODEL\s*=/m.test(existing); - const parts = []; - if (!keys.has("OPENAI_API_KEY")) { - parts.push(`${DOC_OPENAI[0]}\nOPENAI_API_KEY=\n`); + const needOpenai = !keys.has("OPENAI_API_KEY"); + const needCommit = !keys.has("COMMIT_AI_MODEL") && !hasCommitPlaceholder; + const hasSection = hasAiCommitSectionHeader(existing); + + if (!needOpenai && !needCommit) { + return null; } - if (!keys.has("COMMIT_AI_MODEL") && !hasCommitPlaceholder) { - parts.push(`${DOC_COMMIT_MODEL[0]}\n# COMMIT_AI_MODEL=\n`); + + if (needOpenai && needCommit) { + return [ + ...SECTION_HEADER, + DOC_OPENAI[0], + "OPENAI_API_KEY=", + "", + SUBSECTION_OPTIONAL_MODEL, + "# COMMIT_AI_MODEL=", + "", + ].join("\n"); } - if (parts.length === 0) { - return null; + + if (needOpenai) { + return [...SECTION_HEADER, DOC_OPENAI[0], "OPENAI_API_KEY=", ""].join("\n"); + } + + if (hasSection) { + return [SUBSECTION_OPTIONAL_MODEL, "# COMMIT_AI_MODEL=", ""].join("\n"); } - return parts.join("\n"); + + return [...SECTION_HEADER, "", SUBSECTION_OPTIONAL_MODEL, "# COMMIT_AI_MODEL=", ""].join("\n"); } /** @@ -124,7 +168,7 @@ function buildAiCommitEnvAppend(existing) { * @param {string} destPath * @param {string} bundledPath * @param {{ force?: boolean }} [options] - * @returns {{ kind: 'replaced' | 'wrote' | 'merged' | 'unchanged' }} + * @returns {{ kind: 'replaced' | 'wrote' | 'unchanged' }} */ function mergeAiCommitEnvFile(destPath, bundledPath, options = {}) { const { force = false } = options; From 4d34b4e7aab3b9fc2d13377c937ad5b6a408f118 Mon Sep 17 00:00:00 2001 From: JFusco Date: Wed, 1 Apr 2026 21:38:26 -0400 Subject: [PATCH 3/5] fix(lib): Update environment configuration for clarity This commit enhances the clarity of the environment configuration files by adding additional newlines in both the `.env-example` and `lib/init-env.js` files. The extra newlines improve the readability of the configuration sections, making it easier for developers to understand and modify the settings as needed. These changes do not affect the functionality of the application, but they contribute to better maintainability and usability of the environment setup process. Clearer configuration files can help reduce errors during setup and improve onboarding for new developers. --- .env-example | 1 + lib/init-env.js | 12 ++++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/.env-example b/.env-example index b714978..c80b5dc 100644 --- a/.env-example +++ b/.env-example @@ -8,6 +8,7 @@ OPENAI_API_KEY= # Optional — default is gpt-4o-mini # COMMIT_AI_MODEL= + # @verndale/ai-pr — GH_TOKEN: Set for local CLI runs; CI uses workflow env / secrets. Also reads GITHUB_TOKEN. GH_TOKEN= diff --git a/lib/init-env.js b/lib/init-env.js index bd4a911..83ead5c 100644 --- a/lib/init-env.js +++ b/lib/init-env.js @@ -149,6 +149,7 @@ function buildAiCommitEnvAppend(existing) { SUBSECTION_OPTIONAL_MODEL, "# COMMIT_AI_MODEL=", "", + "", ].join("\n"); } @@ -157,10 +158,17 @@ function buildAiCommitEnvAppend(existing) { } if (hasSection) { - return [SUBSECTION_OPTIONAL_MODEL, "# COMMIT_AI_MODEL=", ""].join("\n"); + return [SUBSECTION_OPTIONAL_MODEL, "# COMMIT_AI_MODEL=", "", ""].join("\n"); } - return [...SECTION_HEADER, "", SUBSECTION_OPTIONAL_MODEL, "# COMMIT_AI_MODEL=", ""].join("\n"); + return [ + ...SECTION_HEADER, + "", + SUBSECTION_OPTIONAL_MODEL, + "# COMMIT_AI_MODEL=", + "", + "", + ].join("\n"); } /** From 913096c1e4535efa199718cb93d2a167cea52e2d Mon Sep 17 00:00:00 2001 From: JFusco Date: Wed, 1 Apr 2026 21:42:21 -0400 Subject: [PATCH 4/5] fix(ci): Update PR workflow command in configuration The command used to create pull requests in the GitHub Actions workflow has been updated from `pnpm open-pr` to `pnpm pr:create`. This change aligns the command with the latest updates in the associated package, ensuring that the workflow functions as intended. Additionally, the README has been updated to reflect this change, providing users with accurate information on how to utilize the new command. This update improves clarity and helps maintain consistency across documentation and workflow configurations. --- .github/workflows/pr.yml | 2 +- README.md | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 833b8d2..fa50bd4 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -67,4 +67,4 @@ jobs: PR_AI_ENDPOINT: ${{ vars.PR_AI_ENDPOINT }} PR_AI_MODEL: ${{ vars.PR_AI_MODEL }} PR_AI_API_KEY: ${{ secrets.PR_AI_API_KEY }} - run: pnpm open-pr + run: pnpm pr:create diff --git a/README.md b/README.md index 973da06..789121b 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ Use **`ai-commit init --force`** to replace **`.env`** and **`.env-example`** wi - **`OPENAI_API_KEY`** — Required for `ai-commit run` (and for AI-filled `prepare-commit-msg` when you want the model). Optional `COMMIT_AI_MODEL` (default `gpt-4o-mini`). - **Shared env vars** — If another tool already documents **`OPENAI_API_KEY`** or **`COMMIT_AI_MODEL`**, **`ai-commit init`** adds its own `# @verndale/ai-commit — …` line immediately above the assignment when missing; it does not remove or replace existing comment lines. - The CLI loads **`.env`** then **`.env.local`** from the current working directory (project root); values in `.env.local` override `.env` for the same key. -- **Optional tooling:** `PR_*` env vars for [`@verndale/ai-pr`](https://www.npmjs.com/package/@verndale/ai-pr) (`pnpm open-pr` in this repo) / the **Create or update PR** workflow; `RELEASE_NOTES_AI_*` for [`tools/semantic-release-notes.cjs`](./tools/semantic-release-notes.cjs). Use a GitHub PAT as **`GH_TOKEN`** (or `GITHUB_TOKEN`) when calling the GitHub API outside Actions. +- **Optional tooling:** `PR_*` env vars for [`@verndale/ai-pr`](https://www.npmjs.com/package/@verndale/ai-pr) (`pnpm pr:create` in this repo) / the **Create or update PR** workflow; `RELEASE_NOTES_AI_*` for [`tools/semantic-release-notes.cjs`](./tools/semantic-release-notes.cjs). Use a GitHub PAT as **`GH_TOKEN`** (or `GITHUB_TOKEN`) when calling the GitHub API outside Actions. ## Commit policy (v2) @@ -125,10 +125,10 @@ Copy **`.env-example`** to `.env` and/or `.env.local` and set **`OPENAI_API_KEY` | Workflow | Trigger | Purpose | | --- | --- | --- | | [`.github/workflows/commitlint.yml`](./.github/workflows/commitlint.yml) | PRs to `main`, pushes to non-`main` branches | Commitlint on PR range or last push commit | -| [`.github/workflows/pr.yml`](./.github/workflows/pr.yml) | Pushes (not `main`) and `workflow_dispatch` | Install deps, run **`pnpm open-pr`** ([**`@verndale/ai-pr`**](https://www.npmjs.com/package/@verndale/ai-pr)) — set **`PR_HEAD_BRANCH`** / **`PR_BASE_BRANCH`** in CI via env (workflow sets them). Use a PAT secret **`PR_BOT_TOKEN`** if branch protection requires it; otherwise document your org’s policy. | +| [`.github/workflows/pr.yml`](./.github/workflows/pr.yml) | Pushes (not `main`) and `workflow_dispatch` | Install deps, run **`pnpm pr:create`** ([**`@verndale/ai-pr`**](https://www.npmjs.com/package/@verndale/ai-pr)) — set **`PR_HEAD_BRANCH`** / **`PR_BASE_BRANCH`** in CI via env (workflow sets them). Use a PAT secret **`PR_BOT_TOKEN`** if branch protection requires it; otherwise document your org’s policy. | | [`.github/workflows/release.yml`](./.github/workflows/release.yml) | Push to **`main`** (including when a PR merges) | **`semantic-release`** — version bump, `CHANGELOG.md`, git tag, npm publish (with provenance), GitHub Release | -Optional **`pnpm open-pr`** locally: set **`GH_TOKEN`** (or **`GITHUB_TOKEN`**) and branch overrides **`PR_BASE_BRANCH`** / **`PR_HEAD_BRANCH`** as needed. +Optional **`pnpm pr:create`** locally: set **`GH_TOKEN`** (or **`GITHUB_TOKEN`**) and branch overrides **`PR_BASE_BRANCH`** / **`PR_HEAD_BRANCH`** as needed. ## Publishing (maintainers) From 94690bd779a6c715a29163a852e5d24af4dcd681 Mon Sep 17 00:00:00 2001 From: JFusco Date: Wed, 1 Apr 2026 21:43:54 -0400 Subject: [PATCH 5/5] fix(ci): Update command in workflow and documentation This commit modifies the command used to create pull requests in the GitHub Actions workflow. The command has been changed from `pnpm pr:create` to `pnpm run pr:create` to ensure proper execution of the script. This change aligns with the standard usage of npm scripts and enhances clarity for developers. Additionally, the README documentation has been updated to reflect this change. The updated command is now consistent throughout the documentation, which will help prevent confusion for users interacting with the pull request creation process. No functional changes are introduced by this update, but it improves the overall consistency and usability of the project. --- .github/workflows/pr.yml | 2 +- README.md | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index fa50bd4..555f739 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -67,4 +67,4 @@ jobs: PR_AI_ENDPOINT: ${{ vars.PR_AI_ENDPOINT }} PR_AI_MODEL: ${{ vars.PR_AI_MODEL }} PR_AI_API_KEY: ${{ secrets.PR_AI_API_KEY }} - run: pnpm pr:create + run: pnpm run pr:create diff --git a/README.md b/README.md index 789121b..d6b10c1 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ Use **`ai-commit init --force`** to replace **`.env`** and **`.env-example`** wi - **`OPENAI_API_KEY`** — Required for `ai-commit run` (and for AI-filled `prepare-commit-msg` when you want the model). Optional `COMMIT_AI_MODEL` (default `gpt-4o-mini`). - **Shared env vars** — If another tool already documents **`OPENAI_API_KEY`** or **`COMMIT_AI_MODEL`**, **`ai-commit init`** adds its own `# @verndale/ai-commit — …` line immediately above the assignment when missing; it does not remove or replace existing comment lines. - The CLI loads **`.env`** then **`.env.local`** from the current working directory (project root); values in `.env.local` override `.env` for the same key. -- **Optional tooling:** `PR_*` env vars for [`@verndale/ai-pr`](https://www.npmjs.com/package/@verndale/ai-pr) (`pnpm pr:create` in this repo) / the **Create or update PR** workflow; `RELEASE_NOTES_AI_*` for [`tools/semantic-release-notes.cjs`](./tools/semantic-release-notes.cjs). Use a GitHub PAT as **`GH_TOKEN`** (or `GITHUB_TOKEN`) when calling the GitHub API outside Actions. +- **Optional tooling:** `PR_*` env vars for [`@verndale/ai-pr`](https://www.npmjs.com/package/@verndale/ai-pr) (`pnpm run pr:create` in this repo) / the **Create or update PR** workflow; `RELEASE_NOTES_AI_*` for [`tools/semantic-release-notes.cjs`](./tools/semantic-release-notes.cjs). Use a GitHub PAT as **`GH_TOKEN`** (or `GITHUB_TOKEN`) when calling the GitHub API outside Actions. ## Commit policy (v2) @@ -125,10 +125,10 @@ Copy **`.env-example`** to `.env` and/or `.env.local` and set **`OPENAI_API_KEY` | Workflow | Trigger | Purpose | | --- | --- | --- | | [`.github/workflows/commitlint.yml`](./.github/workflows/commitlint.yml) | PRs to `main`, pushes to non-`main` branches | Commitlint on PR range or last push commit | -| [`.github/workflows/pr.yml`](./.github/workflows/pr.yml) | Pushes (not `main`) and `workflow_dispatch` | Install deps, run **`pnpm pr:create`** ([**`@verndale/ai-pr`**](https://www.npmjs.com/package/@verndale/ai-pr)) — set **`PR_HEAD_BRANCH`** / **`PR_BASE_BRANCH`** in CI via env (workflow sets them). Use a PAT secret **`PR_BOT_TOKEN`** if branch protection requires it; otherwise document your org’s policy. | +| [`.github/workflows/pr.yml`](./.github/workflows/pr.yml) | Pushes (not `main`) and `workflow_dispatch` | Install deps, run **`pnpm run pr:create`** ([**`@verndale/ai-pr`**](https://www.npmjs.com/package/@verndale/ai-pr)) — set **`PR_HEAD_BRANCH`** / **`PR_BASE_BRANCH`** in CI via env (workflow sets them). Use a PAT secret **`PR_BOT_TOKEN`** if branch protection requires it; otherwise document your org’s policy. | | [`.github/workflows/release.yml`](./.github/workflows/release.yml) | Push to **`main`** (including when a PR merges) | **`semantic-release`** — version bump, `CHANGELOG.md`, git tag, npm publish (with provenance), GitHub Release | -Optional **`pnpm pr:create`** locally: set **`GH_TOKEN`** (or **`GITHUB_TOKEN`**) and branch overrides **`PR_BASE_BRANCH`** / **`PR_HEAD_BRANCH`** as needed. +Optional **`pnpm run pr:create`** locally: set **`GH_TOKEN`** (or **`GITHUB_TOKEN`**) and branch overrides **`PR_BASE_BRANCH`** / **`PR_HEAD_BRANCH`** as needed. ## Publishing (maintainers)