🙈 chore(build): untrack dist/, keep publishing it - #52
Conversation
`npm run build` has been failing on master. `packages/grab-url-cli/src/index.ts`
carried a second `export { … } from './transfer/ytdlp-transfer.js'` block whose
names were either already exported a few lines above or never existed at all
(`parseYtDlpSize`, `parseYtDlpEta`, `runYtDlpDownload`, `YtDlpMetadata`), so
esbuild rejected the duplicates and rollup then rejected the missing ones.
`page/archive-page.ts` imported that same never-written pair, so the `--page`
video step could not have run. Implement both in `ytdlp-transfer.ts` under the
names archive-page and `test/page-archive.test.ts` already expect:
- `probeYtDlp(url)` — a `--dump-single-json --skip-download` probe returning
`YtDlpMetadata` or null, so an ordinary article skips the video step quietly.
- `runYtDlpDownload(url, opts)` — the quiet counterpart to `runYtDlpTransfer`,
reporting saved paths from yt-dlp's own `after_move:filepath` print.
`findYtDlp` and `ytDlpInstallHint` are re-exported from `ytdlp-transfer` so
archive-page takes its whole yt-dlp surface from one module. The barrel keeps
exporting `ytdlp-binary`'s `probeYtDlp`, so the public API is unchanged.
CI runs only `test:coverage`, never `build`, which is how this reached master.
Test suite is unchanged at 343 passed / 11 failed — those 11 are a separate
pre-existing conflict between two yt-dlp progress-parsing designs.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R3wkKQsRoi6k3DTvBRQhHd
`dist` was already listed in .gitignore, but 130 build artifacts were tracked anyway — gitignore does not apply to files git already follows. The committed bundle had also gone stale: it predated a package reshuffle, so its `.d.ts` tree no longer matched the source it claimed to come from, and it masked the fact that `npm run build` was failing. Untracks root `dist/`, `packages/archiver-web/dist/` (35 stale copies of the root build, unrelated to that package) and `packages/quantum-sphere-loading-animation/dist/`. The files stay on disk; only git stops following them. `packages/native-app-wrapper/dist/index.html` stays tracked — it is not build output but the hand-written UI Tauri serves as `frontendDist`, so .gitignore re-includes that one directory. Publishing is unaffected: a `files` entry cannot be excluded by .gitignore, so `npm pack` still carries dist, and `prepublishOnly` rebuilds it first. Verified with `npm pack --dry-run` — the root tarball packs the same 91 files as before, and all 18 paths named by package.json's main/types/module/bin/exports resolve in a from-scratch build. Adds the missing `prepublishOnly` to quantum-sphere-loading-icon so a manual publish cannot ship without one. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01R3wkKQsRoi6k3DTvBRQhHd
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
CI:
|
| Tests | |
|---|---|
master baseline |
343 passed / 11 failed |
| this branch | 343 passed / 11 failed |
Same 11, same names. This PR neither causes nor worsens them.
What the 11 failures actually are. test/page-archive.test.ts is written against a different generation of packages/grab-url-cli/src/transfer/ytdlp-transfer.ts than the one on disk — the --page feature (#49) landed with tests for one design while the module implements another:
| The test expects | The module implements |
|---|---|
parseYtDlpSize('1.00KiB') → 1024 |
(does not exist) |
parseYtDlpEta('01:02:03') → 3723 |
(does not exist) |
parseYtDlpProgress() parses yt-dlp's human console line ([download] 23.4% of ~12.00MiB at 1.00MiB/s ETA 00:42) and returns a percent |
parses the @GRAB@ --progress-template sentinel and returns status / estimated / fragmentIndex |
buildYtDlpArgs(url, { filename }) → 'My Video.%(ext)s' |
takes output, used verbatim |
describeYtDlpExit(1) === 'download failed' |
'download failed — the media may be private, region-locked or removed' |
Why I am not fixing it here. Nine of the eleven are additive and safe (parseYtDlpSize, parseYtDlpEta, accepting filename alongside output, shortening the exit string). The remaining two are not: parseYtDlpProgress cannot satisfy both designs at once, and the sentinel version is the one runYtDlpTransfer feeds its live progress bar from. Fixing nine leaves CI red anyway, so it buys nothing and widens a .gitignore PR into a rewrite of the downloader's progress path. Which design is canonical is a call for the repo owner, not something to decide inside this PR.
Proposed patch, for whoever picks it up. Keep the sentinel design — it is what production uses, and it is strictly more informative. Then:
- Add
parseYtDlpSize/parseYtDlpEtaas pure helpers (the tests fully specify them). - Accept
filenameinYtDlpOptionsasfilename + '.%(ext)s', keepingoutputfor the verbatim case. - Update the
parseYtDlpProgresstests to the sentinel format rather than the console format — the console-parsing API they describe is not reachable from any caller. - Decide on the
describeYtDlpExit(1)wording and align test and module.
This is not a flake, so I have not spent a re-run on it: a re-run would fail identically.
One thing this PR does fix: npm run build was also broken on master (duplicate and non-existent re-exports in grab-url-cli/src/index.ts, plus archive-page.ts importing a runYtDlpDownload that was never written). That is repaired in 596d7b1 and the build is green. It went unnoticed because tests.yml runs only npm run test:coverage and never npm run build — worth adding a build step to CI in a follow-up.
Vercel is a separate known issue: the project's Root Directory is still docs, a folder #47 deleted, so every deployment fails at clone. That is a dashboard setting, already documented in .claude/architecture/documentation.md by #51 — nothing in this diff affects it.
Generated by Claude Code
Hides
dist/from git while keeping it in every npm tarball.The problem
distwas already listed in.gitignore, but 130 build artifacts were tracked anyway —.gitignorehas no effect on files git already follows. Worse, the committed bundle had gone stale: it predated a package reshuffle, so its.d.tstree (dist/grab-api/*.d.ts) no longer matched the current source layout (dist/grab-api/src/*.d.ts). That stale bundle was masking the fact thatnpm run buildhas been failing onmaster.What changed
Untracked (files stay on disk; only git stops following them):
dist/packages/archiver-web/dist/grab-api,grab-url-cli,log,icons, nothing of archiver-web'spackages/quantum-sphere-loading-animation/dist/tsupoutputsKept tracked:
packages/native-app-wrapper/dist/index.html. It is not build output — it is the hand-written UI Tauri serves asfrontendDist(src-tauri/tauri.conf.json), and its own comment says "no build step and no npm dependency"..gitignorere-includes that one directory.Build fix (separate commit, required to make the above safe):
packages/grab-url-cli/src/index.tscarried a duplicateexport { … } from './transfer/ytdlp-transfer.js'block whose names were either already exported a few lines above or never existed at all.page/archive-page.tsimported that same never-written pair, so the--pagevideo step could not have run. ImplementedprobeYtDlp(url)andrunYtDlpDownload(url, opts)inytdlp-transfer.tsunder the namesarchive-page.tsandtest/page-archive.test.tsalready expect.Why publishing still works
A
filesentry cannot be excluded by.gitignoreor.npmignore— sonpm packstill carriesdist, andprepublishOnlyrebuilds it beforehand. Also adds the missingprepublishOnlytoquantum-sphere-loading-iconso a manualnpm publishcannot ship without one.Verification
rm -rf dist && npm run build→ rebuilds clean; all 18 paths named bypackage.json'smain/types/module/bin/exportsresolve.npm pack --dry-run→ 91 files, identical to before (125 dist entries after the rebuild, up from the stale 87).git statusclean after a build — no dist noise.npx vitest run→ 343 passed / 11 failed, byte-identical to themasterbaseline (verified via agit worktreeofHEAD). Those 11 failures are pre-existing and untouched here.Left for a follow-up
masteris red onnpm testindependently of this PR:test/page-archive.test.tsis written against a different yt-dlp module design than the one on disk — it expectsparseYtDlpSize,parseYtDlpEta, apercent-bearingparseYtDlpProgressthat parses yt-dlp's human console line, andbuildYtDlpArgs({ filename }), whereas the module implements a--progress-templatesentinel design withoutput. Reconciling those two is a design decision, not a build fix, so it is deliberately out of scope.Worth noting: CI (
tests.yml) runs onlynpm run test:coverage, nevernpm run build— which is how a broken build reachedmasterunnoticed.🤖 Generated with Claude Code
https://claude.ai/code/session_01R3wkKQsRoi6k3DTvBRQhHd
Generated by Claude Code