@shgroup/dsh-serenity-hooks 1.48.0 → 1.48.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.
- package/dsh.plugin.json +1 -1
- package/lib/index.js +104 -29
- package/lib/opencode-provider.d.ts +15 -1
- package/package.json +1 -1
package/dsh.plugin.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "dsh-serenity-hooks",
|
|
3
|
-
"version": "1.48.
|
|
3
|
+
"version": "1.48.1",
|
|
4
4
|
"main": "lib/index.js",
|
|
5
5
|
"description": "宁静号 ACC harness(Native Cordis 插件):给 DSH 装一个「AI 工作区」——11 个工具(container_fs/container_trajectory/dashboard/container_git/msm/praxis/handyman/localstore/container_admin/im-bridge/acc-diag;后两个按配置条件出现)+ 机械约束(安全模式/工作区围墙/密钥守卫)+ 轨迹日志与原地重建 + 网页登录入口/微信桥/子角色/对外问答页/trajectory 唤醒注册表。适配 DSH 0.1.5-rc.2(deepseek-ai/deepseek-harness)。",
|
|
6
6
|
"engines": {
|
package/lib/index.js
CHANGED
|
@@ -17031,6 +17031,7 @@ function opencodeRouteHeaders() {
|
|
|
17031
17031
|
const OPENCODE_EXTRA_MODELS = { "deepseek-v4.1-flash": {
|
|
17032
17032
|
name: "DeepSeek V4.1 Flash",
|
|
17033
17033
|
api: "openai-completions",
|
|
17034
|
+
baseUrl: "https://opencode.ai/zen/go/v1",
|
|
17034
17035
|
contextWindow: 1e6,
|
|
17035
17036
|
maxTokens: 384e3,
|
|
17036
17037
|
input: ["text"],
|
|
@@ -17074,41 +17075,104 @@ const OPENCODE_GO_NON_COMPLETIONS = /* @__PURE__ */ new Set([
|
|
|
17074
17075
|
"muse-spark-1.2-contributor"
|
|
17075
17076
|
]);
|
|
17076
17077
|
/**
|
|
17077
|
-
*
|
|
17078
|
+
* 把 {@link OPENCODE_EXTRA_MODELS} 落到一个**已有显式 `models` 列表**的路由上(**纯函数**)。
|
|
17078
17079
|
*
|
|
17079
|
-
*
|
|
17080
|
-
*
|
|
17081
|
-
*
|
|
17082
|
-
*
|
|
17080
|
+
* 两种落法(v1.48.1 起):
|
|
17081
|
+
* · **追加**(模型不在表里)—— 目录里没有它,连条目都得我们造。
|
|
17082
|
+
* · **补规格**(模型已在表里、但缺 `reasoningEfforts`)—— 🔴 **这是"手加过"的形态**:
|
|
17083
|
+
* 用户把模型抄进列表了,可没抄推理档 ⇒ 宿主 `resolveModelReasoning` 走 `base?.reasoning ?? false`
|
|
17084
|
+
* ⇒ **能用但永远不出 thinking**。只补"缺失的模型"是补不到这一形态的。
|
|
17085
|
+
*
|
|
17086
|
+
* 拒绝条件(每条都对应一个会让配置变坏的真实形态;宁可不动也不硬来):
|
|
17087
|
+
* ① **没有显式 `models` 列表**(含空表)⇒ 该路由此刻服务的是 pi-ai 目录本体;
|
|
17088
|
+
* 一旦我们写出 `models`,**整个目录会被顶掉**(宿主的 `models` 是"整体替换"语义)。
|
|
17083
17089
|
* ② **列表里出现已知异协议模型** ⇒ 设路由级 `api` 会覆盖它们的 `base.api`,把它们配坏。
|
|
17084
17090
|
* ③ **路由已显式设了别的 `api`** ⇒ 同上,且那是用户的显式选择,不覆盖。
|
|
17091
|
+
* ④ **要补规格却判不出协议**(路由没写 `api`,又不追加任何模型)⇒ 无法保证 compat 合法。
|
|
17085
17092
|
*/
|
|
17086
17093
|
function planExtraModels(profile) {
|
|
17087
17094
|
const raw = profile.models;
|
|
17088
17095
|
if (!Array.isArray(raw) || raw.length === 0) return {
|
|
17089
17096
|
addedIds: [],
|
|
17097
|
+
enrichedIds: [],
|
|
17090
17098
|
skip: "catalog-served"
|
|
17091
17099
|
};
|
|
17092
|
-
const
|
|
17093
|
-
for (const entry of raw) if (isPlainObject$1(entry) && typeof entry.id === "string")
|
|
17094
|
-
const
|
|
17095
|
-
if (missing.length === 0) return { addedIds: [] };
|
|
17096
|
-
for (const id of ids) if (OPENCODE_GO_NON_COMPLETIONS.has(id)) return {
|
|
17100
|
+
const byId = /* @__PURE__ */ new Map();
|
|
17101
|
+
for (const entry of raw) if (isPlainObject$1(entry) && typeof entry.id === "string") byId.set(entry.id, entry);
|
|
17102
|
+
for (const id of byId.keys()) if (OPENCODE_GO_NON_COMPLETIONS.has(id)) return {
|
|
17097
17103
|
addedIds: [],
|
|
17104
|
+
enrichedIds: [],
|
|
17098
17105
|
skip: "mixed-protocol"
|
|
17099
17106
|
};
|
|
17100
|
-
const
|
|
17101
|
-
|
|
17107
|
+
const missing = Object.entries(OPENCODE_EXTRA_MODELS).filter(([id]) => !byId.has(id));
|
|
17108
|
+
const existingApi = typeof profile.api === "string" && profile.api !== "" ? profile.api : void 0;
|
|
17109
|
+
let pendingApi;
|
|
17110
|
+
if (missing.length > 0) {
|
|
17111
|
+
const apis = new Set(missing.map(([, model]) => model.api));
|
|
17112
|
+
if (apis.size !== 1) return {
|
|
17113
|
+
addedIds: [],
|
|
17114
|
+
enrichedIds: [],
|
|
17115
|
+
skip: "mixed-protocol"
|
|
17116
|
+
};
|
|
17117
|
+
pendingApi = [...apis][0];
|
|
17118
|
+
}
|
|
17119
|
+
if (existingApi !== void 0 && pendingApi !== void 0 && existingApi !== pendingApi) return {
|
|
17102
17120
|
addedIds: [],
|
|
17103
|
-
|
|
17121
|
+
enrichedIds: [],
|
|
17122
|
+
skip: "api-conflict"
|
|
17104
17123
|
};
|
|
17105
|
-
|
|
17106
|
-
const
|
|
17107
|
-
|
|
17124
|
+
/** 写完之后该路由的**有效协议**(第三方条目也会按它解析) */
|
|
17125
|
+
const effectiveApi = existingApi ?? pendingApi;
|
|
17126
|
+
const toEnrich = [];
|
|
17127
|
+
for (const [id, model] of Object.entries(OPENCODE_EXTRA_MODELS)) {
|
|
17128
|
+
const entry = byId.get(id);
|
|
17129
|
+
if (entry === void 0) continue;
|
|
17130
|
+
if (entry.reasoningEfforts !== void 0) continue;
|
|
17131
|
+
if (effectiveApi === void 0) return {
|
|
17132
|
+
addedIds: [],
|
|
17133
|
+
enrichedIds: [],
|
|
17134
|
+
skip: "api-missing"
|
|
17135
|
+
};
|
|
17136
|
+
if (effectiveApi !== model.api) return {
|
|
17137
|
+
addedIds: [],
|
|
17138
|
+
enrichedIds: [],
|
|
17139
|
+
skip: "api-conflict"
|
|
17140
|
+
};
|
|
17141
|
+
toEnrich.push([
|
|
17142
|
+
id,
|
|
17143
|
+
model,
|
|
17144
|
+
entry
|
|
17145
|
+
]);
|
|
17146
|
+
}
|
|
17147
|
+
if (missing.length === 0 && toEnrich.length === 0) return {
|
|
17108
17148
|
addedIds: [],
|
|
17109
|
-
|
|
17149
|
+
enrichedIds: []
|
|
17110
17150
|
};
|
|
17111
|
-
|
|
17151
|
+
let baseUrl;
|
|
17152
|
+
if (!(typeof profile.baseURL === "string" && profile.baseURL !== "")) {
|
|
17153
|
+
const want = new Set([...missing.map(([, m]) => m), ...toEnrich.map(([, m]) => m)].map((m) => m.baseUrl));
|
|
17154
|
+
if (want.size !== 1) return {
|
|
17155
|
+
addedIds: [],
|
|
17156
|
+
enrichedIds: [],
|
|
17157
|
+
skip: "mixed-protocol"
|
|
17158
|
+
};
|
|
17159
|
+
baseUrl = [...want][0];
|
|
17160
|
+
}
|
|
17161
|
+
const enrichById = new Map(toEnrich.map(([id, model]) => [id, model]));
|
|
17162
|
+
const models = raw.map((entry) => {
|
|
17163
|
+
if (!isPlainObject$1(entry) || typeof entry.id !== "string") return entry;
|
|
17164
|
+
const model = enrichById.get(entry.id);
|
|
17165
|
+
if (model === void 0) return entry;
|
|
17166
|
+
return {
|
|
17167
|
+
...entry,
|
|
17168
|
+
reasoningEfforts: { ...model.reasoningEfforts },
|
|
17169
|
+
compat: {
|
|
17170
|
+
...model.compat,
|
|
17171
|
+
...isPlainObject$1(entry.compat) ? entry.compat : {}
|
|
17172
|
+
}
|
|
17173
|
+
};
|
|
17174
|
+
});
|
|
17175
|
+
for (const [id, model] of missing) models.push({
|
|
17112
17176
|
id,
|
|
17113
17177
|
name: model.name,
|
|
17114
17178
|
contextWindow: model.contextWindow,
|
|
@@ -17116,11 +17180,13 @@ function planExtraModels(profile) {
|
|
|
17116
17180
|
input: [...model.input],
|
|
17117
17181
|
reasoningEfforts: { ...model.reasoningEfforts },
|
|
17118
17182
|
compat: { ...model.compat }
|
|
17119
|
-
})
|
|
17183
|
+
});
|
|
17120
17184
|
return {
|
|
17121
|
-
models
|
|
17122
|
-
...existingApi ===
|
|
17123
|
-
|
|
17185
|
+
models,
|
|
17186
|
+
...pendingApi !== void 0 && existingApi === void 0 ? { api: pendingApi } : {},
|
|
17187
|
+
...baseUrl === void 0 ? {} : { baseUrl },
|
|
17188
|
+
addedIds: missing.map(([id]) => id),
|
|
17189
|
+
enrichedIds: toEnrich.map(([id]) => id)
|
|
17124
17190
|
};
|
|
17125
17191
|
}
|
|
17126
17192
|
function isPlainObject$1(value) {
|
|
@@ -17198,16 +17264,24 @@ function planOpencodeAutoConfig(input) {
|
|
|
17198
17264
|
route,
|
|
17199
17265
|
reason: extra.skip
|
|
17200
17266
|
});
|
|
17201
|
-
else
|
|
17202
|
-
|
|
17203
|
-
|
|
17204
|
-
|
|
17205
|
-
|
|
17206
|
-
|
|
17267
|
+
else {
|
|
17268
|
+
if (extra.addedIds.length > 0) actions.push({
|
|
17269
|
+
kind: "add-models",
|
|
17270
|
+
route,
|
|
17271
|
+
ids: extra.addedIds,
|
|
17272
|
+
api: extra.api ?? null
|
|
17273
|
+
});
|
|
17274
|
+
if (extra.enrichedIds.length > 0) actions.push({
|
|
17275
|
+
kind: "enrich-models",
|
|
17276
|
+
route,
|
|
17277
|
+
ids: extra.enrichedIds
|
|
17278
|
+
});
|
|
17279
|
+
}
|
|
17207
17280
|
const routePatch = {};
|
|
17208
17281
|
if (keys.length > 0) routePatch.headers = missing;
|
|
17209
17282
|
if (extra.models !== void 0) routePatch.models = extra.models;
|
|
17210
17283
|
if (extra.api !== void 0) routePatch.api = extra.api;
|
|
17284
|
+
if (extra.baseUrl !== void 0) routePatch.baseURL = extra.baseUrl;
|
|
17211
17285
|
if (keys.length === 0 && Object.keys(routePatch).length === 0) {
|
|
17212
17286
|
actions.push({
|
|
17213
17287
|
kind: "skip-route",
|
|
@@ -17249,7 +17323,8 @@ function describeOpencodeAction(action) {
|
|
|
17249
17323
|
case "create-route": return `创建 ${action.route} 路由(检测到 ${OPENCODE_API_KEY_ENV})+ 路由头`;
|
|
17250
17324
|
case "skip-route": return `${action.route} 路由头已齐备(跳过)`;
|
|
17251
17325
|
case "add-models": return `为 ${action.route} 补目录未收录的模型:${action.ids.join(", ")}` + (action.api === null ? "" : `(并设路由 api=${action.api})`);
|
|
17252
|
-
case "
|
|
17326
|
+
case "enrich-models": return `为 ${action.route} 已列出的模型补推理档:${action.ids.join(", ")}(此前「能用但没 thinking」)`;
|
|
17327
|
+
case "skip-models": return `${action.route} 未补模型(${action.reason === "catalog-served" ? "该路由未声明 models 列表,补 models 会顶掉整个目录" : action.reason === "mixed-protocol" ? "该路由含异协议模型,设路由 api 会把它们配坏" : action.reason === "api-missing" ? "该模型已列出但缺推理档,而路由没写 api ⇒ 判不出该用哪套 compat" : "该路由的 api 与本表规格不一致"})`;
|
|
17253
17328
|
case "idle": return `无需动作(${action.reason})`;
|
|
17254
17329
|
}
|
|
17255
17330
|
}
|
|
@@ -94,6 +94,16 @@ export interface OpencodeExtraModel {
|
|
|
94
94
|
readonly name: string;
|
|
95
95
|
/** 该模型说的 wire 协议;见 {@link OPENCODE_GO_NON_COMPLETIONS} 的安全闸 */
|
|
96
96
|
readonly api: string;
|
|
97
|
+
/**
|
|
98
|
+
* 该模型的端点基址 —— 🔴 **目录外模型的必需品**(v1.48.1 补)。
|
|
99
|
+
*
|
|
100
|
+
* 宿主 `resolveRouteModels` 的兜底链是 `request.baseURL ?? base?.baseUrl ?? providerBaseUrl`;
|
|
101
|
+
* 目录里没有它 ⇒ `base` 为 undefined,而 pi-ai 的 `opencodeGoProvider()` **也没有 provider 级
|
|
102
|
+
* baseUrl** ⇒ 三级全空 ⇒ 宿主**严格写入直接把整条补丁拒掉**(v1.48.0 真机实测原文:
|
|
103
|
+
* `model "deepseek-v4.1-flash" needs a baseURL; the installed catalog does not describe this route`)。
|
|
104
|
+
* 故本字段是**唯一可控的那一环**:路由自身没写 `baseURL` 时,必须由我们补上。
|
|
105
|
+
*/
|
|
106
|
+
readonly baseUrl: string;
|
|
97
107
|
readonly contextWindow: number;
|
|
98
108
|
readonly maxTokens: number;
|
|
99
109
|
readonly input: readonly string[];
|
|
@@ -135,10 +145,14 @@ type OpencodeAutoConfigAction = {
|
|
|
135
145
|
route: string;
|
|
136
146
|
ids: readonly string[];
|
|
137
147
|
api: string | null;
|
|
148
|
+
} | {
|
|
149
|
+
kind: 'enrich-models';
|
|
150
|
+
route: string;
|
|
151
|
+
ids: readonly string[];
|
|
138
152
|
} | {
|
|
139
153
|
kind: 'skip-models';
|
|
140
154
|
route: string;
|
|
141
|
-
reason: 'catalog-served' | 'mixed-protocol' | 'api-conflict';
|
|
155
|
+
reason: 'catalog-served' | 'mixed-protocol' | 'api-conflict' | 'api-missing';
|
|
142
156
|
} | {
|
|
143
157
|
kind: 'idle';
|
|
144
158
|
reason: 'namespace-unregistered' | 'no-route';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shgroup/dsh-serenity-hooks",
|
|
3
|
-
"version": "1.48.
|
|
3
|
+
"version": "1.48.1",
|
|
4
4
|
"description": "宁静号 ACC harness(Native Cordis 插件)——给 DeepSeek Harness 装一个「AI 工作区」:11 个工具(container_fs/container_trajectory/dashboard/container_git/msm/praxis/handyman/localstore/container_admin/im-bridge/acc-diag)+ 机械约束(安全模式/工作区围墙/密钥守卫/对外输出守卫)+ 工作日志与原地重建 + 网页登录入口/微信桥/子角色/对外问答页/trajectory 唤醒注册表。适配 DSH 0.1.7-rc.1。",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|