Add Braintree plugin publish skill - #44
Conversation
Codifies changelog/version gates, typecheck, lint, pack, and npm publish so releases follow a consistent checklist. Co-authored-by: Cursor <cursoragent@cursor.com>
WalkthroughAdds a Cursor skill for publishing ChangesBraintree plugin publication
Estimated code review effort: 1 (Trivial) | ~5 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 7
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.cursor/skills/publish-braintree-plugin/SKILL.md:
- Around line 37-58: Update the publishing workflow around the Gate 1 commit
comparison to inspect the working tree for staged, unstaged, and untracked
changes under plugins/braintree-payment before publishing. Require a clean
plugin worktree and fail with a clear summary if local changes exist, or
incorporate those changes into the ## LOCAL_VERSION changelog comparison so
undocumented content cannot be published.
- Around line 40-53: Update the release-boundary guidance around PREV_COMMIT and
the practical check to identify the previous release commit, not merely any
commit matching the version string. Restrict the search to the addition of
PREV_VERSION in package.json, and if no such version-bump commit exists, fall
back to the commit that introduced the PREV_VERSION changelog header. Ensure the
resulting PREV_COMMIT..HEAD range includes all changes since that previous
release.
- Around line 22-30: Update the Publish Progress code fence in the skill
instructions to specify the text language, using ```text while preserving the
checklist contents unchanged.
- Around line 102-106: The Gate 5 workflow in publish-braintree-plugin must
build the Braintree plugin before packing. Add yarn workspace
`@lambdacurry/medusa-payment-braintree` build before npm pack, then verify the
generated tarball contains the expected .medusa/server output included by the
package files configuration.
- Around line 131-137: Update the local publication and verification commands in
the publish-braintree skill to include --registry=https://registry.npmjs.org on
npm whoami, npm publish, every npm view command, and the dry-run command. Keep
the existing command behavior otherwise unchanged.
- Around line 68-75: Update the version-checking steps in the publish workflow
to read npm’s complete versions list via versions --json, filter it according to
the release policy, and compare LOCAL_VERSION against the highest allowed
published version rather than the latest dist-tag. Keep the existing
exact-version check using npm view package@$LOCAL_VERSION version as a separate
guard.
- Around line 134-140: Update the publish verification instructions to query the
exact package version using npm view with the package@LOCAL_VERSION specifier,
version field, and --prefer-online. Retry this lookup with bounded backoff when
registry propagation delays prevent an exact match, then report the final error;
remove the unqualified latest-version check.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 9fc2b409-aaf0-43c8-9f32-2af8f9c7232a
📒 Files selected for processing (1)
.cursor/skills/publish-braintree-plugin/SKILL.md
Tighten changelog/worktree gates, version comparison against full npm versions, explicit build-before-pack, pinned registry, and post-publish exact-version polling. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.cursor/skills/publish-braintree-plugin/SKILL.md:
- Around line 49-59: Update the PREV_COMMIT lookups in the publish flow to use
patch-aware searches that identify the commit adding the exact PREV_VERSION
line, removing the --diff-filter=A restriction from both package.json and
CHANGELOG.md searches. Select the intended release boundary from the results,
ensuring the newest matching commit is chosen rather than tail -1 returning the
oldest.
- Around line 141-146: Update the packaging and publishing steps in the skill to
capture the exact filename returned by npm pack as TARBALL, inspect that archive
rather than using a wildcard, and explicitly fail when no .medusa/server entry
is found. Publish the verified archive with npm publish "$TARBALL" instead of
publishing the package directory, avoiding a repack through prepublishOnly.
- Around line 164-171: Make the dist-tag explicit across all publication paths:
add --tag latest to stable npm publish and dry-run examples, and update the
publish workflow to derive latest for stable versions or the prerelease channel
(such as next) for prerelease versions before passing it to npm publish.
- Around line 90-105: Update the publishing instructions around the full-version
and exact-version npm view commands to explicitly inspect exit status. Fail
immediately if the versions query fails, and run the exact-version check only
when its result is a confirmed E404; stop for every other error while still
failing when the exact version is returned.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 22aead9c-92e3-4c56-b40c-49e22952a5cc
📒 Files selected for processing (1)
.cursor/skills/publish-braintree-plugin/SKILL.md
| # Prefer the commit that introduced PREV_VERSION in package.json (addition only). | ||
| PREV_COMMIT=$( | ||
| git log -S"\"version\": \"$PREV_VERSION\"" --diff-filter=A --format=%H -- \ | ||
| plugins/braintree-payment/package.json | tail -1 | ||
| ) | ||
|
|
||
| # Fallback: commit that introduced the PREV_VERSION changelog header. | ||
| if [ -z "$PREV_COMMIT" ]; then | ||
| PREV_COMMIT=$( | ||
| git log -S"## $PREV_VERSION" --diff-filter=A --format=%H -- \ | ||
| plugins/braintree-payment/CHANGELOG.md | tail -1 |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major
Fix the PREV_COMMIT lookup.
--diff-filter=A selects commits where the file was added. It does not select a modified package.json commit that adds the matching version line. Git defines -S as an occurrence-count search and A as an added-path filter. A normal version bump therefore returns no commit for an existing package.json; the changelog fallback has the same defect. tail -1 also selects the oldest result because git log is reverse chronological by default. (git-scm.com)
Use a patch-aware search that identifies the commit adding the exact version line, then select the intended release boundary.
🧰 Tools
🪛 SkillSpector (2.5.1)
[warning] 130: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.
Remediation: Pin the version: npx @scope/server@1.2.3
(MCP Rug Pull (RP1))
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.cursor/skills/publish-braintree-plugin/SKILL.md around lines 49 - 59,
Update the PREV_COMMIT lookups in the publish flow to use patch-aware searches
that identify the commit adding the exact PREV_VERSION line, removing the
--diff-filter=A restriction from both package.json and CHANGELOG.md searches.
Select the intended release boundary from the results, ensuring the newest
matching commit is chosen rather than tail -1 returning the oldest.
| 2. Read the full published version list (not the `latest` dist-tag alone): | ||
|
|
||
| ```bash | ||
| npm view @lambdacurry/medusa-payment-braintree versions --json \ | ||
| --registry=https://registry.npmjs.org | ||
| ``` | ||
|
|
||
| 3. Filter that list per the release policy above, take the highest allowed published version as `HIGHEST_ALLOWED`, and **fail** unless `LOCAL_VERSION` is strictly greater (semver). | ||
| 4. Exact-version guard (separate from the highest-version check): | ||
|
|
||
| ```bash | ||
| npm view "@lambdacurry/medusa-payment-braintree@$LOCAL_VERSION" version \ | ||
| --registry=https://registry.npmjs.org | ||
| ``` | ||
|
|
||
| **Fail** if that command returns `LOCAL_VERSION` (already published). |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -u
file=".cursor/skills/publish-braintree-plugin/SKILL.md"
printf '%s\n' "== file status =="
git ls-files -- "$file"
printf '%s\n' "== lines 1-180 =="
sed -n '1,180p' "$file"
printf '%s\n' "== related references =="
rg -n -C 3 'npm view|versions --json|LOCAL_VERSION|HIGHEST_ALLOWED|set -e|exit status|not-found|not found|fail closed|registry' .cursor/skills .github 2>/dev/null || trueRepository: lambda-curry/medusa-plugins
Length of output: 18124
🏁 Script executed:
#!/bin/bash
set +e
pkg='`@lambdacurry/medusa-payment-braintree`'
missing='0.0.0-coderabbit-review-nonexistent'
run() {
label="$1"
shift
"$@" >/tmp/npm-review-out 2>/tmp/npm-review-err
status=$?
printf '\n== %s ==\nstatus=%s\nstdout=%s\nstderr=%s\n' \
"$label" "$status" "$(cat /tmp/npm-review-out)" "$(head -5 /tmp/npm-review-err)"
}
if command -v npm >/dev/null 2>&1; then
run "missing exact version" npm view "$pkg@$missing" version \
--registry=https://registry.npmjs.org
run "unreachable registry" npm view "$pkg@$missing" version \
--registry=http://127.0.0.1:1
else
printf 'npm is unavailable; no runtime probe executed\n'
fi
rm -f /tmp/npm-review-out /tmp/npm-review-errRepository: lambda-curry/medusa-plugins
Length of output: 157
🌐 Web query:
npm CLI documentation npm view package version not found exit code registry error
💡 Result:
When the npm CLI cannot find a requested package or specific version, it typically returns an exit code of 1 and an E404 error [1][2][3]. Key details regarding this behavior include: Exit Codes and Error Handling Historically, some versions of the npm CLI exhibited inconsistent behavior where certain "not found" scenarios would result in a zero exit code with no output [4][5][1]. However, modern versions of the npm CLI have been updated to ensure that requesting a non-existent package or a specific non-existent version correctly triggers an E404 error and a non-zero (1) exit code [1][2]. Common Causes for "Not Found" (E404) When you encounter an E404 error, it generally indicates that the registry does not contain the specified package or version [3]. Common causes include: - Incorrect Package Name: Typographical errors in the package name [3]. - Incorrect Registry Configuration: The npm CLI may be pointing to a registry that does not host the package (e.g., a private registry instead of the public npm registry or a misconfigured scope) [3][6]. - Missing Version/Tag: The specific version or dist-tag requested does not exist [5][1][2]. - Unpublishing or Deletion: The package or specific version may have been unpublished or removed by the author [3]. - Temporary Registry Issues: Intermittent issues with the npm registry itself can occasionally cause valid packages to be reported as not found [7][8]. Troubleshooting Steps If you receive an E404 error for a package you believe should exist: 1. Verify Registry Settings: Run npm config get registry to ensure you are pointing to the intended registry (commonly https://registry.npmjs.org/) [6]. 2. Check Package Availability: Search the npm website directly to confirm the package and version exist [3]. 3. Check Network/Proxies: If in a corporate environment, verify if a proxy is interfering with registry requests [7]. 4. Retry: If the error seems sporadic, it may be a transient issue with the registry [7][8]. For further details, refer to the official npm documentation on common errors and the npm-view command [7][9].
Citations:
- 1: fix(view): error on missing version npm/cli#5035
- 2: [BUG] npm view --json outputs illegal JSON for existing package but non-existent version npm/cli#3184
- 3: https://fixdevs.com/blog/npm-err-code-e404/
- 4: [BUG] npm info exits with zero exit code if package@version is not found npm/cli#4964
- 5: [BUG]
npm view package@latestexits with code 0 and no output iflatesttag does not exist npm/cli#6408 - 6: Couldn't find package "package-name" on the "npm" registry. npm/cli#1816
- 7: https://docs.npmjs.com/common-errors/
- 8: [BUG] npm i failing for random packages on retry saying package not found npm/cli#6644
- 9: https://docs.npmjs.com/cli/v10/commands/npm-view/
Fail closed on npm lookup errors.
Handle the exit status of both npm view commands explicitly. Continue the exact-version check only for a confirmed E404 (“not found”) result. Stop for all other errors. Fail if the full versions --json query does not succeed.
🧰 Tools
🪛 SkillSpector (2.5.1)
[warning] 130: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.
Remediation: Pin the version: npx @scope/server@1.2.3
(MCP Rug Pull (RP1))
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.cursor/skills/publish-braintree-plugin/SKILL.md around lines 90 - 105,
Update the publishing instructions around the full-version and exact-version npm
view commands to explicitly inspect exit status. Fail immediately if the
versions query fails, and run the exact-version check only when its result is a
confirmed E404; stop for every other error while still failing when the exact
version is returned.
| ```bash | ||
| tar -tzf lambdacurry-medusa-payment-braintree-*.tgz | head -50 | ||
| tar -tzf lambdacurry-medusa-payment-braintree-*.tgz | grep -E '\.medusa/server/' | head -20 | ||
| ``` | ||
|
|
||
| **Fail** if `.medusa/server` paths are missing from the tarball. |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
sed -n '120,185p' .cursor/skills/publish-braintree-plugin/SKILL.mdRepository: lambda-curry/medusa-plugins
Length of output: 2410
🏁 Script executed:
printf '%s\n' '--- skill file ---'
sed -n '136,178p' .cursor/skills/publish-braintree-plugin/SKILL.md
printf '%s\n' '--- package metadata ---'
cat plugins/braintree-payment/package.json
printf '%s\n' '--- publish workflow references ---'
rg -n -C 5 'npm (pack|publish)|prepublishOnly|medusa plugin:build' .github plugins/braintree-payment/package.json
printf '%s\n' '--- deterministic shell behavior ---'
python3 - <<'PY'
import subprocess
for command in [
"printf '%s\\n' absent | grep -E '\\.medusa/server/' | head -20",
"set -o pipefail; printf '%s\\n' absent | grep -E '\\.medusa/server/' | head -20",
]:
result = subprocess.run(["bash", "-c", command], text=True, capture_output=True)
print(f"{command}\nstatus={result.returncode}")
PYRepository: lambda-curry/medusa-plugins
Length of output: 6019
Publish the exact tarball that you verify.
The wildcard can select stale or multiple archives. Without pipefail, grep ... | head exits successfully when no .medusa/server path exists. Capture the filename from npm pack, validate that exact archive with an explicit failure check, and publish it with npm publish "$TARBALL". Publishing the package directory repacks it and runs prepublishOnly, so Gate 6 does not publish the archive inspected by Gate 5.
🧰 Tools
🪛 SkillSpector (2.5.1)
[warning] 130: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.
Remediation: Pin the version: npx @scope/server@1.2.3
(MCP Rug Pull (RP1))
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.cursor/skills/publish-braintree-plugin/SKILL.md around lines 141 - 146,
Update the packaging and publishing steps in the skill to capture the exact
filename returned by npm pack as TARBALL, inspect that archive rather than using
a wildcard, and explicitly fail when no .medusa/server entry is found. Publish
the verified archive with npm publish "$TARBALL" instead of publishing the
package directory, avoiding a repack through prepublishOnly.
| ```bash | ||
| # Stable example: | ||
| npm publish ./plugins/braintree-payment --access public \ | ||
| --registry=https://registry.npmjs.org | ||
|
|
||
| # Prerelease example (0.2.0-next → tag next): | ||
| npm publish ./plugins/braintree-payment --access public --tag next \ | ||
| --registry=https://registry.npmjs.org |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '--- target skill context ---'
sed -n '130,225p' .cursor/skills/publish-braintree-plugin/SKILL.md
printf '%s\n' '--- workflow files ---'
git ls-files | rg '(^|/)\.github/workflows/|publish|braintree' | head -200
printf '%s\n' '--- publication-related references ---'
rg -n -C 4 --glob '*.yml' --glob '*.yaml' --glob '*.md' --glob '*.json' \
'npm (publish|pack|view)|--tag|dist-tag|braintree-payment|PREV_COMMIT|git log|git diff|npx' .Repository: lambda-curry/medusa-plugins
Length of output: 11180
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '--- publish workflow ---'
cat -n .github/workflows/publish.yml
printf '%s\n' '--- npm configuration and publish references ---'
git ls-files | rg '(^|/)(\.npmrc|package\.json)$' | xargs -r -n1 sh -c 'echo "--- $0"; cat -n "$0"'
rg -n -C 5 'npm publish|--dry-run|--tag|dist-tag|publish' .github .cursor plugins/braintree-payment/package.json 2>/dev/null || true
printf '%s\n' '--- relevant history-independent file metadata ---'
git diff --stat
git status --shortRepository: lambda-curry/medusa-plugins
Length of output: 37191
🌐 Web query:
npm publish default dist-tag prerelease version --tag latest official documentation
💡 Result:
By default, the npm publish command tags all published versions, including prerelease versions, with the latest distribution tag [1][2][3]. This behavior is the default behavior of the npm CLI unless the --tag option is explicitly provided during publication [1][2][4]. To avoid assigning the latest tag to a prerelease version, you must use the --tag flag to specify a different, non-latest tag [1][2]. Example of publishing a prerelease version without overwriting the latest tag: npm publish --tag beta In this example, the version will be tagged as beta instead of latest. When users run npm install <package_name> without a specific version or tag, npm will continue to install the version associated with the latest tag [5][2]. Official documentation indicates that this is intended behavior, though it is often noted by the community as a point of friction ("footgun") when developers inadvertently update the latest version for all users with a prerelease [6][3][7]. Projects typically use latest for stable releases and separate tags (e.g., beta, next, alpha) for unstable or prerelease versions to manage distribution effectively [1][2][8].
Citations:
- 1: https://docs.npmjs.com/adding-dist-tags-to-packages/
- 2: https://docs.npmjs.com/cli/v11/commands/npm-dist-tag/
- 3: [BUG] "npm publish" tags pre-versions as "latest" npm/cli#7553
- 4: https://docs.npmjs.com/cli/v10/commands/npm-publish/
- 5: https://docs.npmjs.com/cli/v11/commands/npm-publish/
- 6: RFC: No implicit tagging for non-latest release versions npm/rfcs#776
- 7: "npm publish" tags pre-versions as "latest" npm/npm#13248
- 8: https://docs.npmjs.com/cli/v8/commands/npm-dist-tag/
🏁 Script executed:
#!/bin/bash
set -eu
python3 - <<'PY'
from pathlib import Path
import re
skill = Path(".cursor/skills/publish-braintree-plugin/SKILL.md").read_text()
workflow = Path(".github/workflows/publish.yml").read_text()
publish_lines = [
line.strip()
for text in (skill, workflow)
for line in text.splitlines()
if re.search(r"\bnpm publish\b", line)
]
print("Publish commands:")
for line in publish_lines:
print(line)
print("\nExplicit-tag status:")
for line in publish_lines:
print(f"{'tag-present' if re.search(r'--tag(?:=|\s+)\S+', line) else 'tag-absent'}: {line}")
print("\nCurrent Braintree version:")
package = Path("plugins/braintree-payment/package.json").read_text()
match = re.search(r'"version"\s*:\s*"([^"]+)"', package)
print(match.group(1) if match else "not found")
assert "npm publish \"./$dir\" --access public" in workflow
assert "npm publish ./plugins/braintree-payment --access public \\" in skill
assert "--tag next" in skill
PYRepository: lambda-curry/medusa-plugins
Length of output: 450
🏁 Script executed:
#!/bin/bash
set -eu
python3 - <<'PY'
from pathlib import Path
import re
skill = Path(".cursor/skills/publish-braintree-plugin/SKILL.md").read_text()
workflow = Path(".github/workflows/publish.yml").read_text()
print("Skill publish blocks:")
for match in re.finditer(r"npm publish[^\n]*(?:\\\n[^\n]*)*", skill):
command = match.group(0).replace("\\\n", " ")
print(command)
print("\nWorkflow publish command:")
for line in workflow.splitlines():
if "npm publish" in line:
print(line.strip())
print("\nExplicit tag checks:")
commands = [
match.group(0).replace("\\\n", " ")
for match in re.finditer(r"npm publish[^\n]*(?:\\\n[^\n]*)*", skill)
]
commands += [line.strip() for line in workflow.splitlines() if "npm publish" in line]
for command in commands:
has_tag = bool(re.search(r"--tag(?:=|\s+)\S+", command))
print(("tag-present" if has_tag else "tag-absent") + ": " + command)
package = Path("plugins/braintree-payment/package.json").read_text()
version = re.search(r'"version"\s*:\s*"([^"]+)"', package).group(1)
print("\nCurrent Braintree version: " + version)
print("Current version is prerelease: " + str("-" in version))
assert "npm publish \"./$dir\" --access public" in workflow
assert any("--tag next" in command for command in commands)
assert "-next" in version
PYRepository: lambda-curry/medusa-plugins
Length of output: 904
Make the dist-tag explicit on every publication path.
Pass --tag latest for stable publish and dry-run commands. In .github/workflows/publish.yml, derive latest for stable versions and the prerelease channel (for example, next) for prerelease versions, then pass it to npm publish. Otherwise, the current 0.2.0-next release can update latest.
🧰 Tools
🪛 SkillSpector (2.5.1)
[warning] 130: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.
Remediation: Pin the version: npx @scope/server@1.2.3
(MCP Rug Pull (RP1))
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.cursor/skills/publish-braintree-plugin/SKILL.md around lines 164 - 171,
Make the dist-tag explicit across all publication paths: add --tag latest to
stable npm publish and dry-run examples, and update the publish workflow to
derive latest for stable versions or the prerelease channel (such as next) for
prerelease versions before passing it to npm publish.
Summary
.cursor/skills/publish-braintree-pluginfor releasing@lambdacurry/medusa-payment-braintree.Test plan
npm publish --dry-runonly.tgzartifacts are committedMade with Cursor
Summary by CodeRabbit