pi-leetcode-tools

Unofficial native Pi tool calls for LeetCode Global and CN

Packages

Package details

extension

Install pi-leetcode-tools from npm and Pi will load the resources declared by the package manifest.

$ pi install npm:pi-leetcode-tools
Package
pi-leetcode-tools
Version
0.1.5
Published
Jul 21, 2026
Downloads
325/mo · 325/wk
Author
tech7
License
MIT
Types
extension
Size
3.1 MB
Dependencies
3 dependencies · 2 peers
Pi manifest JSON
{
  "extensions": [
    "./dist/extensions/index.js"
  ]
}

Security note

Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.

README

pi-leetcode-tools

npm version npm downloads CI Node.js Tests MCP parity License GitHub stars Last commit LINUX DO - Where possible begins

简体中文

Unofficial native Pi tool calls for LeetCode Global and LeetCode CN.

The package exposes fourteen Pi tools:

Tool Purpose Authentication
lc_daily Read the daily challenge No
lc_search Search and page through problems by category/tag/difficulty/text No
lc_problem Read a problem and code snippets No
lc_solution_search List a bounded page of answer-bearing community solutions No
lc_solution Read one full answer-bearing community solution article No
lc_profile Read a public user's normalized profile No
lc_contest Read a public user's contest ranking and bounded history No
lc_progress Read account progress Session
lc_history Read account-wide or per-problem submission history Session
lc_user_submissions Read a public user's recent/accepted submissions No
lc_submission Read one submission; source code requires explicit includeCode=true Session
lc_run Execute code remotely without a formal submission Session + CSRF
lc_submit Submit code after Pi-owned UI confirmation Session + CSRF
lc_operation_status Recover or refresh a recorded run/submit operation Session + CSRF

Quick start

Install the package through Pi and start a fresh interactive session:

pi install npm:pi-leetcode-tools
pi list
pi

The extension loads automatically. Ask Pi in natural language, or name a tool when you want deterministic selection:

Use lc_daily to show today's LeetCode CN challenge.
Use lc_search to find medium array problems on LeetCode Global.
Use lc_problem to read two-sum on CN and show the C++ snippet.
Use lc_progress to summarize my CN account progress.

The first three examples are public reads. lc_progress, lc_history, lc_submission, lc_run, lc_submit, and lc_operation_status require the matching regional account credentials. Sign in with the local authentication CLI:

pi-leetcode auth login --region cn --profile personal-cn

Pi keeps package executables in its managed npm prefix, which is not always on the shell PATH. If pi-leetcode is not found, run it through that prefix.

macOS/Linux:

npm exec --prefix "${PI_CODING_AGENT_DIR:-$HOME/.pi/agent}/npm" -- \
  pi-leetcode auth login --region cn --profile personal-cn

Windows PowerShell:

$agentDir = if ($env:PI_CODING_AGENT_DIR) { $env:PI_CODING_AGENT_DIR } else { "$HOME\.pi\agent" }
npm exec --prefix "$agentDir\npm" -- pi-leetcode auth login --region cn --profile personal-cn

Use auth import instead of auth login when the isolated browser cannot pass the site challenge and you need the system default browser. After logging in or switching profiles, start a new Pi session. lc_submit is available only in an interactive session and always requires a fresh Pi-owned UI confirmation. See Credentials and profiles for the complete flow.

If an installed resource is disabled, run pi config, enable it, and start a new Pi session.

Verification

pi-leetcode-tools@0.1.5 implements all 24 pinned reference interfaces as 16 native-tool mappings, 5 Gateway capabilities, and 3 static contract resources, with no partial, missing, superseded, or explicitly unsupported mapping.

Capability class Current evidence
Contract and upstream parity Source 344/344, packed 344/344, packed target resolution 24/24, and independent adapter/Gateway/resource fixtures 24/24 pass
Package verification Typecheck, 29 test files / 283 tests, packed install, 14-tool Pi activation, and local supply-chain checks pass on Node 22.19.0 and 24.18.0
Public-read smoke tests Global/CN daily, search, and problem reads pass 6/6
Authenticated safe matrix Global passes 19 operations and CN passes 21 operations with zero failures; the matrix covers all region-supported safe reads plus lc_run -> lc_operation_status
Write safeguards The safe matrix forcibly skips lc_submit and Notes create/update/write unless a separate, explicitly authorized interactive verification is running

LeetCode is a third-party service. API behavior can change without notice, and using this package does not exempt you from LeetCode's terms or rate limits.

Reference MCP interface parity

The package is checked against the pinned @jinzcdev/leetcode-mcp-server@1.4.0 surface: 19 MCP tools and 5 MCP resources. The package ships the immutable inventory in upstream/reference-surface.json and the current semantic mapping in upstream/parity.json. Verification does not trust that inventory alone: it checks the pinned npm tgz receipt (size, SHA-256 and SHA-512 integrity), extracts the registrations offline, and requires the extracted Tool/Resource names, URI templates, and input fields to match the declared surface exactly. Because the MCP implementation delegates most GraphQL behavior to leetcode-query, the semantic surface independently pins leetcode-query@2.0.1 by tgz integrity, lib/index.js digest, and the digest of its 19 embedded GraphQL queries. A compatible version range is not accepted as semantic evidence. The default archive path is .artifacts/upstream-reference/jinzcdev-leetcode-mcp-server-1.4.0.tgz at the workspace root; CI may pass --reference-tarball <path> after provisioning the same receipt. A missing archive is a hard failure, and the verifier never fetches or silently substitutes network state.

Use the report command while implementing gaps:

npm run verify:upstream-parity:report --workspace pi-leetcode-tools

The strict source precheck and final source-plus-packed completeness checks are:

npm run verify:tools:upstream-completeness:source
npm run verify:tools:upstream-completeness

The strict command fails unless every upstream interface is implemented as a validated native_tool, gateway_capability, or static_contract_resource. missing, partial, superseded, and explicitly_unsupported mappings all block completion. Each implemented mapping must separately verify eight semantic dimensions: input schema/field map, output schema, authentication and subject scope, regional endpoint/operation, capability and side effect, pagination/defaults, sensitive-data controls, and normalized error semantics. Stable per-interface/per-variant case IDs, deterministic source/packed execution receipts, packed JavaScript behavior probes, and exact README anchors are mandatory evidence in addition to those eight dimensions. A test file that merely contains some test/it call is not parity evidence. Missing receipts, missing or duplicate cases, non-passed cases, stale runner/target/reference digests, and packed JavaScript that cannot resolve all 24 targets fail closed. Version 0.1.5 maps all 24 pinned interfaces and passes the strict source and packed completeness gates: 344/344 conformance cases in each form, 24/24 packed JavaScript target resolution, and 24/24 independent actual adapter/Gateway/static-resource fixtures.

Ordinary npm pack --dry-run --workspace pi-leetcode-tools keeps the non-strict report behavior. Release packaging and npm publish run the strict gate; an incomplete package cannot be published.

The generated contract/catalogs.json artifact is the versioned source for the pinned upstream problem categories, problem tags, and language identifiers. lc_search defaults to category all-code-essentials, accepts only cataloged categories/tags, uses a 10-item default page, and maps canonical difficulty and keyword fields to the regional query. Run/submit language conversion and the published language resource use the same registry, including cangjie.

lc_daily returns the UTC invocation date plus a strict, region-specific copy of the complete pinned daily payload. lc_problem returns the simplified MCP projection, including all hints, the first three similar questions, and the C++/Python3/Java snippets. Setting includeResourcePayload=true additionally returns the complete pinned problem://{titleSlug} payload through an explicit bounded schema with additionalProperties:false; unknown future fields are not forwarded to the model.

Run and submit parity

lc_run and lc_submit cover the pinned MCP's Global and CN interpret_solution -> check and submit -> check flows. Their renamed input fields are lang -> language, typedCode -> code, and (for runs) dataInput -> testcase. All 20 upstream language slugs are accepted; golang is normalized to the package's canonical go ID and mapped back to golang on the wire. Omitting the operation controls uses the pinned upstream defaults timeoutMs=120000 and pollIntervalMs=1500. Positive sub-second values are accepted; polling still applies the upstream 200 ms effective minimum. The package keeps a 120-second total timeout and 5-second requested poll ceiling as explicit resource-safety bounds.

The originating successful call returns questionId, the complete bounded start JSON object, the fixed HTTPS checkUrl, and the complete bounded terminal check JSON object in addition to the normalized operation/result fields. These two upstream objects are transient (persistence=never): they are recursively bounded, rejected if they contain source, credential, prototype-pollution, or other forbidden fields, and never enter the operation journal, logs, or release evidence. Later lc_operation_status and duplicate-result reads intentionally return the durable minimal normalized result rather than replaying transient judge output. This preserves recovery and deduplication without persisting code, testcases, stdout, expected output, or diagnostics.

When lc_run.testcase is omitted, the adapter resolves and sends the problem's exact public sampleTestCase bytes. This is the package's fail-closed equivalent of the upstream empty data_input default: a problem with no public default is rejected before dispatch instead of guessing or sending an ambiguous empty testcase. lc_submit retains the per-call Pi UI confirmation, durable dispatch intent, duplicate protection, explicit unknown retry, and explicit completed resubmission rules described below.

Public profile and contest reads

lc_profile and lc_contest accept an explicit public username and never use the active account as an implicit subject. Both support Global and CN; lc_profile includes the Global submission totals and the CN accepted, failed, untouched, social-account, skill-topic, and topic-area-score facets from the pinned query. lc_contest includes Global badge and regional trend fields, defaults to attended contests, and provides exact 50-record offset pages so the complete upstream history remains accessible without an unbounded model response. The one upstream GraphQL response is still protected by the shared 2 MiB transport limit and a fail-closed 2,000-record normalization ceiling.

lc_progress uses the upstream defaults offset=0 and limit=100, echoes the normalized question-status and difficulty filters, and exposes the exact progress-question facets. It deliberately does not invent a questionId or paidOnly value that the upstream progress query did not return.

Authenticated session identity is available only through the non-model user.status Gateway RPC. It defaults to Global, accepts an optional region, and returns a canonical account slug plus a separate CN display name when signed in. It is intentionally not registered as an lc_* model tool.

Answer-bearing solution reads

lc_solution_search lists a bounded page of community solution metadata for one problem, and lc_solution reads exactly one article by Global topicId or CN slug. Both are public reads but are classified as answer_read with disclosureRisk=solution. They run only after an explicit caller request; the package does not prefetch, bulk crawl, cache, log, persist, or place solution summaries/content in evidence. Returned article text is untrusted third-party content. Calling applications should expose these tools only after an explicit user request to read solution material.

Personal Notes Gateway

The non-model notes.search, notes.get, notes.create, and notes.update Gateway RPC methods expose the current authenticated CN account's arbitrary personal notes separately from the revisioned state NotesPort. Search/get default to bounded limit=10 and skip=0; search also defaults to DESCENDING. Create/update require a fresh Pi-owned UI confirmation for every call, never automatically retry, and return UNKNOWN_WRITE_OUTCOME when a remote write cannot be safely verified. Note content, titles, and keywords are never logged or stored in evidence; confirmation displays only byte counts and SHA-256 digests.

Requirements and compatibility

  • Node.js >=22.19.0.
  • The currently verified Pi runtime is @earendil-works/pi-coding-agent@0.80.7.
  • Package 0.1.5 publishes contract 1.1.0 and RPC protocol 1.0.0.
  • Public JavaScript imports are limited to pi-leetcode-tools/embedded, pi-leetcode-tools/types, and pi-leetcode-tools/contract. Package-root and dist/ imports are intentionally blocked.

Consumers must discover the active provider and compare the package version, contract version, protocol version, schema digest, and capability-manifest digest before calling it. A mismatch must be treated as incompatible, not guessed around. Loading more than one provider instance is also rejected with PROVIDER_CONFLICT until only one remains.

Install, update, and remove

Install the npm latest release for Pi:

pi install npm:pi-leetcode-tools@latest
pi list

Use -l with pi install or pi remove for project-local settings. Update and removal use the same source recorded at installation:

pi update npm:pi-leetcode-tools
pi remove npm:pi-leetcode-tools

Release artifacts are validated through a closed temporary registry that binds dist.integrity to the selected tgz, followed by a new Pi process activation probe. A bare local tgz is useful for ordinary npm production-tree audits, but Pi 0.80.7 does not treat it as authoritative Pi Package activation evidence.

Removing the extension does not promise to delete its durable operation journal. Review the storage section before cleaning that data.

Credentials and profiles

Public daily, search, and problem reads need no credentials. Authenticated tools resolve credentials from environment variables first, then from the operating-system credential store. Credentials are never accepted as tool arguments.

The local authentication CLI has a fixed command surface:

pi-leetcode auth login --region global --profile personal-global
pi-leetcode auth status --profile personal-global
pi-leetcode auth list
pi-leetcode auth use --profile personal-global
pi-leetcode auth doctor --profile personal-global

Use --region cn for LeetCode China. The command launches an isolated local Edge or Chrome profile and waits for the user to finish LeetCode's normal login flow. Passwords, CAPTCHA, MFA, and third-party sign-in remain in the browser. Only the resulting session and CSRF cookies are saved in the OS credential store. The temporary browser profile is deleted after success, timeout, browser closure, or failure.

If an isolated browser cannot pass a site challenge, use the explicit fallback:

pi-leetcode auth import --region cn --profile personal-cn

auth import opens the system default browser but never scans its Cookie DB, password vault, history, extensions, debugging port, clipboard, or any other domain. After sign-in, it reads LEETCODE_SESSION and csrftoken only from two hidden prompts in the local visible terminal. Piped input and non-TTY execution fail with auth_tty_required; secrets are not accepted in argv or printed.

Both login paths run a bounded, read-only status probe against the fixed region endpoint before changing the keyring. Existing credentials are not overwritten unless --force is supplied. A replacement updates the credential record, non-secret profile index, active pointer, and credential epoch as one recoverable transaction; a probe or keyring failure preserves the old bundle. A successful login/import selects the profile. Profile IDs use 1–128 characters from A-Z a-z 0-9 . _ : -, matching the capability/RPC identifier grammar.

To remove a saved login:

pi-leetcode auth logout --region global --profile personal-global

auth logout removes exactly one profile/region bundle. If this removes the active profile's final bundle, the CLI selects default when it exists, otherwise the lexicographically first remaining profile, or clears the stored pointer so runtime selection returns to the unconfigured default namespace. It never leaves an active pointer to a deleted profile.

auth status and auth list emit only profile, region, source, configured, operationReady, active, and safe verification/expiry state. They never display cookie content, length, digest, keyring account names, or a remote username. auth use changes only the non-secret stored active pointer. An explicit PI_LEETCODE_PROFILE_ID remains the effective runtime selection and is reported as auth_profile_overridden_by_environment. auth doctor performs a new read-only probe and returns stable reason codes for missing, partial, expired, rejected, region-mismatched, unavailable, or malformed authentication; its exit code is 0 only when every inspected region is healthy and 2 when a diagnostic issue was found.

Environment variables remain supported for CI and headless deployments. Source priority is a complete environment bundle, then the same profile/region bundle in the OS credential store, then unconfigured. A half environment bundle shadows the keyring and fails closed with auth_environment_bundle_partial; it is never combined with a stored value.

Region Session cookie value CSRF cookie value
Global (global) LEETCODE_SESSION LEETCODE_CSRF_TOKEN
China (cn) LEETCODE_CN_SESSION LEETCODE_CN_CSRF_TOKEN

Set values before starting Pi. Use your shell's secret-management facilities; the placeholders below are not literal values:

export LEETCODE_SESSION='<session-cookie-value>'
export LEETCODE_CSRF_TOKEN='<csrf-cookie-value>'
export PI_LEETCODE_PROFILE_ID='personal-global'

PowerShell equivalent:

$env:LEETCODE_CN_SESSION = '<session-cookie-value>'
$env:LEETCODE_CN_CSRF_TOKEN = '<csrf-cookie-value>'
$env:PI_LEETCODE_PROFILE_ID = 'personal-cn'

PI_LEETCODE_PROFILE_ID is a non-secret local namespace, defaulting to default. Give different LeetCode accounts different stable profile IDs. The profile ID partitions operation journals and locks, binds authenticated cursors, and appears in non-secret capability metadata. Reusing one profile ID for different accounts can make operation recovery ambiguous; changing it can make old operations and cursors unavailable from the new profile.

Runtime credential providers observe active-profile changes and expose a process-local monotonic credential revision. The revision advances when the profile, presence, or secret bytes change without exposing or persisting a token-derived digest. Consumers use it to invalidate old context, cursors, confirmations, and undispatched write intents after rotation.

After auth use, login replacement, import, or logout changes the effective profile, start a new Pi session (or perform an explicit provider rediscovery) before continuing authenticated work. The current runtime increments contextRevision immediately, so stale cursors and confirmations fail closed; the revisioned NotesPort also keeps its original account binding and rejects a hot-switched profile until the runtime is recreated. This prevents note writes from crossing account boundaries.

The native keyring backend maps to Windows Credential Manager, macOS Keychain, and Linux Secret Service. If the platform service is absent or locked, commands fail deterministically with credential_store_unavailable. There is no fallback to plaintext JSON, .env, the project directory, or a home-directory secret file. Keyring index and epoch entries contain only profile IDs, regions, boolean readiness, safe timestamps, and a random mutation revision—not Cookie material.

Treat session and CSRF values like passwords. Do not paste them into prompts, tool arguments, source files, logs, issue reports, or committed .env files. Rotate them immediately if exposed. The package redacts known credential and code fields from its safe logging path, but it cannot protect secrets disclosed outside that path.

Interactive and headless use

lc_submit always requires a confirmation created by the currently active Tools extension through Pi's own interactive UI. An RPC caller cannot supply or forge that confirmation callback. In --print, RPC-only, or any other session without UI, submission fails closed with INTERACTION_REQUIRED.

Read tools, lc_run, and lc_operation_status can operate without UI when their credential requirements are met. lc_run still sends code to LeetCode for remote execution, so call it only for code the user intends to execute.

The internal NotesPort follows the same boundary: CN note writes require Tools-owned UI confirmation; Global notes are unsupported. CN notes are limited to 16 KiB and use best-effort compare-and-set rather than a server-native atomic revision primitive.

Durable operations and unknown recovery

Runs and submissions are journaled before dispatch. A returned state of unknown means the remote outcome could not be proven. It does not mean the request failed, and blindly sending the same submission can create a duplicate.

For an unknown operation:

  1. Keep its operationId and call lc_operation_status with that ID.
  2. If LeetCode can now answer, the record advances to polling, completed, or failed.
  3. If a submission remains unknown, retry only after the user accepts the duplicate-submission risk. Send the exact same region, problem, language, and code to lc_submit with retryUnknownOperationId set to the old ID.
  4. Approve the new interactive confirmation. The new record links the old one through supersedesOperationId.

A mismatched retry reference is rejected with STALE_OPERATION. Identical pending or unresolved submissions are blocked. A normal lc_submit matching a retained completed operation returns the previous result; deliberately sending the same code again requires resubmitCompletedOperationId, another explicit confirmation, and creates a new record linked by repeatsOperationId. Cancellation after remote dispatch may still produce unknown; local cancellation is not proof that LeetCode cancelled the request.

Storage

Durable state is stored below:

<resolved-pi-agent-directory>/leetcode-tools/
  operations/<sha256(profile-id + region)>/operations.json
  locks/

Run/submit durability uses Pi's resolved agent directory: ~/.pi/agent by default, or the directory selected by PI_CODING_AGENT_DIR when that optional override is set. Deployments that override it must preserve the same directory across restarts. Embedded SDK hosts with a custom agent directory can pass the matching storageDirectory option to createLeetCodeToolsRuntime.

The operation journal stores IDs, state transitions, remote IDs, timestamps, problem/language metadata, results, and a SHA-256 code hash. Its persistence policy rejects source code, testcase content, credentials, cookies, CSRF tokens, and confirmation tokens. The journal is not encrypted, so protect the agent directory with normal OS account permissions and backups appropriate for the metadata it contains.

Do not delete the journal while operations are pending or unknown; doing so removes the evidence used for recovery and duplicate-submit protection. Before manual cleanup, resolve or explicitly abandon those operations and stop every Pi process using the same profile directory.

Submission history and detail

lc_history reads the authenticated account. Use scope: "account" without a titleSlug for account-wide history, or scope: "problem" with a titleSlug for one problem. LeetCode CN additionally supports canonical language and status: "accepted" | "wrong_answer" filters. Global rejects those CN-only filters instead of filtering a single remote page locally.

lc_user_submissions is public and requires an explicit username. Global supports mode: "recent" and mode: "accepted"; CN supports accepted-only public history. Results are a bounded recent window, not a complete account history.

lc_submission is an authenticated sensitive read. It returns bounded judge metadata for one numeric submissionId. Source code is omitted by default and is requested from LeetCode only when the caller explicitly sets includeCode: true. Returned code and judge output are untrusted sensitive content and are never written to the operation journal, Notes, diagnostics, or release evidence.

Pagination cursors

lc_search and lc_history return opaque HMAC-SHA256 cursors. A cursor is at most 1,000 characters, expires after 15 minutes, and is bound to its tool, region, query fingerprint, and pagination position. History cursors are also bound to the credential profile.

The signing key is runtime-local. Cursors are therefore intentionally not portable across Pi restarts, provider instances, profile changes, or package upgrades. Never parse, edit, persist long-term, or share a cursor. On STALE_CURSOR, restart pagination without the old cursor.

Authentication CLI reason codes

CLI failures are printed as pi-leetcode [reason_code]: safe message. Scripts should use the bracketed code and must not parse browser/keyring native text.

Code Meaning / operator action
credentials_already_exist The exact profile/region already exists; choose a new profile or explicitly use --force.
auth_environment_bundle_partial Only one environment credential is present or a value is malformed; supply both or clear both.
auth_tty_required / auth_import_cancelled Import needs a visible hidden-input terminal, or the local prompt was cancelled.
auth_browser_unavailable / auth_browser_closed / auth_login_timeout The isolated browser could not start, was closed, or did not finish in time.
auth_probe_rejected / auth_expired LeetCode did not accept the session; sign in again without overwriting the old bundle until probe succeeds.
auth_region_mismatch The imported session redirected away from the selected Global/CN origin; verify the region and copied cookies.
auth_probe_timeout / auth_probe_unavailable The bounded read-only verification could not complete; retry later.
credential_store_unavailable The OS keyring/secret service is absent, locked, or denied; enable it. No plaintext fallback is used.
credential_store_corrupt The non-secret profile index, active pointer, or epoch is malformed; inspect/repair the local keyring entries.
credential_store_rollback_failed A keyring write failed and recovery also failed; stop and inspect with auth doctor before further replacement.

Result and error handling

Every tool returns a structured success or failure envelope. On failure, use error.code, honor retryable, wait for retryAfterMs when present, and retain operationId when supplied. Do not retry solely from the human-readable message.

Code Meaning / caller action
VALIDATION_ERROR Input violates the published schema; fix the request.
AUTH_REQUIRED Required regional credentials are absent.
AUTH_EXPIRED The configured session is no longer accepted; rotate it.
PERMISSION_DENIED The account or upstream policy refused the action.
INTERACTION_REQUIRED A trusted Pi UI confirmation is required.
NOT_FOUND The problem or locally journaled operation was not found.
RATE_LIMITED Back off and honor retryAfterMs when provided.
REMOTE_UNAVAILABLE LeetCode or the network is temporarily unavailable.
EXECUTION_FAILED The tool/runtime could not complete the operation safely; inspect retryable and the operation state. Judge verdicts such as WA/TLE remain successful business results.
UNSUPPORTED_REGION The requested region is not supported.
STALE_OPERATION The operation is duplicate, terminal, mismatched, or needs an explicit unknown retry reference.
STALE_CURSOR The opaque cursor is expired, invalid, or bound to another context.
UNKNOWN_WRITE_OUTCOME A Notes write may have succeeded but could not be verified; read before deciding whether to retry, and never auto-replay it.
CANCELLED Local work was cancelled; dispatched remote work may still be unknown.
CAPABILITY_UNAVAILABLE The runtime, storage, credentials, or regional capability is unavailable.
REMOTE_SCHEMA_CHANGED LeetCode's response no longer matches the adapter; upgrade or report it.
PROVIDER_CONFLICT More than one Tools provider is active; remove the duplicate.
CONTRACT_MISMATCH Package/consumer contract evidence does not match; do not call across it.
PROTOCOL_TIMEOUT An internal RPC request missed its deadline; rediscover context before retrying.

Security and release evidence

See SECURITY.md for the threat model and private reporting guidance. Published artifacts are checked from the final .tgz, including its file allowlist, required security notice, built-in secret scan, actual isolated production dependency tree, license policy, and generated CycloneDX SBOM and release-evidence record.

Local development

npm ci
npm run typecheck
npm test
npm run build
pi -e ./packages/pi-leetcode-tools