free-coding-models 0.1.82 → 0.1.84
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 +53 -51
- package/bin/free-coding-models.js +429 -4276
- package/package.json +2 -2
- package/sources.js +3 -2
- package/src/account-manager.js +600 -0
- package/src/analysis.js +197 -0
- package/{lib → src}/config.js +122 -0
- package/src/constants.js +116 -0
- package/src/error-classifier.js +154 -0
- package/src/favorites.js +98 -0
- package/src/key-handler.js +1005 -0
- package/src/log-reader.js +174 -0
- package/src/model-merger.js +78 -0
- package/src/openclaw.js +131 -0
- package/src/opencode-sync.js +159 -0
- package/src/opencode.js +952 -0
- package/src/overlays.js +840 -0
- package/src/ping.js +186 -0
- package/src/provider-metadata.js +218 -0
- package/src/provider-quota-fetchers.js +319 -0
- package/src/proxy-server.js +543 -0
- package/src/quota-capabilities.js +112 -0
- package/src/render-helpers.js +239 -0
- package/src/render-table.js +567 -0
- package/src/request-transformer.js +180 -0
- package/src/setup.js +105 -0
- package/src/telemetry.js +382 -0
- package/src/tier-colors.js +37 -0
- package/src/token-stats.js +310 -0
- package/src/token-usage-reader.js +63 -0
- package/src/updater.js +237 -0
- package/src/usage-reader.js +245 -0
- package/{lib → src}/utils.js +55 -0
package/src/favorites.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file favorites.js
|
|
3
|
+
* @description Favorites management for model rows — persisted per user in ~/.free-coding-models.json.
|
|
4
|
+
* Extracted from bin/free-coding-models.js to allow unit testing in isolation.
|
|
5
|
+
*
|
|
6
|
+
* @details
|
|
7
|
+
* Favorites are stored as an ordered array of strings in the format "providerKey/modelId"
|
|
8
|
+
* (e.g. "groq/llama-3.1-70b-versatile"). Insertion order matters: it determines the
|
|
9
|
+
* `favoriteRank` used by `sortResultsWithPinnedFavorites` to keep pinned rows at the top.
|
|
10
|
+
*
|
|
11
|
+
* How it works at runtime:
|
|
12
|
+
* 1. On startup, `syncFavoriteFlags()` is called once to attach `isFavorite`/`favoriteRank`
|
|
13
|
+
* metadata to every result row based on the persisted favorites list.
|
|
14
|
+
* 2. When the user presses F, `toggleFavoriteModel()` mutates the config array and persists
|
|
15
|
+
* immediately via `saveConfig()`.
|
|
16
|
+
* 3. The renderer reads `r.isFavorite` and `r.favoriteRank` from the row to decide whether
|
|
17
|
+
* to show the ⭐ prefix and how to sort the row relative to non-favorites.
|
|
18
|
+
*
|
|
19
|
+
* @functions
|
|
20
|
+
* → ensureFavoritesConfig(config) — Ensure config.favorites is a clean deduped array
|
|
21
|
+
* → toFavoriteKey(providerKey, modelId) — Build the canonical "providerKey/modelId" string
|
|
22
|
+
* → syncFavoriteFlags(results, config) — Attach isFavorite/favoriteRank to result rows
|
|
23
|
+
* → toggleFavoriteModel(config, providerKey, modelId) — Add/remove favorite and persist
|
|
24
|
+
*
|
|
25
|
+
* @exports
|
|
26
|
+
* ensureFavoritesConfig, toFavoriteKey, syncFavoriteFlags, toggleFavoriteModel
|
|
27
|
+
*
|
|
28
|
+
* @see src/config.js — saveConfig used here to persist changes immediately
|
|
29
|
+
* @see bin/free-coding-models.js — calls syncFavoriteFlags on startup and toggleFavoriteModel on F key
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
import { saveConfig } from './config.js'
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* 📖 Ensure favorites config shape exists and remains clean.
|
|
36
|
+
* 📖 Stored format: ["providerKey/modelId", ...] in insertion order.
|
|
37
|
+
* @param {Record<string, unknown>} config
|
|
38
|
+
*/
|
|
39
|
+
export function ensureFavoritesConfig(config) {
|
|
40
|
+
if (!Array.isArray(config.favorites)) config.favorites = []
|
|
41
|
+
const seen = new Set()
|
|
42
|
+
config.favorites = config.favorites.filter((entry) => {
|
|
43
|
+
if (typeof entry !== 'string' || entry.trim().length === 0) return false
|
|
44
|
+
if (seen.has(entry)) return false
|
|
45
|
+
seen.add(entry)
|
|
46
|
+
return true
|
|
47
|
+
})
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* 📖 Build deterministic key used to persist one favorite model row.
|
|
52
|
+
* @param {string} providerKey
|
|
53
|
+
* @param {string} modelId
|
|
54
|
+
* @returns {string}
|
|
55
|
+
*/
|
|
56
|
+
export function toFavoriteKey(providerKey, modelId) {
|
|
57
|
+
return `${providerKey}/${modelId}`
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* 📖 Sync per-row favorite metadata from config (used by renderer and sorter).
|
|
62
|
+
* 📖 Mutates each row in-place — adds favoriteKey, isFavorite, favoriteRank.
|
|
63
|
+
* @param {Array<Record<string, unknown>>} results
|
|
64
|
+
* @param {Record<string, unknown>} config
|
|
65
|
+
*/
|
|
66
|
+
export function syncFavoriteFlags(results, config) {
|
|
67
|
+
ensureFavoritesConfig(config)
|
|
68
|
+
const favoriteRankMap = new Map(config.favorites.map((entry, index) => [entry, index]))
|
|
69
|
+
for (const row of results) {
|
|
70
|
+
const favoriteKey = toFavoriteKey(row.providerKey, row.modelId)
|
|
71
|
+
const rank = favoriteRankMap.get(favoriteKey)
|
|
72
|
+
row.favoriteKey = favoriteKey
|
|
73
|
+
row.isFavorite = rank !== undefined
|
|
74
|
+
row.favoriteRank = rank !== undefined ? rank : Number.MAX_SAFE_INTEGER
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* 📖 Toggle favorite state and persist immediately.
|
|
80
|
+
* 📖 Returns true when row is now favorite, false when removed.
|
|
81
|
+
* @param {Record<string, unknown>} config
|
|
82
|
+
* @param {string} providerKey
|
|
83
|
+
* @param {string} modelId
|
|
84
|
+
* @returns {boolean}
|
|
85
|
+
*/
|
|
86
|
+
export function toggleFavoriteModel(config, providerKey, modelId) {
|
|
87
|
+
ensureFavoritesConfig(config)
|
|
88
|
+
const favoriteKey = toFavoriteKey(providerKey, modelId)
|
|
89
|
+
const existingIndex = config.favorites.indexOf(favoriteKey)
|
|
90
|
+
if (existingIndex >= 0) {
|
|
91
|
+
config.favorites.splice(existingIndex, 1)
|
|
92
|
+
saveConfig(config)
|
|
93
|
+
return false
|
|
94
|
+
}
|
|
95
|
+
config.favorites.push(favoriteKey)
|
|
96
|
+
saveConfig(config)
|
|
97
|
+
return true
|
|
98
|
+
}
|