@sayknow-cli/coding-agent 0.6.1 → 0.6.3
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.
- package/CHANGELOG.md +8 -0
- package/package.json +7 -7
- package/src/modes/components/model-selector.ts +52 -36
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.6.3] - 2026-09-25
|
|
6
|
+
|
|
7
|
+
## [0.6.2] - 2026-09-24
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- `/model` list search now matches vendor-style version punctuation. Typing `opus 5.5` (or just `5.5`) in the ALL or provider tab returned "No matching models" even though `anthropic/claude-opus-5-5` was in the list, because those tabs fuzzy-matched only `${id} ${provider}` and `5.5` cannot be a subsequence of `5-5`. The ALL/provider tabs now use the same punctuation-insensitive pipeline as the CANONICAL tab (id + provider + display name, alpha-token and compact-substring prefilters, fuzzy only for ranking/typo rescue), so `opus 5.5`, `5.5`, `opus55` and `opus-5-5` all land on Opus 5.5.
|
|
12
|
+
|
|
5
13
|
## [0.6.1] - 2026-09-24
|
|
6
14
|
|
|
7
15
|
### Added
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@sayknow-cli/coding-agent",
|
|
4
|
-
"version": "0.6.
|
|
4
|
+
"version": "0.6.3",
|
|
5
5
|
"description": "Sayknow-CLI CLI with read, bash, edit, write tools and session management",
|
|
6
6
|
"homepage": "https://sayknow-cli.com",
|
|
7
7
|
"author": "jaybeyond",
|
|
@@ -54,12 +54,12 @@
|
|
|
54
54
|
"@agentclientprotocol/sdk": "1.3.0",
|
|
55
55
|
"@babel/parser": "^7.29.3",
|
|
56
56
|
"@mozilla/readability": "^0.6.0",
|
|
57
|
-
"@sayknow-cli/stats": "0.6.
|
|
58
|
-
"@sayknow-cli/agent-core": "0.6.
|
|
59
|
-
"@sayknow-cli/ai": "0.6.
|
|
60
|
-
"@sayknow-cli/natives": "0.6.
|
|
61
|
-
"@sayknow-cli/tui": "0.6.
|
|
62
|
-
"@sayknow-cli/utils": "0.6.
|
|
57
|
+
"@sayknow-cli/stats": "0.6.3",
|
|
58
|
+
"@sayknow-cli/agent-core": "0.6.3",
|
|
59
|
+
"@sayknow-cli/ai": "0.6.3",
|
|
60
|
+
"@sayknow-cli/natives": "0.6.3",
|
|
61
|
+
"@sayknow-cli/tui": "0.6.3",
|
|
62
|
+
"@sayknow-cli/utils": "0.6.3",
|
|
63
63
|
"@puppeteer/browsers": "^2.13.0",
|
|
64
64
|
"@types/turndown": "5.0.6",
|
|
65
65
|
"@xterm/headless": "^6.0.0",
|
|
@@ -64,11 +64,49 @@ function getAlphaSearchTokens(query: string): string[] {
|
|
|
64
64
|
return [...normalizeSearchText(query).matchAll(/[a-z]+/g)].map(match => match[0]).filter(token => token.length > 0);
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
+
interface SearchableItem {
|
|
68
|
+
searchText: string;
|
|
69
|
+
normalizedSearchText: string;
|
|
70
|
+
compactSearchText: string;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function buildSearchFields(parts: readonly string[]): SearchableItem {
|
|
74
|
+
const searchText = parts.join(" ");
|
|
75
|
+
return {
|
|
76
|
+
searchText,
|
|
77
|
+
normalizedSearchText: normalizeSearchText(searchText),
|
|
78
|
+
compactSearchText: compactSearchText(searchText),
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Punctuation-insensitive search shared by every list view. Users type model
|
|
84
|
+
* names the way vendors print them ("opus 5.5", "gpt 5.4"), while ids spell
|
|
85
|
+
* the same thing with dashes ("claude-opus-5-5"). The alpha-token and compact
|
|
86
|
+
* substring passes bridge that gap; the fuzzy pass only ranks (or, when both
|
|
87
|
+
* prefilters are empty, rescues typos) over the display text.
|
|
88
|
+
*/
|
|
89
|
+
function filterSearchableItems<T extends SearchableItem>(items: T[], query: string): T[] {
|
|
90
|
+
const alphaTokens = getAlphaSearchTokens(query);
|
|
91
|
+
const alphaFiltered =
|
|
92
|
+
alphaTokens.length === 0
|
|
93
|
+
? items
|
|
94
|
+
: items.filter(item => alphaTokens.every(token => item.normalizedSearchText.includes(token)));
|
|
95
|
+
const compactQuery = compactSearchText(query);
|
|
96
|
+
const substringFiltered =
|
|
97
|
+
compactQuery.length === 0
|
|
98
|
+
? alphaFiltered
|
|
99
|
+
: alphaFiltered.filter(item => item.compactSearchText.includes(compactQuery));
|
|
100
|
+
const fuzzySource =
|
|
101
|
+
substringFiltered.length > 0 ? substringFiltered : alphaFiltered.length > 0 ? alphaFiltered : items;
|
|
102
|
+
return fuzzyFilter(fuzzySource, query, ({ searchText }) => searchText);
|
|
103
|
+
}
|
|
104
|
+
|
|
67
105
|
function computeModelRank(model: Model, roles: Record<string, RoleAssignment | undefined>): number {
|
|
68
106
|
return roles.default && modelsAreEqual(roles.default.model, model) ? 0 : 1;
|
|
69
107
|
}
|
|
70
108
|
|
|
71
|
-
interface ModelItem {
|
|
109
|
+
interface ModelItem extends SearchableItem {
|
|
72
110
|
kind: "provider";
|
|
73
111
|
provider: string;
|
|
74
112
|
id: string;
|
|
@@ -78,15 +116,12 @@ interface ModelItem {
|
|
|
78
116
|
explicitThinkingLevel?: boolean;
|
|
79
117
|
}
|
|
80
118
|
|
|
81
|
-
interface CanonicalModelItem {
|
|
119
|
+
interface CanonicalModelItem extends SearchableItem {
|
|
82
120
|
kind: "canonical";
|
|
83
121
|
id: string;
|
|
84
122
|
model: Model;
|
|
85
123
|
selector: string;
|
|
86
124
|
variantCount: number;
|
|
87
|
-
searchText: string;
|
|
88
|
-
normalizedSearchText: string;
|
|
89
|
-
compactSearchText: string;
|
|
90
125
|
thinkingLevel?: ThinkingLevel;
|
|
91
126
|
explicitThinkingLevel?: boolean;
|
|
92
127
|
}
|
|
@@ -732,6 +767,7 @@ export class ModelSelectorComponent extends Container {
|
|
|
732
767
|
selector: `${scoped.model.provider}/${scoped.model.id}`,
|
|
733
768
|
thinkingLevel: scoped.thinkingLevel,
|
|
734
769
|
explicitThinkingLevel: scoped.explicitThinkingLevel,
|
|
770
|
+
...buildSearchFields([scoped.model.id, scoped.model.provider, scoped.model.name]),
|
|
735
771
|
}));
|
|
736
772
|
} else {
|
|
737
773
|
// Reload config and cached discovery state without blocking on live provider refresh
|
|
@@ -754,6 +790,7 @@ export class ModelSelectorComponent extends Container {
|
|
|
754
790
|
id: model.id,
|
|
755
791
|
model,
|
|
756
792
|
selector: `${model.provider}/${model.id}`,
|
|
793
|
+
...buildSearchFields([model.id, model.provider, model.name]),
|
|
757
794
|
}));
|
|
758
795
|
} catch (error) {
|
|
759
796
|
this.#allModels = [];
|
|
@@ -779,23 +816,20 @@ export class ModelSelectorComponent extends Container {
|
|
|
779
816
|
});
|
|
780
817
|
if (!selectedModel) return undefined;
|
|
781
818
|
const selectedSelector = `${selectedModel.provider}/${selectedModel.id}`;
|
|
782
|
-
const searchText = [
|
|
783
|
-
record.id,
|
|
784
|
-
record.name,
|
|
785
|
-
selectedModel.provider,
|
|
786
|
-
selectedModel.id,
|
|
787
|
-
selectedModel.name,
|
|
788
|
-
...record.variants.flatMap(variant => [variant.selector, variant.model.name]),
|
|
789
|
-
].join(" ");
|
|
790
819
|
const item: CanonicalModelItem = {
|
|
791
820
|
kind: "canonical",
|
|
792
821
|
id: record.id,
|
|
793
822
|
model: selectedModel,
|
|
794
823
|
selector: record.id,
|
|
795
824
|
variantCount: record.variants.length,
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
825
|
+
...buildSearchFields([
|
|
826
|
+
record.id,
|
|
827
|
+
record.name,
|
|
828
|
+
selectedModel.provider,
|
|
829
|
+
selectedModel.id,
|
|
830
|
+
selectedModel.name,
|
|
831
|
+
...record.variants.flatMap(variant => [variant.selector, variant.model.name]),
|
|
832
|
+
]),
|
|
799
833
|
};
|
|
800
834
|
const scopedThinkingLevel = scopedThinkingBySelector.get(selectedSelector);
|
|
801
835
|
if (scopedThinkingLevel !== undefined) {
|
|
@@ -925,29 +959,11 @@ export class ModelSelectorComponent extends Container {
|
|
|
925
959
|
}
|
|
926
960
|
|
|
927
961
|
if (isCanonicalTab) {
|
|
928
|
-
const
|
|
929
|
-
const alphaFiltered =
|
|
930
|
-
alphaTokens.length === 0
|
|
931
|
-
? baseCanonicalModels
|
|
932
|
-
: baseCanonicalModels.filter(item =>
|
|
933
|
-
alphaTokens.every(token => item.normalizedSearchText.includes(token)),
|
|
934
|
-
);
|
|
935
|
-
const compactQuery = compactSearchText(query);
|
|
936
|
-
const substringFiltered =
|
|
937
|
-
compactQuery.length === 0
|
|
938
|
-
? alphaFiltered
|
|
939
|
-
: alphaFiltered.filter(item => item.compactSearchText.includes(compactQuery));
|
|
940
|
-
const fuzzySource =
|
|
941
|
-
substringFiltered.length > 0
|
|
942
|
-
? substringFiltered
|
|
943
|
-
: alphaFiltered.length > 0
|
|
944
|
-
? alphaFiltered
|
|
945
|
-
: baseCanonicalModels;
|
|
946
|
-
const fuzzyMatches = fuzzyFilter(fuzzySource, query, ({ searchText }) => searchText);
|
|
962
|
+
const fuzzyMatches = filterSearchableItems(baseCanonicalModels, query);
|
|
947
963
|
this.#sortCanonicalModels(fuzzyMatches);
|
|
948
964
|
this.#filteredCanonicalModels = fuzzyMatches;
|
|
949
965
|
} else {
|
|
950
|
-
const fuzzyMatches =
|
|
966
|
+
const fuzzyMatches = filterSearchableItems(baseModels, query);
|
|
951
967
|
this.#sortModels(fuzzyMatches);
|
|
952
968
|
this.#filteredModels = fuzzyMatches;
|
|
953
969
|
}
|