Skip to content

feat(cli): port recent opensrc features (fetch command, lockfile parsers, GITHUB_TOKEN auth)#117

Merged
amondnet merged 10 commits into
mainfrom
amondnet/opensrc
Jul 2, 2026
Merged

feat(cli): port recent opensrc features (fetch command, lockfile parsers, GITHUB_TOKEN auth)#117
amondnet merged 10 commits into
mainfrom
amondnet/opensrc

Conversation

@amondnet

@amondnet amondnet commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Summary

Ports the features introduced upstream in vercel-labs/opensrc between our previous submodule pin (a3b9d21, 2026-04-10) and v0.7.3 (f96078a) into the ASK CLI, and bumps the vendor/opensrc submodule to that tag.

1. Format-aware pnpm/yarn lockfile parsers (port of vercel-labs/opensrc#51)

Replaces the regex-based parsers in packages/cli/src/lockfiles/, which misidentified versions in common real-world cases: pnpm peer-dep suffixes like 18.2.0(react@17.0.0) leaked false matches for the inner package, yarn multi-specifier headers only matched the first specifier, and pnpm monorepos returned whichever version the regex hit first.

  • pnpm: indent-aware stack parser covering v5–v9 (importers, devDependencies, optionalDependencies, nested peer-dep suffixes) with BFS transitive resolution over the snapshots:/packages: dependency graph — unreachable versions lose to root-reachable ones
  • yarn: block-based parser handling classic v1 and Berry v2+ in one code path
  • package.json fallback now skips protocol versions (workspace:*, link:, file:, git+…, npm: aliases) via isRegistryVersion
  • upstream fixtures (yarn v1, yarn Berry, pnpm v9 monorepo) and 58 unit tests ported

2. ask fetch command (port of vercel-labs/opensrc#53/#56)

New top-level command that warms the checkout cache via the shared ensureCheckout helper without printing paths — the prefetch counterpart to ask src / ask docs.

  • multiple specs, -q/--quiet, per-spec ✓ fetched / already cached lines + summary
  • per-spec failures print to stderr, remaining specs still run, non-zero exit at the end
  • EnsureCheckoutResult gains a fromCache flag
  • replaces the documented workaround of running ask docs <spec> just to warm the cache before ask add's offline-first docs-path prompt

3. GITHUB_TOKEN authenticated fetch with strict host validation (port of vercel-labs/opensrc#52 + #66)

  • authenticatedCloneUrl parses the clone URL and injects x-access-token:<GITHUB_TOKEN> only on an exact https://github.com host match — prefix-confusable hosts (github.com.evil.com, evilgithub.com, subdomains), non-https schemes, and ssh remotes pass through untouched (Resolve pre-existing tsc errors blocking bun run build in packages/cli #66 host-confusion fix)
  • auth is applied at the exec boundary (clone, ls-remote); error messages keep the token-free URL and redactToken scrubs git/execFileSync output so the secret never reaches logs or thrown errors (hardening beyond upstream)
  • tar.gz fallback switches to the api.github.com tarball endpoint when a token is set: undici drops the Authorization header on the cross-origin redirect to codeload, but GitHub embeds a temporary token in the redirect Location, so private downloads still work

Intentionally not ported

  • GitLab/Bitbucket tokens & Bitbucket API resolution — ASK's store layout and resolvers are github.com-only for MVP; extend with the same pattern when multi-host lands
  • thiserror structured errors (track: in-place-npm-docs-20260410 #56) — Rust-specific refactor; ASK already uses typed error classes and injected exit callbacks
  • upstream repo chores (docs favicon, release prep, trusted npm publishing)

Also included

  • test(cli): git test fixtures now pass -c tag.gpgsign=false / -c commit.gpgsign=false so they are hermetic on machines with global gpg signing enabled (21 pre-existing local failures)
  • docs: README, skills/ask/SKILL.md, and CLAUDE.md updated for the new command and token support
  • chore: vendor/opensrc submodule bumped to v0.7.3

Test plan

  • bun run --cwd packages/cli test — 621 pass / 0 fail
  • bun run --cwd packages/cli lint / build — clean
  • E2E: ask fetch github:sindresorhus/is-plain-obj@v4.1.0 (fresh fetch → cache hit → -q), ask fetch <bogus> exits 1 with stderr error
  • authenticatedCloneUrl unit tests cover exact-host match, host-prefix/suffix confusion, subdomains, non-https schemes, ssh remotes

Summary by cubic

Ports recent opensrc features into the ASK CLI: adds ask fetch, rewrites pnpm/yarn lockfile parsers (incl. pnpm v5 keys), enables private GitHub fetch via GITHUB_TOKEN, improves cache‑hit reporting, and bumps vendor/opensrc to v0.7.3.

  • New Features

    • ask fetch <spec...> warms the source cache; supports multiple specs, -q/--quiet, per‑spec errors, non‑zero exit on any failure; reports “fetched” vs “already cached.”
    • Lockfile parsers: pnpm v5–v9 with transitive resolution (v5 /name/version[_peerhash] keys canonicalized), and yarn v1 + Berry; package.json fallback skips protocol versions via isRegistryVersion.
    • Private GitHub: inject GITHUB_TOKEN only for exact https://github.com remotes; tokens redacted; API tarballs used when a token is set. Cache hits are reported accurately via EnsureCheckoutResult.fromCache and FetchResult.fromStoreCache.
  • Bug Fixes

    • ensure-checkout: null‑safe access to injected fetcher results (fetcher.fetch(): Promise<FetchResult | undefined>), keeping cache‑hit reporting correct when tests/materialization bypass a FetchResult.

Written for commit 14e5584. Summary will update on new commits.

Summary by CodeRabbit

  • New Features

    • Added ask fetch to warm the cache for specs without printing paths.
    • Improved support for private GitHub repositories when GITHUB_TOKEN is set.
  • Bug Fixes

    • More reliably resolves package versions from lockfiles across pnpm and Yarn formats.
    • Better handles workspace, file, link, and other non-registry dependency entries.
  • Documentation

    • Updated user guides and command docs to reflect the current ask workflow and cache behavior.

amondnet added 6 commits July 2, 2026 21:14
Pulls in 9 upstream commits (2026-04-14 .. 2026-06-23):
- opensrc fetch subcommand + shared core::fetcher module (#53, #56)
- Bitbucket Cloud support via BITBUCKET_TOKEN + auth docs (#52)
- Lockfile parsers rewritten with transitive pnpm resolution (#51)
- Structured error handling via thiserror across the CLI (#56)
- Authenticated clone host validation fix (#66)
- Trusted npm publishing, v0.7.2/v0.7.3 releases, docs favicon
…olution

Port of vercel-labs/opensrc#51. The previous regex-based parsers
misidentified versions in common real-world cases: yarn multi-specifier
headers only matched the first specifier, pnpm peer-dep suffixes like
18.2.0(react@17.0.0) leaked false matches for the inner package, and
pnpm monorepos returned whichever version the regex engine hit first.

- pnpm: indent-aware stack parser covering v5 through v9 (importers,
  devDependencies, optionalDependencies, nested peer-dep suffixes) with
  BFS transitive resolution over the snapshots/packages dep graph
- yarn: block-based parser handling classic v1 and Berry v2+ in one path
- package.json fallback now skips protocol versions (workspace:*,
  link:, file:, git+..., npm: aliases) via isRegistryVersion
- fixtures (yarn v1, yarn Berry, pnpm v9 monorepo) and 58 unit tests
  ported from upstream
Port of opensrc fetch (vercel-labs/opensrc#53/#56). ask fetch <spec...>
resolves each spec through the shared ensureCheckout helper without
printing paths — the prefetch counterpart to ask src / ask docs.

- supports multiple specs, -q/--quiet, per-spec ✓ fetched / already
  cached lines and a summary; per-spec failures print to stderr and the
  command exits non-zero at the end
- EnsureCheckoutResult gains a fromCache flag so callers can tell a
  store hit from a fresh fetch
- warms the cache that ask add's offline-first docs-path prompt reads,
  removing the need to abuse ask docs for prefetching
…lidation

Port of vercel-labs/opensrc#52 + #66 (scoped to GitHub — ASK's store
layout is github.com-only for MVP, so the GitLab/Bitbucket token paths
do not apply).

- authenticatedCloneUrl parses the clone URL and injects
  x-access-token:<GITHUB_TOKEN> ONLY on an exact https://github.com
  host match; prefix-confusable hosts (github.com.evil.com,
  evilgithub.com, subdomains), non-https schemes, and ssh remotes pass
  through untouched (#66 host-confusion fix)
- auth is applied at the exec boundary (clone, ls-remote); error
  messages keep the token-free URL and redactToken scrubs git/
  execFileSync output so the secret never reaches logs or thrown errors
- tar.gz fallback switches to the api.github.com tarball endpoint when
  a token is set: undici drops the Authorization header on the
  cross-origin redirect to codeload, but GitHub embeds a temporary
  token in the redirect Location, so private downloads still work
Machines with global tag.gpgsign=true failed createLocalRemote setup —
git tag <name> becomes a signed annotated tag that requires a message.
Pass -c tag.gpgsign=false / -c commit.gpgsign=false so the fixtures are
hermetic regardless of the developer's global git config.
- README / SKILL.md: add ask fetch to the command tables, note the
  cache-warming use case and private-repo token support
- CLAUDE.md: update the top-level command list, point cache-warming
  guidance at ask fetch, and add gotchas for the format-aware lockfile
  parsers and the exact-host token injection rule
@dosubot dosubot Bot added size:XL This PR changes 500-999 lines, ignoring generated files. type:feature New feature or request labels Jul 2, 2026
@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a new ask fetch CLI command for cache-warming checkouts, propagates fromCache/fromStoreCache flags through ensureCheckout and GithubSource, introduces GitHub token authentication for private repos, and rewrites pnpm/yarn/package.json lockfile version resolution with new shared parsing helpers. Documentation and tests are updated accordingly.

Changes

ask fetch command and cache-hit reporting

Layer / File(s) Summary
ensureCheckout cache-hit reporting
packages/cli/src/commands/ensure-checkout.ts, packages/cli/test/commands/ensure-checkout.test.ts
EnsureCheckoutResult gains fromCache: boolean, set true on primary cache hits and derived from fetchResult.fromStoreCache on cache misses, with new tests.
GitHub token authentication and store-hit flag
packages/cli/src/sources/github.ts, packages/cli/src/sources/index.ts, packages/cli/test/sources/github-auth.test.ts
Adds githubToken/authenticatedCloneUrl/redactToken helpers used in ls-remote, clone, and tarball fetches; fetch() returns fromStoreCache: true on verified hits; FetchResult interface updated.
runFetch implementation and CLI wiring
packages/cli/src/commands/fetch.ts, packages/cli/src/index.ts, packages/cli/test/commands/fetch.test.ts
New runFetch/fetchCmd warm checkout caches per spec, track fetched vs cached counts, support quiet mode, continue past per-spec errors, and exit 1 on failure; wired into main subCommands with tests.
Documentation updates
CLAUDE.md, README.md, skills/ask/SKILL.md
Documents ask fetch, private GitHub token behavior, cache verification/quarantine, and related implementation notes (checkout flags, cpDirAtomic, prompt typing, ask add flow).
Test GPG signing fixes
packages/cli/test/sources/github.test.ts, packages/cli/test/sources/github-monorepo.test.ts
Git commit/tag helper invocations in test fixtures disable GPG signing explicitly.

Lockfile parser rewrite

Layer / File(s) Summary
Shared parsing helpers
packages/cli/src/lockfiles/parse-helpers.ts
New utilities for stripping peer suffixes, YAML inline comments, quotes, splitting package specs, and validating registry versions.
package.json reader filtering
packages/cli/src/lockfiles/package-json.ts
parse() skips non-registry specifiers (workspace:*, link:, file:, git+) via isRegistryVersion.
pnpm graph-based parser
packages/cli/src/lockfiles/pnpm.ts
Replaces regex parsing with an indent-aware stack that builds a dependency graph and resolves versions via direct match then BFS transitive resolution across pnpm v5–v9 formats.
yarn block-based parser
packages/cli/src/lockfiles/yarn.ts
Replaces regex parsing with block-splitting logic supporting classic and Berry header formats and protocol filtering.
Lockfile tests and fixtures
packages/cli/test/lockfiles/*
New pnpm v9 fixture and extensive tests covering helpers, direct/transitive pnpm resolution, yarn v1/Berry parsing, and package.json protocol filtering.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CLI as fetchCmd
  participant RunFetch as runFetch
  participant EnsureCheckout as ensureCheckout
  participant Github as GithubSource

  CLI->>RunFetch: specs, quiet
  loop each spec
    RunFetch->>EnsureCheckout: ensureCheckout(spec)
    alt cache miss
      EnsureCheckout->>Github: fetch(spec)
      Github-->>EnsureCheckout: fromStoreCache flag
    end
    EnsureCheckout-->>RunFetch: result.fromCache
    RunFetch->>RunFetch: increment fetched/cached, log unless quiet
  end
  RunFetch-->>CLI: log summary, exit(1) if any spec failed
Loading

Estimated code review effort: 4 (Complex) | ~60 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main changes: the new fetch command, lockfile parser updates, and GitHub token auth.
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch amondnet/opensrc

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@codecov

codecov Bot commented Jul 2, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 97.30458% with 10 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
packages/cli/src/commands/fetch.ts 85.07% 10 Missing ⚠️

📢 Thoughts on this report? Let us know!

@codacy-production

codacy-production Bot commented Jul 2, 2026

Copy link
Copy Markdown

Not up to standards ⛔

🔴 Issues 6 critical · 2 high

Alerts:
⚠ 8 issues (≤ 0 issues of at least minor severity)

Results:
8 new issues

Category Results
Security 6 critical
2 high

View in Codacy

🟢 Metrics 246 complexity · 1 duplication

Metric Results
Complexity 246
Duplication 1

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 2, 2026

Copy link
Copy Markdown

Deploying ask with  Cloudflare Pages  Cloudflare Pages

Latest commit: 14e5584
Status: ✅  Deploy successful!
Preview URL: https://f3b3a228.ask-6im.pages.dev
Branch Preview URL: https://amondnet-opensrc.ask-6im.pages.dev

View logs

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 2, 2026

Copy link
Copy Markdown

Deploying ask-registry with  Cloudflare Pages  Cloudflare Pages

Latest commit: 14e5584
Status: ✅  Deploy successful!
Preview URL: https://17141118.ask-registry.pages.dev
Branch Preview URL: https://amondnet-opensrc.ask-registry.pages.dev

View logs

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

3 issues found across 20 files

Architecture diagram
sequenceDiagram
    participant User as CLI User
    participant FetchCmd as fetchCmd (citty)
    participant RunFetch as runFetch()
    participant EnsureCheckout as ensureCheckout()
    participant GithubSrc as GithubSource
    participant Git as git process
    participant Env as Environment
    participant Lockfiles as npmEcosystemReader
    participant PnpmParser as parsePnpmLock
    participant YarnParser as parseYarnLock
    participant Helpers as parse-helpers

    Note over User,Git: Flow 1: ask fetch command

    User->>FetchCmd: ask fetch -q github:owner/repo@v1.0.0 react
    FetchCmd->>RunFetch: runFetch({ specs, projectDir, quiet: true })
    loop for each spec
        RunFetch->>EnsureCheckout: ensureCheckout({ spec, projectDir })
        alt Spec not in ~/.ask store
            EnsureCheckout->>GithubSrc: cloneAtTag(remoteUrl, candidate)
            alt GITHUB_TOKEN set
                GithubSrc->>GithubSrc: authenticatedCloneUrl(remoteUrl, token)
                Note over GithubSrc: Parses URL, checks hostname === 'github.com'<br/>and protocol === 'https:'<br/>Rejects github.com.evil.com, evilgithub.com, subdomains
                GithubSrc->>Git: execFileSync('git clone', authenticatedUrl)
                Git-->>GithubSrc: stdout/stderr
                GithubSrc->>GithubSrc: redactToken(output) → log/error safe
            else no token
                GithubSrc->>Git: execFileSync('git clone', remoteUrl)
            end
            Git-->>GithubSrc: result
            GithubSrc->>EnsureCheckout: resolvedCheckoutDir
            EnsureCheckout-->>RunFetch: { fromCache: false, ... }
        else Cache hit (store exists)
            EnsureCheckout-->>RunFetch: { fromCache: true, ... }
        end
        RunFetch->>RunFetch: Format display line
        alt quiet mode
            Note over RunFetch: No log lines (errors still to stderr)
        else verbose
            RunFetch->>RunFetch: log "✓ fetched" or "already cached"
        end
    end
    RunFetch->>RunFetch: Print summary (X fetched, Y already cached)
    alt any spec failed
        RunFetch->>RunFetch: error to stderr per failure
        RunFetch->>RunFetch: exit(1)
    end

    Note over User,PnpmParser: Flow 2: Lockfile parsing (npm entries)

    User->>Lockfiles: ask install (npm spec)
    Lockfiles->>Lockfiles: Try bun.lock → package-lock.json
    Lockfiles->>PnpmParser: read pnpm-lock.yaml content
    PnpmParser->>Helpers: isRegistryVersion, stripPeerSuffix, splitPkgSpec
    alt Direct match in importers or top-level deps
        PnpmParser-->>Lockfiles: version (e.g., "18.2.0")
    else No direct match -> transitive BFS
        PnpmParser->>PnpmParser: build dep graph from snapshots/packages
        PnpmParser->>PnpmParser: BFS from root->roots to find reachable version
        alt Reachable version exists
            PnpmParser-->>Lockfiles: version
        else Unreachable -> fallback to packages key
            PnpmParser->>Helpers: isRegistryVersion check
            PnpmParser-->>Lockfiles: version (or null)
        end
    end
    alt Protocol version (workspace:*, link:, file:)
        Helpers-->>PnpmParser: isRegistryVersion false -> skip
    end

    Lockfiles->>YarnParser: read yarn.lock content
    YarnParser->>Helpers: cleanValue, stripPeerSuffix, etc.
    YarnParser->>YarnParser: Split into blocks, parse header for specifier matching pkg
    alt Block mentions pkg
        YarnParser->>Helpers: isRegistryVersion check on version line
        alt Valid registry version
            YarnParser-->>Lockfiles: version
        else Workspace sentinel or protocol -> skip, check next block
        end
    end
    Lockfiles-->>User: exact version for install

    Note over User,Env: Flow 3: Authenticated clone with host validation

    User->>Env: export GITHUB_TOKEN=ghp_...
    User->>Git: ask src github:private/repo
    Git->>Git: probeRemoteTag(remoteUrl) -> authenticatedCloneUrl
    alt exact https://github.com match
        Git->>GithubSrc: authenticated URL used for ls-remote
        GithubSrc-->>Env: token injected, host validated (no prefix confusion)
    else any other host (e.g., gist.github.com, github.com.evil.com)
        Git->>GithubSrc: original URL passed through unchanged
    end
    Git->>Git: shallowCloneRef -> authenticatedCloneUrl
    Note over Git: token redacted from error messages by redactToken()
    Git-->>GithubSrc: commit SHA, checkout dir
    GithubSrc-->>User: path to cached source
Loading

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread packages/cli/src/lockfiles/pnpm.ts Outdated
Comment thread packages/cli/src/commands/fetch.ts
Comment thread packages/cli/src/commands/ensure-checkout.ts Outdated
@greptile-apps

greptile-apps Bot commented Jul 2, 2026

Copy link
Copy Markdown

Greptile Summary

This PR ports three features from vercel-labs/opensrc into the ASK CLI and bumps vendor/opensrc to v0.7.3. The changes are well-scoped, thoroughly tested (621 passing), and accompanied by careful security commentary in code.

  • ask fetch <spec...>: New top-level command that warms the checkout cache via the shared ensureCheckout helper; supports multiple specs, -q/--quiet, per-spec status lines, and exits non-zero if any spec fails while continuing the rest.
  • Format-aware lockfile parsers: Replaces regex-based pnpm/yarn parsers with an indent-aware stack parser (pnpm v5–v9, BFS transitive resolution) and a block-based parser (yarn v1 + Berry), plus isRegistryVersion filtering in the package.json fallback to skip workspace/link/file protocol entries.
  • GITHUB_TOKEN auth: authenticatedCloneUrl injects credentials only on an exact https://github.com host match; redactToken scrubs git error output; the tarball fallback switches to the api.github.com endpoint to work around undici's header-stripping on cross-origin redirects.

Confidence Score: 5/5

Safe to merge — all three feature areas are correctly implemented, all edge cases are covered by tests, and the security-sensitive auth path is well-hardened.

The host-validation logic in authenticatedCloneUrl is exact and proven by dedicated unit tests (prefix/suffix confusion, subdomains, non-https, SSH). Token redaction wraps every exec boundary. The indent-aware pnpm parser and block-based yarn parser handle every documented edge case (peer suffixes, v5 slash keys, multi-specifier headers, workspace sentinels) with 58 unit tests plus fixture files. The ask fetch command correctly propagates fromCache through the fromStoreCache flag added to FetchResult, and the test suite confirms both fresh-fetch and cache-hit paths. No logic errors, no data races introduced, no security gaps found.

No files require special attention.

Important Files Changed

Filename Overview
packages/cli/src/commands/fetch.ts New ask fetch command; wires citty CLI surface to runFetch, correctly separates concerns between the thin CLI shim and the injectable core logic.
packages/cli/src/commands/ensure-checkout.ts Adds fromCache to EnsureCheckoutResult, correctly delegating to fetchResult?.fromStoreCache for ref-candidate-variant hits and using fs.existsSync for the primary-key short-circuit.
packages/cli/src/sources/github.ts Adds GITHUB_TOKEN auth: authenticatedCloneUrl with exact-host validation, redactToken scrubbing of git error output, and API tarball endpoint fallback for authenticated private downloads. Logic is sound and well-guarded.
packages/cli/src/lockfiles/pnpm.ts Full rewrite to indent-aware stack parser with BFS transitive resolution; covers pnpm v5–v9, importers, peer-dep suffixes, and v5 slash keys. Logic is correct; comprehensive tests back every code path.
packages/cli/src/lockfiles/yarn.ts Block-based parser handles yarn v1 and Berry in one pass; correctly splits multi-specifier headers and skips workspace/protocol sentinels.
packages/cli/src/lockfiles/parse-helpers.ts New shared helpers (stripPeerSuffix, cleanValue, splitPkgSpec, isRegistryVersion) extracted from parsers; all helpers are correct and individually tested.
packages/cli/src/lockfiles/package-json.ts Adds isRegistryVersion guard before returning a version; correctly skips workspace/link/file/git protocol strings that would confuse the resolver.
packages/cli/src/sources/index.ts Adds optional fromStoreCache flag to FetchResult; clean addition with no breaking changes to existing callers.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant User
    participant fetchCmd
    participant runFetch
    participant ensureCheckout
    participant GithubSource
    participant Store

    User->>fetchCmd: ask fetch spec1 spec2
    fetchCmd->>runFetch: "specs=[spec1,spec2], projectDir"

    loop for each spec
        runFetch->>ensureCheckout: "{spec, projectDir}"
        ensureCheckout->>Store: fs.existsSync(checkoutDir)?
        alt cache hit
            Store-->>ensureCheckout: dir exists
            ensureCheckout-->>runFetch: "{fromCache: true, ...}"
            runFetch->>User: ✓ spec already cached
        else cache miss
            Store-->>ensureCheckout: miss
            ensureCheckout->>GithubSource: fetch(opts)
            alt git available
                GithubSource->>GithubSource: authenticatedCloneUrl(remoteUrl, GITHUB_TOKEN)
                GithubSource->>Store: shallowClone → cpDirAtomic → stampEntry
                GithubSource-->>ensureCheckout: "{storePath, fromStoreCache?}"
            else fallback
                GithubSource->>GithubSource: build archiveUrl (api.github.com if token)
                GithubSource->>GithubSource: "fetch(archiveUrl, {Authorization: Bearer TOKEN})"
                GithubSource->>Store: tar xz → cpDirAtomic → stampEntry
                GithubSource-->>ensureCheckout: "{storePath}"
            end
            ensureCheckout-->>runFetch: "{fromCache: fromStoreCache??false, ...}"
            runFetch->>User: "✓ Fetched spec@ref"
        end
    end
    runFetch->>User: summary (N fetched, M already cached)
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant User
    participant fetchCmd
    participant runFetch
    participant ensureCheckout
    participant GithubSource
    participant Store

    User->>fetchCmd: ask fetch spec1 spec2
    fetchCmd->>runFetch: "specs=[spec1,spec2], projectDir"

    loop for each spec
        runFetch->>ensureCheckout: "{spec, projectDir}"
        ensureCheckout->>Store: fs.existsSync(checkoutDir)?
        alt cache hit
            Store-->>ensureCheckout: dir exists
            ensureCheckout-->>runFetch: "{fromCache: true, ...}"
            runFetch->>User: ✓ spec already cached
        else cache miss
            Store-->>ensureCheckout: miss
            ensureCheckout->>GithubSource: fetch(opts)
            alt git available
                GithubSource->>GithubSource: authenticatedCloneUrl(remoteUrl, GITHUB_TOKEN)
                GithubSource->>Store: shallowClone → cpDirAtomic → stampEntry
                GithubSource-->>ensureCheckout: "{storePath, fromStoreCache?}"
            else fallback
                GithubSource->>GithubSource: build archiveUrl (api.github.com if token)
                GithubSource->>GithubSource: "fetch(archiveUrl, {Authorization: Bearer TOKEN})"
                GithubSource->>Store: tar xz → cpDirAtomic → stampEntry
                GithubSource-->>ensureCheckout: "{storePath}"
            end
            ensureCheckout-->>runFetch: "{fromCache: fromStoreCache??false, ...}"
            runFetch->>User: "✓ Fetched spec@ref"
        end
    end
    runFetch->>User: summary (N fetched, M already cached)
Loading

Reviews (5): Last reviewed commit: "fix: restore null-safe access to the inj..." | Re-trigger Greptile

Comment thread packages/cli/src/commands/fetch.ts
- pnpm parser: support v5 /name/version keys in the packages:/snapshots:
  pass with a last-slash split (scoped names intact, _peerhash stripped)
  and canonical name@version node keys so v5 fallback and transitive
  resolution connect (cubic review)
- ensure-checkout: propagate GithubSource's store-hit via a new
  FetchResult.fromStoreCache flag so fromCache is not misreported as a
  fresh fetch when the source found a ref-candidate cache entry with
  zero network I/O (cubic review)

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

0 issues found across 6 files (changes from recent commits).

Requires human review: Ports major features like format-aware lockfile parsers (pnpm/yarn) and a new fetch command, plus GitHub token authentication. These changes touch core logic and auth paths, carrying high risk and warrant human review.

Re-trigger cubic

@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: 1

🧹 Nitpick comments (6)
packages/cli/src/commands/fetch.ts (1)

29-74: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider extracting per-spec handling/summary logic.

SonarCloud flags this function's cognitive complexity (25 vs. the 15 allowed threshold). Splitting the per-spec try/catch body and the summary-string composition into small helpers (e.g. processSpec, buildSummary) would make each piece independently testable and bring complexity down without behavior changes.

🤖 Prompt for 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.

In `@packages/cli/src/commands/fetch.ts` around lines 29 - 74, The runFetch
function is too complex because it mixes per-spec checkout handling, error
capture, and summary composition in one loop. Refactor the logic in runFetch by
extracting the try/catch spec-processing block into a helper such as
processSpec, and move the fetched/cached summary string building into a helper
such as buildSummary; keep behavior unchanged while using the existing
ensureCheckout, log, error, and exit dependencies.

Source: Linters/SAST tools

CLAUDE.md (1)

95-96: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Fix markdownlint MD038 (space inside code span).

markdownlint flags a code span with extraneous internal spacing around line 96.

🤖 Prompt for 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.

In `@CLAUDE.md` around lines 95 - 96, The markdownlint MD038 issue comes from an
inline code span in the CLAUDE.md guidance text having extra spaces inside the
backticks. Update the affected sentence in that release/publish guidance so the
inline code token is written without leading or trailing spaces, keeping the
wording unchanged otherwise.

Source: Linters/SAST tools

packages/cli/src/sources/github.ts (2)

462-477: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Extract the nested ternary for readability.

isTagCandidate ? 'tags' : 'heads' nested inside the token ? ... : ... ternary is harder to scan.

♻️ Suggested extraction
-        const token = githubToken()
-        const archiveUrl = token
-          ? `https://api.github.com/repos/${repo}/tarball/${candidate}`
-          : `https://github.com/${repo}/archive/refs/${isTagCandidate ? 'tags' : 'heads'}/${candidate}.tar.gz`
+        const token = githubToken()
+        const refKind = isTagCandidate ? 'tags' : 'heads'
+        const archiveUrl = token
+          ? `https://api.github.com/repos/${repo}/tarball/${candidate}`
+          : `https://github.com/${repo}/archive/refs/${refKind}/${candidate}.tar.gz`
🤖 Prompt for 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.

In `@packages/cli/src/sources/github.ts` around lines 462 - 477, The archive URL
construction in github source is harder to read because the isTagCandidate
branch is nested inside the token ternary. Refactor the archiveUrl assignment in
github.ts by extracting the path segment choice into a separate named value or
small helper around the fetch/archiveUrl logic, so the token-based URL selection
and the tags/heads selection are not nested together.

Source: Linters/SAST tools


85-93: 🔒 Security & Privacy | 🔵 Trivial | 💤 Low value

redactToken relies on literal string matching; percent-encoded credentials would slip through.

parsed.password = token in authenticatedCloneUrl gets percent-encoded by URL.toString() for any userinfo-unsafe characters. If a token ever contains such characters, the string embedded in a clone URL (and thus in err.message) would differ from the raw token, and msg.split(token).join('***') would fail to redact it. Current GitHub token formats (ghp_, github_pat_, fine-grained PATs) are alphanumeric/underscore only, so this is low risk today.

🛡️ Defensive option
 function redactToken(msg: string, token: string | undefined = githubToken()): string {
-  return token ? msg.split(token).join('***') : msg
+  if (!token)
+    return msg
+  const encoded = encodeURIComponent(token)
+  return msg.split(token).join('***').split(encoded).join('***')
 }
🤖 Prompt for 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.

In `@packages/cli/src/sources/github.ts` around lines 85 - 93, The redaction in
redactionToken only matches the raw token string, so it can miss percent-encoded
credentials that appear in authenticatedCloneUrl output or err.message. Update
redactionToken to also handle the encoded form of githubToken() by comparing
against the URL-encoded token before replacing, and keep the existing callers in
github.ts using the same helper so all logged or thrown messages are scrubbed
consistently.
packages/cli/src/lockfiles/yarn.ts (1)

29-106: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Reduce cognitive complexity of parseYarnLock.

SonarCloud reports cognitive complexity at 44 vs. an allowed 15 and surfaces it as a failing check. The block-splitting/header-matching/version-extraction logic is correct (verified against v1, Berry, multi-specifier, __metadata-skip, and CRLF test cases), but combining block splitting, header parsing, and version-line scanning in one function makes it hard to follow.

Consider extracting splitIntoBlocks(text), parseBlockHeader(block) (returns header/body), and matchesPackage(headerBody, pkg) as separate helpers to bring this under the complexity threshold.

🤖 Prompt for 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.

In `@packages/cli/src/lockfiles/yarn.ts` around lines 29 - 106, Refactor
parseYarnLock to reduce its cognitive complexity while preserving the current
behavior for v1, Berry, multi-specifier headers, __metadata skipping, and CRLF
handling. Extract the block-building logic into splitIntoBlocks(text), move
header/body detection into parseBlockHeader(block), and isolate package matching
into matchesPackage(headerBody, pkg) so parseYarnLock only orchestrates these
helpers and scans for the version value. Keep the version extraction and
registry-version filtering behavior unchanged.

Source: Linters/SAST tools

packages/cli/src/lockfiles/pnpm.ts (1)

153-162: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Non-null assertions flagged as forbidden by static analysis.

stack.at(-1)! (lines 154, 162) and queue.shift()! (line 274) are functionally safe — the comment at lines 151-152 correctly explains the root frame never pops and queue.length > 0 is checked before shift() — but the lint rule explicitly flags these as "Forbidden non-null assertion," which suggests the project's ESLint config disallows !. This could fail CI lint checks.

Consider a small typed helper to centralize the assertion with an explicit runtime check instead of !:

♻️ Suggested helper
+function peek<T>(items: readonly T[]): T {
+  const last = items[items.length - 1]
+  if (last === undefined)
+    throw new Error('unreachable: stack/queue must not be empty here')
+  return last
+}

Then replace stack.at(-1)! with peek(stack) and queue.shift()! with a similar pattern (or keep shift() and use peek+splice if a non-mutating check is preferred).

Also applies to: 274-274

🤖 Prompt for 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.

In `@packages/cli/src/lockfiles/pnpm.ts` around lines 153 - 162, The lockfile
parser uses forbidden non-null assertions in the pnpm helper, which will trip
ESLint/CI. In the relevant parsing logic in the pnpm lockfile code, replace
`stack.at(-1)!` and `queue.shift()!` with a small typed helper that performs an
explicit runtime check before returning the value. Use the helper at the `stack`
access points and in the `queue` consumption path so the behavior stays the same
without any `!` assertions.

Source: Linters/SAST tools

🤖 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/src/lockfiles/pnpm.ts`:
- Around line 106-259: `parsePnpmLock` is failing the cognitive complexity gate
because its entire line-by-line state machine is implemented in one large
switch. Refactor the parsing flow in `parsePnpmLock` by extracting the
`root`/`importers`/`importer` handling, the `depGroup`/`depBlock` handling, and
the `packages`/`snapshots`/`pkgEntry`/`pkgDeps` handling into small named
helpers that operate on the shared `stack` and `graph`. Keep the return logic
and behavior unchanged, but move each case branch’s parsing rules into helpers
so the main function becomes a thin dispatcher.

---

Nitpick comments:
In `@CLAUDE.md`:
- Around line 95-96: The markdownlint MD038 issue comes from an inline code span
in the CLAUDE.md guidance text having extra spaces inside the backticks. Update
the affected sentence in that release/publish guidance so the inline code token
is written without leading or trailing spaces, keeping the wording unchanged
otherwise.

In `@packages/cli/src/commands/fetch.ts`:
- Around line 29-74: The runFetch function is too complex because it mixes
per-spec checkout handling, error capture, and summary composition in one loop.
Refactor the logic in runFetch by extracting the try/catch spec-processing block
into a helper such as processSpec, and move the fetched/cached summary string
building into a helper such as buildSummary; keep behavior unchanged while using
the existing ensureCheckout, log, error, and exit dependencies.

In `@packages/cli/src/lockfiles/pnpm.ts`:
- Around line 153-162: The lockfile parser uses forbidden non-null assertions in
the pnpm helper, which will trip ESLint/CI. In the relevant parsing logic in the
pnpm lockfile code, replace `stack.at(-1)!` and `queue.shift()!` with a small
typed helper that performs an explicit runtime check before returning the value.
Use the helper at the `stack` access points and in the `queue` consumption path
so the behavior stays the same without any `!` assertions.

In `@packages/cli/src/lockfiles/yarn.ts`:
- Around line 29-106: Refactor parseYarnLock to reduce its cognitive complexity
while preserving the current behavior for v1, Berry, multi-specifier headers,
__metadata skipping, and CRLF handling. Extract the block-building logic into
splitIntoBlocks(text), move header/body detection into parseBlockHeader(block),
and isolate package matching into matchesPackage(headerBody, pkg) so
parseYarnLock only orchestrates these helpers and scans for the version value.
Keep the version extraction and registry-version filtering behavior unchanged.

In `@packages/cli/src/sources/github.ts`:
- Around line 462-477: The archive URL construction in github source is harder
to read because the isTagCandidate branch is nested inside the token ternary.
Refactor the archiveUrl assignment in github.ts by extracting the path segment
choice into a separate named value or small helper around the fetch/archiveUrl
logic, so the token-based URL selection and the tags/heads selection are not
nested together.
- Around line 85-93: The redaction in redactionToken only matches the raw token
string, so it can miss percent-encoded credentials that appear in
authenticatedCloneUrl output or err.message. Update redactionToken to also
handle the encoded form of githubToken() by comparing against the URL-encoded
token before replacing, and keep the existing callers in github.ts using the
same helper so all logged or thrown messages are scrubbed consistently.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 2a307ae7-539e-4c60-8d42-3f4e1091b2e1

📥 Commits

Reviewing files that changed from the base of the PR and between a6f7a2c and 54844a1.

⛔ Files ignored due to path filters (2)
  • packages/cli/test/lockfiles/fixtures/yarn-berry.lock is excluded by !**/*.lock
  • packages/cli/test/lockfiles/fixtures/yarn-v1.lock is excluded by !**/*.lock
📒 Files selected for processing (20)
  • CLAUDE.md
  • README.md
  • packages/cli/src/commands/ensure-checkout.ts
  • packages/cli/src/commands/fetch.ts
  • packages/cli/src/index.ts
  • packages/cli/src/lockfiles/package-json.ts
  • packages/cli/src/lockfiles/parse-helpers.ts
  • packages/cli/src/lockfiles/pnpm.ts
  • packages/cli/src/lockfiles/yarn.ts
  • packages/cli/src/sources/github.ts
  • packages/cli/src/sources/index.ts
  • packages/cli/test/commands/ensure-checkout.test.ts
  • packages/cli/test/commands/fetch.test.ts
  • packages/cli/test/lockfiles/fixtures/pnpm-v9-workspace.yaml
  • packages/cli/test/lockfiles/parsers.test.ts
  • packages/cli/test/sources/github-auth.test.ts
  • packages/cli/test/sources/github-monorepo.test.ts
  • packages/cli/test/sources/github.test.ts
  • skills/ask/SKILL.md
  • vendor/opensrc

Comment thread packages/cli/src/lockfiles/pnpm.ts
Addresses the SonarCloud cognitive-complexity finding (85 > 15) raised
via CodeRabbit review. The line loop now delegates to one small handler
per frame kind (root/importers/importer/depGroup/depBlock/packages/
pkgEntry/pkgDeps) over a shared ParseState, with the root scope
represented by an empty stack instead of a sentinel frame.

Also clears the Codacy warnings on the same function: no while(true),
no non-null assertions (currentFrame returns Frame | undefined;
resolveTransitive uses index-pointer BFS instead of queue.shift()!).

Behavior unchanged — covered by the 84 lockfile parser tests.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

0 issues found across 1 file (changes from recent commits).

Auto-approved: Ports upstream opensrc features: rewritten pnpm/yarn lockfile parsers with transitive resolution, new ask fetch command, and GITHUB_TOKEN auth with host validation. All tests pass.

Re-trigger cubic

fetcher.fetch() returns a non-nullable FetchResult, so the ?. on
fromStoreCache access was dead — flagged by Codacy.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

0 issues found across 1 file (changes from recent commits).

Requires human review: Ports new fetch command, format-aware lockfile parsers, and GITHUB_TOKEN auth—these changes affect core dependency resolution and security, requiring human review.

Re-trigger cubic

bec57a0 dropped the optional chain because FetchResult was declared
non-nullable, but the ensureCheckout test seam legitimately simulates a
successful fetch by materializing the checkout dir without returning a
FetchResult — cache-sharing.test.ts crashed in CI. Widen the seam type
to Promise<FetchResult | undefined> so the type states the real
contract and the ?. is justified rather than dead.
@sonarqubecloud

sonarqubecloud Bot commented Jul 2, 2026

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

0 issues found across 1 file (changes from recent commits).

Requires human review: Core logic changes to lockfile parsers and auth handling affect critical dependency resolution and security; higher risk than low-impact changes.

Re-trigger cubic

@amondnet amondnet merged commit de0e942 into main Jul 2, 2026
12 of 13 checks passed
@amondnet amondnet deleted the amondnet/opensrc branch July 2, 2026 15:01
@github-actions github-actions Bot mentioned this pull request Jul 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL This PR changes 500-999 lines, ignoring generated files. type:feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant