dsh-model 0.22.0 → 0.22.1

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.
@@ -52,6 +52,12 @@ async function checkLocation(state, location, force) {
52
52
  return warnings;
53
53
  }
54
54
  /** 写入 / 移除一组项。所有权记在 state.dsh.ownedProviders / ownedRefs */
55
+ /**
56
+ * 上次安装留下的东西(台账丢了,例如卸载没走完、或手动删过 ~/.dsh-model):
57
+ * dsh-model 格式的 key(dshm_ + 43 位),或指向 DSH_MODEL_API_KEY 的 dsh-model* provider。直接接管,不让用户去手动删。
58
+ */
59
+ export const isLeftoverKey = (value) => /^dshm_[A-Za-z0-9_-]{43}$/.test(value);
60
+ const isLeftoverProvider = (id, spec) => id.startsWith('dsh-model') && spec?.apiKeyEnv === KEY_REF;
55
61
  export async function applyDsh(ctx, state, items, opts) {
56
62
  const location = await locateDsh(ctx, opts.profile);
57
63
  const warnings = await checkLocation(state, location, opts.force);
@@ -72,7 +78,12 @@ export async function applyDsh(ctx, state, items, opts) {
72
78
  continue;
73
79
  }
74
80
  if (existing !== undefined && !ownedRefs.has(name) && !opts.isOwnRef?.(name, existing)) {
75
- throw new DshModelError('credential_ref_conflict', L(`dsh 凭据里已有 ${name},且不是 dsh-model 写的`, `dsh credentials already contain ${name}, not written by dsh-model`), L('不会覆盖它。要让 dsh-model 接管,请先在 dsh 设置里删掉它再重试', 'It will not be overwritten. To let dsh-model manage it, remove it in dsh settings and retry'));
81
+ if (name === KEY_REF && isLeftoverKey(existing)) {
82
+ warnings.push(L(`接管了上次安装留下的 ${name}(换成这次的 key)`, `Took over ${name} left by an earlier install (replaced with this install's key)`));
83
+ }
84
+ else {
85
+ throw new DshModelError('credential_ref_conflict', L(`dsh 凭据里已有 ${name},且不是 dsh-model 写的`, `dsh credentials already contain ${name}, not written by dsh-model`), L('不会覆盖它。要让 dsh-model 接管,请先在 dsh 设置里删掉它再重试', 'It will not be overwritten. To let dsh-model manage it, remove it in dsh settings and retry'));
86
+ }
76
87
  }
77
88
  credAfter = upsertRef(credAfter === '' ? null : credAfter, value, name);
78
89
  ownedRefs.add(name);
@@ -88,7 +99,11 @@ export async function applyDsh(ctx, state, items, opts) {
88
99
  }
89
100
  continue;
90
101
  }
91
- if (!ownedProviders.has(id) && readProvider(patchAfter === '' ? null : patchAfter, id)) {
102
+ const existingProvider = ownedProviders.has(id) ? null : readProvider(patchAfter === '' ? null : patchAfter, id);
103
+ if (existingProvider && isLeftoverProvider(id, existingProvider)) {
104
+ warnings.push(L(`接管了上次安装留下的 provider ${id}`, `Took over provider ${id} left by an earlier install`));
105
+ }
106
+ else if (existingProvider) {
92
107
  throw new DshModelError('provider_conflict', L(`dsh 里已有 provider ${id},且不是 dsh-model 写的`, `dsh already has a provider ${id}, not written by dsh-model`), L('不会覆盖它', 'It will not be overwritten'));
93
108
  }
94
109
  const r = upsertProvider(patchAfter === '' ? null : patchAfter, id, spec);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-model",
3
- "version": "0.22.0",
3
+ "version": "0.22.1",
4
4
  "description": "One OpenAI-compatible address for all your models: subscriptions (Codex, Kimi…), free tiers (WorkBuddy, Gemini, Groq, OpenRouter), local models (Ollama, LM Studio), daily check-in credits, auto failover. Works with DeepSeek Harness (dsh) and any OpenAI-compatible tool. 一个地址用上你所有的模型。",
5
5
  "keywords": [
6
6
  "dsh-plugin",