@asterxsk/kiln 0.4.0 → 0.4.2
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/README.md +155 -155
- package/agent/AGENTS.md +67 -67
- package/agent/README.md +5 -5
- package/agent/extensions/ask-user/index.ts +418 -418
- package/agent/extensions/ask-user/install.ps1 +27 -27
- package/agent/extensions/ask-user/install.sh +24 -24
- package/agent/extensions/ask-user/package-lock.json +769 -769
- package/agent/extensions/ask-user/package.json +19 -19
- package/agent/extensions/ask-user/prompt.ts +45 -45
- package/agent/extensions/ask-user/tsconfig.json +7 -7
- package/agent/extensions/background-terminals/docs/implementation-guide.md +942 -942
- package/agent/extensions/background-terminals/index.ts +627 -627
- package/agent/extensions/background-terminals/install.ps1 +27 -27
- package/agent/extensions/background-terminals/install.sh +24 -24
- package/agent/extensions/background-terminals/manager.test.ts +735 -735
- package/agent/extensions/background-terminals/output.test.ts +109 -109
- package/agent/extensions/background-terminals/package-lock.json +769 -769
- package/agent/extensions/background-terminals/package.json +17 -17
- package/agent/extensions/background-terminals/prompt.test.ts +125 -125
- package/agent/extensions/background-terminals/ps.test.ts +82 -82
- package/agent/extensions/background-terminals/result-delivery.test.ts +44 -44
- package/agent/extensions/background-terminals/src/domain.ts +87 -87
- package/agent/extensions/background-terminals/src/manager.ts +907 -907
- package/agent/extensions/background-terminals/src/output.ts +84 -84
- package/agent/extensions/background-terminals/src/prompt.ts +142 -142
- package/agent/extensions/background-terminals/src/result-delivery.ts +27 -27
- package/agent/extensions/background-terminals/src/runtime.ts +36 -36
- package/agent/extensions/background-terminals/src/ui/output-view.ts +79 -79
- package/agent/extensions/background-terminals/src/ui/ps.ts +621 -621
- package/agent/extensions/background-terminals/tsconfig.json +7 -7
- package/agent/extensions/destructive/README.md +31 -31
- package/agent/extensions/destructive/index.ts +88 -88
- package/agent/extensions/destructive/install.ps1 +27 -27
- package/agent/extensions/destructive/install.sh +24 -24
- package/agent/extensions/file-search/index.spec.ts +443 -443
- package/agent/extensions/file-search/index.ts +459 -459
- package/agent/extensions/file-search/install.ps1 +27 -27
- package/agent/extensions/file-search/install.sh +24 -24
- package/agent/extensions/file-search/package-lock.json +2253 -2253
- package/agent/extensions/file-search/package.json +23 -23
- package/agent/extensions/file-search/src/args.ts +122 -122
- package/agent/extensions/file-search/src/binaries.ts +422 -422
- package/agent/extensions/file-search/src/output.ts +126 -126
- package/agent/extensions/file-search/src/process.ts +146 -146
- package/agent/extensions/file-search/src/prompt.ts +52 -52
- package/agent/extensions/file-search/tsconfig.json +7 -7
- package/agent/extensions/goal/README.md +50 -50
- package/agent/extensions/goal/index.ts +155 -155
- package/agent/extensions/goal/install.ps1 +27 -27
- package/agent/extensions/goal/install.sh +24 -24
- package/agent/extensions/kiln-update/README.md +38 -25
- package/agent/extensions/kiln-update/index.ts +177 -99
- package/agent/extensions/modelconf/PLAN.md +915 -915
- package/agent/extensions/modelconf/README.md +66 -66
- package/agent/extensions/modelconf/index.ts +296 -296
- package/agent/extensions/modelconf/install.ps1 +27 -27
- package/agent/extensions/modelconf/install.sh +24 -24
- package/agent/extensions/modelconf/package-lock.json +1809 -1809
- package/agent/extensions/modelconf/package.json +13 -13
- package/agent/extensions/modelconf/src/fuzzy.ts +26 -26
- package/agent/extensions/modelconf/src/glob.ts +13 -13
- package/agent/extensions/modelconf/src/persistence.test.ts +46 -46
- package/agent/extensions/modelconf/src/persistence.ts +164 -164
- package/agent/extensions/modelconf/src/ui/ModelConfView.test.ts +75 -75
- package/agent/extensions/modelconf/src/ui/ModelConfView.ts +1101 -1101
- package/agent/extensions/modelconf/tsconfig.json +15 -15
- package/agent/extensions/pi-web-access/CHANGELOG.md +690 -690
- package/agent/extensions/pi-web-access/LICENSE +21 -21
- package/agent/extensions/pi-web-access/README.md +470 -470
- package/agent/extensions/pi-web-access/SECURITY.md +5 -5
- package/agent/extensions/pi-web-access/activity.ts +101 -101
- package/agent/extensions/pi-web-access/auth-fetch.ts +148 -148
- package/agent/extensions/pi-web-access/brightdata-unlocker.ts +272 -272
- package/agent/extensions/pi-web-access/chrome-cookies.ts +669 -669
- package/agent/extensions/pi-web-access/content-find.ts +139 -139
- package/agent/extensions/pi-web-access/credential-source.ts +191 -191
- package/agent/extensions/pi-web-access/data-uri-sanitize.ts +406 -406
- package/agent/extensions/pi-web-access/datalab-pdf-extract.ts +568 -568
- package/agent/extensions/pi-web-access/declared-web-links.ts +173 -173
- package/agent/extensions/pi-web-access/evidence/CONTRACT-EVIDENCE.md +496 -496
- package/agent/extensions/pi-web-access/evidence/contract-probe.mjs +140 -140
- package/agent/extensions/pi-web-access/exa.ts +526 -526
- package/agent/extensions/pi-web-access/extract.ts +1196 -1196
- package/agent/extensions/pi-web-access/feature-config.ts +29 -29
- package/agent/extensions/pi-web-access/fetch-params.ts +111 -111
- package/agent/extensions/pi-web-access/gemini-adc.ts +298 -298
- package/agent/extensions/pi-web-access/gemini-api.ts +353 -353
- package/agent/extensions/pi-web-access/gemini-pdf-extract.ts +108 -108
- package/agent/extensions/pi-web-access/gemini-search.ts +21 -21
- package/agent/extensions/pi-web-access/gemini-url-context.ts +128 -128
- package/agent/extensions/pi-web-access/gemini-web-config.ts +101 -101
- package/agent/extensions/pi-web-access/gemini-web.ts +487 -487
- package/agent/extensions/pi-web-access/github-api.ts +197 -197
- package/agent/extensions/pi-web-access/github-extract.ts +746 -746
- package/agent/extensions/pi-web-access/github-issue-pr.ts +700 -700
- package/agent/extensions/pi-web-access/index.ts +1737 -1737
- package/agent/extensions/pi-web-access/package-lock.json +5808 -5808
- package/agent/extensions/pi-web-access/package.json +64 -64
- package/agent/extensions/pi-web-access/page-query.ts +96 -96
- package/agent/extensions/pi-web-access/pdf-extract.ts +409 -409
- package/agent/extensions/pi-web-access/promise-try.d.ts +7 -7
- package/agent/extensions/pi-web-access/query-rewrite.ts +51 -51
- package/agent/extensions/pi-web-access/render-search-error.ts +170 -170
- package/agent/extensions/pi-web-access/rsc-extract.ts +338 -338
- package/agent/extensions/pi-web-access/search-types.ts +20 -20
- package/agent/extensions/pi-web-access/source-check.ts +282 -282
- package/agent/extensions/pi-web-access/ssrf-protection.ts +526 -526
- package/agent/extensions/pi-web-access/storage.ts +521 -521
- package/agent/extensions/pi-web-access/summary-model-scope.ts +125 -125
- package/agent/extensions/pi-web-access/test/auth-fetch.test.mjs +208 -208
- package/agent/extensions/pi-web-access/test/brightdata-unlocker.test.mjs +840 -840
- package/agent/extensions/pi-web-access/test/chrome-cookie-extraction.test.mjs +441 -441
- package/agent/extensions/pi-web-access/test/config-path.test.mjs +283 -283
- package/agent/extensions/pi-web-access/test/content-find.test.mjs +25 -25
- package/agent/extensions/pi-web-access/test/credential-source.test.mjs +118 -118
- package/agent/extensions/pi-web-access/test/data-uri-sanitize.test.mjs +210 -210
- package/agent/extensions/pi-web-access/test/datalab-pdf-extract.test.mjs +552 -552
- package/agent/extensions/pi-web-access/test/declared-web-links.test.mjs +212 -212
- package/agent/extensions/pi-web-access/test/fetch-answer-storage.test.mjs +40 -40
- package/agent/extensions/pi-web-access/test/fetch-cache-storage.test.mjs +334 -334
- package/agent/extensions/pi-web-access/test/fetch-content-domain-policy.test.mjs +95 -95
- package/agent/extensions/pi-web-access/test/fetch-modes.test.mjs +53 -53
- package/agent/extensions/pi-web-access/test/fetch-not-found-guidance.test.mjs +92 -92
- package/agent/extensions/pi-web-access/test/fetch-params.test.mjs +86 -86
- package/agent/extensions/pi-web-access/test/fetch-render-call.test.mjs +34 -34
- package/agent/extensions/pi-web-access/test/fetch-routing.test.mjs +173 -173
- package/agent/extensions/pi-web-access/test/gemini-adc-auth.test.mjs +257 -257
- package/agent/extensions/pi-web-access/test/gemini-api-transport.test.mjs +170 -170
- package/agent/extensions/pi-web-access/test/gemini-pdf-extract.test.mjs +133 -133
- package/agent/extensions/pi-web-access/test/gemini-web-cookie-opt-in.test.mjs +178 -178
- package/agent/extensions/pi-web-access/test/gemini-web-header-overflow.test.mjs +148 -148
- package/agent/extensions/pi-web-access/test/get-search-content.test.mjs +223 -223
- package/agent/extensions/pi-web-access/test/github-extract.test.mjs +378 -378
- package/agent/extensions/pi-web-access/test/github-issue-pr.test.mjs +565 -565
- package/agent/extensions/pi-web-access/test/inline-content-config.test.mjs +99 -99
- package/agent/extensions/pi-web-access/test/lazy-extract-load.test.mjs +118 -118
- package/agent/extensions/pi-web-access/test/local-video-oversize.test.mjs +52 -52
- package/agent/extensions/pi-web-access/test/package-typebox-dependency.test.mjs +50 -50
- package/agent/extensions/pi-web-access/test/page-query.test.mjs +51 -51
- package/agent/extensions/pi-web-access/test/pdf-config.test.mjs +140 -140
- package/agent/extensions/pi-web-access/test/pdf-extract.test.mjs +500 -500
- package/agent/extensions/pi-web-access/test/proxy-transport.test.mjs +286 -286
- package/agent/extensions/pi-web-access/test/query-rewrite.test.mjs +52 -52
- package/agent/extensions/pi-web-access/test/rsc-fallback.test.mjs +102 -102
- package/agent/extensions/pi-web-access/test/search-error-render.test.mjs +152 -152
- package/agent/extensions/pi-web-access/test/search-providers.test.mjs +274 -274
- package/agent/extensions/pi-web-access/test/source-check.test.mjs +179 -179
- package/agent/extensions/pi-web-access/test/ssrf-allow-ranges-config.test.mjs +205 -205
- package/agent/extensions/pi-web-access/test/ssrf-protection.test.mjs +456 -456
- package/agent/extensions/pi-web-access/test/summary-model-scope.test.mjs +106 -106
- package/agent/extensions/pi-web-access/test/tool-registration-config.test.mjs +182 -182
- package/agent/extensions/pi-web-access/test/web-search-answer-render.test.mjs +66 -66
- package/agent/extensions/pi-web-access/test/youtube-extract-errors.test.mjs +64 -64
- package/agent/extensions/pi-web-access/tsconfig.json +11 -11
- package/agent/extensions/pi-web-access/utils.ts +451 -451
- package/agent/extensions/pi-web-access/video-extract.ts +392 -392
- package/agent/extensions/pi-web-access/youtube-extract.ts +328 -328
- package/agent/extensions/shared/activity-status.ts +31 -31
- package/agent/extensions/shared/child-session.test.ts +270 -270
- package/agent/extensions/shared/child-session.ts +148 -148
- package/agent/extensions/shared/context-utilization.test.ts +48 -48
- package/agent/extensions/shared/context-utilization.ts +47 -47
- package/agent/extensions/shared/dashboard-state.ts +99 -99
- package/agent/extensions/shared/install.ps1 +27 -27
- package/agent/extensions/shared/install.sh +24 -24
- package/agent/extensions/shared/tool-call-timeout.test.ts +117 -117
- package/agent/extensions/shared/tool-call-timeout.ts +104 -104
- package/agent/extensions/skillsconf/README.md +74 -74
- package/agent/extensions/skillsconf/index.ts +92 -92
- package/agent/extensions/skillsconf/install.ps1 +27 -27
- package/agent/extensions/skillsconf/install.sh +24 -24
- package/agent/extensions/skillsconf/package-lock.json +1809 -1809
- package/agent/extensions/skillsconf/package.json +18 -18
- package/agent/extensions/skillsconf/src/delete-skill.test.ts +64 -64
- package/agent/extensions/skillsconf/src/delete-skill.ts +45 -45
- package/agent/extensions/skillsconf/src/filter.test.ts +80 -80
- package/agent/extensions/skillsconf/src/filter.ts +74 -74
- package/agent/extensions/skillsconf/src/fuzzy.ts +26 -26
- package/agent/extensions/skillsconf/src/persistence.test.ts +72 -72
- package/agent/extensions/skillsconf/src/persistence.ts +169 -169
- package/agent/extensions/skillsconf/src/ui/SkillConfView.test.ts +337 -337
- package/agent/extensions/skillsconf/src/ui/SkillConfView.ts +758 -758
- package/agent/extensions/skillsconf/src/ui/text-input.ts +91 -91
- package/agent/extensions/skillsconf/src/ui/tui-helpers.ts +144 -144
- package/agent/extensions/skillsconf/tsconfig.json +15 -15
- package/agent/extensions/statusline/index.ts +273 -282
- package/agent/extensions/statusline/install.ps1 +27 -27
- package/agent/extensions/statusline/install.sh +24 -24
- package/agent/extensions/subagents/by-the-way.test.ts +29 -29
- package/agent/extensions/subagents/claude.test.ts +119 -119
- package/agent/extensions/subagents/codex.test.ts +102 -102
- package/agent/extensions/subagents/context-usage.test.ts +107 -107
- package/agent/extensions/subagents/docs/design-plan.md +568 -568
- package/agent/extensions/subagents/docs/effect-v4-extension-guide.md +354 -354
- package/agent/extensions/subagents/docs/effect-v4-notes.md +571 -571
- package/agent/extensions/subagents/index.ts +779 -779
- package/agent/extensions/subagents/install.ps1 +27 -27
- package/agent/extensions/subagents/install.sh +24 -24
- package/agent/extensions/subagents/manager.test.ts +276 -276
- package/agent/extensions/subagents/package-lock.json +2244 -2244
- package/agent/extensions/subagents/package.json +19 -19
- package/agent/extensions/subagents/result-delivery.test.ts +27 -27
- package/agent/extensions/subagents/src/backend.ts +73 -73
- package/agent/extensions/subagents/src/backends/claude.ts +701 -701
- package/agent/extensions/subagents/src/backends/codex.ts +1060 -1060
- package/agent/extensions/subagents/src/backends/pi.ts +575 -575
- package/agent/extensions/subagents/src/backends/stub.ts +300 -300
- package/agent/extensions/subagents/src/by-the-way.ts +21 -21
- package/agent/extensions/subagents/src/domain.ts +253 -253
- package/agent/extensions/subagents/src/format.ts +74 -74
- package/agent/extensions/subagents/src/manager.ts +736 -736
- package/agent/extensions/subagents/src/prompt.ts +92 -92
- package/agent/extensions/subagents/src/result-delivery.ts +20 -20
- package/agent/extensions/subagents/src/runtime.ts +53 -53
- package/agent/extensions/subagents/src/ui/takeover.ts +583 -583
- package/agent/extensions/subagents/src/ui/transcript.ts +201 -201
- package/agent/extensions/subagents/takeover.test.ts +29 -29
- package/agent/extensions/subagents/tsconfig.json +7 -7
- package/agent/extensions/todo/AGENTS.md +38 -38
- package/agent/extensions/todo/LICENSE +21 -21
- package/agent/extensions/todo/config.ts +55 -55
- package/agent/extensions/todo/index.ts +151 -151
- package/agent/extensions/todo/install.ps1 +27 -27
- package/agent/extensions/todo/install.sh +24 -24
- package/agent/extensions/todo/locales/de.json +17 -17
- package/agent/extensions/todo/locales/en.json +15 -15
- package/agent/extensions/todo/locales/es.json +17 -17
- package/agent/extensions/todo/locales/fr.json +17 -17
- package/agent/extensions/todo/locales/pt-BR.json +17 -17
- package/agent/extensions/todo/locales/pt.json +17 -17
- package/agent/extensions/todo/locales/ru.json +17 -17
- package/agent/extensions/todo/locales/uk.json +17 -17
- package/agent/extensions/todo/locales/zh.json +17 -17
- package/agent/extensions/todo/package-lock.json +3358 -3358
- package/agent/extensions/todo/package.json +67 -67
- package/agent/extensions/todo/state/i18n-bridge.ts +64 -64
- package/agent/extensions/todo/state/invariants.ts +20 -20
- package/agent/extensions/todo/state/replay.ts +38 -38
- package/agent/extensions/todo/state/selectors.ts +107 -107
- package/agent/extensions/todo/state/state-reducer.ts +326 -326
- package/agent/extensions/todo/state/state.ts +18 -18
- package/agent/extensions/todo/state/store.ts +82 -82
- package/agent/extensions/todo/state/task-graph.ts +57 -57
- package/agent/extensions/todo/todo-overlay.ts +200 -200
- package/agent/extensions/todo/todo.ts +155 -155
- package/agent/extensions/todo/tool/response-envelope.ts +109 -109
- package/agent/extensions/todo/tool/types.ts +206 -206
- package/agent/extensions/todo/view/format.ts +177 -177
- package/agent/extensions/trim-context/README.md +54 -54
- package/agent/extensions/trim-context/index.ts +487 -487
- package/agent/extensions/trim-context/install.ps1 +27 -27
- package/agent/extensions/trim-context/install.sh +24 -24
- package/agent/keybindings.json +7 -7
- package/agent/version.txt +1 -1
- package/bin/kiln.js +20 -13
- package/package.json +1 -1
- package/agent/extensions/taste/index.ts +0 -443
- package/agent/extensions/taste/install.ps1 +0 -27
- package/agent/extensions/taste/install.sh +0 -24
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "modelconf",
|
|
3
|
-
"private": true,
|
|
4
|
-
"type": "module",
|
|
5
|
-
"version": "0.1.0",
|
|
6
|
-
"description": "Per-provider model visibility manager with fuzzy search and bulk glob",
|
|
7
|
-
"scripts": {
|
|
8
|
-
"check": "tsc --noEmit"
|
|
9
|
-
},
|
|
10
|
-
"devDependencies": { "typescript": "^5.6.0" },
|
|
11
|
-
"allowScripts": {},
|
|
12
|
-
"dependencies": {}
|
|
13
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "modelconf",
|
|
3
|
+
"private": true,
|
|
4
|
+
"type": "module",
|
|
5
|
+
"version": "0.1.0",
|
|
6
|
+
"description": "Per-provider model visibility manager with fuzzy search and bulk glob",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"check": "tsc --noEmit"
|
|
9
|
+
},
|
|
10
|
+
"devDependencies": { "typescript": "^5.6.0" },
|
|
11
|
+
"allowScripts": {},
|
|
12
|
+
"dependencies": {}
|
|
13
|
+
}
|
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
export function fuzzyScore(query: string, target: string): number | null {
|
|
2
|
-
if (!query) return 0;
|
|
3
|
-
const q = query.toLowerCase();
|
|
4
|
-
const t = target.toLowerCase();
|
|
5
|
-
let qi = 0, ti = 0, score = 0, last = -2;
|
|
6
|
-
for (; qi < q.length && ti < t.length; ti++) {
|
|
7
|
-
if (q[qi] === t[ti]) {
|
|
8
|
-
// bonus for contiguous + start-of-word
|
|
9
|
-
score += (ti === last + 1 ? 2 : 1);
|
|
10
|
-
if (ti === 0 || t[ti-1] === "/" || t[ti-1] === "-" || t[ti-1] === "_") score += 2;
|
|
11
|
-
last = ti; qi++;
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
if (qi !== q.length) return null;
|
|
15
|
-
// penalize longer targets slightly
|
|
16
|
-
score -= Math.floor(t.length / 20);
|
|
17
|
-
return score;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function fuzzyFilter<T>(query: string, items: T[], key: (t:T)=>string): T[] {
|
|
21
|
-
if (!query.trim()) return items;
|
|
22
|
-
const scored = items.map(i => ({ i, s: fuzzyScore(query, key(i)) }))
|
|
23
|
-
.filter(x => x.s !== null) as Array<{i:T; s:number}>;
|
|
24
|
-
scored.sort((a,b)=> b.s - a.s);
|
|
25
|
-
return scored.map(x=>x.i);
|
|
26
|
-
}
|
|
1
|
+
export function fuzzyScore(query: string, target: string): number | null {
|
|
2
|
+
if (!query) return 0;
|
|
3
|
+
const q = query.toLowerCase();
|
|
4
|
+
const t = target.toLowerCase();
|
|
5
|
+
let qi = 0, ti = 0, score = 0, last = -2;
|
|
6
|
+
for (; qi < q.length && ti < t.length; ti++) {
|
|
7
|
+
if (q[qi] === t[ti]) {
|
|
8
|
+
// bonus for contiguous + start-of-word
|
|
9
|
+
score += (ti === last + 1 ? 2 : 1);
|
|
10
|
+
if (ti === 0 || t[ti-1] === "/" || t[ti-1] === "-" || t[ti-1] === "_") score += 2;
|
|
11
|
+
last = ti; qi++;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
if (qi !== q.length) return null;
|
|
15
|
+
// penalize longer targets slightly
|
|
16
|
+
score -= Math.floor(t.length / 20);
|
|
17
|
+
return score;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function fuzzyFilter<T>(query: string, items: T[], key: (t:T)=>string): T[] {
|
|
21
|
+
if (!query.trim()) return items;
|
|
22
|
+
const scored = items.map(i => ({ i, s: fuzzyScore(query, key(i)) }))
|
|
23
|
+
.filter(x => x.s !== null) as Array<{i:T; s:number}>;
|
|
24
|
+
scored.sort((a,b)=> b.s - a.s);
|
|
25
|
+
return scored.map(x=>x.i);
|
|
26
|
+
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
export function globToRegExp(pattern: string): RegExp {
|
|
2
|
-
let p = pattern;
|
|
3
|
-
if (!p.includes("*") && !p.includes("?")) p = `*${p}*`;
|
|
4
|
-
const esc = p.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".");
|
|
5
|
-
return new RegExp(`^${esc}$`, "i");
|
|
6
|
-
}
|
|
7
|
-
export function matchesGlob(input: string, pattern: string): boolean {
|
|
8
|
-
return globToRegExp(pattern).test(input);
|
|
9
|
-
}
|
|
10
|
-
export function filterByGlob<T>(pattern: string, items: T[], key:(t:T)=>string): T[] {
|
|
11
|
-
const rx = globToRegExp(pattern);
|
|
12
|
-
return items.filter(i => rx.test(key(i)));
|
|
13
|
-
}
|
|
1
|
+
export function globToRegExp(pattern: string): RegExp {
|
|
2
|
+
let p = pattern;
|
|
3
|
+
if (!p.includes("*") && !p.includes("?")) p = `*${p}*`;
|
|
4
|
+
const esc = p.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".");
|
|
5
|
+
return new RegExp(`^${esc}$`, "i");
|
|
6
|
+
}
|
|
7
|
+
export function matchesGlob(input: string, pattern: string): boolean {
|
|
8
|
+
return globToRegExp(pattern).test(input);
|
|
9
|
+
}
|
|
10
|
+
export function filterByGlob<T>(pattern: string, items: T[], key:(t:T)=>string): T[] {
|
|
11
|
+
const rx = globToRegExp(pattern);
|
|
12
|
+
return items.filter(i => rx.test(key(i)));
|
|
13
|
+
}
|
|
@@ -1,46 +1,46 @@
|
|
|
1
|
-
import { isVisible, toModelId, getVisibilityMap, toggleInEnabled, applyBulk } from "./persistence.js";
|
|
2
|
-
import type { ModelId } from "./persistence.js";
|
|
3
|
-
import assert from "node:assert";
|
|
4
|
-
|
|
5
|
-
const all = ["opencode/a","opencode/b","9router/c"] as unknown as ModelId[];
|
|
6
|
-
|
|
7
|
-
// isVisible (denylist: the list holds HIDDEN models)
|
|
8
|
-
assert.equal(isVisible("opencode/a" as ModelId, undefined, [...all]), true);
|
|
9
|
-
assert.equal(isVisible("opencode/a" as ModelId, [], [...all]), true);
|
|
10
|
-
assert.equal(isVisible("opencode/a" as ModelId, ["opencode/a"], [...all]), false);
|
|
11
|
-
assert.equal(isVisible("opencode/b" as ModelId, ["opencode/a"], [...all]), true);
|
|
12
|
-
|
|
13
|
-
// toModelId
|
|
14
|
-
assert.equal(toModelId({ provider: "opencode", id: "a" }), "opencode/a");
|
|
15
|
-
|
|
16
|
-
// getVisibilityMap
|
|
17
|
-
const vis = getVisibilityMap([{provider:"opencode",id:"a"},{provider:"opencode",id:"b"}], ["opencode/a"]);
|
|
18
|
-
assert.equal(vis.get("opencode/a" as ModelId), false);
|
|
19
|
-
assert.equal(vis.get("opencode/b" as ModelId), true);
|
|
20
|
-
const visAll = getVisibilityMap([{provider:"opencode",id:"a"},{provider:"opencode",id:"b"}], undefined);
|
|
21
|
-
assert.equal(visAll.get("opencode/a" as ModelId), true);
|
|
22
|
-
assert.equal(visAll.get("opencode/b" as ModelId), true);
|
|
23
|
-
|
|
24
|
-
// toggleInEnabled (denylist: toggling a visible model HIDES it and vice versa)
|
|
25
|
-
// undefined => hide just this one
|
|
26
|
-
assert.deepEqual(toggleInEnabled("opencode/a" as ModelId, undefined, [...all]), ["opencode/a"]);
|
|
27
|
-
// toggle visible => append exact id
|
|
28
|
-
assert.deepEqual(toggleInEnabled("9router/c" as ModelId, ["opencode/a"], [...all]), ["opencode/a","9router/c"]);
|
|
29
|
-
// toggle hidden => remove exact id
|
|
30
|
-
assert.deepEqual(toggleInEnabled("opencode/a" as ModelId, ["opencode/a","opencode/b"], [...all]), ["opencode/b"]);
|
|
31
|
-
// removing the last hidden id collapses to undefined (all visible)
|
|
32
|
-
assert.equal(toggleInEnabled("opencode/a" as ModelId, ["opencode/a"], [...all]), undefined);
|
|
33
|
-
// hidden via glob: showing removes the matching pattern so the model becomes visible
|
|
34
|
-
assert.equal(toggleInEnabled("opencode/a" as ModelId, ["*a"], [...all]), undefined);
|
|
35
|
-
|
|
36
|
-
// applyBulk exclude = hide (union into denylist, sorted)
|
|
37
|
-
assert.deepEqual(applyBulk(undefined, [...all], ["opencode/a" as ModelId], "exclude"), ["opencode/a"]);
|
|
38
|
-
assert.deepEqual(applyBulk(["opencode/a","opencode/b","9router/c"] as unknown as ModelId[], [...all], ["opencode/a" as ModelId], "exclude"), ["9router/c","opencode/a","opencode/b"]);
|
|
39
|
-
|
|
40
|
-
// applyBulk include = show (remove exact ids from denylist)
|
|
41
|
-
assert.deepEqual(applyBulk(["opencode/a","opencode/b"] as unknown as ModelId[], [...all], ["opencode/b" as ModelId], "include"), ["opencode/a"]);
|
|
42
|
-
assert.equal(applyBulk(undefined, [...all], [...all], "include"), undefined); // all visible => undefined
|
|
43
|
-
assert.deepEqual(applyBulk(["opencode/a","opencode/b","9router/c"] as unknown as ModelId[], [...all], [] as ModelId[], "include"), ["opencode/a","opencode/b","9router/c"]); // empty selection changes nothing
|
|
44
|
-
assert.deepEqual(applyBulk(["*luna*","opencode/a"] as unknown as ModelId[], [...all], ["opencode/a" as ModelId], "include"), ["*luna*"]); // exact-only removal keeps unrelated globs
|
|
45
|
-
|
|
46
|
-
console.log("persistence test pass");
|
|
1
|
+
import { isVisible, toModelId, getVisibilityMap, toggleInEnabled, applyBulk } from "./persistence.js";
|
|
2
|
+
import type { ModelId } from "./persistence.js";
|
|
3
|
+
import assert from "node:assert";
|
|
4
|
+
|
|
5
|
+
const all = ["opencode/a","opencode/b","9router/c"] as unknown as ModelId[];
|
|
6
|
+
|
|
7
|
+
// isVisible (denylist: the list holds HIDDEN models)
|
|
8
|
+
assert.equal(isVisible("opencode/a" as ModelId, undefined, [...all]), true);
|
|
9
|
+
assert.equal(isVisible("opencode/a" as ModelId, [], [...all]), true);
|
|
10
|
+
assert.equal(isVisible("opencode/a" as ModelId, ["opencode/a"], [...all]), false);
|
|
11
|
+
assert.equal(isVisible("opencode/b" as ModelId, ["opencode/a"], [...all]), true);
|
|
12
|
+
|
|
13
|
+
// toModelId
|
|
14
|
+
assert.equal(toModelId({ provider: "opencode", id: "a" }), "opencode/a");
|
|
15
|
+
|
|
16
|
+
// getVisibilityMap
|
|
17
|
+
const vis = getVisibilityMap([{provider:"opencode",id:"a"},{provider:"opencode",id:"b"}], ["opencode/a"]);
|
|
18
|
+
assert.equal(vis.get("opencode/a" as ModelId), false);
|
|
19
|
+
assert.equal(vis.get("opencode/b" as ModelId), true);
|
|
20
|
+
const visAll = getVisibilityMap([{provider:"opencode",id:"a"},{provider:"opencode",id:"b"}], undefined);
|
|
21
|
+
assert.equal(visAll.get("opencode/a" as ModelId), true);
|
|
22
|
+
assert.equal(visAll.get("opencode/b" as ModelId), true);
|
|
23
|
+
|
|
24
|
+
// toggleInEnabled (denylist: toggling a visible model HIDES it and vice versa)
|
|
25
|
+
// undefined => hide just this one
|
|
26
|
+
assert.deepEqual(toggleInEnabled("opencode/a" as ModelId, undefined, [...all]), ["opencode/a"]);
|
|
27
|
+
// toggle visible => append exact id
|
|
28
|
+
assert.deepEqual(toggleInEnabled("9router/c" as ModelId, ["opencode/a"], [...all]), ["opencode/a","9router/c"]);
|
|
29
|
+
// toggle hidden => remove exact id
|
|
30
|
+
assert.deepEqual(toggleInEnabled("opencode/a" as ModelId, ["opencode/a","opencode/b"], [...all]), ["opencode/b"]);
|
|
31
|
+
// removing the last hidden id collapses to undefined (all visible)
|
|
32
|
+
assert.equal(toggleInEnabled("opencode/a" as ModelId, ["opencode/a"], [...all]), undefined);
|
|
33
|
+
// hidden via glob: showing removes the matching pattern so the model becomes visible
|
|
34
|
+
assert.equal(toggleInEnabled("opencode/a" as ModelId, ["*a"], [...all]), undefined);
|
|
35
|
+
|
|
36
|
+
// applyBulk exclude = hide (union into denylist, sorted)
|
|
37
|
+
assert.deepEqual(applyBulk(undefined, [...all], ["opencode/a" as ModelId], "exclude"), ["opencode/a"]);
|
|
38
|
+
assert.deepEqual(applyBulk(["opencode/a","opencode/b","9router/c"] as unknown as ModelId[], [...all], ["opencode/a" as ModelId], "exclude"), ["9router/c","opencode/a","opencode/b"]);
|
|
39
|
+
|
|
40
|
+
// applyBulk include = show (remove exact ids from denylist)
|
|
41
|
+
assert.deepEqual(applyBulk(["opencode/a","opencode/b"] as unknown as ModelId[], [...all], ["opencode/b" as ModelId], "include"), ["opencode/a"]);
|
|
42
|
+
assert.equal(applyBulk(undefined, [...all], [...all], "include"), undefined); // all visible => undefined
|
|
43
|
+
assert.deepEqual(applyBulk(["opencode/a","opencode/b","9router/c"] as unknown as ModelId[], [...all], [] as ModelId[], "include"), ["opencode/a","opencode/b","9router/c"]); // empty selection changes nothing
|
|
44
|
+
assert.deepEqual(applyBulk(["*luna*","opencode/a"] as unknown as ModelId[], [...all], ["opencode/a" as ModelId], "include"), ["*luna*"]); // exact-only removal keeps unrelated globs
|
|
45
|
+
|
|
46
|
+
console.log("persistence test pass");
|
|
@@ -1,164 +1,164 @@
|
|
|
1
|
-
import fs from "node:fs/promises";
|
|
2
|
-
import os from "node:os";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
import { globToRegExp } from "./glob.js";
|
|
5
|
-
|
|
6
|
-
export type ModelId = `${string}/${string}`;
|
|
7
|
-
|
|
8
|
-
export function toModelId(m: { provider: string; id: string }): ModelId {
|
|
9
|
-
return `${m.provider}/${m.id}` as ModelId;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
function settingsPath(): string {
|
|
13
|
-
return path.join(os.homedir(), ".pi", "agent", "settings.json");
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const VALID_THINKING = new Set(["off", "minimal", "low", "medium", "high", "xhigh", "max"]);
|
|
17
|
-
function stripThinkingLevel(pattern: string): string {
|
|
18
|
-
const idx = pattern.lastIndexOf(":");
|
|
19
|
-
if (idx !== -1) {
|
|
20
|
-
const suffix = pattern.slice(idx + 1);
|
|
21
|
-
if (VALID_THINKING.has(suffix)) return pattern.slice(0, idx);
|
|
22
|
-
}
|
|
23
|
-
return pattern;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function matchesPattern(modelRef: string, pattern: string): boolean {
|
|
27
|
-
const pat = stripThinkingLevel(pattern);
|
|
28
|
-
const lowerRef = modelRef.toLowerCase();
|
|
29
|
-
const lowerPat = pat.toLowerCase();
|
|
30
|
-
const bareId = modelRef.split("/").slice(1).join("/")?.toLowerCase() ?? lowerRef;
|
|
31
|
-
const hasGlob = /[*?\[\]]/.test(pat);
|
|
32
|
-
if (hasGlob) {
|
|
33
|
-
const rx = globToRegExp(pat);
|
|
34
|
-
if (rx.test(modelRef)) return true;
|
|
35
|
-
if (rx.test(bareId)) return true;
|
|
36
|
-
return false;
|
|
37
|
-
} else {
|
|
38
|
-
return lowerRef === lowerPat || bareId === lowerPat;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function modelMatchesAnyPattern(modelRef: string, patterns: string[]): boolean {
|
|
43
|
-
for (const p of patterns) if (matchesPattern(modelRef, p)) return true;
|
|
44
|
-
return false;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// ---------- hiddenModels (denylist) — hides from full picker list ----------
|
|
48
|
-
export async function loadHiddenModels(): Promise<string[] | undefined> {
|
|
49
|
-
try {
|
|
50
|
-
const raw = await fs.readFile(settingsPath(), "utf8");
|
|
51
|
-
const j = JSON.parse(raw) as { hiddenModels?: string[] };
|
|
52
|
-
return j.hiddenModels;
|
|
53
|
-
} catch { return undefined; }
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// Backward compat alias — old code used enabledModels
|
|
57
|
-
export async function loadEnabledModels(): Promise<string[] | undefined> {
|
|
58
|
-
return loadHiddenModels();
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export async function saveHiddenModels(ids: string[] | undefined): Promise<void> {
|
|
62
|
-
const p = settingsPath();
|
|
63
|
-
let j: Record<string, unknown> = {};
|
|
64
|
-
try {
|
|
65
|
-
const raw = await fs.readFile(p, "utf8");
|
|
66
|
-
j = JSON.parse(raw) as Record<string, unknown>;
|
|
67
|
-
} catch (e: any) {
|
|
68
|
-
if ((e as any)?.code !== "ENOENT") {
|
|
69
|
-
j = {};
|
|
70
|
-
try { const raw = await fs.readFile(p, "utf8"); JSON.parse(raw); } catch {}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
if (ids === undefined || ids.length === 0) delete (j as any).hiddenModels;
|
|
74
|
-
else (j as any).hiddenModels = ids;
|
|
75
|
-
// Do not touch enabledModels — this extension no longer manages it.
|
|
76
|
-
await fs.writeFile(p, JSON.stringify(j, null, 2) + "\n", "utf8");
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
export async function saveEnabledModels(ids: string[] | undefined): Promise<void> {
|
|
80
|
-
return saveHiddenModels(ids);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
export function isHidden(modelId: ModelId, hidden: string[] | undefined): boolean {
|
|
84
|
-
if (!hidden || hidden.length === 0) return false;
|
|
85
|
-
return modelMatchesAnyPattern(modelId, hidden) || modelMatchesAnyPattern(modelId.split("/").slice(1).join("/") as ModelId, hidden);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export function isVisible(modelId: ModelId, hidden: string[] | undefined, _allIds: ModelId[]): boolean {
|
|
89
|
-
if (!hidden || hidden.length === 0) return true;
|
|
90
|
-
return !isHidden(modelId, hidden);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
export function getVisibilityMap(all: Array<{provider:string;id:string}>, hidden: string[]|undefined): Map<ModelId, boolean> {
|
|
94
|
-
const map = new Map<ModelId, boolean>();
|
|
95
|
-
const allIds = all.map(toModelId);
|
|
96
|
-
for (const m of all) map.set(toModelId(m), isVisible(toModelId(m), hidden, allIds));
|
|
97
|
-
return map;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// Hide/show operates on the FULL model list (allIds = full catalogue).
|
|
101
|
-
// hidden is a denylist: adding = hide, removing = show.
|
|
102
|
-
export function toggleHidden(modelId: ModelId, hidden: string[] | undefined, _allIds: ModelId[]): string[] | undefined {
|
|
103
|
-
if (!hidden || hidden.length === 0) {
|
|
104
|
-
return [modelId];
|
|
105
|
-
}
|
|
106
|
-
// Exact match toggle. If hidden contains globs that already hide this model, we still toggle exact id.
|
|
107
|
-
// If model is hidden via pattern, toggling will add exact? Instead remove matching patterns? Simplify: exact toggle.
|
|
108
|
-
const hasExact = hidden.includes(modelId);
|
|
109
|
-
// Also consider pattern hiding: if model matches a pattern, showing should remove? But we can't know which pattern.
|
|
110
|
-
// For now, if hidden via pattern and not exact, toggling to "show" should add an exception? Simpler: if currently hidden (pattern or exact), remove exact and also remove any pattern that matches it? That's ambiguous.
|
|
111
|
-
// We treat visibility via pattern: if isHidden true but not exact, toggling "show" means we need to keep patterns but add exception — not supported.
|
|
112
|
-
// Simplest: if currently hidden, remove exact if present, otherwise add exact and keep patterns — model stays hidden. To actually show, we'd need to remove matching patterns.
|
|
113
|
-
// So if hidden via pattern, show action should remove matching patterns.
|
|
114
|
-
const currentlyHidden = isHidden(modelId, hidden);
|
|
115
|
-
if (currentlyHidden) {
|
|
116
|
-
// Remove exact if present
|
|
117
|
-
let next = hidden.filter(id => id !== modelId);
|
|
118
|
-
// Also remove any glob pattern that matches this model (so it becomes visible)
|
|
119
|
-
next = next.filter(p => !matchesPattern(modelId, p));
|
|
120
|
-
if (next.length === 0) return undefined;
|
|
121
|
-
return next;
|
|
122
|
-
} else {
|
|
123
|
-
// Currently visible — hide by adding exact id
|
|
124
|
-
if (hasExact) return hidden.filter(id => id !== modelId);
|
|
125
|
-
return [...hidden, modelId];
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// Aliases for old names
|
|
130
|
-
export function toggleInEnabled(modelId: ModelId, hidden: string[] | undefined, allIds: ModelId[]): string[] | undefined {
|
|
131
|
-
return toggleHidden(modelId, hidden, allIds);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
export function applyBulk(hidden: string[]|undefined, allIds: ModelId[], matching: ModelId[], action: "include"|"exclude"): string[]|undefined {
|
|
135
|
-
// For denylist: "exclude" = hide (add to hidden), "include" = show (remove from hidden)
|
|
136
|
-
if (action === "exclude") {
|
|
137
|
-
const base = hidden === undefined ? [] : [...hidden];
|
|
138
|
-
const set = new Set(base);
|
|
139
|
-
for (const id of matching) set.add(id);
|
|
140
|
-
const arr = [...set].sort();
|
|
141
|
-
if (arr.length === 0) return undefined;
|
|
142
|
-
return arr;
|
|
143
|
-
} else {
|
|
144
|
-
// include = show
|
|
145
|
-
if (!hidden || hidden.length === 0) return undefined;
|
|
146
|
-
// Remove exact ids and any pattern that matches them? For now remove exact and patterns that match
|
|
147
|
-
let next = [...hidden];
|
|
148
|
-
for (const id of matching) {
|
|
149
|
-
next = next.filter(p => p !== id && !matchesPattern(id, p));
|
|
150
|
-
// If p is exact id matching model, remove; if p is glob that would match id, also remove? But glob may hide other models — removing it would unhide others unintentionally.
|
|
151
|
-
// Better only remove exact matches for bulk include, keep globs.
|
|
152
|
-
// Rebuild: only remove exact ids
|
|
153
|
-
}
|
|
154
|
-
// Recompute strictly exact removal to avoid over-removing globs
|
|
155
|
-
const exactSet = new Set(matching as string[]);
|
|
156
|
-
next = (hidden as string[]).filter(p => {
|
|
157
|
-
// If p is exact id in matching, remove
|
|
158
|
-
if (exactSet.has(p)) return false;
|
|
159
|
-
return true;
|
|
160
|
-
});
|
|
161
|
-
if (next.length === 0) return undefined;
|
|
162
|
-
return next;
|
|
163
|
-
}
|
|
164
|
-
}
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { globToRegExp } from "./glob.js";
|
|
5
|
+
|
|
6
|
+
export type ModelId = `${string}/${string}`;
|
|
7
|
+
|
|
8
|
+
export function toModelId(m: { provider: string; id: string }): ModelId {
|
|
9
|
+
return `${m.provider}/${m.id}` as ModelId;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function settingsPath(): string {
|
|
13
|
+
return path.join(os.homedir(), ".pi", "agent", "settings.json");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const VALID_THINKING = new Set(["off", "minimal", "low", "medium", "high", "xhigh", "max"]);
|
|
17
|
+
function stripThinkingLevel(pattern: string): string {
|
|
18
|
+
const idx = pattern.lastIndexOf(":");
|
|
19
|
+
if (idx !== -1) {
|
|
20
|
+
const suffix = pattern.slice(idx + 1);
|
|
21
|
+
if (VALID_THINKING.has(suffix)) return pattern.slice(0, idx);
|
|
22
|
+
}
|
|
23
|
+
return pattern;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function matchesPattern(modelRef: string, pattern: string): boolean {
|
|
27
|
+
const pat = stripThinkingLevel(pattern);
|
|
28
|
+
const lowerRef = modelRef.toLowerCase();
|
|
29
|
+
const lowerPat = pat.toLowerCase();
|
|
30
|
+
const bareId = modelRef.split("/").slice(1).join("/")?.toLowerCase() ?? lowerRef;
|
|
31
|
+
const hasGlob = /[*?\[\]]/.test(pat);
|
|
32
|
+
if (hasGlob) {
|
|
33
|
+
const rx = globToRegExp(pat);
|
|
34
|
+
if (rx.test(modelRef)) return true;
|
|
35
|
+
if (rx.test(bareId)) return true;
|
|
36
|
+
return false;
|
|
37
|
+
} else {
|
|
38
|
+
return lowerRef === lowerPat || bareId === lowerPat;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function modelMatchesAnyPattern(modelRef: string, patterns: string[]): boolean {
|
|
43
|
+
for (const p of patterns) if (matchesPattern(modelRef, p)) return true;
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// ---------- hiddenModels (denylist) — hides from full picker list ----------
|
|
48
|
+
export async function loadHiddenModels(): Promise<string[] | undefined> {
|
|
49
|
+
try {
|
|
50
|
+
const raw = await fs.readFile(settingsPath(), "utf8");
|
|
51
|
+
const j = JSON.parse(raw) as { hiddenModels?: string[] };
|
|
52
|
+
return j.hiddenModels;
|
|
53
|
+
} catch { return undefined; }
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Backward compat alias — old code used enabledModels
|
|
57
|
+
export async function loadEnabledModels(): Promise<string[] | undefined> {
|
|
58
|
+
return loadHiddenModels();
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export async function saveHiddenModels(ids: string[] | undefined): Promise<void> {
|
|
62
|
+
const p = settingsPath();
|
|
63
|
+
let j: Record<string, unknown> = {};
|
|
64
|
+
try {
|
|
65
|
+
const raw = await fs.readFile(p, "utf8");
|
|
66
|
+
j = JSON.parse(raw) as Record<string, unknown>;
|
|
67
|
+
} catch (e: any) {
|
|
68
|
+
if ((e as any)?.code !== "ENOENT") {
|
|
69
|
+
j = {};
|
|
70
|
+
try { const raw = await fs.readFile(p, "utf8"); JSON.parse(raw); } catch {}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (ids === undefined || ids.length === 0) delete (j as any).hiddenModels;
|
|
74
|
+
else (j as any).hiddenModels = ids;
|
|
75
|
+
// Do not touch enabledModels — this extension no longer manages it.
|
|
76
|
+
await fs.writeFile(p, JSON.stringify(j, null, 2) + "\n", "utf8");
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export async function saveEnabledModels(ids: string[] | undefined): Promise<void> {
|
|
80
|
+
return saveHiddenModels(ids);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function isHidden(modelId: ModelId, hidden: string[] | undefined): boolean {
|
|
84
|
+
if (!hidden || hidden.length === 0) return false;
|
|
85
|
+
return modelMatchesAnyPattern(modelId, hidden) || modelMatchesAnyPattern(modelId.split("/").slice(1).join("/") as ModelId, hidden);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function isVisible(modelId: ModelId, hidden: string[] | undefined, _allIds: ModelId[]): boolean {
|
|
89
|
+
if (!hidden || hidden.length === 0) return true;
|
|
90
|
+
return !isHidden(modelId, hidden);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function getVisibilityMap(all: Array<{provider:string;id:string}>, hidden: string[]|undefined): Map<ModelId, boolean> {
|
|
94
|
+
const map = new Map<ModelId, boolean>();
|
|
95
|
+
const allIds = all.map(toModelId);
|
|
96
|
+
for (const m of all) map.set(toModelId(m), isVisible(toModelId(m), hidden, allIds));
|
|
97
|
+
return map;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Hide/show operates on the FULL model list (allIds = full catalogue).
|
|
101
|
+
// hidden is a denylist: adding = hide, removing = show.
|
|
102
|
+
export function toggleHidden(modelId: ModelId, hidden: string[] | undefined, _allIds: ModelId[]): string[] | undefined {
|
|
103
|
+
if (!hidden || hidden.length === 0) {
|
|
104
|
+
return [modelId];
|
|
105
|
+
}
|
|
106
|
+
// Exact match toggle. If hidden contains globs that already hide this model, we still toggle exact id.
|
|
107
|
+
// If model is hidden via pattern, toggling will add exact? Instead remove matching patterns? Simplify: exact toggle.
|
|
108
|
+
const hasExact = hidden.includes(modelId);
|
|
109
|
+
// Also consider pattern hiding: if model matches a pattern, showing should remove? But we can't know which pattern.
|
|
110
|
+
// For now, if hidden via pattern and not exact, toggling to "show" should add an exception? Simpler: if currently hidden (pattern or exact), remove exact and also remove any pattern that matches it? That's ambiguous.
|
|
111
|
+
// We treat visibility via pattern: if isHidden true but not exact, toggling "show" means we need to keep patterns but add exception — not supported.
|
|
112
|
+
// Simplest: if currently hidden, remove exact if present, otherwise add exact and keep patterns — model stays hidden. To actually show, we'd need to remove matching patterns.
|
|
113
|
+
// So if hidden via pattern, show action should remove matching patterns.
|
|
114
|
+
const currentlyHidden = isHidden(modelId, hidden);
|
|
115
|
+
if (currentlyHidden) {
|
|
116
|
+
// Remove exact if present
|
|
117
|
+
let next = hidden.filter(id => id !== modelId);
|
|
118
|
+
// Also remove any glob pattern that matches this model (so it becomes visible)
|
|
119
|
+
next = next.filter(p => !matchesPattern(modelId, p));
|
|
120
|
+
if (next.length === 0) return undefined;
|
|
121
|
+
return next;
|
|
122
|
+
} else {
|
|
123
|
+
// Currently visible — hide by adding exact id
|
|
124
|
+
if (hasExact) return hidden.filter(id => id !== modelId);
|
|
125
|
+
return [...hidden, modelId];
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Aliases for old names
|
|
130
|
+
export function toggleInEnabled(modelId: ModelId, hidden: string[] | undefined, allIds: ModelId[]): string[] | undefined {
|
|
131
|
+
return toggleHidden(modelId, hidden, allIds);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export function applyBulk(hidden: string[]|undefined, allIds: ModelId[], matching: ModelId[], action: "include"|"exclude"): string[]|undefined {
|
|
135
|
+
// For denylist: "exclude" = hide (add to hidden), "include" = show (remove from hidden)
|
|
136
|
+
if (action === "exclude") {
|
|
137
|
+
const base = hidden === undefined ? [] : [...hidden];
|
|
138
|
+
const set = new Set(base);
|
|
139
|
+
for (const id of matching) set.add(id);
|
|
140
|
+
const arr = [...set].sort();
|
|
141
|
+
if (arr.length === 0) return undefined;
|
|
142
|
+
return arr;
|
|
143
|
+
} else {
|
|
144
|
+
// include = show
|
|
145
|
+
if (!hidden || hidden.length === 0) return undefined;
|
|
146
|
+
// Remove exact ids and any pattern that matches them? For now remove exact and patterns that match
|
|
147
|
+
let next = [...hidden];
|
|
148
|
+
for (const id of matching) {
|
|
149
|
+
next = next.filter(p => p !== id && !matchesPattern(id, p));
|
|
150
|
+
// If p is exact id matching model, remove; if p is glob that would match id, also remove? But glob may hide other models — removing it would unhide others unintentionally.
|
|
151
|
+
// Better only remove exact matches for bulk include, keep globs.
|
|
152
|
+
// Rebuild: only remove exact ids
|
|
153
|
+
}
|
|
154
|
+
// Recompute strictly exact removal to avoid over-removing globs
|
|
155
|
+
const exactSet = new Set(matching as string[]);
|
|
156
|
+
next = (hidden as string[]).filter(p => {
|
|
157
|
+
// If p is exact id in matching, remove
|
|
158
|
+
if (exactSet.has(p)) return false;
|
|
159
|
+
return true;
|
|
160
|
+
});
|
|
161
|
+
if (next.length === 0) return undefined;
|
|
162
|
+
return next;
|
|
163
|
+
}
|
|
164
|
+
}
|