Skip to content

Ship README and LICENSE in published npm packages - #182

Merged
gtbuchanan merged 2 commits into
mainfrom
ship-readme-license
Jun 17, 2026
Merged

Ship README and LICENSE in published npm packages#182
gtbuchanan merged 2 commits into
mainfrom
ship-readme-license

Conversation

@gtbuchanan

Copy link
Copy Markdown
Owner

Summary

The packages were published for the first time missing their README and LICENSE. npm only auto-includes those files from the publish directory, which publishConfig.directory redirects to dist/source/ — but pack:npm only copied the generated manifest and skills/ there. There was also no LICENSE file or license field anywhere in the repo.

  • Add an MIT LICENSE (no copyright year, to avoid drift) and a root license field.
  • pack:npm now copies each package's README.md and the workspace-root LICENSE into dist/source/, and the published package.json carries a license field.
  • A package-level README / LICENSE / license overrides the shared root one (resolveDoc / resolveLicense, package-then-root precedence). buildRepoFields keeps root-precedence for the scoped repo coordinates; license is handled separately since the package should win.
  • Wire the doc copies as pack:npm turbo inputs (cache invalidates on edit) and outputs (cache-hit publishes restore them), excluding the self-generated copies from the input glob like the existing package.json exclusion.
  • Patch-bump every npm-published package so the next release re-publishes them with the corrected docs.

Testing

  • New resolveLicense units + prepack integration tests (README/LICENSE copy, package-over-root override, absent-docs, license-field precedence).
  • pnpm build green (67/67 tasks, incl. e2e against packed tarballs); gtb verify reports no drift; lint clean.
  • Verified end-to-end by packing @gtbuchanan/eslint-config: tarball ships package/README.md + package/LICENSE, manifest has "license": "MIT".

🤖 Generated with Claude Code

pack:npm now copies each package's README.md and the workspace-root
LICENSE into dist/source/ (the directory publishConfig.directory
redirects publishing to), and the published package.json carries a
license field. A package-level README/LICENSE/license overrides the
shared root one.

npm only auto-includes README/LICENSE from the publish directory, so
they were absent from the first release. Add the MIT LICENSE and a
root license field, wire the copies as pack:npm turbo inputs/outputs
so cache-hit publishes restore them, and patch-bump every published
package to re-publish with the corrected docs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@codecov-commenter

codecov-commenter commented Jun 17, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 93.75000% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 81.57%. Comparing base (165b777) to head (a730a9d).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
packages/cli/src/commands/task/pack-npm.ts 92.85% 1 Missing ⚠️

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@coderabbitai

coderabbitai Bot commented Jun 17, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 32eeaec7-1d86-4e7d-b819-62ced6928b8b

📥 Commits

Reviewing files that changed from the base of the PR and between 32a8cf7 and a730a9d.

📒 Files selected for processing (4)
  • packages/cli/skills/gtb-build-pipeline/SKILL.md
  • packages/cli/src/commands/task/pack-npm.ts
  • packages/cli/src/lib/turbo-config.ts
  • packages/cli/test/prepack.test.ts
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • gtbuchanan/tooling (manual)
📜 Recent review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: CI / Build
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Prefer interface for defining object shapes in TypeScript
Use camelCase for variable names in TypeScript
Use JSDoc on exports in TypeScript files

Files:

  • packages/cli/src/lib/turbo-config.ts
  • packages/cli/test/prepack.test.ts
  • packages/cli/src/commands/task/pack-npm.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Suppress ESLint warnings with -- reason suffix on suppressions

Files:

  • packages/cli/src/lib/turbo-config.ts
  • packages/cli/test/prepack.test.ts
  • packages/cli/src/commands/task/pack-npm.ts
**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.test.{ts,tsx}: Use expect(result).toMatchObject({ exitCode: 0 }) instead of expect(result.exitCode).toBe(0) when asserting on CommandResult
Generate incidental test data via @gtbuchanan/test-utils/builders with pattern: import * as build from '@gtbuchanan/test-utils/builders', then const name = build.scopedPackageName()
Use Vitest native tag system for slow tests (test('name', { tags: ['slow'] }, ...) or /** @module-tag slow */)

Files:

  • packages/cli/test/prepack.test.ts
🧠 Learnings (3)
📚 Learning: 2026-06-15T19:58:14.171Z
Learnt from: gtbuchanan
Repo: gtbuchanan/tooling PR: 162
File: packages/cli/test/discovery.test.ts:86-94
Timestamp: 2026-06-15T19:58:14.171Z
Learning: In the gtbuchanan/tooling repo, hand-authored `.pkl` source files are expected to live at the package root (top level), not under subdirectories like `src/`. Accordingly, when reviewing `discoverPackage` logic for `hasPkl`, ensure it only detects top-level `.pkl` files in the package root and does not require (or add) recursive/nested-directory `.pkl` discovery.

Applied to files:

  • packages/cli/src/lib/turbo-config.ts
  • packages/cli/test/prepack.test.ts
  • packages/cli/src/commands/task/pack-npm.ts
📚 Learning: 2026-06-04T02:26:02.824Z
Learnt from: gtbuchanan
Repo: gtbuchanan/tooling PR: 139
File: packages/cli/test/coverage-codecov-upload.test.ts:2-2
Timestamp: 2026-06-04T02:26:02.824Z
Learning: In tests within **/{test,e2e,__tests__}/**/*.{test,spec}.{ts,tsx,js,jsx}, follow the AGENTS.md faker convention: direct `faker-js/faker` usage is allowed only for one-off primitives when the produced value’s shape is exactly what faker returns (e.g., `faker.git.commitSha()`, `faker.string.uuid()`). Use `gtbuchanan/test-utils/builders` only when there is a domain-shaped value worth centralizing (e.g., scoped package names, semver ranges, GitHub URLs). Do not wrap a native faker generator in a builder for a plain primitive (e.g., a raw commit SHA), since that adds indirection without centralizing any domain shape.

Applied to files:

  • packages/cli/test/prepack.test.ts
📚 Learning: 2026-06-15T19:58:27.007Z
Learnt from: gtbuchanan
Repo: gtbuchanan/tooling PR: 162
File: packages/cli/test/typecheck-pkl.test.ts:8-23
Timestamp: 2026-06-15T19:58:27.007Z
Learning: When reviewing tests (e.g., in packages/**/test/**/*.test.ts), if the system-under-test explicitly branches on specific string-literal values (such as sort order, extension filters, or reserved filename exclusions like "PklProject"), require those branching inputs to be hardcoded literals in the test rather than generated via test-data builders. Do not recommend replacing these literals with builder patterns, because it would obscure what behavior is being exercised. Allow builder patterns only for incidental, domain-shaped data where the exact values do not affect the assertion logic (e.g., scoped package names or semver ranges used as opaque inputs).

Applied to files:

  • packages/cli/test/prepack.test.ts
🪛 SkillSpector (2.1.1)
packages/cli/skills/gtb-build-pipeline/SKILL.md

[error] 114: [YR1] YARA rule 'backdoor_persistence': Backdoor persistence with malicious payloads (shell commands, SSH key injection, hidden root users) [malware]: YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).

Remediation: Remove the malware payload or compromised file entirely. Investigate how it entered the skill and audit all other artifacts for additional indicators of compromise.

(YARA Match (YR1))

🔇 Additional comments (7)
packages/cli/src/commands/task/pack-npm.ts (2)

62-64: LGTM!


79-94: LGTM!

packages/cli/src/lib/turbo-config.ts (1)

195-217: LGTM!

packages/cli/test/prepack.test.ts (3)

11-14: LGTM!


228-238: LGTM!


264-276: LGTM!

packages/cli/skills/gtb-build-pipeline/SKILL.md (1)

53-55: LGTM!


📝 Walkthrough

Walkthrough

Adds a root LICENSE (MIT) file and license field to the root package.json. Extends manifest schemas with an optional license field and introduces a resolveLicense helper. Updates pack-npm.ts to inject the resolved license into the generated package.json and copy README.md/LICENSE into dist/source/ with package-level override precedence. Updates Turbo task config to hash and cache these new artifacts.

Changes

README/LICENSE Publishing in pack:npm

Layer / File(s) Summary
Root license files and manifest schema contract
LICENSE, package.json, packages/cli/src/lib/manifest.ts
Adds the root MIT LICENSE file and license: "MIT" to package.json. Extends RootManifestSchema and ManifestSchema with an optional license field. Introduces the exported resolveLicense(manifest, root) helper that prefers the package-level license and falls back to the root, returning undefined if neither is set.
pack-npm: license injection and doc copying
packages/cli/src/commands/task/pack-npm.ts
Imports cpSync, existsSync, and resolveLicense. Adds resolveDoc (package-then-root path resolution) and copyPackageDocs (copies README.md and LICENSE into dist/source/). writeSourceManifest conditionally injects the resolved license field. Both preparePackage and prepareAndPack call copyPackageDocs.
Turbo task input/output config
packages/cli/src/lib/turbo-config.ts, turbo.json
Adds $TURBO_ROOT$/LICENSE and $TURBO_ROOT$/README.md as pack:npm inputs, excludes generated dist/source/LICENSE, dist/source/README.md, and dist/source/package.json from the dist/source/** input glob, and declares those three files as task outputs.
Tests, skill docs, and changeset
packages/cli/test/manifest.test.ts, packages/cli/test/prepack.test.ts, packages/cli/skills/gtb-build-pipeline/SKILL.md, .changeset/publish-readme-license.md
manifest.test.ts adds resolveLicense tests covering precedence, fallback, and undefined. prepack.test.ts refactors setup into a scaffoldPackage helper and adds tests for README copying, root-vs-package LICENSE precedence, absent doc omission, and license field injection. SKILL.md documents the new dist/source/ file behavior. Changeset records patch bumps.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The pull request title accurately and concisely describes the main objective: shipping README and LICENSE files in published npm packages, matching the primary changes throughout the changeset.
Description check ✅ Passed The pull request description is comprehensive and directly related to the changeset, detailing the problem, solution, implementation approach, and testing performed.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 `@packages/cli/skills/gtb-build-pipeline/SKILL.md`:
- Around line 53-57: The documentation for the pack:npm task currently describes
README and LICENSE handling in a way that suggests different precedence rules
for each file. Update the wording to explicitly clarify that both README.md and
LICENSE follow the same precedence pattern: package-level files are preferred,
with a fallback to workspace-root versions if the package-level copy does not
exist. Replace the phrase "copies the package `README.md` plus the
workspace-root `LICENSE` (a package-level copy of either wins)" with clearer
wording that makes it obvious both files use identical package-then-root
precedence logic to avoid confusion for operators.

In `@packages/cli/src/commands/task/pack-npm.ts`:
- Around line 88-93: In the loop that iterates over the doc files (README.md and
LICENSE) in the pack-npm.ts file, add an else clause to handle the case when
source is undefined. When a doc file no longer exists in the source (source ===
undefined), delete the corresponding file from the target directory using the
same target path construction (path.join(target, name)) to prevent stale files
from persisting across builds and getting published incorrectly.

In `@packages/cli/src/lib/turbo-config.ts`:
- Around line 206-212: Add the missing root README.md file to the inputs array
for cache correctness. In the turbo-config.ts file where the pack:npm task
inputs are defined (around line 206-212), the array includes
'$TURBO_ROOT$/LICENSE' but is missing '$TURBO_ROOT$/README.md'. Since the
copyPackageDocs function treats both LICENSE and README.md files symmetrically
and falls back to root files when package-specific versions don't exist, you
need to add '$TURBO_ROOT$/README.md' to the inputs array alongside
'$TURBO_ROOT$/LICENSE' to ensure cache invalidation when the root README.md
changes.

In `@packages/cli/test/prepack.test.ts`:
- Around line 14-17: Extract the inline object type definition for the overrides
parameter in the scaffoldPackage function into a separate interface to match the
repository's TypeScript style guide. Create a new interface that defines the
shape with the pkgManifest and rootManifest properties (both typed as
Record<string, unknown>), then update the overrides parameter to reference this
new interface instead of using the inline type definition.
🪄 Autofix (Beta)

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: ASSERTIVE

Plan: Pro Plus

Run ID: 2cf09700-329b-4b20-ad4e-264c99d37dbc

📥 Commits

Reviewing files that changed from the base of the PR and between dda38a6 and 32a8cf7.

📒 Files selected for processing (10)
  • .changeset/publish-readme-license.md
  • LICENSE
  • package.json
  • packages/cli/skills/gtb-build-pipeline/SKILL.md
  • packages/cli/src/commands/task/pack-npm.ts
  • packages/cli/src/lib/manifest.ts
  • packages/cli/src/lib/turbo-config.ts
  • packages/cli/test/manifest.test.ts
  • packages/cli/test/prepack.test.ts
  • turbo.json
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • gtbuchanan/tooling (manual)
📜 Review details
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Prefer interface for defining object shapes in TypeScript
Use camelCase for variable names in TypeScript
Use JSDoc on exports in TypeScript files

Files:

  • packages/cli/test/manifest.test.ts
  • packages/cli/src/lib/manifest.ts
  • packages/cli/src/lib/turbo-config.ts
  • packages/cli/test/prepack.test.ts
  • packages/cli/src/commands/task/pack-npm.ts
**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.test.{ts,tsx}: Use expect(result).toMatchObject({ exitCode: 0 }) instead of expect(result.exitCode).toBe(0) when asserting on CommandResult
Generate incidental test data via @gtbuchanan/test-utils/builders with pattern: import * as build from '@gtbuchanan/test-utils/builders', then const name = build.scopedPackageName()
Use Vitest native tag system for slow tests (test('name', { tags: ['slow'] }, ...) or /** @module-tag slow */)

Files:

  • packages/cli/test/manifest.test.ts
  • packages/cli/test/prepack.test.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Suppress ESLint warnings with -- reason suffix on suppressions

Files:

  • packages/cli/test/manifest.test.ts
  • packages/cli/src/lib/manifest.ts
  • packages/cli/src/lib/turbo-config.ts
  • packages/cli/test/prepack.test.ts
  • packages/cli/src/commands/task/pack-npm.ts
.changeset/*.md

📄 CodeRabbit inference engine (AGENTS.md)

.changeset/*.md: Every PR requires a changeset; create a .changeset/.md file with YAML frontmatter listing affected packages and bump types
For PRs that don't affect published packages, create an empty changeset with no packages in frontmatter

Files:

  • .changeset/publish-readme-license.md
🧠 Learnings (3)
📚 Learning: 2026-06-04T02:26:02.824Z
Learnt from: gtbuchanan
Repo: gtbuchanan/tooling PR: 139
File: packages/cli/test/coverage-codecov-upload.test.ts:2-2
Timestamp: 2026-06-04T02:26:02.824Z
Learning: In tests within **/{test,e2e,__tests__}/**/*.{test,spec}.{ts,tsx,js,jsx}, follow the AGENTS.md faker convention: direct `faker-js/faker` usage is allowed only for one-off primitives when the produced value’s shape is exactly what faker returns (e.g., `faker.git.commitSha()`, `faker.string.uuid()`). Use `gtbuchanan/test-utils/builders` only when there is a domain-shaped value worth centralizing (e.g., scoped package names, semver ranges, GitHub URLs). Do not wrap a native faker generator in a builder for a plain primitive (e.g., a raw commit SHA), since that adds indirection without centralizing any domain shape.

Applied to files:

  • packages/cli/test/manifest.test.ts
  • packages/cli/test/prepack.test.ts
📚 Learning: 2026-06-15T19:58:14.171Z
Learnt from: gtbuchanan
Repo: gtbuchanan/tooling PR: 162
File: packages/cli/test/discovery.test.ts:86-94
Timestamp: 2026-06-15T19:58:14.171Z
Learning: In the gtbuchanan/tooling repo, hand-authored `.pkl` source files are expected to live at the package root (top level), not under subdirectories like `src/`. Accordingly, when reviewing `discoverPackage` logic for `hasPkl`, ensure it only detects top-level `.pkl` files in the package root and does not require (or add) recursive/nested-directory `.pkl` discovery.

Applied to files:

  • packages/cli/test/manifest.test.ts
  • packages/cli/src/lib/manifest.ts
  • packages/cli/src/lib/turbo-config.ts
  • packages/cli/test/prepack.test.ts
  • packages/cli/src/commands/task/pack-npm.ts
📚 Learning: 2026-06-15T19:58:27.007Z
Learnt from: gtbuchanan
Repo: gtbuchanan/tooling PR: 162
File: packages/cli/test/typecheck-pkl.test.ts:8-23
Timestamp: 2026-06-15T19:58:27.007Z
Learning: When reviewing tests (e.g., in packages/**/test/**/*.test.ts), if the system-under-test explicitly branches on specific string-literal values (such as sort order, extension filters, or reserved filename exclusions like "PklProject"), require those branching inputs to be hardcoded literals in the test rather than generated via test-data builders. Do not recommend replacing these literals with builder patterns, because it would obscure what behavior is being exercised. Allow builder patterns only for incidental, domain-shaped data where the exact values do not affect the assertion logic (e.g., scoped package names or semver ranges used as opaque inputs).

Applied to files:

  • packages/cli/test/manifest.test.ts
  • packages/cli/test/prepack.test.ts
🪛 markdownlint-cli2 (0.22.1)
.changeset/publish-readme-license.md

[warning] 13-13: First line in a file should be a top-level heading

(MD041, first-line-heading, first-line-h1)

🪛 SkillSpector (2.1.1)
packages/cli/skills/gtb-build-pipeline/SKILL.md

[error] 116: [YR1] YARA rule 'backdoor_persistence': Backdoor persistence with malicious payloads (shell commands, SSH key injection, hidden root users) [malware]: YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).

Remediation: Remove the malware payload or compromised file entirely. Investigate how it entered the skill and audit all other artifacts for additional indicators of compromise.

(YARA Match (YR1))

🔇 Additional comments (8)
LICENSE (1)

1-22: LGTM!

package.json (1)

10-10: LGTM!

packages/cli/src/lib/manifest.ts (1)

27-28: LGTM!

Also applies to: 38-39, 51-54, 69-77

packages/cli/src/commands/task/pack-npm.ts (1)

1-75: LGTM!

Also applies to: 96-147

turbo.json (1)

145-153: Same issue: missing "$TURBO_ROOT$/README.md" in inputs.

This file is auto-generated from turbo-config.ts, so fixing the missing $TURBO_ROOT$/README.md input in the TypeScript source (see previous comment) will automatically correct this generated JSON.

packages/cli/test/manifest.test.ts (1)

1-8: LGTM!

Also applies to: 144-172

packages/cli/test/prepack.test.ts (1)

200-280: LGTM!

.changeset/publish-readme-license.md (1)

1-20: LGTM!

Comment thread packages/cli/skills/gtb-build-pipeline/SKILL.md Outdated
Comment thread packages/cli/src/commands/task/pack-npm.ts Outdated
Comment thread packages/cli/src/lib/turbo-config.ts
Comment thread packages/cli/test/prepack.test.ts Outdated
- Make pack:npm README copy package-only (no workspace-root fallback);
  a README documents one package, so falling back to the monorepo root
  README would publish a wrong one. LICENSE stays package-then-root
  since a license is repo-wide.
- Remove a stale dist/source/README.md or LICENSE left by a prior run
  so a since-deleted doc isn't republished.
- Extract scaffoldPackage's overrides into a ScaffoldPackageOverrides
  interface; tighten the pack:npm SKILL.md note to one line.
- Add tests: README does not fall back to root; stale doc removal.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@gtbuchanan
gtbuchanan merged commit d8f16ea into main Jun 17, 2026
11 checks passed
@gtbuchanan
gtbuchanan deleted the ship-readme-license branch June 17, 2026 03:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants