diff --git a/contextzip/cli.py b/contextzip/cli.py index 7897f12..841b837 100644 --- a/contextzip/cli.py +++ b/contextzip/cli.py @@ -927,6 +927,18 @@ def _run( if saved: project_cfg = load_project_config(project_dir) + # ── Include/exclude inputs shared by every scan mode ───────────────────── + # CLI --exclude/-e patterns plus any standing always_exclude patterns from + # project config — both are additive, persistent behavior comes from + # config.json so it doesn't need to be re-typed every run. always_include + # is a standing negation. Built once here so standard and --git-changes + # runs honour project config identically. + normalized_exclude = [normalize_pattern(p) for p in extra_exclude or []] + normalized_exclude += [normalize_pattern(p) for p in project_cfg.always_exclude] + force_include = build_force_include_spec( + [normalize_pattern(p) for p in project_cfg.always_include] + ) + # ── Git-changes mode ───────────────────────────────────────────────────── if git_changes: with console.status("[cyan]Querying git for changed files…[/]", spinner="dots"): @@ -939,7 +951,7 @@ def _run( print_git_deleted_and_submodules(git_result) if git_result.is_empty: - info("Nothing to package — working tree is clean.") + info("Nothing to compress in this one — working tree is clean.") return scan_label, scan_detail = git_scan_label_and_detail(git_result) @@ -953,27 +965,21 @@ def _run( large_file_warn_bytes=int( project_cfg.limits.max_file_size_mb * 1024 * 1024 ), + extra_exclude=normalized_exclude if normalized_exclude else None, + include_only=include_only if include_only else None, + force_include=force_include, ) else: # ── Build exclusion spec ───────────────────────────────────────────── gitignore_path = None if no_gitignore else (project_dir / ".gitignore") - # CLI --exclude/-e patterns plus any standing always_exclude patterns - # from project config — both are additive, persistent behavior comes - # from config.json so it doesn't need to be re-typed every run. - normalized_exclude = [normalize_pattern(p) for p in extra_exclude or []] - normalized_exclude += [normalize_pattern(p) for p in project_cfg.always_exclude] - with console.status("[cyan]Building exclusion rules…[/]", spinner="dots"): spec = build_spec( rule_modules=detection.rule_modules, extra_exclude=normalized_exclude if normalized_exclude else None, gitignore_path=gitignore_path, ) - force_include = build_force_include_spec( - [normalize_pattern(p) for p in project_cfg.always_include] - ) # ── Resolve files ───────────────────────────────────────────────────── with console.status("[cyan]Scanning project files…[/]", spinner="dots"): @@ -1027,7 +1033,7 @@ def _run( return if not resolved.included: - err("Nothing to package — all files were excluded.") + err("Nothing to compress in this one — all files were excluded.") info("Try contextzip include PATH or -i PATH to override.") return diff --git a/contextzip/cli_ai.py b/contextzip/cli_ai.py index 47e849c..2b49468 100644 --- a/contextzip/cli_ai.py +++ b/contextzip/cli_ai.py @@ -15,38 +15,11 @@ from pathlib import Path from rich.console import Console from contextzip.cli_display import print_ai_selection, err, warn, info +from contextzip.filters import normalize_pattern # noqa: F401 (re-exported for cli.py) console = Console() -# --------------------------------------------------------------------------- -# Pattern normalisation -# --------------------------------------------------------------------------- - - -def normalize_pattern(p: str) -> str: - """ - Canonicalise a user-supplied exclusion pattern. - - Rules applied in order: - 1. Strip a leading ``./`` or ``.\\`` so that ``./CHANGELOG.md`` - and ``CHANGELOG.md`` are treated identically. - 2. Replace every backslash with a forward slash for cross-platform - consistency (Windows paths entered on the CLI). - 3. Collapse ``folder/*`` → ``folder/`` so that gitignore-style - directory globs work as expected. - """ - # 1. Strip leading ./ or .\\ - if p.startswith("./") or p.startswith(".\\"): - p = p[2:] - # 2. Normalise path separators - p = p.replace("\\", "/") - # 3. folder/* → folder/ - if p.endswith("/*"): - p = p[:-1] - return p - - # --------------------------------------------------------------------------- # AI selection (full run — produces ZIP) # --------------------------------------------------------------------------- diff --git a/contextzip/cli_display.py b/contextzip/cli_display.py index a4bc3c2..5e933e4 100644 --- a/contextzip/cli_display.py +++ b/contextzip/cli_display.py @@ -64,6 +64,10 @@ def print_detection(detection, *, con: Console = console) -> None: """One line: what was detected and how confident contextzip is.""" if detection.is_unknown: ok("Detected", "unknown ecosystem, base rules only", con=con) + info( + "Don't see your language? Add it here: https://example.com", + con=con, + ) return parts = []