#7

Crash: duplicate generated command name when a tag has multiple collection `GET`s (`cannot add command 'list-priorities'`)

Openpcomansopened 2mo ago

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

  • specli 0.0.39 (via npx 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.json

Actual 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:

  1. Disambiguate from operationId. Both operations have unique operationIds (getPriorities, searchPriorities); using/falling back to them yields unique command names.
  2. De-duplicate on collision by suffixing (e.g. list-priorities, list-priorities-2) or by including the path (list-priority, list-priority-search).
  3. 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 with specli at all — it dies on the first collision.
  • For comparison, restish handles the same spec because it derives command names from operationId.

Activity

1
pcomans2mo ago

@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