This issue is generated by Cursor agent, I will review ASAP.
Summary
specli exec <spec> crashes before running any command when an OpenAPI spec has two operations that map to the same generated command name. Command names appear to be derived from the HTTP method + tag (e.g. a collection GET becomes list-<tag>), so two collection GETs under one tag collide, and commander throws on the duplicate registration instead of de-duplicating.
This makes specli unusable against any spec that has more than one collection GET in a tag — including the Atlassian Jira Cloud platform REST API v3 spec (getPriorities = GET /rest/api/3/priority and searchPriorities = GET /rest/api/3/priority/search, both tagged Issue priorities), which fails immediately with cannot add command 'list-priorities'.
Environment
specli0.0.39 (vianpx specli)- Node v22.14.0
- Linux x86_64
Minimal reproduction
repro.json:
{
"openapi": "3.0.1",
"info": { "title": "specli dup-command repro", "version": "1.0.0" },
"servers": [{ "url": "https://example.com" }],
"paths": {
"/priority": { "get": { "operationId": "getPriorities", "tags": ["Issue priorities"], "summary": "Get priorities", "responses": { "200": { "description": "ok" } } } },
"/priority/search": { "get": { "operationId": "searchPriorities", "tags": ["Issue priorities"], "summary": "Search priorities", "responses": { "200": { "description": "ok" } } } }
}
}Run:
npx specli exec ./repro.jsonActual behavior
node_modules/commander/lib/command.js:655
throw new Error(
^
Error: cannot add command 'list-priorities' as already have command 'list-priorities'
at Command._registerCommand (node_modules/commander/lib/command.js:655:13)
at Command.command (node_modules/commander/lib/command.js:174:10)
at addGeneratedCommands (node_modules/specli/dist/cli/runtime/generated.js:81:37)
at main (node_modules/specli/dist/cli/main.js:189:5)
at async execCommand (node_modules/specli/dist/cli/exec.js:49:5)The process exits non-zero and no commands (not even unrelated ones) can be run.
Expected behavior
specli should register both operations without crashing. Options:
- Disambiguate from
operationId. Both operations have uniqueoperationIds (getPriorities,searchPriorities); using/falling back to them yields unique command names. - De-duplicate on collision by suffixing (e.g.
list-priorities,list-priorities-2) or by including the path (list-priority,list-priority-search). - At minimum, don't throw: detect the collision,
console.warn, and skip/rename the second command so the rest of the CLI still works.
Notes
- Real-world impact: the public Jira Cloud v3 spec (
https://dac-static.atlassian.com/cloud/jira/platform/swagger-v3.v3.json, ~421 paths) can't be used withspecliat all — it dies on the first collision. - For comparison,
restishhandles the same spec because it derives command names fromoperationId.
@AndrewBarba I validated that this is actually an issue with the Atlassian spec. This PR fixes the issue cleanly IMO, without resulting in broader changes to the generated command schema. Let me know what you think! https://github.com/vercel-labs/specli/pull/9