Conversation
The problems cache embeds per-user solve state and was trusted forever, so a months-old snapshot reads as mass "not solved" desync. Refresh it when a problemsMeta marker is missing or older than 24h; local updateProblem patches do not renew the TTL. On refresh failure serve the stale list with a warning instead of failing outright. Co-Authored-By: Claude <noreply@anthropic.com>
Only password login (plugin.login) went through the cache plugin's purge hook; cookie/github/linkedin logins resolved straight to the leetcode plugin via the prototype chain, leaving the previous account's problems.json behind. Wrap all four entry points with the same purge. retry.relogin is left alone on purpose: it re-authenticates the same saved user, so the identity cannot change. Use module-level `plugin` refs instead of `this` since commands/user.js invokes github/linkedin login detached from the plugin object. Co-Authored-By: Claude <noreply@anthropic.com>
Fixed-width columns broke as content grew past the assumed width: stat bars went ragged once the ac/total counts hit 4 digits, list's 60-col name field overflows for 61 titles (up to 79 chars, shifting the level column), and cache's size/created columns shift on cache names longer than 60. Derive the widths from the data being printed instead of hardcoding them. Known residual: titles containing zero-width/narrow unicode chars (e.g. U+200C, U+2011) still drift 1-2 cols because sprintf's len() counts every non-ascii char as 2 columns; fixing that needs a proper east-asian-width table. Co-Authored-By: Claude <noreply@anthropic.com>
checkError mapped every 401/403 to "session expired, please login again", but leetcode now signals auth failures with 401 (REST) or 200 + empty user fields (GraphQL / problem list). A 403/429 is cloudflare blocking or rate limiting the client with a perfectly valid session, so report it as BLOCKED instead. This also stops the autologin machinery from firing doomed relogins on transient 403s: retry only engages on the EXPIRED object. Co-Authored-By: Claude <noreply@anthropic.com>
Fixes the "Cannot read property 'toString' of undefined" crash when a caller passes a missing value to any log method. Co-Authored-By: Claude <noreply@anthropic.com>
parseCookie took (cookie, body, cb) while cookieLogin called it with (cookie, cb), so on an invalid cookie the error callback landed on the unused `body` param and the caller crashed dereferencing the undefined return value instead of showing "invalid cookie?". Make parseCookie a pure function returning null on failure and have both call sites check. Co-Authored-By: Claude <noreply@anthropic.com>
The `user { isCurrentUserPremium }` query returns http 400 on
leetcode.cn, so user.paid was never set there (locked problems then
fail to load even for premium users, upstream skygragon#228/skygragon#207). Query
`userStatus { username isPremium }` instead, which works on both
sites. On fetch failure keep the (still valid) login but warn instead
of silently saving a user without name, and fall back to the login
label in the success message instead of printing "login as undefined".
Also pins the login tests' user-info call to a nock instead of relying
on a real network request happening to fail.
Co-Authored-By: Claude <noreply@anthropic.com>
Cookie/third-party logins store no password, so an EXPIRED-triggered relogin ran the dead password form flow twice per request and only produced "invalid password?" noise. Warn and skip instead, pointing the user at a manual re-login. Co-Authored-By: Claude <noreply@anthropic.com>
The month header position is fractional whenever the month's day-1 is not a whole number of weeks away, and modern node throws ERR_OUT_OF_RANGE on the non-integer Buffer.write offset instead of silently coercing it. `leetcode stat -c` crashed on any recent node. Co-Authored-By: Claude <noreply@anthropic.com>
Ported from leetcode-tools#60 with the graphql query replaced: the PR's currentDailyCodingChallenge field no longer exists on leetcode.com, activeDailyCodingChallengeQuestion does. Co-Authored-By: Claude <noreply@anthropic.com>
Fetch the `hints` field on question detail and print it under the description (plain terminal lines instead of the upstream PR's raw <details> HTML), and emit a Hint section in the detailed template. Per-problem caches saved before this change lack the field, so extend the existing staleness check to treat missing hints as too old. Co-Authored-By: Claude <noreply@anthropic.com>
Extract the slug from urls like https://leetcode.com/problems/two-sum/ before the usual lookup, so show/test/submit all accept pasted links. Also default hints to an empty array in exportProblem so the detailed template renders for problems (and older caches) without hints. Co-Authored-By: Claude <noreply@anthropic.com>
Removals (all verified unreferenced or trivially replaced): - sqlite3: zero require sites, 15 audit findings, native build cost - lodash: only startCase was used; moved to helper.startCase - wordwrap: abandoned; replaced with a local greedy wrap in core.js (exportProblem's detailed tests pin the exact output) - mkdirp: superseded by fs.mkdirSync(recursive) - pkg: vercel pkg is deprecated and pkg4 cannot target node >= 20; single-binary builds belong to @yao-pkg/pkg if wanted later Bumps: underscore 1.13.8 (fixes a prototype/recursion advisory), cheerio 1.2.0, nconf 0.13.0, mocha 11, nock 14, nyc 18, chai 6, rewire 9. Also fixes a test isolation bug exposed by the mocha bump: test_file.js set process.env.HOME/USERPROFILE without restoring them, poisoning every suite loaded afterwards (config.init then tried to write into /home/skygragon). With that fixed the full suite passes for the first time: 167 passing, 0 failing. Audit: 55 findings (2 critical) -> 18 (1 critical, all in the eslint/request chains slated for a separate upgrade). Co-Authored-By: Claude <noreply@anthropic.com>
prompt (and its winston dependency chain) was the source of the padLevels circular-dependency warning on modern node. helper.readInput covers the four call sites (login, cookie, third-party, github 2FA) with secret muting for hidden fields. Co-Authored-By: Claude <noreply@anthropic.com>
Replace the archived eslint-config-google bridge with a flat config generated from the old stack's effective ruleset (eslint --print-config on eslint 5, active rules only). Most google style rules were already off in practice, so the 59-rule inline set reproduces lint behavior exactly: 0 errors, same warning classes. Co-Authored-By: Claude <noreply@anthropic.com>
yargs snapshots process.argv at require time and exits silently when the leading option is unknown, so `leetcode -v <cmd>` / `-vv <cmd>` produced no output at all (the flags predate this branch's work — a latent yargs 12 -> 17 migration gap). initLogLevel consumes them first; they are now removed from argv before yargs is required. Co-Authored-By: Claude <noreply@anthropic.com>
request has been unmaintained since 2020 and accounts for the last
runtime audit findings (including a critical via form-data). lib/http
reimplements the request call surface the codebase relies on —
cb(e, resp, body), resp.statusCode / resp.request.uri.href, opts.json
/ opts.form, defaults({jar}) for the github/linkedin login flows,
response streaming for plugin downloads and a -vv trace hook — with
redirects followed manually so cookies propagate across hops and
error statuses stay checkError's job. All 167 tests pass unchanged
against the adapter and live commands hit leetcode.com successfully.
Co-Authored-By: Claude <noreply@anthropic.com>
The description was printed as raw HTML (lists, code tags, entities). Decode it for the terminal the same way exportProblem does for generated files, leaving the cached raw HTML untouched. Co-Authored-By: Claude <noreply@anthropic.com>
The REST problem list carries no tags, so `-t stack` and friends silently matched nothing. Fetch the whole tag map from the paged problemsetQuestionListV2 graphql endpoint after the category list and merge it into the problems before caching. A tag-fetch failure keeps the list usable with a warning. problemsMeta gains a version field so existing caches refresh once and pick tags up. Co-Authored-By: Claude <noreply@anthropic.com>
log.fail, failing tests, rejected submissions and failed downloads now set process.exitCode = 1 (instead of always exiting 0), so scripts can detect failures; batch commands still run to completion. Also print a blank line after the test command's stdout block. Co-Authored-By: Claude <noreply@anthropic.com>
`leetcode cache` now cross-references the problems list and shows a check mark on per-problem caches whose problem is solved. The solution.discuss plugin follows leetcode's move from /discuss/ to /solutions/ for community solution pages. Co-Authored-By: Claude <noreply@anthropic.com>
The emitWarning filter in bin/leetcode silenced prompt's winston circular-dependency warning; prompt is gone now. Plugin dependency installation shells out to pnpm, matching this checkout and avoiding a hard npm dependency. Co-Authored-By: Claude <noreply@anthropic.com>
- chmod 0600 on user.json: it holds a live session cookie and was world-readable (existing files fixed too, via saveUser path) - drop the dead "pkg" config block and the unused solved variable in the cache listing; stop linting the vendored company tag list - remove the stale skygragon-era docs/ folder - password login now reports that leetcode.com rejects it and points at cookie login instead of a misleading "invalid password?"; the session-expired message names the actual remedy (leetcode user -c) - mechanical lint cleanup: unused catch bindings/imports, a missing semicolon, .parse() instead of the bare .argv expression; warnings drop from 31 to 17, all remaining ones are deliberate Co-Authored-By: Claude <noreply@anthropic.com>
Node 20/22/24 matrix, pnpm with frozen lockfile, running the same `pnpm test` entry point locally used (lint + mocha across lib, command and plugin suites). Co-Authored-By: Claude <noreply@anthropic.com>
New test/commands suite (list, stat, show, user, cache, submission) exercising handlers with stubbed core + temp-dir caches: filter semantics and the -s summary, stat bars and graph legend, plain-text desc/hints rendering, code generation, the solved marker in cache listings, submission download + error exit codes. Assertions strip ANSI so colored output stays testable. `pnpm test` now runs lib, commands and plugin suites. Co-Authored-By: Claude <noreply@anthropic.com>
A push to main builds @yao-pkg/pkg binaries (linux/mac x64+arm64, win x64), attaches sha256 checksums and publishes a GitHub Release tagged from the package version; re-pushing without a version bump is a no-op. pkg config restored with arm64 targets added; the local macos-arm64 build was verified end to end (version/stat/show all work from the snapshot). ci.yml now follows the main-based flow. Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
🟡 Changes recommended
It introduces at least one confirmed runtime-breaking bug in the new HTTP shim integration (and other issues) that should be fixed before merge.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR is a large “dev backlog” merge that modernizes the project’s dependencies and CI/release pipeline while adding several LeetCode feature fixes (daily challenge, tags, hints, cache TTL/purging) and replacing the deprecated request dependency with an axios-backed adapter.
Changes:
- Replaced
request(and other legacy deps) with an axios-backed HTTP shim and updated plugins/commands accordingly. - Added/extended CLI functionality and resiliency (daily challenge, hints/tag support, better cache semantics, non-zero exit codes on failures).
- Modernized engineering workflow (ESLint flat config, expanded unit tests, CI matrix, automated release workflow + pkg targets).
File summaries
| File | Description |
|---|---|
| test/test_plugin.js | Updates expected install command string for plugin deps. |
| test/test_log.js | Adds coverage for null/undefined log args and exit code behavior. |
| test/test_file.js | Prevents env var leakage across test suites. |
| test/test_core.js | Adds tests for URL keywords and daily challenge resolution. |
| test/plugins/test_retry.js | Adds coverage for skipping relogin without saved password. |
| test/plugins/test_leetcode.js | Adds extensive coverage for cookie login, error mapping, tags, hints, daily challenge. |
| test/plugins/test_cache.js | Adds coverage for problems cache TTL/meta + purge-on-login behavior. |
| test/mock/find-the-difference.json.20171216 | Updates fixture to include hints and normalized JSON formatting. |
| test/commands/test_user.js | Adds command-layer tests for user output/logout/error exit codes. |
| test/commands/test_submission.js | Adds command-layer tests for submission download and error exit codes. |
| test/commands/test_stat.js | Adds command-layer tests for progress/graph rendering. |
| test/commands/test_show.js | Adds command-layer tests for plain-text rendering + hints + codegen. |
| test/commands/test_list.js | Adds command-layer tests for listing/filtering and warnings. |
| test/commands/test_cache.js | Adds command-layer tests for solved markers and deletion. |
| templates/detailed.tpl | Emits hints into generated detailed templates. |
| package.json | Updates dependencies/devDependencies and expands test script paths; pkg targets/output. |
| lib/session.js | Adds BLOCKED error and chmod hardening for persisted session cookie file. |
| lib/plugins/solution.discuss.js | Switches HTTP client to new adapter and updates solution URL path. |
| lib/plugins/retry.js | Avoids burning retries when no saved password is available. |
| lib/plugins/leetcode.js | Migrates off request, adds tags fetch, daily challenge, hints, improved error mapping, cookie parsing changes. |
| lib/plugins/leetcode.cn.js | Migrates off request to new adapter. |
| lib/plugins/cache.js | Adds problems TTL/meta versioning, stale fallback, and purges caches on all login methods. |
| lib/plugin.js | Uses new HTTP adapter; changes plugin dep install command; refactors download/copy logic. |
| lib/log.js | Sets process.exitCode on failures; makes logging tolerant of null/undefined args. |
| lib/http.js | Adds axios-backed drop-in request shim with redirect and jar support. |
| lib/helper.js | Adds problemsMeta key, startCase helper, and readInput prompt replacement. |
| lib/file.js | Replaces mkdirp with fs.mkdirSync(..., {recursive:true}). |
| lib/core.js | Accepts full problem URLs as keywords; adds daily challenge flow; replaces wordwrap dependency. |
| lib/commands/version.js | Uses optional catch binding cleanup. |
| lib/commands/user.js | Replaces prompt with readline-based input and avoids “login as undefined”. |
| lib/commands/test.js | Replaces lodash.startCase; sets exit code on failed tests. |
| lib/commands/submit.js | Replaces lodash.startCase; sets exit code on failed submits. |
| lib/commands/submission.js | Sets exit code when per-problem task fails. |
| lib/commands/stat.js | Fixes width alignment + Buffer.write out-of-range issue. |
| lib/commands/show.js | Adds daily option, plain-text description output, and hint printing. |
| lib/commands/session.js | Removes prompt dependency (cleanup). |
| lib/commands/list.js | Makes output columns dynamic to data widths. |
| lib/commands/config.js | Uses optional catch binding cleanup. |
| lib/commands/cache.js | Widens columns dynamically and adds solved markers for per-problem caches. |
| lib/cli.js | Routes TRACE HTTP debugging to new adapter; fixes yargs -v/-vv handling. |
| eslint.config.js | Adds ESLint flat config equivalent to previous ruleset. |
| docs/releases.md | Removes legacy Jekyll release notes page content. |
| docs/install.md | Removes legacy Jekyll installation page content. |
| docs/index.html | Removes legacy Jekyll docs landing page content. |
| docs/demo.html | Removes legacy Jekyll demo page content. |
| docs/commands.md | Removes legacy Jekyll command docs content. |
| docs/advanced.md | Removes legacy Jekyll advanced tips content. |
| docs/_config.yml | Removes Jekyll theme config. |
| bin/leetcode | Removes process.emitWarning suppression wrapper. |
| 1.js | Adds a sample solution file (likely accidental/temporary). |
| .github/workflows/release.yml | Adds release workflow to build pkg binaries and publish GitHub Releases. |
| .github/workflows/ci.yml | Adds CI workflow for lint/test on Node 20/22/24. |
| .eslintrc.js | Removes legacy ESLint config in favor of flat config. |
Review details
Suppressed comments (1)
lib/plugin.js:73
- Switching plugin dependency installation to
pnpm addintroduces a new runtime requirement: end users who installed leetcode-cli via npm (or run the packaged binaries) are unlikely to havepnpmavailable on PATH, so plugin installs may start failing. Consider usingnpm install --save(always present with Node) or adding a fallback/detection layer.
- Files reviewed: 52/57 changed files
- Comments generated: 3
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+61
to
+67
| function shim(resp, finalUrl) { | ||
| return { | ||
| statusCode: resp.status, | ||
| headers: Object.assign({}, resp.headers), | ||
| request: {uri: {href: finalUrl}} | ||
| }; | ||
| } |
Comment on lines
31
to
34
| cache.set(h.KEYS.user, _user); | ||
| // the file holds a live session cookie, keep it private | ||
| fs.chmodSync(file.cacheFile(h.KEYS.user), 0o600); | ||
| }; |
Comment on lines
+54
to
+58
| // per-problem caches get a solved marker from the problems list | ||
| const problems = name === '' ? cache.get(h.KEYS.problems) : null; | ||
|
|
||
| log.info(chalk.gray(sprintf(' %-' + width + 's %8s %s', 'Cache', 'Size', 'Created'))); | ||
| log.info(chalk.gray('-'.repeat(width + 26))); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Batch of work accumulated on dev since the last merge to main:
Bug fixes (from upstream backlog triage + local incidents)
Features
lc show -ddaily challenge; official hints in show + generated files-t stack), fetched via graphqllc showlc cacheDependency modernization
Engineering
Merging this to main will trigger the first binary release (v3.0.0 tag).
🤖 Generated with Claude Code