Summary
pantry publish:commit '.' (single-path argument) has two bugs that compound:
private: trueis not honored when the argument is a direct path (only the/*glob branch checks forprivate).- The whole repo gets tarred because the monorepo root's
package.jsonlacks afilesfield, socreateTarballDefaultis used and the entire workspace is rsync'd — ignoring child packages'filesfields.
Combined, this means pantry publish:commit '.' from a monorepo root happily attempts to publish a private workspace-root package and produces tarballs that blow past the 50MB registry limit.
Reproduction
Monorepo root package.json:
{
"name": "ts-watches",
"private": true,
"version": "0.1.0",
"workspaces": ["packages/*"]
}Child packages/ts-watches/package.json:
{
"name": "ts-watches",
"version": "0.1.0",
"files": ["README.md", "dist"]
}Run from repo root:
pantry publish:commit '.'Output:
Found 1 package(s) to publish:
- ts-watches (v0.1.0) ← root pkg, marked private:true, picked up anyway
Publishing ts-watches...
Scanning for ignore files in: /repo/.
...
Tarball: 73735916 bytes ← whole repo tarred; child's files:[] field ignored
Upload error: {"error":"Tarball for ts-watches exceeds maximum size of 50MB"}Expected behavior:
- Either skip the private root, or
- Resolve
'.'to discoverable child packages (same as'./packages/*') and use each child'sfilesfield for the tarball.
Root cause (code review)
In packages/zig/src/cli/commands/publish_commit.zig, resolveGlobPattern:
The
/*branch (lines ~387–472) iterates child dirs and does check `private`:// Skip private packages const is_private = if (root.object.get(\"private\")) |p| if (p == .bool) p.bool else false else false; if (is_private) { style.print(\" Skipping {s} (private)\n\", .{entry.name}); ... continue; }The single-path branch (lines ~474+, `// Treat as a direct path to a single package`) does not read `private` at all — it just calls `readPackageName` / `readPackageVersion` and appends to `packages`.
Then in `registry.zig` `createTarball`, the package_dir is the repo root. Since the root `package.json` has no `files` field, it falls through to `createTarballDefault`, which rsyncs the entire `package_dir` (the whole repo) with only `.pantryignore` exclusions. The child package's `files: ["README.md", "dist"]` field — which would have made the tarball ~600KB — is never consulted.
Suggested fix
Two small fixes that together resolve this cleanly:
In the single-path branch of `resolveGlobPattern`, mirror the `private: true` check from the `/*` branch and skip the package if it's private (with a clear message — currently it silently proceeds).
For monorepo roots: when the resolved single path's `package.json` declares `workspaces`, either:
- error out with a hint (`"This looks like a monorepo root — try `pantry publish:commit './packages/*'` to publish individual workspace packages"`), or
- auto-expand to the workspace globs (closer to what `detectMonorepoPackages` does in the no-args case).
Fix #1 alone would have surfaced the user error here ("private package, refusing to publish") instead of producing a 70MB tarball and a confusing size-limit error. Fix #2 makes the happy path work for monorepos.
Related
Companion to #202 (`.pantryignore` glob behavior) — different bug, same end-user symptom of oversized tarballs from `publish:commit`.
Environment
- pantry 0.9.28 (
109f016) - Repro repo: stacksjs/ts-watches