feat(tui): scoped-models allowlist for Ctrl+P / cycle_model (#26)#200
Merged
Conversation
Adds the user-defined scoped-models allowlist requested in issue #26. Resolution order: 1. --models <pat,pat,pat> CLI flag => JCODE_SCOPED_MODELS env 2. provider.scoped_models config (~/.jcode/config.toml) 3. Empty -> falls back to provider.available_models_for_switching() (existing behavior, bit-for-bit preserved) Patterns match by case-insensitive substring or by shell-style glob (* and ?). The first non-empty match anywhere in the model id counts. Filter output preserves the allowlist's order so flips are deterministic across cycles. When the allowlist matches zero available models, cycle_model surfaces a clear error mentioning the configured patterns instead of silently falling back to the unscoped list (which would be confusing). Implementation: - src/scoped_models.rs (new): resolve_allowlist + filter_by_allowlist + tiny iterative-DP glob matcher. Avoids pulling a glob crate. - src/lib.rs: register the new pub mod. - crates/jcode-config-types: provider.scoped_models: Vec<String> with default []. - src/cli/args.rs: --models <patterns> with value_delimiter = ','. - src/cli/startup.rs: parse_and_prepare_args translates the flag into JCODE_SCOPED_MODELS so deep code paths read it without arg threading. - src/tui/app/model_context.rs: cycle_model applies the allowlist filter before computing next_index; empty-after-filter prints a helpful error instead of falling back. 7 unit tests in src/scoped_models.rs: - empty_allowlist_returns_input_unchanged - substring_pattern_matches_case_insensitively - glob_pattern_matches - dedup_preserves_first_pattern_match_order - unmatched_patterns_are_silently_dropped - parse_pattern_list_trims_and_drops_empty - glob_match_question_mark_is_single_char Note: the Ctrl+P / Shift+Ctrl+P keybinding rebind from auto-poke (the issue's recommendation) is intentionally NOT applied here — that is a keybinding-policy decision worth its own PR. cycle_model itself is already callable from any binding, so this PR is fully usable today via /model-cycle (existing) plus --models. Closes #26
quangdang46
added a commit
that referenced
this pull request
May 22, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds the user-defined scoped-models allowlist requested in issue #26. Users can now restrict model cycling to a curated list (
sonnet:high↔gpt-5-codex, etc.) instead of cycling through every available model.Resolution order
--models <pat,pat,pat>CLI flag →JCODE_SCOPED_MODELSenvprovider.scoped_modelsconfig (~/.jcode/config.toml)provider.available_models_for_switching()(existing behavior, bit-for-bit preserved)Patterns match by case-insensitive substring or by shell-style glob (
*and?). Filter output preserves the allowlist's order so flips are deterministic across cycles.When the allowlist matches zero available models,
cycle_modelsurfaces a clear error mentioning the configured patterns instead of silently falling back to the unscoped list.Changes
resolve_allowlist+filter_by_allowlist+ tiny iterative-DP glob matcher. Avoids pulling a glob crate.provider.scoped_models: Vec<String>with default[].--models <patterns>withvalue_delimiter = ','.parse_and_prepare_argstranslates the flag intoJCODE_SCOPED_MODELSso deep code paths read it without arg threading.cycle_modelapplies the allowlist filter before computingnext_index; empty-after-filter prints a helpful error instead of falling back.Tests
Notes / scope deviation from issue text
The
Ctrl+P/Shift+Ctrl+Pkeybinding rebind from auto-poke (the issue's recommendation) is intentionally NOT applied here — that is a keybinding-policy decision worth its own PR.cycle_modelitself is already callable from any binding, so this PR is fully usable today via/model-cycle(existing) plus--models.Closes #26