* feat(cli): add `py` script type & Python interpreter resolution (#3278)
Introduce a third script variant alongside `sh`/`ps` as the foundation
for unifying workflow scripts under a single Python implementation.
- Add `"py": "Python"` to `SCRIPT_TYPE_CHOICES`; `VALID_SCRIPT_TYPES`
consumers (init workflow step, init command, _helpers) pick it up
automatically since they derive from that mapping.
- Add `IntegrationBase.resolve_python_interpreter()` (project venv →
`python3` → `python`, falling back to `python3`).
- Prefix the resolved interpreter when `process_template()` expands
`{SCRIPT}` for the `py` script type so `.py` scripts run portably
(notably on Windows); thread `project_root` through callers so venv
preference works.
- Make `install_scripts()` mark copied `.py` files executable too.
Includes positive and negative unit tests for interpreter resolution,
`py` template processing, the new choice, and script installation.
Assisted-by: GitHub Copilot (model: Claude Opus 4.8, autonomous)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix(cli): return repo-relative venv interpreter & correct docstring
Address PR review feedback on #3285:
- `resolve_python_interpreter()` now returns the venv interpreter as a
path relative to the project root (`.venv/bin/python` /
`.venv/Scripts/python.exe`) instead of an absolute/joined path, so the
generated `{SCRIPT}` invocation stays portable and runnable from the
repo root regardless of where the project lives.
- Update `install_scripts()` docstring to note `.py` scripts are now
made executable alongside `.sh`.
- Update tests to assert the repo-relative interpreter path.
Assisted-by: GitHub Copilot (model: Claude Opus 4.8, autonomous)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix(cli): fall back to sys.executable for interpreter resolution
When neither python3 nor python is discoverable on PATH (and no project
venv is found), resolve_python_interpreter() now returns the running
interpreter (sys.executable) so the generated {SCRIPT} invocation works
in the current environment, falling back to "python3" only if that is
also unavailable. Update unit tests accordingly.
* fix(cli): quote py interpreter path when it contains whitespace
For the `py` script type, the resolved interpreter may be an absolute
path containing spaces (notably `sys.executable` under Windows
`Program Files`). Quote it when it contains whitespace so the `{SCRIPT}`
invocation isn't split into multiple arguments. Add positive/negative
tests for the quoting behavior.
* test: guard executable-bit assertions from Windows chmod semantics
The Windows CI job failed because `os.chmod` does not set POSIX
executable bits on Windows, so `install_scripts()` cannot make `.py`/
`.sh` files executable there (nor is it needed — the interpreter is
invoked explicitly). Split the install_scripts test so file-copy
behavior is still verified cross-platform, and skip the executable-bit
assertions on win32 (matching the repo's existing pattern).
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Initial plan
* feat!: remove legacy --ai, --ai-commands-dir, and --ai-skills flags at 0.10.0
* refactor(tests): rename stale test_ai_help_* methods to test_agent_config_*
* fix: address review — derive agent folder for generic integration and remove redundant test
- Security notice now falls back to integration_parsed_options['commands_dir']
when AGENT_CONFIG folder is None (generic integration).
- Remove test_agent_config_includes_kiro_cli which duplicates the assertion
in test_runtime_config_uses_kiro_cli_and_removes_q.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* docs: scrub all remaining --ai flag references from source and tests
- Remove dead AI_ASSISTANT_ALIASES, AI_ASSISTANT_HELP, and
_build_ai_assistant_help() from _agent_config.py
- Update comments/docstrings in extensions.py, presets.py, and
integration subpackages to reference 'skills mode' or
'--integration' instead of the removed flags
- Fix catalog.json generic integration description
- Update test docstrings/comments in test_extension_skills.py,
test_extensions.py, and test_presets.py
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* test: remove legacy --ai flag rejection tests
The flags are fully removed from the CLI; typer handles unknown options
generically. No custom rejection logic exists to test.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* revert: remove manual CHANGELOG.md entry
CHANGELOG is generated automatically; manual edits should not be made.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: make generic catalog description self-explanatory
Include the required --commands-dir sub-option in the description so
readers don't need to look up integration docs.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix(tests): rename duplicate test classes to avoid shadowing
The rename from Test*AutoPromote to Test*Integration collided with the
existing Test*Integration(SkillsIntegrationTests) base classes, causing
the shared test suites to be silently overwritten. Rename the CLI init
flow classes to Test*InitFlow instead.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Manfred Riem <mnriem@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Clear pre-existing lint debt flagged by repo-wide `ruff check` (the lint
config only scopes src/, so tests/ had drifted). No behavior change.
- F401/F541: drop unused imports and redundant f-string prefixes (autofix)
- E741: rename ambiguous `l` to `ln` in comprehensions
- E702: split semicolon-joined statements onto separate lines
- F841: drop unused bindings while keeping the side-effecting calls
(_minimal_feature, install_from_directory)
Full suite: 3344 passed, 40 skipped. ruff check (repo-wide): clean.
* refactor(integrations): co-locate integration commands in integrations/ domain dir
- Remove commands/ stubs (handlers will live in domain dirs)
- Move all integration CLI handlers out of __init__.py into integrations/
- Split into focused modules under integrations/:
_helpers.py (340 lines) — domain helpers
_install_commands.py (306 lines) — install / uninstall
_migrate_commands.py (487 lines) — switch / upgrade
_query_commands.py (442 lines) — list / use / search / info / catalog
_commands.py (34 lines) — app objects + register()
- __init__.py reduced by ~1400 lines; integration block replaced with register() call
- Fix patch paths in tests to new module locations
* fix(integrations): restore original integration list output in refactor
Preserve the CLI Required column, post-table default/installed summary,
and no-installed guidance that were dropped during the no-behavior-change
refactor of integration list into _query_commands.py.
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* fix(integrations): restore _clear/_update_init_options public imports
The refactor that split integration commands moved
_clear_init_options_for_integration and _update_init_options_for_integration
into integrations/_helpers.py, but tests still import them from the top-level
specify_cli package, causing ImportError. Re-export them with explicit aliases
at the end of __init__.py to preserve the public import surface.
---------
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* refactor: create commands/ package and move init handler (PR-4/8)
- Extract agent configuration constants (AGENT_CONFIG, AI_ASSISTANT_HELP,
SCRIPT_TYPE_CHOICES, etc.) to _agent_config.py to avoid circular imports
- Create commands/ package skeleton with stub modules for each command group
- Move init command handler (~670 lines) from __init__.py to commands/init.py
using the register(app) pattern; lazy imports inside the handler body
prevent circular dependencies with __init__.py
- Re-export AGENT_CONFIG, AI_ASSISTANT_HELP, SCRIPT_TYPE_CHOICES from
__init__.py for backward compatibility
- Add tests/test_commands_package.py to verify package structure
* fix(tests): update patch targets after moving init handler to commands/init.py
_stdin_is_interactive and select_with_arrows are now bound in
specify_cli.commands.init, not specify_cli directly.
* fix(lint): remove unused imports and mark re-exports in __init__.py
- Remove shutil, shlex top-level imports (used lazily inside functions)
- Remove rich.live.Live import (moved to commands/init.py)
- Mark select_with_arrows and _locate_bundled_workflow as explicit
re-exports to satisfy ruff F401
* chore: add from __future__ import annotations to new modules
Aligns with the project convention established in _console.py, _assets.py,
_utils.py, and other modules.
* docs(cli): align init help with bundled scaffolding
Potential fix for pull request finding
Update command package documentation and init help text to reflect the current implementation: init uses bundled assets and integration setup, while placeholder command modules are import anchors until extracted. Remove the unused tracker-active flag assignment that had no reader in the codebase.
Constraint: --offline is hidden/no-op and init no longer downloads templates from GitHub releases
Rejected: Add no-op register functions to placeholder modules | would imply extracted command groups are implemented there
Confidence: high
Scope-risk: narrow
Directive: Keep CLI help text aligned with the actual init scaffolding path
Tested: uv run specify init --help; uv run pytest tests/test_commands_package.py tests/test_agent_config_consistency.py -q; uv run pytest tests/test_commands_package.py tests/test_console_imports.py tests/integrations/test_cli.py -q
Not-tested: full test suite
* fix(init): align preset failure reporting with _print_cli_warning helper
Use the _print_cli_warning helper (introduced in main) for preset install
failures so that output matches the expected format:
"Failed to install preset '<name>': ..."
"Continuing without the optional preset."
* fix(init): remove unused lazy imports
The init command imported CLI error formatting helpers through its circular-dependency-safe lazy import block, but the module does not use them. Remove those imports so ruff does not report F401.
Constraint: uvx ruff check src/ must pass.
Rejected: Wire the helpers into init error handling | Existing preset warnings already use _print_cli_warning, and changing behavior is unnecessary for this lint fix.
Confidence: high
Scope-risk: narrow
Directive: Keep lazy import blocks limited to names consumed in the importing module.
Tested: uvx ruff check src/
Not-tested: Full pytest suite
Co-authored-by: OmX <omx@oh-my-codex.dev>
---------
Co-authored-by: OmX <omx@oh-my-codex.dev>