Implement the following plan:
The urls command already accepts PURLs (pkg:cargo/serde@1.0.0) as its package argument, parsing out the ecosystem, name, and version. Other commands that take a package name argument still require plain names plus a separate --ecosystem flag. This change extends PURL support to 8 more commands so users can write git-pkgs why pkg:npm/lodash instead of git-pkgs why lodash -e npm.
Add ParsePackageArg to cmd/helpers.go:
When the arg is a PURL, the ecosystem is derived from the PURL type and the --ecosystem flag is ignored. When it's a plain name, the ecosystem comes from the flag (may be empty) and version is empty.
These use ecosystem to filter database queries. The change is the same pattern: call ParsePackageArg at the top, use the returned ecosystem instead of the raw flag.
cmd/why.go (runWhy) - replace packageName := args[0] + ecosystem flag read with ParsePackageArg(args[0], ecosystem). Pass returned ecosystem and name to db.GetWhy().
cmd/history.go (runHistory) - same pattern. Pass ecosystem and name to db.GetPackageHistory().
cmd/where.go (runWhere) - same pattern. The returned ecosystem filters which manifest types to search. The name is used for the regex search.
cmd/vulns.go (runVulnsHistory, ~line 1428) - same pattern, but this command currently has no --ecosystem flag. Add one. Use the returned ecosystem to also filter the strings.EqualFold(d.Name, packageName) loop to also check ecosystem when set, avoiding false matches across ecosystems.
These use ecosystem to filter detected package managers. The change: call ParsePackageArg, use returned ecosystem for FilterByEcosystem, and use returned name as the package arg passed to the manager.
cmd/browse.go (runBrowse) - parse PURL, use name as pkg for mgr.Path(), use ecosystem for FilterByEcosystem.
cmd/add.go (runAdd) - parse PURL, use name as package and version from PURL (if present) as version arg. So git-pkgs add pkg:npm/lodash@4.17.21 works like git-pkgs add lodash 4.17.21 -e npm.
cmd/remove.go (runRemove) - parse PURL, use name as package, ecosystem for filtering.
cmd/update.go (runUpdate) - parse PURL when a package arg is provided, use name as package, ecosystem for filtering.
cmd/helpers.go - add ParsePackageArg, add purl importcmd/why.go - use ParsePackageArgcmd/history.go - use ParsePackageArgcmd/where.go - use ParsePackageArgcmd/vulns.go - add --ecosystem flag to vulns history, use ParsePackageArgcmd/browse.go - use ParsePackageArgcmd/add.go - use ParsePackageArg, use version from PURLcmd/remove.go - use ParsePackageArgcmd/update.go - use ParsePackageArgAdd to cmd/urls_test.go (or a new cmd/helpers_test.go since ParsePackageArg lives in helpers):
TestParsePackageArg - unit tests for the shared helper covering: PURL input extracts ecosystem/name/version, plain name passes through ecosystem flag, PURL with namespace, invalid PURL returns error, ecosystem flag ignored when PURL providedAdd integration tests for each command (following the urls_test.go pattern with createTestRepo/runCmd):
--ecosystem + plain namecd /Users/andrew/code/git-pkgs/git-pkgs && go build ./...go test ./cmd/ -run TestParsePackageArggo test ./cmd/ -v (full test suite)go vet ./... and golangci-lint run if availableIf you need specific details from before exiting plan mode (like exact code snippets, error messages, or content you generated), read the full transcript at: /Users/andrew/.claude/projects/-Users-andrew-code-git-pkgs/cadb53f4-f34f-4fcf-9066-e88933cb2fbc.jsonl
I'll start by reading the key files to understand the current patterns before implementing.
Now let me check the existing test patterns and the purl package.
Let me read the test helpers and a few more files I need.
Let me check for test fixture data used across tests.
Good, I have all the context I need. Let me now implement the changes. I'll create tasks to track progress.
Now let me add the ParsePackageArg helper to cmd/helpers.go.
The import will be used once we save; the diagnostic is transient since we just added the function. Let me verify it compiles.
Now let me update all 8 commands. I'll do the database-querying ones first, then the manager-operating ones.
1. cmd/why.go - replace packageName := args[0] + ecosystem flag read with ParsePackageArg:
2. cmd/history.go - same pattern:
3. cmd/where.go - same pattern:
4. cmd/vulns.go (runVulnsHistory) - add --ecosystem flag and use ParsePackageArg:
Now update the runVulnsHistory function to use ParsePackageArg and the ecosystem flag:
Now update the loop in runVulnsHistory that matches the package name to also filter by ecosystem when set:
Good, the ecosystem variable from ParsePackageArg is now used in the loop. Wait, the diagnostic says "declared and not used" - let me check. The ecosystem variable is declared in the ParsePackageArg call on line ~1435 and used in the loop. Let me re-check the file.
The code looks correct - ecosystem is used on line 1475. The diagnostic may have been stale. Let me now update the manager-operating commands.
5. cmd/browse.go - parse PURL:
6. cmd/add.go - parse PURL, use version from PURL:
7. cmd/remove.go - parse PURL:
8. cmd/update.go - parse PURL when package arg is provided:
Now let me verify the build compiles before writing tests.
Clean build. Now let me write the tests.
Now let me run the new tests first.
All unit tests pass. Now run the integration tests.
All passing. Now run the full test suite.
All tests pass. Let me also run go vet.
Everything passes. Here's a summary of what was done:
New helper (cmd/helpers.go):
ParsePackageArg(arg, ecosystemFlag) that returns (ecosystem, name, version, error). When the arg is a PURL, it parses out the ecosystem, name, and version; when it's a plain name, it passes through the ecosystem flag.8 commands updated:
why, history, where -- call ParsePackageArg at the top, use returned ecosystem/name for database queriesvulns history -- added --ecosystem flag it was missing, call ParsePackageArg, filter the dep-matching loop by ecosystem when setbrowse, remove -- call ParsePackageArg, use returned ecosystem for FilterByEcosystem and name as the package argadd -- call ParsePackageArg, use PURL version as the version arg when no explicit version argument is given (so git-pkgs add pkg:npm/lodash@4.17.21 works like git-pkgs add lodash 4.17.21 -e npm)update -- call ParsePackageArg when a package arg is provided, use returned ecosystem for filteringTests (cmd/helpers_test.go):
TestParsePackageArg -- 9 cases covering plain names, PURLs with/without version, namespaced PURLs, ecosystem mapping, flag-ignored-when-PURL, invalid PURL errorwhy, history, where verifying PURL produces same output as --ecosystem flagopen a pr
Let me check the current state of the repo first.
The parent git-pkgs directory isn't a git repo -- the actual repo must be in a subdirectory. Let me find it.
Good. Let me also check the remote and read the README before creating the branch and PR.
Now I need to add PURL documentation to the README. Let me add examples to the relevant command sections.
Now add a general note about PURL support. The urls section already explains PURLs. I'll add a note in the Configuration section about PURL arguments being accepted across commands.
Now let me make sure everything still builds and tests pass with the README changes, then create the branch, commit, and PR.
Now let me create the branch, commit, and push.
PR created: https://github.com/git-pkgs/git-pkgs/pull/119