gitwise-cli 0.29.0__tar.gz → 0.31.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.29.0 → gitwise_cli-0.31.0}/CHANGELOG.md +12 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/PKG-INFO +1 -1
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/__init__.py +4 -1
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/__main__.py +4 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/_cli_completions.py +4 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/_cli_dispatch.py +91 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/_cli_introspection.py +14 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/_cli_parser.py +29 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/_cli_setup_agents.py +5 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/_i18n_data.json +44 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/_runtime_config.py +17 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/audit.py +11 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/branches.py +10 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/clean.py +6 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/commit.py +84 -1
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/conflicts.py +8 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/context.py +9 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/design.py +26 -0
- gitwise_cli-0.31.0/gitwise/diff.py +544 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/doctor.py +5 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/git.py +40 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/health.py +25 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/i18n.py +13 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/log.py +20 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/merge.py +10 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/optimize.py +12 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/output.py +45 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/pick.py +6 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/pr.py +31 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/schema.py +5 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/setup.py +28 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/setup_agents/exec.py +31 -3
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/setup_agents/format.py +8 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/setup_agents/plan.py +17 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/setup_agents/plan_gitfiles.py +11 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/setup_agents/plan_skills.py +10 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/setup_agents/providers/__init__.py +9 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/setup_agents/providers/base.py +9 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/setup_agents/providers/claude.py +18 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/setup_agents/state.py +7 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/setup_agents/types.py +5 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/show.py +9 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/snapshot.py +6 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/stash.py +8 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/status.py +1 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/suggest.py +10 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/summarize.py +5 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/sync.py +13 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/tag.py +11 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/undo.py +9 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/update.py +1 -0
- gitwise_cli-0.31.0/gitwise/utils/secret_scan.py +201 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/worktree.py +5 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/pyproject.toml +1 -1
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/share/schemas/v1/input/commit.json +5 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/share/schemas/v1/input/diff.json +21 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/tests/test_commit.py +58 -0
- gitwise_cli-0.31.0/tests/test_diff.py +351 -0
- gitwise_cli-0.31.0/tests/test_secret_scan.py +177 -0
- gitwise_cli-0.29.0/gitwise/diff.py +0 -321
- gitwise_cli-0.29.0/tests/test_diff.py +0 -168
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/.gitignore +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/LICENSE +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/README.md +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/bin/gitwise +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/_paths.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/py.typed +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/setup_agents/__init__.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/setup_agents/adapters/__init__.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/setup_agents/adapters/aider.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/setup_agents/adapters/base.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/setup_agents/adapters/codex.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/setup_agents/adapters/continue_adapter.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/setup_agents/adapters/cursor.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/setup_agents/adapters/opencode.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/setup_agents/adapters/pi.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/setup_agents/providers/aider.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/setup_agents/providers/codex.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/setup_agents/providers/continue_adapter.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/setup_agents/providers/cursor.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/setup_agents/providers/opencode.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/setup_agents/providers/pi.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/utils/__init__.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/utils/git_output.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/utils/in_progress.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/utils/json_envelope.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/gitwise/utils/parsing.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/install.sh +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/share/agents/skills/git-audit/SKILL.md +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/share/agents/skills/git-clean/SKILL.md +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/share/agents/skills/git-optimize/SKILL.md +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/share/aider/CONVENTIONS.md.template +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/share/aider/aider.conf.yml.template +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/share/claude/CLAUDE.md.template +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/share/claude/rules/gitwise.md +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/share/claude/settings.json.template +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/share/claude/skills/git-audit/SKILL.md +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/share/claude/skills/git-clean/SKILL.md +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/share/claude/skills/git-optimize/SKILL.md +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/share/codex/agents/gitwise.toml.template +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/share/continue/rules/gitwise.md.template +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/share/cursor/rules/gitwise.mdc.template +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/share/git-config-modern.txt +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/share/hooks/commit-msg +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/share/hooks/pre-commit +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/share/opencode/agents/gitwise.md.template +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/share/pi/skills/gitwise.md.template +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/share/schemas/v1/input/audit.json +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/share/schemas/v1/input/branches.json +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/share/schemas/v1/input/clean.json +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/share/schemas/v1/input/commands.json +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/share/schemas/v1/input/completions.json +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/share/schemas/v1/input/conflicts.json +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/share/schemas/v1/input/context.json +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/share/schemas/v1/input/doctor.json +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/share/schemas/v1/input/health.json +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/share/schemas/v1/input/log.json +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/share/schemas/v1/input/merge.json +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/share/schemas/v1/input/optimize.json +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/share/schemas/v1/input/pick.json +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/share/schemas/v1/input/pr.json +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/share/schemas/v1/input/schema.json +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/share/schemas/v1/input/setup-agents.json +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/share/schemas/v1/input/setup.json +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/share/schemas/v1/input/show.json +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/share/schemas/v1/input/snapshot.json +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/share/schemas/v1/input/stash.json +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/share/schemas/v1/input/status.json +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/share/schemas/v1/input/suggest.json +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/share/schemas/v1/input/summarize.json +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/share/schemas/v1/input/sync.json +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/share/schemas/v1/input/tag.json +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/share/schemas/v1/input/undo.json +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/share/schemas/v1/input/update.json +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/share/schemas/v1/input/worktree.json +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/tests/__init__.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/tests/conftest.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/tests/test_adapters.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/tests/test_audit.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/tests/test_branches.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/tests/test_clean.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/tests/test_conflicts.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/tests/test_context.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/tests/test_design.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/tests/test_doctor.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/tests/test_edge_cases.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/tests/test_git.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/tests/test_git_output_utils.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/tests/test_health.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/tests/test_i18n.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/tests/test_in_progress.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/tests/test_json_envelope_utils.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/tests/test_log.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/tests/test_main.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/tests/test_md_links_script.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/tests/test_merge.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/tests/test_optimize.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/tests/test_output.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/tests/test_parsing_utils.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/tests/test_pick.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/tests/test_pr.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/tests/test_roadmap_baseline_script.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/tests/test_sa_plan.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/tests/test_sa_unit.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/tests/test_schema_catalog.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/tests/test_setup.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/tests/test_setup_agents.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/tests/test_show.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/tests/test_snapshot.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/tests/test_stash.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/tests/test_status.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/tests/test_suggest.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/tests/test_summarize.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/tests/test_sync.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/tests/test_sync_changelog_es_script.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/tests/test_tag.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/tests/test_undo.py +0 -0
- {gitwise_cli-0.29.0 → gitwise_cli-0.31.0}/tests/test_worktree.py +0 -0
|
@@ -3,6 +3,18 @@
|
|
|
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.31.0 (2026-06-19)
|
|
7
|
+
|
|
8
|
+
### Feat
|
|
9
|
+
|
|
10
|
+
- **secret-scan**: commit-time guard and diff --scan-secrets (Sprint 2 D3) (#68)
|
|
11
|
+
|
|
12
|
+
## v0.30.0 (2026-06-19)
|
|
13
|
+
|
|
14
|
+
### Feat
|
|
15
|
+
|
|
16
|
+
- **diff**: support refs, path scope, and summary (Sprint 2 PR-A) (#66)
|
|
17
|
+
|
|
6
18
|
## v0.29.0 (2026-06-19)
|
|
7
19
|
|
|
8
20
|
### Feat
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gitwise-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.31.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.31.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,73 @@ 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,
|
|
196
|
+
scan_secrets=args.scan_secrets,
|
|
133
197
|
as_json=args.json,
|
|
134
198
|
)
|
|
135
199
|
|
|
136
200
|
|
|
137
201
|
def _run_log(args: argparse.Namespace) -> int:
|
|
202
|
+
"""Dispatch to ``log`` subcommand."""
|
|
138
203
|
from .log import run_log
|
|
139
204
|
|
|
140
205
|
return run_log(
|
|
@@ -151,12 +216,14 @@ def _run_log(args: argparse.Namespace) -> int:
|
|
|
151
216
|
|
|
152
217
|
|
|
153
218
|
def _run_show(args: argparse.Namespace) -> int:
|
|
219
|
+
"""Dispatch to ``show`` subcommand."""
|
|
154
220
|
from .show import run_show
|
|
155
221
|
|
|
156
222
|
return run_show(ref=args.ref, stat=args.stat, as_json=args.json)
|
|
157
223
|
|
|
158
224
|
|
|
159
225
|
def _run_commit(args: argparse.Namespace) -> int:
|
|
226
|
+
"""Dispatch to ``commit`` subcommand."""
|
|
160
227
|
from .commit import run_commit
|
|
161
228
|
|
|
162
229
|
return run_commit(
|
|
@@ -166,17 +233,20 @@ def _run_commit(args: argparse.Namespace) -> int:
|
|
|
166
233
|
breaking=args.breaking,
|
|
167
234
|
amend=args.amend,
|
|
168
235
|
dry_run=args.dry_run,
|
|
236
|
+
allow_secret=args.allow_secret,
|
|
169
237
|
as_json=args.json,
|
|
170
238
|
)
|
|
171
239
|
|
|
172
240
|
|
|
173
241
|
def _run_branches(args: argparse.Namespace) -> int:
|
|
242
|
+
"""Dispatch to ``branches`` subcommand."""
|
|
174
243
|
from .branches import run_branches
|
|
175
244
|
|
|
176
245
|
return run_branches(stale=args.stale, remote=args.remote, sort=args.sort, as_json=args.json)
|
|
177
246
|
|
|
178
247
|
|
|
179
248
|
def _run_sync(args: argparse.Namespace) -> int:
|
|
249
|
+
"""Dispatch to ``sync`` subcommand."""
|
|
180
250
|
from .sync import run_sync
|
|
181
251
|
|
|
182
252
|
return run_sync(
|
|
@@ -189,12 +259,14 @@ def _run_sync(args: argparse.Namespace) -> int:
|
|
|
189
259
|
|
|
190
260
|
|
|
191
261
|
def _run_pr(args: argparse.Namespace) -> int:
|
|
262
|
+
"""Dispatch to ``pr`` subcommand."""
|
|
192
263
|
from .pr import run_pr
|
|
193
264
|
|
|
194
265
|
return run_pr(action=args.action, selector=args.selector, as_json=args.json)
|
|
195
266
|
|
|
196
267
|
|
|
197
268
|
def _run_undo(args: argparse.Namespace) -> int:
|
|
269
|
+
"""Dispatch to ``undo`` subcommand."""
|
|
198
270
|
from .undo import run_undo
|
|
199
271
|
|
|
200
272
|
return run_undo(
|
|
@@ -208,18 +280,21 @@ def _run_undo(args: argparse.Namespace) -> int:
|
|
|
208
280
|
|
|
209
281
|
|
|
210
282
|
def _run_context(args: argparse.Namespace) -> int:
|
|
283
|
+
"""Dispatch to ``context`` subcommand."""
|
|
211
284
|
from .context import run_context
|
|
212
285
|
|
|
213
286
|
return run_context(as_json=args.json)
|
|
214
287
|
|
|
215
288
|
|
|
216
289
|
def _run_health(args: argparse.Namespace) -> int:
|
|
290
|
+
"""Dispatch to ``health`` subcommand."""
|
|
217
291
|
from .health import run_health
|
|
218
292
|
|
|
219
293
|
return run_health(as_json=args.json)
|
|
220
294
|
|
|
221
295
|
|
|
222
296
|
def _run_stash(args: argparse.Namespace) -> int:
|
|
297
|
+
"""Dispatch to ``stash`` subcommand."""
|
|
223
298
|
from .stash import run_stash
|
|
224
299
|
|
|
225
300
|
return run_stash(
|
|
@@ -233,6 +308,7 @@ def _run_stash(args: argparse.Namespace) -> int:
|
|
|
233
308
|
|
|
234
309
|
|
|
235
310
|
def _run_tag(args: argparse.Namespace) -> int:
|
|
311
|
+
"""Dispatch to ``tag`` subcommand."""
|
|
236
312
|
from .tag import run_tag
|
|
237
313
|
|
|
238
314
|
return run_tag(
|
|
@@ -247,6 +323,7 @@ def _run_tag(args: argparse.Namespace) -> int:
|
|
|
247
323
|
|
|
248
324
|
|
|
249
325
|
def _run_merge(args: argparse.Namespace) -> int:
|
|
326
|
+
"""Dispatch to ``merge`` subcommand."""
|
|
250
327
|
from .merge import run_merge
|
|
251
328
|
|
|
252
329
|
return run_merge(
|
|
@@ -262,18 +339,21 @@ def _run_merge(args: argparse.Namespace) -> int:
|
|
|
262
339
|
|
|
263
340
|
|
|
264
341
|
def _run_conflicts(args: argparse.Namespace) -> int:
|
|
342
|
+
"""Dispatch to ``conflicts`` subcommand."""
|
|
265
343
|
from .conflicts import run_conflicts
|
|
266
344
|
|
|
267
345
|
return run_conflicts(ours=args.ours, theirs=args.theirs, as_json=args.json)
|
|
268
346
|
|
|
269
347
|
|
|
270
348
|
def _run_suggest(args: argparse.Namespace) -> int:
|
|
349
|
+
"""Dispatch to ``suggest`` subcommand."""
|
|
271
350
|
from .suggest import run_suggest
|
|
272
351
|
|
|
273
352
|
return run_suggest(as_json=args.json)
|
|
274
353
|
|
|
275
354
|
|
|
276
355
|
def _run_pick(args: argparse.Namespace) -> int:
|
|
356
|
+
"""Dispatch to ``pick`` / ``cherry-pick`` subcommand."""
|
|
277
357
|
from .pick import run_pick
|
|
278
358
|
|
|
279
359
|
return run_pick(
|
|
@@ -287,12 +367,18 @@ def _run_pick(args: argparse.Namespace) -> int:
|
|
|
287
367
|
|
|
288
368
|
|
|
289
369
|
def _run_status(args: argparse.Namespace) -> int:
|
|
370
|
+
"""Dispatch to ``status`` subcommand."""
|
|
290
371
|
from .status import run_status
|
|
291
372
|
|
|
292
373
|
return run_status(as_json=args.json)
|
|
293
374
|
|
|
294
375
|
|
|
295
376
|
def _run_completions(args: argparse.Namespace) -> int:
|
|
377
|
+
"""Generate and output a shell completions script.
|
|
378
|
+
|
|
379
|
+
Returns 1 on missing dependency (shtab), unsupported shell, or
|
|
380
|
+
runtime error.
|
|
381
|
+
"""
|
|
296
382
|
shell = args.shell
|
|
297
383
|
prog = args.prog
|
|
298
384
|
try:
|
|
@@ -346,6 +432,7 @@ def _run_completions(args: argparse.Namespace) -> int:
|
|
|
346
432
|
|
|
347
433
|
|
|
348
434
|
def _run_commands(args: argparse.Namespace) -> int:
|
|
435
|
+
"""List all registered subcommands with aliases."""
|
|
349
436
|
parser = build_parser()
|
|
350
437
|
commands = commands_metadata(parser)
|
|
351
438
|
payload = {
|
|
@@ -374,6 +461,10 @@ def _run_commands(args: argparse.Namespace) -> int:
|
|
|
374
461
|
|
|
375
462
|
|
|
376
463
|
def _run_schema(args: argparse.Namespace) -> int:
|
|
464
|
+
"""Print the JSON Schema for a subcommand's CLI input.
|
|
465
|
+
|
|
466
|
+
Returns 1 when the command is unknown or its schema file is missing.
|
|
467
|
+
"""
|
|
377
468
|
from .schema import load_command_input_schema
|
|
378
469
|
|
|
379
470
|
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,29 @@ 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
|
+
"--scan-secrets",
|
|
189
|
+
action="store_true",
|
|
190
|
+
help="scan the diff for leaked credentials (advisory, opt-in)",
|
|
191
|
+
)
|
|
192
|
+
p.add_argument(
|
|
193
|
+
"refspec",
|
|
194
|
+
nargs="?",
|
|
195
|
+
default=None,
|
|
196
|
+
help="commit, branch, or range to diff (e.g. HEAD~3, main..feat, main...feat)",
|
|
197
|
+
)
|
|
198
|
+
p.add_argument(
|
|
199
|
+
"paths",
|
|
200
|
+
nargs="*",
|
|
201
|
+
metavar="PATH",
|
|
202
|
+
help="limit to paths (use -- to separate from refspec)",
|
|
203
|
+
)
|
|
180
204
|
|
|
181
205
|
p = sub.add_parser("log", help="pretty git log with filters", parents=[parent])
|
|
182
206
|
p.add_argument("--oneline", action="store_true", help="one line per commit")
|
|
@@ -199,6 +223,11 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
199
223
|
p.add_argument("--breaking", action="store_true", help="breaking change (!)")
|
|
200
224
|
p.add_argument("--amend", action="store_true", help="amend last commit")
|
|
201
225
|
p.add_argument("--dry-run", action="store_true", help="show without committing")
|
|
226
|
+
p.add_argument(
|
|
227
|
+
"--allow-secret",
|
|
228
|
+
action="store_true",
|
|
229
|
+
help="proceed past a high-severity secret finding (with confirmation)",
|
|
230
|
+
)
|
|
202
231
|
|
|
203
232
|
p = sub.add_parser("branches", help="branch intelligence dashboard", parents=[parent])
|
|
204
233
|
p.add_argument("--stale", action="store_true", help="show stale [gone] branches only")
|
|
@@ -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):
|
|
@@ -447,10 +447,54 @@
|
|
|
447
447
|
"es": "Diagnóstico{suffix} — {count} observación(es):",
|
|
448
448
|
"en": "Diagnostic{suffix} — {count} finding(s):"
|
|
449
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
|
+
},
|
|
450
454
|
"diff_prefix": {
|
|
451
455
|
"es": "diff: {stat}",
|
|
452
456
|
"en": "diff: {stat}"
|
|
453
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
|
+
},
|
|
466
|
+
"secret_scan_clean": {
|
|
467
|
+
"es": "no se detectaron secretos en el diff",
|
|
468
|
+
"en": "no secrets detected in the diff"
|
|
469
|
+
},
|
|
470
|
+
"secret_scan_found": {
|
|
471
|
+
"es": "{rule} en {path}:{line} ({preview})",
|
|
472
|
+
"en": "{rule} at {path}:{line} ({preview})"
|
|
473
|
+
},
|
|
474
|
+
"secret_scan_found_header": {
|
|
475
|
+
"es": "Secretos detectados -- {count} hallazgo(s):",
|
|
476
|
+
"en": "Secrets detected -- {count} finding(s):"
|
|
477
|
+
},
|
|
478
|
+
"secret_scan_blocked_high": {
|
|
479
|
+
"es": "commit bloqueado: {count} secreto(s) de alta severidad en el área de staging",
|
|
480
|
+
"en": "commit blocked: {count} high-severity secret(s) in the staging area"
|
|
481
|
+
},
|
|
482
|
+
"secret_scan_blocked_hint": {
|
|
483
|
+
"es": "revoque o rote el secreto, remuévalo del stage, o use --allow-secret (con confirmación) para commitear de todos modos",
|
|
484
|
+
"en": "revoke/rotate the secret, unstage it, or use --allow-secret (with confirmation) to commit anyway"
|
|
485
|
+
},
|
|
486
|
+
"secret_scan_allow_confirm": {
|
|
487
|
+
"es": "Se detectaron {count} secreto(s) de alta severidad. ¿Commitear de todos modos?",
|
|
488
|
+
"en": "{count} high-severity secret(s) detected. Commit anyway?"
|
|
489
|
+
},
|
|
490
|
+
"secret_scan_medium_warning": {
|
|
491
|
+
"es": "advertencia: {rule} en {path}:{line} ({preview})",
|
|
492
|
+
"en": "warning: {rule} at {path}:{line} ({preview})"
|
|
493
|
+
},
|
|
494
|
+
"secret_scan_unavailable": {
|
|
495
|
+
"es": "no se pudo escanear el área de staging (fail-closed): {error}",
|
|
496
|
+
"en": "could not scan the staging area (fail-closed): {error}"
|
|
497
|
+
},
|
|
454
498
|
"directory_exists": {
|
|
455
499
|
"es": "el directorio ya existe: {path}",
|
|
456
500
|
"en": "directory already exists: {path}"
|