gitwise-cli 0.28.0__tar.gz → 0.30.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/CHANGELOG.md +22 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/PKG-INFO +1 -1
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/__init__.py +4 -1
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/__main__.py +4 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/_cli_completions.py +4 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/_cli_dispatch.py +91 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/_cli_introspection.py +14 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/_cli_parser.py +29 -1
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/_cli_setup_agents.py +5 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/_i18n_data.json +40 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/_runtime_config.py +17 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/audit.py +11 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/branches.py +10 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/clean.py +6 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/commit.py +38 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/conflicts.py +8 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/context.py +9 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/design.py +26 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/diff.py +196 -23
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/doctor.py +5 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/git.py +40 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/health.py +25 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/i18n.py +13 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/log.py +20 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/merge.py +87 -1
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/optimize.py +12 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/output.py +45 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/pick.py +6 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/pr.py +31 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/schema.py +5 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/setup.py +28 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/setup_agents/exec.py +31 -3
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/setup_agents/format.py +8 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/setup_agents/plan.py +17 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/setup_agents/plan_gitfiles.py +11 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/setup_agents/plan_skills.py +10 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/setup_agents/providers/__init__.py +9 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/setup_agents/providers/base.py +9 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/setup_agents/providers/claude.py +18 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/setup_agents/state.py +7 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/setup_agents/types.py +5 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/show.py +9 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/snapshot.py +6 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/stash.py +8 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/status.py +11 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/suggest.py +32 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/summarize.py +5 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/sync.py +13 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/tag.py +11 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/undo.py +9 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/update.py +1 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/utils/git_output.py +11 -0
- gitwise_cli-0.30.0/gitwise/utils/in_progress.py +112 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/utils/json_envelope.py +17 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/utils/parsing.py +5 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/worktree.py +5 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/pyproject.toml +1 -1
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/share/schemas/v1/input/diff.json +16 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/share/schemas/v1/input/merge.json +12 -5
- gitwise_cli-0.30.0/tests/test_diff.py +327 -0
- gitwise_cli-0.30.0/tests/test_in_progress.py +215 -0
- gitwise_cli-0.28.0/tests/test_diff.py +0 -168
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/.gitignore +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/LICENSE +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/README.md +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/bin/gitwise +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/_paths.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/py.typed +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/setup_agents/__init__.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/setup_agents/adapters/__init__.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/setup_agents/adapters/aider.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/setup_agents/adapters/base.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/setup_agents/adapters/codex.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/setup_agents/adapters/continue_adapter.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/setup_agents/adapters/cursor.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/setup_agents/adapters/opencode.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/setup_agents/adapters/pi.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/setup_agents/providers/aider.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/setup_agents/providers/codex.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/setup_agents/providers/continue_adapter.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/setup_agents/providers/cursor.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/setup_agents/providers/opencode.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/setup_agents/providers/pi.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/gitwise/utils/__init__.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/install.sh +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/share/agents/skills/git-audit/SKILL.md +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/share/agents/skills/git-clean/SKILL.md +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/share/agents/skills/git-optimize/SKILL.md +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/share/aider/CONVENTIONS.md.template +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/share/aider/aider.conf.yml.template +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/share/claude/CLAUDE.md.template +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/share/claude/rules/gitwise.md +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/share/claude/settings.json.template +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/share/claude/skills/git-audit/SKILL.md +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/share/claude/skills/git-clean/SKILL.md +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/share/claude/skills/git-optimize/SKILL.md +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/share/codex/agents/gitwise.toml.template +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/share/continue/rules/gitwise.md.template +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/share/cursor/rules/gitwise.mdc.template +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/share/git-config-modern.txt +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/share/hooks/commit-msg +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/share/hooks/pre-commit +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/share/opencode/agents/gitwise.md.template +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/share/pi/skills/gitwise.md.template +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/share/schemas/v1/input/audit.json +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/share/schemas/v1/input/branches.json +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/share/schemas/v1/input/clean.json +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/share/schemas/v1/input/commands.json +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/share/schemas/v1/input/commit.json +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/share/schemas/v1/input/completions.json +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/share/schemas/v1/input/conflicts.json +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/share/schemas/v1/input/context.json +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/share/schemas/v1/input/doctor.json +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/share/schemas/v1/input/health.json +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/share/schemas/v1/input/log.json +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/share/schemas/v1/input/optimize.json +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/share/schemas/v1/input/pick.json +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/share/schemas/v1/input/pr.json +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/share/schemas/v1/input/schema.json +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/share/schemas/v1/input/setup-agents.json +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/share/schemas/v1/input/setup.json +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/share/schemas/v1/input/show.json +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/share/schemas/v1/input/snapshot.json +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/share/schemas/v1/input/stash.json +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/share/schemas/v1/input/status.json +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/share/schemas/v1/input/suggest.json +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/share/schemas/v1/input/summarize.json +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/share/schemas/v1/input/sync.json +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/share/schemas/v1/input/tag.json +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/share/schemas/v1/input/undo.json +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/share/schemas/v1/input/update.json +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/share/schemas/v1/input/worktree.json +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/tests/__init__.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/tests/conftest.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/tests/test_adapters.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/tests/test_audit.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/tests/test_branches.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/tests/test_clean.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/tests/test_commit.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/tests/test_conflicts.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/tests/test_context.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/tests/test_design.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/tests/test_doctor.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/tests/test_edge_cases.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/tests/test_git.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/tests/test_git_output_utils.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/tests/test_health.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/tests/test_i18n.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/tests/test_json_envelope_utils.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/tests/test_log.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/tests/test_main.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/tests/test_md_links_script.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/tests/test_merge.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/tests/test_optimize.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/tests/test_output.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/tests/test_parsing_utils.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/tests/test_pick.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/tests/test_pr.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/tests/test_roadmap_baseline_script.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/tests/test_sa_plan.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/tests/test_sa_unit.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/tests/test_schema_catalog.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/tests/test_setup.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/tests/test_setup_agents.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/tests/test_show.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/tests/test_snapshot.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/tests/test_stash.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/tests/test_status.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/tests/test_suggest.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/tests/test_summarize.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/tests/test_sync.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/tests/test_sync_changelog_es_script.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/tests/test_tag.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/tests/test_undo.py +0 -0
- {gitwise_cli-0.28.0 → gitwise_cli-0.30.0}/tests/test_worktree.py +0 -0
|
@@ -3,6 +3,28 @@
|
|
|
3
3
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
4
4
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
5
5
|
|
|
6
|
+
## v0.30.0 (2026-06-19)
|
|
7
|
+
|
|
8
|
+
### Feat
|
|
9
|
+
|
|
10
|
+
- **diff**: support refs, path scope, and summary (Sprint 2 PR-A) (#66)
|
|
11
|
+
|
|
12
|
+
## v0.29.0 (2026-06-19)
|
|
13
|
+
|
|
14
|
+
### Feat
|
|
15
|
+
|
|
16
|
+
- in-progress safety + merge --abort/--continue (Sprint 1) (#65)
|
|
17
|
+
- detect in-progress operations and guard suggest/commit (Sprint 1)
|
|
18
|
+
|
|
19
|
+
### Fix
|
|
20
|
+
|
|
21
|
+
- **in_progress**: use os.path.realpath and explicit subprocess timeout (CodeRabbit)
|
|
22
|
+
- **merge**: pick rebase subcommand when state=rebase (gemini PR#65 finding)
|
|
23
|
+
|
|
24
|
+
### Refactor
|
|
25
|
+
|
|
26
|
+
- **merge**: extract _handle_abort_or_continue (Sprint 1 multi-review)
|
|
27
|
+
|
|
6
28
|
## v0.28.0 (2026-06-19)
|
|
7
29
|
|
|
8
30
|
### BREAKING CHANGE
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gitwise-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.30.0
|
|
4
4
|
Summary: Python CLI for optimizing git workflows and Claude Code integration
|
|
5
5
|
Project-URL: Homepage, https://github.com/drzioner/gitwise
|
|
6
6
|
Project-URL: Repository, https://github.com/drzioner/gitwise
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
"""gitwise -- CLI for optimizing git workflows and coding-agent integration."""
|
|
2
|
+
|
|
3
|
+
__version__ = "0.30.0"
|
|
2
4
|
|
|
3
5
|
|
|
4
6
|
def get_version() -> str:
|
|
7
|
+
"""Return the installed package version, falling back to the source version."""
|
|
5
8
|
from importlib.metadata import PackageNotFoundError
|
|
6
9
|
from importlib.metadata import version as _version
|
|
7
10
|
|
|
@@ -11,16 +11,19 @@ from .output import print_dim, print_json, set_json_mode, set_json_pretty
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
def _is_log_json_enabled() -> bool:
|
|
14
|
+
"""Return True when GITWISE_LOG_JSON is set to a truthy value."""
|
|
14
15
|
import os
|
|
15
16
|
|
|
16
17
|
return os.environ.get("GITWISE_LOG_JSON", "").lower() in ("1", "true")
|
|
17
18
|
|
|
18
19
|
|
|
19
20
|
def _should_show_rich_traceback() -> bool:
|
|
21
|
+
"""Return True when rich tracebacks should be used (tty and not in JSON log mode)."""
|
|
20
22
|
return (not _is_log_json_enabled()) and sys.stderr.isatty()
|
|
21
23
|
|
|
22
24
|
|
|
23
25
|
def _install_rich_traceback() -> None:
|
|
26
|
+
"""Install the rich traceback handler if conditions allow; no-op otherwise."""
|
|
24
27
|
if not _should_show_rich_traceback():
|
|
25
28
|
return
|
|
26
29
|
try:
|
|
@@ -56,6 +59,7 @@ def _ensure_utf8_stdio() -> None:
|
|
|
56
59
|
|
|
57
60
|
|
|
58
61
|
def main() -> int:
|
|
62
|
+
"""Parse args, dispatch to the matching subcommand handler, and return an exit code."""
|
|
59
63
|
import os
|
|
60
64
|
|
|
61
65
|
from ._runtime_config import reset_runtime_config
|
|
@@ -7,6 +7,7 @@ from ._cli_parser import build_parser
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
def build_completions_script(*, shell: str, prog: str) -> str:
|
|
10
|
+
"""Return a shell completion script for the given shell and program name."""
|
|
10
11
|
parser = build_parser()
|
|
11
12
|
parser.prog = prog
|
|
12
13
|
|
|
@@ -23,10 +24,12 @@ def build_completions_script(*, shell: str, prog: str) -> str:
|
|
|
23
24
|
|
|
24
25
|
|
|
25
26
|
def _fish_escape(text: str) -> str:
|
|
27
|
+
"""Escape single quotes for use inside a fish completion string literal."""
|
|
26
28
|
return text.replace("'", "\\'")
|
|
27
29
|
|
|
28
30
|
|
|
29
31
|
def _build_fish_option_line(*, prog: str, condition: str, flag: str, help_text: str) -> str:
|
|
32
|
+
"""Return a single fish ``complete`` line for an option, or an empty string for unrecognized flags."""
|
|
30
33
|
escaped_help = _fish_escape(help_text)
|
|
31
34
|
escaped_prog = _fish_escape(prog)
|
|
32
35
|
escaped_condition = _fish_escape(condition)
|
|
@@ -44,6 +47,7 @@ def _build_fish_option_line(*, prog: str, condition: str, flag: str, help_text:
|
|
|
44
47
|
|
|
45
48
|
|
|
46
49
|
def _build_fish_completions_script(*, parser: argparse.ArgumentParser, prog: str) -> str:
|
|
50
|
+
"""Generate a fish completion script from the full argparse parser tree."""
|
|
47
51
|
escaped_prog = _fish_escape(prog)
|
|
48
52
|
lines: list[str] = [f"# fish completion for {escaped_prog}"]
|
|
49
53
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""Command dispatchers: thin wrappers that delegate to subcommand modules."""
|
|
2
2
|
|
|
3
3
|
import argparse
|
|
4
|
+
import sys
|
|
4
5
|
from collections.abc import Callable
|
|
5
6
|
|
|
6
7
|
from . import __version__
|
|
@@ -17,18 +18,21 @@ from .utils.json_envelope import error_envelope
|
|
|
17
18
|
|
|
18
19
|
|
|
19
20
|
def _run_update(args: argparse.Namespace) -> int:
|
|
21
|
+
"""Dispatch to ``update`` subcommand."""
|
|
20
22
|
from .update import run_update
|
|
21
23
|
|
|
22
24
|
return run_update(dry_run=args.dry_run, as_json=args.json)
|
|
23
25
|
|
|
24
26
|
|
|
25
27
|
def _run_doctor(args: argparse.Namespace) -> int:
|
|
28
|
+
"""Dispatch to ``doctor`` subcommand."""
|
|
26
29
|
from .doctor import run_doctor
|
|
27
30
|
|
|
28
31
|
return run_doctor(as_json=args.json)
|
|
29
32
|
|
|
30
33
|
|
|
31
34
|
def _run_setup_agents(args: argparse.Namespace) -> int:
|
|
35
|
+
"""Dispatch to ``setup-agents`` subcommand, handling provider listing."""
|
|
32
36
|
if getattr(args, "list_providers", False) or getattr(args, "list_adapters", False):
|
|
33
37
|
from .i18n import t as _t
|
|
34
38
|
from .setup_agents.providers import list_providers
|
|
@@ -68,6 +72,7 @@ def _run_setup_agents(args: argparse.Namespace) -> int:
|
|
|
68
72
|
|
|
69
73
|
|
|
70
74
|
def _run_setup(args: argparse.Namespace) -> int:
|
|
75
|
+
"""Dispatch to ``setup`` subcommand."""
|
|
71
76
|
from .setup import run_setup
|
|
72
77
|
|
|
73
78
|
return run_setup(
|
|
@@ -79,24 +84,28 @@ def _run_setup(args: argparse.Namespace) -> int:
|
|
|
79
84
|
|
|
80
85
|
|
|
81
86
|
def _run_audit(args: argparse.Namespace) -> int:
|
|
87
|
+
"""Dispatch to ``audit`` subcommand."""
|
|
82
88
|
from .audit import run_audit
|
|
83
89
|
|
|
84
90
|
return run_audit(quick=args.quick, as_json=args.json)
|
|
85
91
|
|
|
86
92
|
|
|
87
93
|
def _run_summarize(args: argparse.Namespace) -> int:
|
|
94
|
+
"""Dispatch to ``summarize`` subcommand."""
|
|
88
95
|
from .summarize import run_summarize
|
|
89
96
|
|
|
90
97
|
return run_summarize(as_json=args.json, diff=args.diff, max_commits=args.max_commits)
|
|
91
98
|
|
|
92
99
|
|
|
93
100
|
def _run_snapshot(args: argparse.Namespace) -> int:
|
|
101
|
+
"""Dispatch to ``snapshot`` subcommand."""
|
|
94
102
|
from .snapshot import run_snapshot
|
|
95
103
|
|
|
96
104
|
return run_snapshot(as_json=args.json)
|
|
97
105
|
|
|
98
106
|
|
|
99
107
|
def _run_clean(args: argparse.Namespace) -> int:
|
|
108
|
+
"""Dispatch to ``clean`` subcommand."""
|
|
100
109
|
from .clean import run_clean
|
|
101
110
|
|
|
102
111
|
return run_clean(
|
|
@@ -109,12 +118,14 @@ def _run_clean(args: argparse.Namespace) -> int:
|
|
|
109
118
|
|
|
110
119
|
|
|
111
120
|
def _run_optimize(args: argparse.Namespace) -> int:
|
|
121
|
+
"""Dispatch to ``optimize`` subcommand."""
|
|
112
122
|
from .optimize import run_optimize
|
|
113
123
|
|
|
114
124
|
return run_optimize(dry_run=args.dry_run, yes=args.yes, as_json=args.json)
|
|
115
125
|
|
|
116
126
|
|
|
117
127
|
def _run_worktree(args: argparse.Namespace) -> int:
|
|
128
|
+
"""Dispatch to ``worktree`` subcommand."""
|
|
118
129
|
from .worktree import run_worktree
|
|
119
130
|
|
|
120
131
|
return run_worktree(
|
|
@@ -122,19 +133,72 @@ def _run_worktree(args: argparse.Namespace) -> int:
|
|
|
122
133
|
)
|
|
123
134
|
|
|
124
135
|
|
|
136
|
+
def _recover_diff_pathspec_boundary() -> tuple[str | None, list[str] | None]:
|
|
137
|
+
"""Recover the explicit ``--`` pathspec boundary argparse loses.
|
|
138
|
+
|
|
139
|
+
With ``refspec nargs="?"`` + ``paths nargs="*"``, a path-only invocation
|
|
140
|
+
like ``gitwise diff -- src/`` mis-assigns ``src/`` to ``refspec``. git
|
|
141
|
+
treats ``--`` as a hard pathspec separator, so honor it here: anything
|
|
142
|
+
positional before ``--`` (excluding flags) feeds ``refspec``; anything
|
|
143
|
+
after ``--`` is literal paths, even values starting with ``-``.
|
|
144
|
+
|
|
145
|
+
Raises ``ValueError`` when more than one positional precedes ``--``, since
|
|
146
|
+
``gitwise diff`` accepts a single refspec (two-commit diffs use ``a..b``);
|
|
147
|
+
failing fast beats silently dropping the extras.
|
|
148
|
+
"""
|
|
149
|
+
try:
|
|
150
|
+
sub_idx = sys.argv.index("diff")
|
|
151
|
+
except ValueError:
|
|
152
|
+
return None, None
|
|
153
|
+
cmd_argv = sys.argv[sub_idx + 1 :]
|
|
154
|
+
if "--" not in cmd_argv:
|
|
155
|
+
return None, None
|
|
156
|
+
sep = cmd_argv.index("--")
|
|
157
|
+
before = [a for a in cmd_argv[:sep] if not a.startswith("-")]
|
|
158
|
+
after = list(cmd_argv[sep + 1 :])
|
|
159
|
+
if len(before) > 1:
|
|
160
|
+
raise ValueError(t("diff_too_many_refs", count=str(len(before))))
|
|
161
|
+
refspec = before[0] if before else None
|
|
162
|
+
paths = after if after else None
|
|
163
|
+
return refspec, paths
|
|
164
|
+
|
|
165
|
+
|
|
125
166
|
def _run_diff(args: argparse.Namespace) -> int:
|
|
167
|
+
"""Dispatch to ``diff`` subcommand."""
|
|
126
168
|
from .diff import run_diff
|
|
169
|
+
from .output import error as error_out
|
|
170
|
+
|
|
171
|
+
refspec = args.refspec
|
|
172
|
+
paths = args.paths
|
|
173
|
+
# Honor `--` as a pathspec separator (git semantics). argparse's nargs="?"
|
|
174
|
+
# + nargs="*" otherwise mis-assigns path-only invocations to refspec.
|
|
175
|
+
if "--" in sys.argv:
|
|
176
|
+
try:
|
|
177
|
+
recovered_refspec, recovered_paths = _recover_diff_pathspec_boundary()
|
|
178
|
+
except ValueError as exc:
|
|
179
|
+
if args.json:
|
|
180
|
+
print_json(error_envelope(error=str(exc), code="too_many_refs"))
|
|
181
|
+
else:
|
|
182
|
+
error_out(str(exc))
|
|
183
|
+
return 1
|
|
184
|
+
if recovered_refspec is not None or recovered_paths is not None:
|
|
185
|
+
refspec = recovered_refspec
|
|
186
|
+
paths = recovered_paths
|
|
127
187
|
|
|
128
188
|
return run_diff(
|
|
189
|
+
refspec=refspec,
|
|
190
|
+
paths=paths,
|
|
129
191
|
staged=args.staged,
|
|
130
192
|
stat=args.stat,
|
|
131
193
|
name_only=args.name_only,
|
|
132
194
|
full=args.full,
|
|
195
|
+
summary=args.summary,
|
|
133
196
|
as_json=args.json,
|
|
134
197
|
)
|
|
135
198
|
|
|
136
199
|
|
|
137
200
|
def _run_log(args: argparse.Namespace) -> int:
|
|
201
|
+
"""Dispatch to ``log`` subcommand."""
|
|
138
202
|
from .log import run_log
|
|
139
203
|
|
|
140
204
|
return run_log(
|
|
@@ -151,12 +215,14 @@ def _run_log(args: argparse.Namespace) -> int:
|
|
|
151
215
|
|
|
152
216
|
|
|
153
217
|
def _run_show(args: argparse.Namespace) -> int:
|
|
218
|
+
"""Dispatch to ``show`` subcommand."""
|
|
154
219
|
from .show import run_show
|
|
155
220
|
|
|
156
221
|
return run_show(ref=args.ref, stat=args.stat, as_json=args.json)
|
|
157
222
|
|
|
158
223
|
|
|
159
224
|
def _run_commit(args: argparse.Namespace) -> int:
|
|
225
|
+
"""Dispatch to ``commit`` subcommand."""
|
|
160
226
|
from .commit import run_commit
|
|
161
227
|
|
|
162
228
|
return run_commit(
|
|
@@ -171,12 +237,14 @@ def _run_commit(args: argparse.Namespace) -> int:
|
|
|
171
237
|
|
|
172
238
|
|
|
173
239
|
def _run_branches(args: argparse.Namespace) -> int:
|
|
240
|
+
"""Dispatch to ``branches`` subcommand."""
|
|
174
241
|
from .branches import run_branches
|
|
175
242
|
|
|
176
243
|
return run_branches(stale=args.stale, remote=args.remote, sort=args.sort, as_json=args.json)
|
|
177
244
|
|
|
178
245
|
|
|
179
246
|
def _run_sync(args: argparse.Namespace) -> int:
|
|
247
|
+
"""Dispatch to ``sync`` subcommand."""
|
|
180
248
|
from .sync import run_sync
|
|
181
249
|
|
|
182
250
|
return run_sync(
|
|
@@ -189,12 +257,14 @@ def _run_sync(args: argparse.Namespace) -> int:
|
|
|
189
257
|
|
|
190
258
|
|
|
191
259
|
def _run_pr(args: argparse.Namespace) -> int:
|
|
260
|
+
"""Dispatch to ``pr`` subcommand."""
|
|
192
261
|
from .pr import run_pr
|
|
193
262
|
|
|
194
263
|
return run_pr(action=args.action, selector=args.selector, as_json=args.json)
|
|
195
264
|
|
|
196
265
|
|
|
197
266
|
def _run_undo(args: argparse.Namespace) -> int:
|
|
267
|
+
"""Dispatch to ``undo`` subcommand."""
|
|
198
268
|
from .undo import run_undo
|
|
199
269
|
|
|
200
270
|
return run_undo(
|
|
@@ -208,18 +278,21 @@ def _run_undo(args: argparse.Namespace) -> int:
|
|
|
208
278
|
|
|
209
279
|
|
|
210
280
|
def _run_context(args: argparse.Namespace) -> int:
|
|
281
|
+
"""Dispatch to ``context`` subcommand."""
|
|
211
282
|
from .context import run_context
|
|
212
283
|
|
|
213
284
|
return run_context(as_json=args.json)
|
|
214
285
|
|
|
215
286
|
|
|
216
287
|
def _run_health(args: argparse.Namespace) -> int:
|
|
288
|
+
"""Dispatch to ``health`` subcommand."""
|
|
217
289
|
from .health import run_health
|
|
218
290
|
|
|
219
291
|
return run_health(as_json=args.json)
|
|
220
292
|
|
|
221
293
|
|
|
222
294
|
def _run_stash(args: argparse.Namespace) -> int:
|
|
295
|
+
"""Dispatch to ``stash`` subcommand."""
|
|
223
296
|
from .stash import run_stash
|
|
224
297
|
|
|
225
298
|
return run_stash(
|
|
@@ -233,6 +306,7 @@ def _run_stash(args: argparse.Namespace) -> int:
|
|
|
233
306
|
|
|
234
307
|
|
|
235
308
|
def _run_tag(args: argparse.Namespace) -> int:
|
|
309
|
+
"""Dispatch to ``tag`` subcommand."""
|
|
236
310
|
from .tag import run_tag
|
|
237
311
|
|
|
238
312
|
return run_tag(
|
|
@@ -247,6 +321,7 @@ def _run_tag(args: argparse.Namespace) -> int:
|
|
|
247
321
|
|
|
248
322
|
|
|
249
323
|
def _run_merge(args: argparse.Namespace) -> int:
|
|
324
|
+
"""Dispatch to ``merge`` subcommand."""
|
|
250
325
|
from .merge import run_merge
|
|
251
326
|
|
|
252
327
|
return run_merge(
|
|
@@ -255,23 +330,28 @@ def _run_merge(args: argparse.Namespace) -> int:
|
|
|
255
330
|
no_ff=args.no_ff,
|
|
256
331
|
dry_run=args.dry_run,
|
|
257
332
|
yes=args.yes,
|
|
333
|
+
abort=args.abort,
|
|
334
|
+
continue_merge=args.continue_merge,
|
|
258
335
|
as_json=args.json,
|
|
259
336
|
)
|
|
260
337
|
|
|
261
338
|
|
|
262
339
|
def _run_conflicts(args: argparse.Namespace) -> int:
|
|
340
|
+
"""Dispatch to ``conflicts`` subcommand."""
|
|
263
341
|
from .conflicts import run_conflicts
|
|
264
342
|
|
|
265
343
|
return run_conflicts(ours=args.ours, theirs=args.theirs, as_json=args.json)
|
|
266
344
|
|
|
267
345
|
|
|
268
346
|
def _run_suggest(args: argparse.Namespace) -> int:
|
|
347
|
+
"""Dispatch to ``suggest`` subcommand."""
|
|
269
348
|
from .suggest import run_suggest
|
|
270
349
|
|
|
271
350
|
return run_suggest(as_json=args.json)
|
|
272
351
|
|
|
273
352
|
|
|
274
353
|
def _run_pick(args: argparse.Namespace) -> int:
|
|
354
|
+
"""Dispatch to ``pick`` / ``cherry-pick`` subcommand."""
|
|
275
355
|
from .pick import run_pick
|
|
276
356
|
|
|
277
357
|
return run_pick(
|
|
@@ -285,12 +365,18 @@ def _run_pick(args: argparse.Namespace) -> int:
|
|
|
285
365
|
|
|
286
366
|
|
|
287
367
|
def _run_status(args: argparse.Namespace) -> int:
|
|
368
|
+
"""Dispatch to ``status`` subcommand."""
|
|
288
369
|
from .status import run_status
|
|
289
370
|
|
|
290
371
|
return run_status(as_json=args.json)
|
|
291
372
|
|
|
292
373
|
|
|
293
374
|
def _run_completions(args: argparse.Namespace) -> int:
|
|
375
|
+
"""Generate and output a shell completions script.
|
|
376
|
+
|
|
377
|
+
Returns 1 on missing dependency (shtab), unsupported shell, or
|
|
378
|
+
runtime error.
|
|
379
|
+
"""
|
|
294
380
|
shell = args.shell
|
|
295
381
|
prog = args.prog
|
|
296
382
|
try:
|
|
@@ -344,6 +430,7 @@ def _run_completions(args: argparse.Namespace) -> int:
|
|
|
344
430
|
|
|
345
431
|
|
|
346
432
|
def _run_commands(args: argparse.Namespace) -> int:
|
|
433
|
+
"""List all registered subcommands with aliases."""
|
|
347
434
|
parser = build_parser()
|
|
348
435
|
commands = commands_metadata(parser)
|
|
349
436
|
payload = {
|
|
@@ -372,6 +459,10 @@ def _run_commands(args: argparse.Namespace) -> int:
|
|
|
372
459
|
|
|
373
460
|
|
|
374
461
|
def _run_schema(args: argparse.Namespace) -> int:
|
|
462
|
+
"""Print the JSON Schema for a subcommand's CLI input.
|
|
463
|
+
|
|
464
|
+
Returns 1 when the command is unknown or its schema file is missing.
|
|
465
|
+
"""
|
|
375
466
|
from .schema import load_command_input_schema
|
|
376
467
|
|
|
377
468
|
parser = build_parser()
|
|
@@ -7,6 +7,7 @@ from . import __version__
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
def _json_safe(value: object) -> object:
|
|
10
|
+
"""Recursively convert an argparse value to a JSON-serializable form."""
|
|
10
11
|
if value is argparse.SUPPRESS:
|
|
11
12
|
return None
|
|
12
13
|
if value is None or isinstance(value, str | int | float | bool):
|
|
@@ -19,6 +20,7 @@ def _json_safe(value: object) -> object:
|
|
|
19
20
|
|
|
20
21
|
|
|
21
22
|
def _subparsers_action(parser: argparse.ArgumentParser) -> argparse._SubParsersAction | None:
|
|
23
|
+
"""Return the first _SubParsersAction from a parser, or None."""
|
|
22
24
|
for action in parser._actions:
|
|
23
25
|
if isinstance(action, argparse._SubParsersAction):
|
|
24
26
|
return action
|
|
@@ -26,6 +28,7 @@ def _subparsers_action(parser: argparse.ArgumentParser) -> argparse._SubParsersA
|
|
|
26
28
|
|
|
27
29
|
|
|
28
30
|
def _serialize_actions(parser: argparse.ArgumentParser) -> list[dict[str, object]]:
|
|
31
|
+
"""Serialize a parser's non-help, non-subparser actions into JSON-friendly dicts."""
|
|
29
32
|
items: list[dict[str, object]] = []
|
|
30
33
|
for action in parser._actions:
|
|
31
34
|
if action.dest in {"help"}:
|
|
@@ -49,6 +52,7 @@ def _serialize_actions(parser: argparse.ArgumentParser) -> list[dict[str, object
|
|
|
49
52
|
|
|
50
53
|
|
|
51
54
|
def extract_command_token(argv: list[str]) -> str | None:
|
|
55
|
+
"""Extract the subcommand name from a raw argv, skipping global flags and their values."""
|
|
52
56
|
skip_next = False
|
|
53
57
|
for token in argv:
|
|
54
58
|
if skip_next:
|
|
@@ -64,6 +68,7 @@ def extract_command_token(argv: list[str]) -> str | None:
|
|
|
64
68
|
|
|
65
69
|
|
|
66
70
|
def help_payload(parser: argparse.ArgumentParser, command: str | None = None) -> dict[str, object]:
|
|
71
|
+
"""Build a structured help payload for the root parser or a specific subcommand."""
|
|
67
72
|
payload: dict[str, object] = {
|
|
68
73
|
"v": 2,
|
|
69
74
|
"ok": True,
|
|
@@ -130,6 +135,8 @@ def help_payload(parser: argparse.ArgumentParser, command: str | None = None) ->
|
|
|
130
135
|
|
|
131
136
|
|
|
132
137
|
class CommandMetadata(TypedDict):
|
|
138
|
+
"""Minimal metadata for a single subcommand."""
|
|
139
|
+
|
|
133
140
|
name: str
|
|
134
141
|
help: str
|
|
135
142
|
aliases: list[str]
|
|
@@ -137,6 +144,7 @@ class CommandMetadata(TypedDict):
|
|
|
137
144
|
|
|
138
145
|
|
|
139
146
|
def canonical_command_name(command_parser: argparse.ArgumentParser) -> str:
|
|
147
|
+
"""Return the canonical name (last prog token) of a subcommand parser."""
|
|
140
148
|
prog = command_parser.prog.strip()
|
|
141
149
|
if not prog:
|
|
142
150
|
return ""
|
|
@@ -145,6 +153,7 @@ def canonical_command_name(command_parser: argparse.ArgumentParser) -> str:
|
|
|
145
153
|
|
|
146
154
|
|
|
147
155
|
def commands_metadata(parser: argparse.ArgumentParser) -> list[CommandMetadata]:
|
|
156
|
+
"""Return metadata for every unique subcommand, deduplicating by parser identity."""
|
|
148
157
|
sub_action = _subparsers_action(parser)
|
|
149
158
|
if sub_action is None:
|
|
150
159
|
return []
|
|
@@ -189,6 +198,7 @@ def commands_metadata(parser: argparse.ArgumentParser) -> list[CommandMetadata]:
|
|
|
189
198
|
|
|
190
199
|
|
|
191
200
|
def _json_type_for_action(action: argparse.Action) -> str:
|
|
201
|
+
"""Map an argparse action to a JSON Schema type string."""
|
|
192
202
|
if isinstance(action, argparse._StoreTrueAction | argparse._StoreFalseAction):
|
|
193
203
|
return "boolean"
|
|
194
204
|
|
|
@@ -201,6 +211,7 @@ def _json_type_for_action(action: argparse.Action) -> str:
|
|
|
201
211
|
|
|
202
212
|
|
|
203
213
|
def _action_property_schema(action: argparse.Action) -> dict[str, object]:
|
|
214
|
+
"""Build a JSON Schema property dict for a single argparse action."""
|
|
204
215
|
value_schema: dict[str, object] = {"type": _json_type_for_action(action)}
|
|
205
216
|
|
|
206
217
|
if action.choices:
|
|
@@ -230,6 +241,7 @@ def _action_property_schema(action: argparse.Action) -> dict[str, object]:
|
|
|
230
241
|
|
|
231
242
|
|
|
232
243
|
def _action_required(action: argparse.Action) -> bool:
|
|
244
|
+
"""Determine whether an argparse action produces a required JSON field."""
|
|
233
245
|
if action.option_strings:
|
|
234
246
|
return bool(getattr(action, "required", False))
|
|
235
247
|
|
|
@@ -242,6 +254,7 @@ def _action_required(action: argparse.Action) -> bool:
|
|
|
242
254
|
|
|
243
255
|
|
|
244
256
|
def command_input_schema(command_parser: argparse.ArgumentParser) -> dict[str, object]:
|
|
257
|
+
"""Generate a JSON Schema (draft 2020-12) describing the CLI input of a subcommand."""
|
|
245
258
|
properties: dict[str, object] = {}
|
|
246
259
|
required: list[str] = []
|
|
247
260
|
|
|
@@ -269,6 +282,7 @@ def command_input_schema(command_parser: argparse.ArgumentParser) -> dict[str, o
|
|
|
269
282
|
def resolve_command_parser(
|
|
270
283
|
*, parser: argparse.ArgumentParser, name: str
|
|
271
284
|
) -> argparse.ArgumentParser | None:
|
|
285
|
+
"""Look up the sub-parser registered under *name*, or return None."""
|
|
272
286
|
sub_action = _subparsers_action(parser)
|
|
273
287
|
if sub_action is None:
|
|
274
288
|
return None
|
|
@@ -8,10 +8,12 @@ from .i18n import t
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
def _root_help_epilog() -> str:
|
|
11
|
+
"""Return the localized environment-variable epilog for root help."""
|
|
11
12
|
return t("help_root_environment_epilog")
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
def build_parser() -> argparse.ArgumentParser:
|
|
16
|
+
"""Build and return the top-level argparse parser with all subcommands registered."""
|
|
15
17
|
parent = argparse.ArgumentParser(add_help=False)
|
|
16
18
|
parent.add_argument(
|
|
17
19
|
"--lang",
|
|
@@ -176,7 +178,24 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
176
178
|
diff_group.add_argument(
|
|
177
179
|
"--full", "--patch", action="store_true", help="show full patch with delta integration"
|
|
178
180
|
)
|
|
181
|
+
diff_group.add_argument(
|
|
182
|
+
"--summary",
|
|
183
|
+
action="store_true",
|
|
184
|
+
help="compact summary: additions/deletions per file, no patch",
|
|
185
|
+
)
|
|
179
186
|
p.add_argument("--stat", action="store_true", help="show diffstat (default behavior)")
|
|
187
|
+
p.add_argument(
|
|
188
|
+
"refspec",
|
|
189
|
+
nargs="?",
|
|
190
|
+
default=None,
|
|
191
|
+
help="commit, branch, or range to diff (e.g. HEAD~3, main..feat, main...feat)",
|
|
192
|
+
)
|
|
193
|
+
p.add_argument(
|
|
194
|
+
"paths",
|
|
195
|
+
nargs="*",
|
|
196
|
+
metavar="PATH",
|
|
197
|
+
help="limit to paths (use -- to separate from refspec)",
|
|
198
|
+
)
|
|
180
199
|
|
|
181
200
|
p = sub.add_parser("log", help="pretty git log with filters", parents=[parent])
|
|
182
201
|
p.add_argument("--oneline", action="store_true", help="one line per commit")
|
|
@@ -269,11 +288,20 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
269
288
|
p.add_argument("--yes", "-y", action="store_true", help="skip confirmation")
|
|
270
289
|
|
|
271
290
|
p = sub.add_parser("merge", help="merge/rebase with pre-flight checks", parents=[parent])
|
|
272
|
-
p.add_argument(
|
|
291
|
+
p.add_argument(
|
|
292
|
+
"branch", nargs="?", help="branch to merge/rebase from (omit with --abort/--continue)"
|
|
293
|
+
)
|
|
273
294
|
p.add_argument("--rebase", action="store_true", help="rebase instead of merge")
|
|
274
295
|
p.add_argument("--no-ff", action="store_true", help="force no-fast-forward")
|
|
275
296
|
p.add_argument("--dry-run", action="store_true", help="show checks without merging")
|
|
276
297
|
p.add_argument("--yes", "-y", action="store_true", help="skip confirmation")
|
|
298
|
+
p.add_argument("--abort", action="store_true", help="abort an in-progress merge or rebase")
|
|
299
|
+
p.add_argument(
|
|
300
|
+
"--continue",
|
|
301
|
+
dest="continue_merge",
|
|
302
|
+
action="store_true",
|
|
303
|
+
help="continue an in-progress merge or rebase after resolving conflicts",
|
|
304
|
+
)
|
|
277
305
|
|
|
278
306
|
p = sub.add_parser(
|
|
279
307
|
"conflicts", help="conflict detection and resolution helper", parents=[parent]
|
|
@@ -194,6 +194,11 @@ def _run_setup_local(
|
|
|
194
194
|
providers: list[str] | None = None,
|
|
195
195
|
adapters_legacy_used: bool = False,
|
|
196
196
|
) -> int:
|
|
197
|
+
"""Install per-repo setup-agents artifacts (CLAUDE.md, settings, skills).
|
|
198
|
+
|
|
199
|
+
Returns 0 on success, 1 on plan/execution errors, 2 when ``--strict``
|
|
200
|
+
mode encounters warnings.
|
|
201
|
+
"""
|
|
197
202
|
cwd = target or Path.cwd()
|
|
198
203
|
|
|
199
204
|
if not is_repo(cwd):
|
|
@@ -251,6 +251,10 @@
|
|
|
251
251
|
"es": "mensaje",
|
|
252
252
|
"en": "msg"
|
|
253
253
|
},
|
|
254
|
+
"commit_blocked_in_progress": {
|
|
255
|
+
"es": "No se puede commitear: hay una operación {state} en curso. Resuélvela o aborta primero.",
|
|
256
|
+
"en": "Cannot commit: a {state} operation is in progress. Resolve or abort it first."
|
|
257
|
+
},
|
|
254
258
|
"commit_no_message": {
|
|
255
259
|
"es": "usa -m para proveer un mensaje de commit",
|
|
256
260
|
"en": "use -m to provide a commit message"
|
|
@@ -443,10 +447,22 @@
|
|
|
443
447
|
"es": "Diagnóstico{suffix} — {count} observación(es):",
|
|
444
448
|
"en": "Diagnostic{suffix} — {count} finding(s):"
|
|
445
449
|
},
|
|
450
|
+
"diff_binary_lfs_hint": {
|
|
451
|
+
"es": "archivo binario {path} ({mib} MiB) -- considera Git LFS",
|
|
452
|
+
"en": "binary file {path} ({mib} MiB) -- consider Git LFS"
|
|
453
|
+
},
|
|
446
454
|
"diff_prefix": {
|
|
447
455
|
"es": "diff: {stat}",
|
|
448
456
|
"en": "diff: {stat}"
|
|
449
457
|
},
|
|
458
|
+
"diff_summary_header": {
|
|
459
|
+
"es": "Resumen -- {count} archivo(s):",
|
|
460
|
+
"en": "Summary -- {count} file(s):"
|
|
461
|
+
},
|
|
462
|
+
"diff_too_many_refs": {
|
|
463
|
+
"es": "demasiados argumentos posicionales antes de '--' ({count}); gitwise diff acepta un unico refspec (usa a..b para un rango)",
|
|
464
|
+
"en": "too many positional arguments before '--' ({count}); gitwise diff accepts a single refspec (use a..b for a range)"
|
|
465
|
+
},
|
|
450
466
|
"directory_exists": {
|
|
451
467
|
"es": "el directorio ya existe: {path}",
|
|
452
468
|
"en": "directory already exists: {path}"
|
|
@@ -847,6 +863,26 @@
|
|
|
847
863
|
"es": "merge",
|
|
848
864
|
"en": "merge"
|
|
849
865
|
},
|
|
866
|
+
"merge_aborted": {
|
|
867
|
+
"es": "Mezcla abortada",
|
|
868
|
+
"en": "Merge aborted"
|
|
869
|
+
},
|
|
870
|
+
"merge_abort_continue_mutually_exclusive": {
|
|
871
|
+
"es": "--abort y --continue son mutuamente excluyentes",
|
|
872
|
+
"en": "--abort and --continue are mutually exclusive"
|
|
873
|
+
},
|
|
874
|
+
"merge_branch_required": {
|
|
875
|
+
"es": "Especifica la rama a mezclar, o usa --abort/--continue para una operación pausada",
|
|
876
|
+
"en": "Specify a branch to merge, or use --abort/--continue for a paused operation"
|
|
877
|
+
},
|
|
878
|
+
"merge_continued": {
|
|
879
|
+
"es": "Mezcla continuada",
|
|
880
|
+
"en": "Merge continued"
|
|
881
|
+
},
|
|
882
|
+
"merge_no_in_progress": {
|
|
883
|
+
"es": "No hay mezcla/rebase en curso (estado actual: {state}). Usa {action} solo cuando gitwise detecta operación pausada.",
|
|
884
|
+
"en": "No merge/rebase in progress (current state: {state}). Use {action} only when gitwise detects a paused operation."
|
|
885
|
+
},
|
|
850
886
|
"merge_ok": {
|
|
851
887
|
"es": "Mezcla completada: {branch} → {into}",
|
|
852
888
|
"en": "Merge completed: {branch} → {into}"
|
|
@@ -1667,6 +1703,10 @@
|
|
|
1667
1703
|
"es": "Sugerencia: {message}",
|
|
1668
1704
|
"en": "Suggestion: {message}"
|
|
1669
1705
|
},
|
|
1706
|
+
"suggest_blocked_in_progress": {
|
|
1707
|
+
"es": "No se puede sugerir commit: hay una operación {state} en curso. Resuélvela o aborta primero.",
|
|
1708
|
+
"en": "Cannot suggest commit: a {state} operation is in progress. Resolve or abort it first."
|
|
1709
|
+
},
|
|
1670
1710
|
"suggest_no_staged": {
|
|
1671
1711
|
"es": "No hay archivos en área de preparación",
|
|
1672
1712
|
"en": "No staged files"
|