feat(setup): ask which package manager to use when the project is ambiguous - #784
Merged
Merged
Conversation
ffantl-ld
force-pushed
the
feat/setup-pm-confidence
branch
from
August 18, 2026 15:22
282f963 to
6df6b57
Compare
ffantl-ld
force-pushed
the
feat/setup-pm-picker
branch
from
August 18, 2026 15:22
5e3b923 to
dddaeee
Compare
ffantl-ld
force-pushed
the
feat/setup-pm-confidence
branch
from
August 18, 2026 15:29
6df6b57 to
3cfd103
Compare
ffantl-ld
force-pushed
the
feat/setup-pm-picker
branch
2 times, most recently
from
August 18, 2026 15:54
9aad062 to
49139fb
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 1416177. Configure here.
ffantl-ld
force-pushed
the
feat/setup-pm-picker
branch
2 times, most recently
from
August 18, 2026 18:00
372500d to
98e4725
Compare
ffantl-ld
force-pushed
the
feat/setup-pm-confidence
branch
from
August 19, 2026 14:12
055976e to
7fef87c
Compare
ffantl-ld
force-pushed
the
feat/setup-pm-picker
branch
from
August 19, 2026 14:12
acce8bc to
96253c2
Compare
ffantl-ld
force-pushed
the
feat/setup-pm-confidence
branch
from
August 19, 2026 15:51
7fef87c to
87e9ed0
Compare
ffantl-ld
force-pushed
the
feat/setup-pm-picker
branch
from
August 19, 2026 15:51
4b3c992 to
90c681c
Compare
ffantl-ld
force-pushed
the
feat/setup-pm-confidence
branch
from
August 19, 2026 16:09
87e9ed0 to
9246e77
Compare
ffantl-ld
force-pushed
the
feat/setup-pm-picker
branch
from
August 19, 2026 16:09
90c681c to
df5ec57
Compare
ffantl-ld
force-pushed
the
feat/setup-pm-confidence
branch
from
August 19, 2026 16:52
9246e77 to
b4e5252
Compare
ffantl-ld
force-pushed
the
feat/setup-pm-picker
branch
from
August 19, 2026 16:52
df5ec57 to
94eebae
Compare
ffantl-ld
force-pushed
the
feat/setup-pm-confidence
branch
from
August 19, 2026 17:39
b4e5252 to
f0a249f
Compare
ffantl-ld
force-pushed
the
feat/setup-pm-picker
branch
from
August 19, 2026 17:39
94eebae to
c3eb89b
Compare
ffantl-ld
force-pushed
the
feat/setup-pm-confidence
branch
from
August 19, 2026 18:18
f0a249f to
c10867f
Compare
ffantl-ld
force-pushed
the
feat/setup-pm-picker
branch
from
August 19, 2026 18:18
c3eb89b to
b0eb796
Compare
cspath1
approved these changes
Aug 19, 2026
ffantl-ld
force-pushed
the
feat/setup-pm-picker
branch
from
August 19, 2026 18:40
b0eb796 to
6ece185
Compare
ffantl-ld
force-pushed
the
feat/setup-pm-confidence
branch
from
August 19, 2026 21:14
acfb88b to
6446556
Compare
ffantl-ld
force-pushed
the
feat/setup-pm-picker
branch
from
August 19, 2026 21:16
6ece185 to
e87936d
Compare
ffantl-ld
force-pushed
the
feat/setup-pm-confidence
branch
from
August 20, 2026 15:13
6446556 to
d56b2d7
Compare
ffantl-ld
force-pushed
the
feat/setup-pm-picker
branch
from
August 20, 2026 15:13
e87936d to
768b8db
Compare
…ntly Detection always returned a manager, so a project that never said which one it used got pip or npm presented as fact. Signals are now split into what the project declares and what it merely implies, and a verdict is definite only when the project names exactly one manager. Recognise the corepack packageManager field, poetry.lock, Pipfile.lock and [tool.pdm], which were previously read as pip or npm. [tool.hatch] is recorded as a signal we cannot act on, since hatch has no dependency-add command. `setup install` now reads the project when --package-manager is omitted, instead of defaulting to pip or npm whatever the lockfiles say, and fails with the candidate list when the project is ambiguous rather than picking for the user. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Real pyproject files rarely carry a bare [tool.x] header, so matching only that left the poetry, uv, pdm and hatch signals near-dead: a hatch project configures [tool.hatch.build], not [tool.hatch]. Nested tables now count, with the trailing delimiter required so [tool.uv] does not match [tool.uvicorn]. A manager the project committed to now settles the verdict even when an unactionable tool is also configured. hatchling is a common build backend for uv and poetry projects, and uv can add the dependency whoever builds the wheel; previously those projects were marked ambiguous and install refused to run. Recognise pdm.lock, so a PDM project that commits only its lockfile is still identified as one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
pnpm refuses to run at all when package.json names it without a version — "No version specified for pnpm in packageManager" — so treating a versionless field as the project's declared manager routed the user into a command that cannot work. Such a field is no longer a declaration: the lockfiles decide, or the user is asked. When a manager still refuses for that reason, say so. The manifest is malformed rather than the command wrong, and repairing someone's manifest is not ours to do. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Corepack accepts only an exact version, so a range is refused outright — "Invalid package manager specification in package.json (pnpm@^11.13.0); expected a semver version" — as is a missing version. Treating either as the project's declared manager routed the user into a command that cannot run. Only an exact MAJOR.MINOR.PATCH, optionally with prerelease or build metadata, now counts; anything else leaves the lockfiles to decide or the user to be asked. When a manager refuses for that reason, say which part is wrong. The manifest is malformed rather than the command, and repairing someone's manifest is not ours to do. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Matching [tool.<name>] as text counted comments and strings, so a uv project whose comment mentioned the tool it migrated away from was marked ambiguous and install refused to run. Reading the declared tables instead means only a declaration counts, and nested tables need no special case: TOML creates the parent implicitly, so [tool.hatch.build] alone still declares hatch. A file we cannot parse declares nothing, which leaves the project ambiguous and the user asked — the honest answer when we cannot read what manages it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Detection parsed the file twice for a Python project: once for the detector's own package manager and again for the confidence verdict. The verdict is now the single source for the languages it models, and the detector leaves the field to it. A language it does not model, such as Java's maven versus gradle, keeps the answer its detector gives. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The packageManager guidance matched a missing or non-semver version anywhere in an install failure, so a gem, a Python package or a Go module reporting either phrase had its real error replaced by advice about a file it does not have. The output has to name package.json, which both corepack refusals do. Say what was actually found when a project is set up for more than one manager: a Pipfile and a [tool.*] table count as commitments too, so naming lockfiles sent the reader looking for files that are not there. Note on stderr when no --package-manager was given, since that used to fall through to npm or pip and now reads the project. Callers parsing output are unaffected. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…iguous A project with lockfiles for two managers, or none at all, has no answer we can read off disk, and picking one is how a yarn project gets installed with npm. The wizard now asks, and says why it is asking. Installed managers are listed first and the cursor starts on one, but an uninstalled manager stays selectable: the choice is the user's and the install step already warns rather than installing tooling. Projects that state their manager go straight to the plan. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The screen draws a title, the reason for asking and a key hint around the list, but the list was sized to the whole window, so the hint — including how to go back — was pushed off the bottom at every terminal size. The list now leaves room for that chrome, and the list's own help line goes away since the screen prints its own. Below fourteen rows the reason is dropped: at that size the question and the choices matter more than the explanation. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The project and environment screens printed a footer of key hints while the list below already rendered its own help, so every instruction appeared twice. The wizard's own bindings now go into the list's help line, which is the single place a screen states them, and the footers are gone. The package-manager picker follows the same shape, and its height reserve is retuned for the help line the list now draws, including the extra row that line takes when the terminal is narrower than it is. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A step naming an absolute entry-point path alongside the warning that no entry file was found runs well past a narrow terminal, and overflowing there hides the warning the step exists to give. Steps now wrap, with what wraps indented under the number so a step still reads as one item. The screen that names the injected file wraps for the same reason. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Wrapping pads every line to the full width, so the newline left inside the wrapped lead put a whole row of spaces in front of the file path and carried it past the edge of the terminal. The newline now sits outside the wrap, and the closing instruction wraps too. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The list inherits the same quit binding as the others, so esc arriving on its own ended the session from the picker. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Verification cannot succeed until the user's application is running, so naming only the SDK left it unclear whether anything was expected of them. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
ffantl-ld
force-pushed
the
feat/setup-pm-confidence
branch
from
August 20, 2026 17:18
d56b2d7 to
04662ac
Compare
ffantl-ld
force-pushed
the
feat/setup-pm-picker
branch
from
August 20, 2026 17:18
768b8db to
79be31b
Compare
Base automatically changed from
feat/setup-pm-confidence
to
fix/setup-rederive-on-override
August 20, 2026 17:31
ffantl-ld
added a commit
that referenced
this pull request
Aug 20, 2026
…iguous (#784) * feat(setup): report package-manager confidence and stop guessing silently Detection always returned a manager, so a project that never said which one it used got pip or npm presented as fact. Signals are now split into what the project declares and what it merely implies, and a verdict is definite only when the project names exactly one manager. Recognise the corepack packageManager field, poetry.lock, Pipfile.lock and [tool.pdm], which were previously read as pip or npm. [tool.hatch] is recorded as a signal we cannot act on, since hatch has no dependency-add command. `setup install` now reads the project when --package-manager is omitted, instead of defaulting to pip or npm whatever the lockfiles say, and fails with the candidate list when the project is ambiguous rather than picking for the user. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(setup): match nested tool tables and let a committed manager win Real pyproject files rarely carry a bare [tool.x] header, so matching only that left the poetry, uv, pdm and hatch signals near-dead: a hatch project configures [tool.hatch.build], not [tool.hatch]. Nested tables now count, with the trailing delimiter required so [tool.uv] does not match [tool.uvicorn]. A manager the project committed to now settles the verdict even when an unactionable tool is also configured. hatchling is a common build backend for uv and poetry projects, and uv can add the dependency whoever builds the wheel; previously those projects were marked ambiguous and install refused to run. Recognise pdm.lock, so a PDM project that commits only its lockfile is still identified as one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(setup): require a version in the packageManager field pnpm refuses to run at all when package.json names it without a version — "No version specified for pnpm in packageManager" — so treating a versionless field as the project's declared manager routed the user into a command that cannot work. Such a field is no longer a declaration: the lockfiles decide, or the user is asked. When a manager still refuses for that reason, say so. The manifest is malformed rather than the command wrong, and repairing someone's manifest is not ours to do. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(setup): require one exact version in the packageManager field Corepack accepts only an exact version, so a range is refused outright — "Invalid package manager specification in package.json (pnpm@^11.13.0); expected a semver version" — as is a missing version. Treating either as the project's declared manager routed the user into a command that cannot run. Only an exact MAJOR.MINOR.PATCH, optionally with prerelease or build metadata, now counts; anything else leaves the lockfiles to decide or the user to be asked. When a manager refuses for that reason, say which part is wrong. The manifest is malformed rather than the command, and repairing someone's manifest is not ours to do. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(setup): read pyproject.toml as TOML to find configured tools Matching [tool.<name>] as text counted comments and strings, so a uv project whose comment mentioned the tool it migrated away from was marked ambiguous and install refused to run. Reading the declared tables instead means only a declaration counts, and nested tables need no special case: TOML creates the parent implicitly, so [tool.hatch.build] alone still declares hatch. A file we cannot parse declares nothing, which leaves the project ambiguous and the user asked — the honest answer when we cannot read what manages it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * refactor(setup): read pyproject.toml once per detection Detection parsed the file twice for a Python project: once for the detector's own package manager and again for the confidence verdict. The verdict is now the single source for the languages it models, and the detector leaves the field to it. A language it does not model, such as Java's maven versus gradle, keeps the answer its detector gives. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(setup): stop misreading other ecosystems' install errors The packageManager guidance matched a missing or non-semver version anywhere in an install failure, so a gem, a Python package or a Go module reporting either phrase had its real error replaced by advice about a file it does not have. The output has to name package.json, which both corepack refusals do. Say what was actually found when a project is set up for more than one manager: a Pipfile and a [tool.*] table count as commitments too, so naming lockfiles sent the reader looking for files that are not there. Note on stderr when no --package-manager was given, since that used to fall through to npm or pip and now reads the project. Callers parsing output are unaffected. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat(setup): ask which package manager to use when the project is ambiguous A project with lockfiles for two managers, or none at all, has no answer we can read off disk, and picking one is how a yarn project gets installed with npm. The wizard now asks, and says why it is asking. Installed managers are listed first and the cursor starts on one, but an uninstalled manager stays selectable: the choice is the user's and the install step already warns rather than installing tooling. Projects that state their manager go straight to the plan. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(setup): keep the package-manager picker inside the terminal The screen draws a title, the reason for asking and a key hint around the list, but the list was sized to the whole window, so the hint — including how to go back — was pushed off the bottom at every terminal size. The list now leaves room for that chrome, and the list's own help line goes away since the screen prints its own. Below fourteen rows the reason is dropped: at that size the question and the choices matter more than the explanation. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(setup): show each screen's key hints once, inside the list The project and environment screens printed a footer of key hints while the list below already rendered its own help, so every instruction appeared twice. The wizard's own bindings now go into the list's help line, which is the single place a screen states them, and the footers are gone. The package-manager picker follows the same shape, and its height reserve is retuned for the help line the list now draws, including the extra row that line takes when the terminal is narrower than it is. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(setup): wrap the plan steps to the terminal width A step naming an absolute entry-point path alongside the warning that no entry file was found runs well past a narrow terminal, and overflowing there hides the warning the step exists to give. Steps now wrap, with what wraps indented under the number so a step still reads as one item. The screen that names the injected file wraps for the same reason. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(setup): stop padding pushing the injected file path off screen Wrapping pads every line to the full width, so the newline left inside the wrapped lead put a whole row of spaces in front of the file path and carried it past the edge of the terminal. The newline now sits outside the wrap, and the closing instruction wraps too. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(setup): stop the package-manager list quitting on esc The list inherits the same quit binding as the others, so esc arriving on its own ended the session from the picker. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat(setup): say the verify step waits for the app as well as the SDK Verification cannot succeed until the user's application is running, so naming only the SDK left it unclear whether anything was expected of them. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
ffantl-ld
added a commit
that referenced
this pull request
Aug 20, 2026
…#782) * fix(setup): re-derive entry point and package manager on SDK override Choosing an SDK by hand replaced the detected entry point with that SDK's bare default in the working directory, so a project whose entry file was src/index.js got a second index.js created beside it. The package manager was left describing the language detection guessed first, so a Ruby install never ran bundle add. Both are now re-derived for the chosen SDK from one shared table of entry-point candidates, which detection also reads. Snippet-only SDKs have no entry point, so the final screen no longer names an empty path. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat(setup): report package-manager confidence and stop guessing silently (#783) * feat(setup): report package-manager confidence and stop guessing silently Detection always returned a manager, so a project that never said which one it used got pip or npm presented as fact. Signals are now split into what the project declares and what it merely implies, and a verdict is definite only when the project names exactly one manager. Recognise the corepack packageManager field, poetry.lock, Pipfile.lock and [tool.pdm], which were previously read as pip or npm. [tool.hatch] is recorded as a signal we cannot act on, since hatch has no dependency-add command. `setup install` now reads the project when --package-manager is omitted, instead of defaulting to pip or npm whatever the lockfiles say, and fails with the candidate list when the project is ambiguous rather than picking for the user. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(setup): match nested tool tables and let a committed manager win Real pyproject files rarely carry a bare [tool.x] header, so matching only that left the poetry, uv, pdm and hatch signals near-dead: a hatch project configures [tool.hatch.build], not [tool.hatch]. Nested tables now count, with the trailing delimiter required so [tool.uv] does not match [tool.uvicorn]. A manager the project committed to now settles the verdict even when an unactionable tool is also configured. hatchling is a common build backend for uv and poetry projects, and uv can add the dependency whoever builds the wheel; previously those projects were marked ambiguous and install refused to run. Recognise pdm.lock, so a PDM project that commits only its lockfile is still identified as one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(setup): require a version in the packageManager field pnpm refuses to run at all when package.json names it without a version — "No version specified for pnpm in packageManager" — so treating a versionless field as the project's declared manager routed the user into a command that cannot work. Such a field is no longer a declaration: the lockfiles decide, or the user is asked. When a manager still refuses for that reason, say so. The manifest is malformed rather than the command wrong, and repairing someone's manifest is not ours to do. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(setup): require one exact version in the packageManager field Corepack accepts only an exact version, so a range is refused outright — "Invalid package manager specification in package.json (pnpm@^11.13.0); expected a semver version" — as is a missing version. Treating either as the project's declared manager routed the user into a command that cannot run. Only an exact MAJOR.MINOR.PATCH, optionally with prerelease or build metadata, now counts; anything else leaves the lockfiles to decide or the user to be asked. When a manager refuses for that reason, say which part is wrong. The manifest is malformed rather than the command, and repairing someone's manifest is not ours to do. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(setup): read pyproject.toml as TOML to find configured tools Matching [tool.<name>] as text counted comments and strings, so a uv project whose comment mentioned the tool it migrated away from was marked ambiguous and install refused to run. Reading the declared tables instead means only a declaration counts, and nested tables need no special case: TOML creates the parent implicitly, so [tool.hatch.build] alone still declares hatch. A file we cannot parse declares nothing, which leaves the project ambiguous and the user asked — the honest answer when we cannot read what manages it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * refactor(setup): read pyproject.toml once per detection Detection parsed the file twice for a Python project: once for the detector's own package manager and again for the confidence verdict. The verdict is now the single source for the languages it models, and the detector leaves the field to it. A language it does not model, such as Java's maven versus gradle, keeps the answer its detector gives. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(setup): stop misreading other ecosystems' install errors The packageManager guidance matched a missing or non-semver version anywhere in an install failure, so a gem, a Python package or a Go module reporting either phrase had its real error replaced by advice about a file it does not have. The output has to name package.json, which both corepack refusals do. Say what was actually found when a project is set up for more than one manager: a Pipfile and a [tool.*] table count as commitments too, so naming lockfiles sent the reader looking for files that are not there. Note on stderr when no --package-manager was given, since that used to fall through to npm or pip and now reads the project. Callers parsing output are unaffected. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat(setup): ask which package manager to use when the project is ambiguous (#784) * feat(setup): report package-manager confidence and stop guessing silently Detection always returned a manager, so a project that never said which one it used got pip or npm presented as fact. Signals are now split into what the project declares and what it merely implies, and a verdict is definite only when the project names exactly one manager. Recognise the corepack packageManager field, poetry.lock, Pipfile.lock and [tool.pdm], which were previously read as pip or npm. [tool.hatch] is recorded as a signal we cannot act on, since hatch has no dependency-add command. `setup install` now reads the project when --package-manager is omitted, instead of defaulting to pip or npm whatever the lockfiles say, and fails with the candidate list when the project is ambiguous rather than picking for the user. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(setup): match nested tool tables and let a committed manager win Real pyproject files rarely carry a bare [tool.x] header, so matching only that left the poetry, uv, pdm and hatch signals near-dead: a hatch project configures [tool.hatch.build], not [tool.hatch]. Nested tables now count, with the trailing delimiter required so [tool.uv] does not match [tool.uvicorn]. A manager the project committed to now settles the verdict even when an unactionable tool is also configured. hatchling is a common build backend for uv and poetry projects, and uv can add the dependency whoever builds the wheel; previously those projects were marked ambiguous and install refused to run. Recognise pdm.lock, so a PDM project that commits only its lockfile is still identified as one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(setup): require a version in the packageManager field pnpm refuses to run at all when package.json names it without a version — "No version specified for pnpm in packageManager" — so treating a versionless field as the project's declared manager routed the user into a command that cannot work. Such a field is no longer a declaration: the lockfiles decide, or the user is asked. When a manager still refuses for that reason, say so. The manifest is malformed rather than the command wrong, and repairing someone's manifest is not ours to do. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(setup): require one exact version in the packageManager field Corepack accepts only an exact version, so a range is refused outright — "Invalid package manager specification in package.json (pnpm@^11.13.0); expected a semver version" — as is a missing version. Treating either as the project's declared manager routed the user into a command that cannot run. Only an exact MAJOR.MINOR.PATCH, optionally with prerelease or build metadata, now counts; anything else leaves the lockfiles to decide or the user to be asked. When a manager refuses for that reason, say which part is wrong. The manifest is malformed rather than the command, and repairing someone's manifest is not ours to do. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(setup): read pyproject.toml as TOML to find configured tools Matching [tool.<name>] as text counted comments and strings, so a uv project whose comment mentioned the tool it migrated away from was marked ambiguous and install refused to run. Reading the declared tables instead means only a declaration counts, and nested tables need no special case: TOML creates the parent implicitly, so [tool.hatch.build] alone still declares hatch. A file we cannot parse declares nothing, which leaves the project ambiguous and the user asked — the honest answer when we cannot read what manages it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * refactor(setup): read pyproject.toml once per detection Detection parsed the file twice for a Python project: once for the detector's own package manager and again for the confidence verdict. The verdict is now the single source for the languages it models, and the detector leaves the field to it. A language it does not model, such as Java's maven versus gradle, keeps the answer its detector gives. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(setup): stop misreading other ecosystems' install errors The packageManager guidance matched a missing or non-semver version anywhere in an install failure, so a gem, a Python package or a Go module reporting either phrase had its real error replaced by advice about a file it does not have. The output has to name package.json, which both corepack refusals do. Say what was actually found when a project is set up for more than one manager: a Pipfile and a [tool.*] table count as commitments too, so naming lockfiles sent the reader looking for files that are not there. Note on stderr when no --package-manager was given, since that used to fall through to npm or pip and now reads the project. Callers parsing output are unaffected. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat(setup): ask which package manager to use when the project is ambiguous A project with lockfiles for two managers, or none at all, has no answer we can read off disk, and picking one is how a yarn project gets installed with npm. The wizard now asks, and says why it is asking. Installed managers are listed first and the cursor starts on one, but an uninstalled manager stays selectable: the choice is the user's and the install step already warns rather than installing tooling. Projects that state their manager go straight to the plan. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(setup): keep the package-manager picker inside the terminal The screen draws a title, the reason for asking and a key hint around the list, but the list was sized to the whole window, so the hint — including how to go back — was pushed off the bottom at every terminal size. The list now leaves room for that chrome, and the list's own help line goes away since the screen prints its own. Below fourteen rows the reason is dropped: at that size the question and the choices matter more than the explanation. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(setup): show each screen's key hints once, inside the list The project and environment screens printed a footer of key hints while the list below already rendered its own help, so every instruction appeared twice. The wizard's own bindings now go into the list's help line, which is the single place a screen states them, and the footers are gone. The package-manager picker follows the same shape, and its height reserve is retuned for the help line the list now draws, including the extra row that line takes when the terminal is narrower than it is. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(setup): wrap the plan steps to the terminal width A step naming an absolute entry-point path alongside the warning that no entry file was found runs well past a narrow terminal, and overflowing there hides the warning the step exists to give. Steps now wrap, with what wraps indented under the number so a step still reads as one item. The screen that names the injected file wraps for the same reason. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(setup): stop padding pushing the injected file path off screen Wrapping pads every line to the full width, so the newline left inside the wrapped lead put a whole row of spaces in front of the file path and carried it past the edge of the terminal. The newline now sits outside the wrap, and the closing instruction wraps too. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(setup): stop the package-manager list quitting on esc The list inherits the same quit binding as the others, so esc arriving on its own ended the session from the picker. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat(setup): say the verify step waits for the app as well as the SDK Verification cannot succeed until the user's application is running, so naming only the SDK left it unclear whether anything was expected of them. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Requirements
Related issues
Step 4 of the package-manager selection design — the wizard step that actually asks. Stacked on #783, which supplies the confidence verdict and candidates.
Describe the solution you've provided
←from the plan returns to the picker when it was shown, and to the SDK list when it was not.Describe alternatives you've considered
pnpminstalled says nothing about whether this repo uses it, and it would give two developers different answers for the same project.Additional context
pmChoicebeing non-nil doubles as the record that the picker was shown, which is what back-navigation from the plan keys off.Testing approaches
go test ./...passes.pnpm@9.1.0) skips the picker entirely, leavespmChoicenil, and planspnpm add.(not installed), and selecting it still reaches the plan withnpmchosen.Gemfileproject, one adds apackage-lock.json, and the sharedoverrideToSDKhelper walks through the picker when it appears, since those tests are about entry points rather than managers.Note
Overview
When the chosen SDK’s project does not identify a single package manager, setup now stops after SDK selection and asks which manager should install the SDK. Definite projects still go straight to the plan.
The picker shows the verdict’s reason, lists the exact install command per row, puts installed tools first, and still lets the user pick an uninstalled one. Back from the plan returns to the picker when it was shown.
Also folds wizard key hints into the list help (instead of duplicating them in a footer), wraps plan steps and the wait-for-app copy so they fit the terminal, and covers skip/ask/back/layout in tests.
Reviewed by Cursor Bugbot for commit 79be31b. Bugbot is set up for automated code reviews on this repo. Configure here.