@klarkxy/dsh-model-hub 0.1.3 → 0.1.5
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 +7 -7
- package/docs/README.zh-CN.md +8 -8
- package/lib/client.inner.cjs +118 -84
- package/lib/client.inner.cjs.map +1 -1
- package/lib/client.js +118 -84
- package/lib/index.js +64 -178
- package/lib/index.js.map +1 -1
- package/package.json +11 -11
package/lib/client.js
CHANGED
|
@@ -5,30 +5,7 @@ window.__ModuleLoader__.load({
|
|
|
5
5
|
var module = { exports: {} };
|
|
6
6
|
var exports = module.exports;
|
|
7
7
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
8
|
-
//#region \0rolldown/runtime.js
|
|
9
|
-
var __create = Object.create;
|
|
10
|
-
var __defProp = Object.defineProperty;
|
|
11
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
12
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
13
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
14
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
15
|
-
var __copyProps = (to, from, except, desc) => {
|
|
16
|
-
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
17
|
-
key = keys[i];
|
|
18
|
-
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
19
|
-
get: ((k) => from[k]).bind(null, key),
|
|
20
|
-
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
21
|
-
});
|
|
22
|
-
}
|
|
23
|
-
return to;
|
|
24
|
-
};
|
|
25
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
|
|
26
|
-
value: mod,
|
|
27
|
-
enumerable: true
|
|
28
|
-
}) : target, mod));
|
|
29
|
-
//#endregion
|
|
30
8
|
let react = require("react");
|
|
31
|
-
react = __toESM(react, 1);
|
|
32
9
|
let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
33
10
|
let react_dom = require("react-dom");
|
|
34
11
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
@@ -226,7 +203,14 @@ function groupModelMenuChoices(choices, query) {
|
|
|
226
203
|
}
|
|
227
204
|
//#endregion
|
|
228
205
|
//#region ../dsh-model-route/src/catalog-ui.tsx
|
|
229
|
-
/**
|
|
206
|
+
/**
|
|
207
|
+
* Also accepts a mapped state from a caller that owns broader async orchestration.
|
|
208
|
+
*
|
|
209
|
+
* The dsh-ui-* classes carry the styling and resolve through the consuming
|
|
210
|
+
* plugin's own officialUiCss scope (every consumer mounts its root class, so
|
|
211
|
+
* e.g. `.dsh-model-hub .dsh-ui-loading` paints this); dsh-model-catalog-status
|
|
212
|
+
* stays as a structural hook for tests and layout, never a colour source.
|
|
213
|
+
*/
|
|
230
214
|
function ModelCatalogStatus({ state, locale }) {
|
|
231
215
|
const zh = locale?.toLowerCase().startsWith("zh") === true;
|
|
232
216
|
const copy = zh ? {
|
|
@@ -242,15 +226,17 @@ function ModelCatalogStatus({ state, locale }) {
|
|
|
242
226
|
};
|
|
243
227
|
if (!state.loading && !state.error && state.failures.length === 0) return null;
|
|
244
228
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
245
|
-
className: "dsh-model-catalog-status",
|
|
229
|
+
className: "dsh-model-catalog-status dsh-ui-stack",
|
|
246
230
|
lang: zh ? "zh" : "en",
|
|
247
231
|
children: [
|
|
248
232
|
state.loading ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
249
233
|
role: "status",
|
|
234
|
+
className: "dsh-ui-loading",
|
|
250
235
|
children: copy.loading
|
|
251
236
|
}) : null,
|
|
252
237
|
state.error ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
253
238
|
role: "alert",
|
|
239
|
+
className: "dsh-ui-error dsh-ui-wrap",
|
|
254
240
|
children: [
|
|
255
241
|
copy.error,
|
|
256
242
|
": ",
|
|
@@ -259,20 +245,27 @@ function ModelCatalogStatus({ state, locale }) {
|
|
|
259
245
|
}) : null,
|
|
260
246
|
state.failures.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
261
247
|
role: "status",
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
failure.
|
|
266
|
-
|
|
248
|
+
className: "dsh-ui-meta",
|
|
249
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: copy.partial }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
250
|
+
className: "dsh-ui-list",
|
|
251
|
+
children: state.failures.map((failure, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", { children: [
|
|
252
|
+
failure.name || failure.id,
|
|
253
|
+
": ",
|
|
254
|
+
failure.message
|
|
255
|
+
] }, `${failure.id}:${index}`))
|
|
256
|
+
})]
|
|
267
257
|
}) : null,
|
|
268
|
-
state.error || state.failures.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
state.
|
|
274
|
-
|
|
275
|
-
|
|
258
|
+
state.error || state.failures.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
259
|
+
className: "dsh-ui-actions",
|
|
260
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
261
|
+
type: "button",
|
|
262
|
+
size: "sm",
|
|
263
|
+
disabled: state.loading,
|
|
264
|
+
onClick: () => {
|
|
265
|
+
state.refresh();
|
|
266
|
+
},
|
|
267
|
+
children: copy.retry
|
|
268
|
+
})
|
|
276
269
|
}) : null
|
|
277
270
|
]
|
|
278
271
|
});
|
|
@@ -292,7 +285,8 @@ function ModelCatalogStatus({ state, locale }) {
|
|
|
292
285
|
* Sticky group headings, subsequence ranking, highlight walking and focus
|
|
293
286
|
* hand-back all match the host. SYNC POINT: when the host's ModelSelect or
|
|
294
287
|
* ModelSelect.module.css changes, this copy must be re-transcribed; styles
|
|
295
|
-
* below may only reference
|
|
288
|
+
* below may only reference allowlisted theme tokens (the --dsw-* set plus the
|
|
289
|
+
* host's --ds-* motion tokens), never literal colors.
|
|
296
290
|
*
|
|
297
291
|
* It statically imports the primitives, so only browser clients should load
|
|
298
292
|
* this entry; host code and node tests use the core entry (`./index.ts`).
|
|
@@ -800,7 +794,8 @@ function ModelMenu(props) {
|
|
|
800
794
|
* sticky group headings (MenuGroup's own CSS), and the l1-stroke prominent
|
|
801
795
|
* elevation at portal z-index 1100. The trigger mirrors the composer's 28px
|
|
802
796
|
* model pill, chevron rotating open. MenuSurface paints fill and backdrop.
|
|
803
|
-
* Only --dsw
|
|
797
|
+
* Only allowlisted --dsw- and --ds- theme tokens may appear here — a literal
|
|
798
|
+
* color is a bug.
|
|
804
799
|
*/
|
|
805
800
|
const modelMenuCss = `
|
|
806
801
|
.dsh-model-menu-root { min-width: 0; position: relative; display: inline-flex; }
|
|
@@ -823,12 +818,14 @@ const modelMenuCss = `
|
|
|
823
818
|
display: flex;
|
|
824
819
|
}
|
|
825
820
|
.dsh-model-menu-trigger:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); }
|
|
826
|
-
.dsh-model-menu-trigger:focus-visible:not([data-selection-focus]) { box-shadow: 0 0 0
|
|
821
|
+
.dsh-model-menu-trigger:focus-visible:not([data-selection-focus]) { box-shadow: 0 0 0 var(--dsw-focus-ring-width) var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary)); }
|
|
827
822
|
.dsh-model-menu-trigger:disabled { color: var(--dsw-alias-label-dimmed); cursor: default; }
|
|
828
823
|
.dsh-model-menu-triggerLabel { text-overflow: ellipsis; white-space: nowrap; min-width: 0; overflow: hidden; }
|
|
829
824
|
.dsh-model-menu-triggerEffort { text-overflow: ellipsis; white-space: nowrap; min-width: 0; color: var(--dsw-alias-label-caption); flex-shrink: 1000; overflow: hidden; }
|
|
830
|
-
.dsh-model-menu-chevron { color: var(--dsw-alias-label-caption); flex: none; transition: transform
|
|
825
|
+
.dsh-model-menu-chevron { color: var(--dsw-alias-label-caption); flex: none; transition: transform var(--ds-transition-duration) var(--ds-ease-in-out); }
|
|
831
826
|
.dsh-model-menu-chevronOpen { transform: rotate(180deg); }
|
|
827
|
+
/* Portal overlay: the host publishes no z-index token, so the card keeps the
|
|
828
|
+
* native menu layer's 1100 verbatim. */
|
|
832
829
|
.dsh-model-menu-menu {
|
|
833
830
|
z-index: 1100;
|
|
834
831
|
--dsw-elevation-stroke-color: var(--dsw-alias-border-l1);
|
|
@@ -854,6 +851,8 @@ const modelMenuCss = `
|
|
|
854
851
|
.dsh-model-menu-searchWithQuery { padding-right: 34px; }
|
|
855
852
|
.dsh-model-menu-searchRow .dsh-model-menu-search input { padding: 0; font-size: 12px; line-height: normal; }
|
|
856
853
|
.dsh-model-menu-searchRow .dsh-model-menu-search input::placeholder { color: var(--dsw-alias-label-caption); }
|
|
854
|
+
/* The clear button is a circle by geometry (border-radius: 50%), a shape the
|
|
855
|
+
* radius token scale does not describe. */
|
|
857
856
|
.dsh-model-menu-searchClear {
|
|
858
857
|
width: 24px;
|
|
859
858
|
height: 24px;
|
|
@@ -1101,6 +1100,17 @@ ${scope} {
|
|
|
1101
1100
|
/* --- Layout scaffolding. --- */
|
|
1102
1101
|
& .dsh-ui-stack { display: flex; flex-direction: column; gap: 12px; }
|
|
1103
1102
|
& .dsh-ui-stack-lg { display: flex; flex-direction: column; gap: 20px; }
|
|
1103
|
+
/* Plugin detail pages share one reading column. These are layout recipes;
|
|
1104
|
+
* controls keep their own primitive styles. Form spacing follows the host's
|
|
1105
|
+
* settings-form/fields.module.css and SettingsForm.module.css. */
|
|
1106
|
+
& .dsh-ui-page { display: flex; flex-direction: column; gap: 16px; width: 100%; max-width: 760px; min-width: 0; }
|
|
1107
|
+
& .dsh-ui-form { display: flex; flex-direction: column; gap: 0; min-width: 0; }
|
|
1108
|
+
&.dsh-ui-form > .dsh-ui-field, & .dsh-ui-form > .dsh-ui-field { padding: 12px 0; }
|
|
1109
|
+
& .dsh-ui-form-footer { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; padding-top: 16px; min-width: 0; }
|
|
1110
|
+
& .dsh-ui-fields-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px 20px; min-width: 0; margin: 0; padding: 0; border: 0; }
|
|
1111
|
+
@media (max-width: 560px) {
|
|
1112
|
+
& .dsh-ui-fields-grid { grid-template-columns: minmax(0, 1fr); }
|
|
1113
|
+
}
|
|
1104
1114
|
& .dsh-ui-row { display: flex; align-items: center; gap: 8px; min-width: 0; }
|
|
1105
1115
|
& .dsh-ui-row-wrap { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; }
|
|
1106
1116
|
& .dsh-ui-spacer { flex: 1; min-width: 0; }
|
|
@@ -1128,6 +1138,9 @@ ${scope} {
|
|
|
1128
1138
|
* official primitive, so this only owns the vertical rhythm. --- */
|
|
1129
1139
|
& .dsh-ui-field { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
|
|
1130
1140
|
& .dsh-ui-field + .dsh-ui-field { border-top: 0.5px solid var(--dsw-alias-border-l2); padding-top: 12px; }
|
|
1141
|
+
/* Grid fields share a row, so the stacked-field divider must not win later in
|
|
1142
|
+
* the cascade. Reset it here, after the field recipe. */
|
|
1143
|
+
& .dsh-ui-fields-grid > .dsh-ui-field { padding: 0; border: 0; }
|
|
1131
1144
|
& .dsh-ui-label { display: flex; align-items: center; gap: 6px; font-size: 13px; line-height: 20px; font-weight: 500; color: var(--dsw-alias-label-primary); }
|
|
1132
1145
|
& .dsh-ui-label-row { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
|
|
1133
1146
|
& .dsh-ui-help { font-size: 12px; line-height: 1.6; color: var(--dsw-alias-label-secondary); }
|
|
@@ -1318,29 +1331,22 @@ ${scope} {
|
|
|
1318
1331
|
& *, & *::before, & *::after { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; }
|
|
1319
1332
|
}
|
|
1320
1333
|
}
|
|
1321
|
-
`.replace(/^& (\.dsh-ui-[a-z0-9-]+)(
|
|
1334
|
+
`.replace(/^& (\.dsh-ui-[a-z0-9-]+)(?=\s*\{)/gm, (_match, className) => `&${className}, & ${className}`);
|
|
1322
1335
|
}
|
|
1323
1336
|
//#endregion
|
|
1324
1337
|
//#region ../dsh-plugin-kit/src/contracts.ts
|
|
1325
|
-
/**
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
method: "watch",
|
|
1338
|
-
mode: "stream",
|
|
1339
|
-
invocation: { kind: "direct" },
|
|
1340
|
-
parameters: [],
|
|
1341
|
-
cancellation: { parameter: "signal" }
|
|
1342
|
-
}]
|
|
1343
|
-
};
|
|
1338
|
+
/** `@klarkxy/dsh-git-commit` becomes `KlarkxyDshGitCommitModelSettingsChanges`. */
|
|
1339
|
+
function modelSettingsChangesIdentity(packageName) {
|
|
1340
|
+
const scoped = /^@([^/]+)\/(.+)$/.exec(packageName);
|
|
1341
|
+
const parts = (scoped ? `${scoped[1]}/${scoped[2]}` : packageName).split(/[^A-Za-z0-9]+/).filter(Boolean);
|
|
1342
|
+
if (!parts.length) throw new Error("Model settings package name has no RPC segment");
|
|
1343
|
+
const segment = `${parts.map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("")}ModelSettingsChanges`;
|
|
1344
|
+
if (!/^[A-Z][A-Za-z0-9]*$/.test(segment)) throw new Error(`Model settings sync name is not an RPC segment: ${segment}`);
|
|
1345
|
+
return {
|
|
1346
|
+
service: segment,
|
|
1347
|
+
namespace: segment
|
|
1348
|
+
};
|
|
1349
|
+
}
|
|
1344
1350
|
//#endregion
|
|
1345
1351
|
//#region ../dsh-plugin-kit/src/model-settings-client.ts
|
|
1346
1352
|
/** This stream carries invalidations only; ready is never a settings snapshot. */
|
|
@@ -1355,21 +1361,44 @@ function parseModelSettingsChangeFrame(value) {
|
|
|
1355
1361
|
};
|
|
1356
1362
|
throw new Error("Invalid model settings change frame");
|
|
1357
1363
|
}
|
|
1358
|
-
/** One contribution
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1364
|
+
/** One owner's contribution. Each package mounts only its own endpoint. */
|
|
1365
|
+
function modelSettingsChangesRemote(packageName, identity = modelSettingsChangesIdentity(packageName)) {
|
|
1366
|
+
return {
|
|
1367
|
+
package: packageName,
|
|
1368
|
+
descriptors: [{
|
|
1369
|
+
id: `${identity.namespace}/watch`,
|
|
1370
|
+
service: identity.service,
|
|
1371
|
+
namespace: identity.namespace,
|
|
1372
|
+
method: "watch",
|
|
1373
|
+
mode: "stream",
|
|
1374
|
+
invocation: { kind: "direct" },
|
|
1375
|
+
parameters: [],
|
|
1376
|
+
cancellation: { parameter: "signal" },
|
|
1377
|
+
result: {
|
|
1378
|
+
mode: "strict",
|
|
1379
|
+
typeSymbol: "ModelSettings.ChangeFrame",
|
|
1380
|
+
create: () => ({ parse: parseModelSettingsChangeFrame })
|
|
1381
|
+
}
|
|
1382
|
+
}]
|
|
1383
|
+
};
|
|
1384
|
+
}
|
|
1385
|
+
/** Mount from a synchronous apply. Disposal waits for an in-flight mount and
|
|
1386
|
+
* then withdraws it, so the contribution cannot outlive the plugin. */
|
|
1387
|
+
function mountModelSettingsChanges(ctx, packageName) {
|
|
1388
|
+
const contribution = modelSettingsChangesRemote(packageName);
|
|
1389
|
+
ctx.inject(["remote"], (injected) => {
|
|
1390
|
+
const scope = injected;
|
|
1391
|
+
const mounting = scope.remote.$mount(contribution);
|
|
1392
|
+
mounting.catch(() => {});
|
|
1393
|
+
scope.effect(() => async () => {
|
|
1394
|
+
await (await mounting.catch(() => void 0))?.();
|
|
1395
|
+
});
|
|
1396
|
+
});
|
|
1397
|
+
}
|
|
1370
1398
|
/** Native RemoteStream owns carrier reconnects; no timers or browser transport.
|
|
1371
1399
|
* A factory shares one logical stream while at least one subscriber remains. */
|
|
1372
|
-
function createModelSettingsSubscriber(ctx,
|
|
1400
|
+
function createModelSettingsSubscriber(ctx, packageName, identity = modelSettingsChangesIdentity(packageName), accept = (ns) => ns === packageName) {
|
|
1401
|
+
const endpoint = identity;
|
|
1373
1402
|
const listeners = /* @__PURE__ */ new Set();
|
|
1374
1403
|
let injection;
|
|
1375
1404
|
let current;
|
|
@@ -1395,12 +1424,18 @@ function createModelSettingsSubscriber(ctx, namespace) {
|
|
|
1395
1424
|
};
|
|
1396
1425
|
const start = () => {
|
|
1397
1426
|
const life = ++lifecycle;
|
|
1398
|
-
injection = ctx.inject(["remote",
|
|
1427
|
+
injection = ctx.inject(["remote", `remote.${endpoint.namespace}`], (injected) => {
|
|
1399
1428
|
if (life !== lifecycle || !listeners.size) return;
|
|
1400
1429
|
const scope = injected;
|
|
1430
|
+
const service = scope.remote[endpoint.namespace];
|
|
1431
|
+
if (!service || !("watch" in service) || !service.watch) {
|
|
1432
|
+
report("Model settings sync service unavailable");
|
|
1433
|
+
return;
|
|
1434
|
+
}
|
|
1435
|
+
const watch = service.watch;
|
|
1401
1436
|
const stream = scope.remote.$stream({
|
|
1402
1437
|
name: "Model settings sync",
|
|
1403
|
-
open: (signal) =>
|
|
1438
|
+
open: (signal) => watch(signal),
|
|
1404
1439
|
ended: (accepted) => /* @__PURE__ */ new Error(`Model settings sync stream ended ${accepted ? "after" : "before"} ready; refresh or reopen the page`)
|
|
1405
1440
|
});
|
|
1406
1441
|
const session = {
|
|
@@ -1435,7 +1470,7 @@ function createModelSettingsSubscriber(ctx, namespace) {
|
|
|
1435
1470
|
invalidate();
|
|
1436
1471
|
} else {
|
|
1437
1472
|
if (!ready) throw new Error("Model settings sync change arrived before ready");
|
|
1438
|
-
if (
|
|
1473
|
+
if (accept(frame.ns)) invalidate();
|
|
1439
1474
|
}
|
|
1440
1475
|
}
|
|
1441
1476
|
} catch (error) {
|
|
@@ -1998,7 +2033,7 @@ function CastPage({ api, locale }) {
|
|
|
1998
2033
|
refresh: refreshNow
|
|
1999
2034
|
};
|
|
2000
2035
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2001
|
-
className: "cast-root dsh-ui-stack",
|
|
2036
|
+
className: "cast-root dsh-model-hub dsh-ui-stack",
|
|
2002
2037
|
"aria-label": t("title"),
|
|
2003
2038
|
"aria-busy": saving !== "" || refreshing,
|
|
2004
2039
|
children: [
|
|
@@ -2428,7 +2463,7 @@ function HubPage({ view, api, locale, initialEntries = null, initialCatalog = nu
|
|
|
2428
2463
|
refresh: refreshNow
|
|
2429
2464
|
};
|
|
2430
2465
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
2431
|
-
className: "dsh-model-hub dsh-ui-
|
|
2466
|
+
className: "dsh-model-hub dsh-ui-page",
|
|
2432
2467
|
lang: t.language,
|
|
2433
2468
|
"aria-label": t("title"),
|
|
2434
2469
|
"aria-busy": writing !== "" || refreshing,
|
|
@@ -2594,11 +2629,10 @@ function HubPage({ view, api, locale, initialEntries = null, initialCatalog = nu
|
|
|
2594
2629
|
]
|
|
2595
2630
|
});
|
|
2596
2631
|
}
|
|
2597
|
-
|
|
2632
|
+
function apply(ctx) {
|
|
2598
2633
|
const client = ctx;
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
const changes = createModelSettingsSubscriber(ctx, "*");
|
|
2634
|
+
mountModelSettingsChanges(ctx, BUNDLE);
|
|
2635
|
+
const changes = createModelSettingsSubscriber(ctx, BUNDLE, modelSettingsChangesIdentity(BUNDLE), () => true);
|
|
2602
2636
|
const call = async (endpoint, payload) => {
|
|
2603
2637
|
const result = await client.connection.rpc.call(CHANNEL, endpoint, payload);
|
|
2604
2638
|
if (!result?.ok) throw new Error(result?.error?.message || "Request failed");
|
package/lib/index.js
CHANGED
|
@@ -1,13 +1,45 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
2
2
|
import { dirname, join } from "node:path";
|
|
3
3
|
import Schema from "@deepseek-ai/schemastery";
|
|
4
4
|
import { registerHostRpc } from "@klarkxy/dsh-plugin-kit/host-rpc";
|
|
5
5
|
import { modelRouteRoleSchemastery, modelRouteSchemastery } from "@klarkxy/dsh-model-route/schemastery";
|
|
6
6
|
import { detectModelFields, modelRouteOverride, normalizeModelRoute } from "@klarkxy/dsh-model-route";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
7
|
+
import { collectModelSettings, notifyModelSettingsChanged } from "@klarkxy/dsh-plugin-kit/model-settings";
|
|
8
|
+
import { isSubagentSession, modelSettingsChangesIdentity } from "@klarkxy/dsh-plugin-kit/contracts";
|
|
9
|
+
import { createModelSettingsChanges } from "@klarkxy/dsh-plugin-kit/model-settings-changes";
|
|
10
|
+
import { mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
11
|
+
//#region src/diagnostics.ts
|
|
12
|
+
/** Invalidation is constant-time. Only startup and explicit reads request a
|
|
13
|
+
* diagnostic; a burst shares one deferred run. Work never reschedules itself. */
|
|
14
|
+
function createProbeDiagnostics(run, onError) {
|
|
15
|
+
let dirty = true;
|
|
16
|
+
let stopped = false;
|
|
17
|
+
let timer;
|
|
18
|
+
let running;
|
|
19
|
+
return {
|
|
20
|
+
invalidate() {
|
|
21
|
+
if (!stopped) dirty = true;
|
|
22
|
+
},
|
|
23
|
+
request() {
|
|
24
|
+
if (stopped || !dirty || timer !== void 0 || running) return;
|
|
25
|
+
timer = setTimeout(() => {
|
|
26
|
+
timer = void 0;
|
|
27
|
+
if (stopped || !dirty) return;
|
|
28
|
+
dirty = false;
|
|
29
|
+
running = Promise.resolve().then(run).catch(onError).finally(() => {
|
|
30
|
+
running = void 0;
|
|
31
|
+
});
|
|
32
|
+
}, 0);
|
|
33
|
+
},
|
|
34
|
+
async dispose() {
|
|
35
|
+
stopped = true;
|
|
36
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
37
|
+
timer = void 0;
|
|
38
|
+
await running;
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
//#endregion
|
|
11
43
|
//#region src/probe.ts
|
|
12
44
|
/**
|
|
13
45
|
* Pure probe-report builder for the model hub. Takes the host's
|
|
@@ -209,170 +241,10 @@ function createHubSettings(events, settings, ownNamespace = "@klarkxy/dsh-model-
|
|
|
209
241
|
}
|
|
210
242
|
//#endregion
|
|
211
243
|
//#region src/changes.ts
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
var __knownSymbol = (name, symbol) => (symbol = Symbol[name]) ? symbol : Symbol.for("Symbol." + name);
|
|
216
|
-
var __typeError = (msg) => {
|
|
217
|
-
throw TypeError(msg);
|
|
218
|
-
};
|
|
219
|
-
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, {
|
|
220
|
-
enumerable: true,
|
|
221
|
-
configurable: true,
|
|
222
|
-
writable: true,
|
|
223
|
-
value
|
|
224
|
-
}) : obj[key] = value;
|
|
225
|
-
var __name = (target, value) => __defProp(target, "name", {
|
|
226
|
-
value,
|
|
227
|
-
configurable: true
|
|
228
|
-
});
|
|
229
|
-
var __decoratorStart = (base) => [
|
|
230
|
-
,
|
|
231
|
-
,
|
|
232
|
-
,
|
|
233
|
-
__create(base?.[__knownSymbol("metadata")] ?? null)
|
|
234
|
-
];
|
|
235
|
-
var __decoratorStrings = [
|
|
236
|
-
"class",
|
|
237
|
-
"method",
|
|
238
|
-
"getter",
|
|
239
|
-
"setter",
|
|
240
|
-
"accessor",
|
|
241
|
-
"field",
|
|
242
|
-
"value",
|
|
243
|
-
"get",
|
|
244
|
-
"set"
|
|
245
|
-
];
|
|
246
|
-
var __expectFn = (fn) => fn !== void 0 && typeof fn !== "function" ? __typeError("Function expected") : fn;
|
|
247
|
-
var __decoratorContext = (kind, name, done, metadata, fns) => ({
|
|
248
|
-
kind: __decoratorStrings[kind],
|
|
249
|
-
name,
|
|
250
|
-
metadata,
|
|
251
|
-
addInitializer: (fn) => done._ ? __typeError("Already initialized") : fns.push(__expectFn(fn || null))
|
|
252
|
-
});
|
|
253
|
-
var __decoratorMetadata = (array, target) => __defNormalProp(target, __knownSymbol("metadata"), array[3]);
|
|
254
|
-
var __runInitializers = (array, flags, self, value) => {
|
|
255
|
-
for (var i = 0, fns = array[flags >> 1], n = fns && fns.length; i < n; i++) flags & 1 ? fns[i].call(self) : value = fns[i].call(self, value);
|
|
256
|
-
return value;
|
|
257
|
-
};
|
|
258
|
-
var __decorateElement = (array, flags, name, decorators, target, extra) => {
|
|
259
|
-
var fn, it, done, ctx, access, k = flags & 7, s = !!(flags & 8), p = !!(flags & 16);
|
|
260
|
-
var j = k > 3 ? array.length + 1 : k ? s ? 1 : 2 : 0, key = __decoratorStrings[k + 5];
|
|
261
|
-
var initializers = k > 3 && (array[j - 1] = []), extraInitializers = array[j] || (array[j] = []);
|
|
262
|
-
var desc = k && (!p && !s && (target = target.prototype), k < 5 && (k > 3 || !p) && __getOwnPropDesc(k < 4 ? target : {
|
|
263
|
-
get [name]() {
|
|
264
|
-
return __privateGet(this, extra);
|
|
265
|
-
},
|
|
266
|
-
set [name](x) {
|
|
267
|
-
return __privateSet(this, extra, x);
|
|
268
|
-
}
|
|
269
|
-
}, name));
|
|
270
|
-
k ? p && k < 4 && __name(extra, (k > 2 ? "set " : k > 1 ? "get " : "") + name) : __name(target, name);
|
|
271
|
-
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
272
|
-
ctx = __decoratorContext(k, name, done = {}, array[3], extraInitializers);
|
|
273
|
-
if (k) {
|
|
274
|
-
ctx.static = s, ctx.private = p, access = ctx.access = { has: p ? (x) => __privateIn(target, x) : (x) => name in x };
|
|
275
|
-
if (k ^ 3) access.get = p ? (x) => (k ^ 1 ? __privateGet : __privateMethod)(x, target, k ^ 4 ? extra : desc.get) : (x) => x[name];
|
|
276
|
-
if (k > 2) access.set = p ? (x, y) => __privateSet(x, target, y, k ^ 4 ? extra : desc.set) : (x, y) => x[name] = y;
|
|
277
|
-
}
|
|
278
|
-
it = (0, decorators[i])(k ? k < 4 ? p ? extra : desc[key] : k > 4 ? void 0 : {
|
|
279
|
-
get: desc.get,
|
|
280
|
-
set: desc.set
|
|
281
|
-
} : target, ctx), done._ = 1;
|
|
282
|
-
if (k ^ 4 || it === void 0) __expectFn(it) && (k > 4 ? initializers.unshift(it) : k ? p ? extra = it : desc[key] = it : target = it);
|
|
283
|
-
else if (typeof it !== "object" || it === null) __typeError("Object expected");
|
|
284
|
-
else __expectFn(fn = it.get) && (desc.get = fn), __expectFn(fn = it.set) && (desc.set = fn), __expectFn(fn = it.init) && initializers.unshift(fn);
|
|
285
|
-
}
|
|
286
|
-
return k || __decoratorMetadata(array, target), desc && __defProp(target, name, desc), p ? k ^ 4 ? extra : desc : target;
|
|
287
|
-
};
|
|
288
|
-
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
289
|
-
var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
|
|
290
|
-
var __privateIn = (member, obj) => Object(obj) !== obj ? __typeError("Cannot use the \"in\" operator on this value") : member.has(obj);
|
|
291
|
-
var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
|
|
292
|
-
var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
|
|
293
|
-
var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
|
|
294
|
-
var _watch_dec;
|
|
295
|
-
var _a;
|
|
296
|
-
var _init;
|
|
297
|
-
async function* watchModelSettingsChanges(events, signal) {
|
|
298
|
-
signal.throwIfAborted();
|
|
299
|
-
const pending = /* @__PURE__ */ new Map();
|
|
300
|
-
let full = false;
|
|
301
|
-
let wake;
|
|
302
|
-
const changed = (ns, revision) => {
|
|
303
|
-
let frame;
|
|
304
|
-
try {
|
|
305
|
-
frame = parseModelSettingsChangeFrame({
|
|
306
|
-
kind: "changed",
|
|
307
|
-
ns,
|
|
308
|
-
revision
|
|
309
|
-
});
|
|
310
|
-
} catch {
|
|
311
|
-
return;
|
|
312
|
-
}
|
|
313
|
-
if (!full) {
|
|
314
|
-
if (!pending.has(ns) && pending.size >= 256) {
|
|
315
|
-
pending.clear();
|
|
316
|
-
full = true;
|
|
317
|
-
} else pending.set(ns, frame);
|
|
318
|
-
}
|
|
319
|
-
wake?.();
|
|
320
|
-
};
|
|
321
|
-
const disposers = [];
|
|
322
|
-
const cleanup = () => {
|
|
323
|
-
for (const off of disposers.splice(0).reverse()) off();
|
|
324
|
-
pending.clear();
|
|
325
|
-
};
|
|
326
|
-
const aborted = () => {
|
|
327
|
-
cleanup();
|
|
328
|
-
wake?.();
|
|
329
|
-
};
|
|
330
|
-
signal.addEventListener("abort", aborted, { once: true });
|
|
331
|
-
try {
|
|
332
|
-
disposers.push(events.on(MODEL_SETTINGS_CHANGED_EVENT, ({ ns, revision }) => changed(ns, revision)));
|
|
333
|
-
disposers.push(events.on("settings/document-updated", changed));
|
|
334
|
-
signal.throwIfAborted();
|
|
335
|
-
yield { kind: "ready" };
|
|
336
|
-
while (true) {
|
|
337
|
-
signal.throwIfAborted();
|
|
338
|
-
if (full) {
|
|
339
|
-
full = false;
|
|
340
|
-
yield { kind: "ready" };
|
|
341
|
-
continue;
|
|
342
|
-
}
|
|
343
|
-
if (pending.size) {
|
|
344
|
-
const [ns, frame] = pending.entries().next().value;
|
|
345
|
-
pending.delete(ns);
|
|
346
|
-
yield frame;
|
|
347
|
-
continue;
|
|
348
|
-
}
|
|
349
|
-
await new Promise((resolve) => {
|
|
350
|
-
wake = resolve;
|
|
351
|
-
if (signal.aborted || full || pending.size) resolve();
|
|
352
|
-
});
|
|
353
|
-
wake = void 0;
|
|
354
|
-
}
|
|
355
|
-
} finally {
|
|
356
|
-
signal.removeEventListener("abort", aborted);
|
|
357
|
-
cleanup();
|
|
358
|
-
}
|
|
244
|
+
/** Model Hub forwards every settings namespace; feature plugins filter their own. */
|
|
245
|
+
function registerHubModelSettingsChanges(ctx) {
|
|
246
|
+
createModelSettingsChanges(ctx, modelSettingsChangesIdentity("@klarkxy/dsh-model-hub"));
|
|
359
247
|
}
|
|
360
|
-
var ModelSettingsChangesController = class extends (_a = TypertRemoteService, _watch_dec = [Remote({ mode: "stream" })], _a) {
|
|
361
|
-
constructor(ctx) {
|
|
362
|
-
super(ctx, MODEL_SETTINGS_CHANGES_REMOTE.descriptors[0].service, { namespace: MODEL_SETTINGS_CHANGES_REMOTE.descriptors[0].namespace });
|
|
363
|
-
__runInitializers(_init, 5, this);
|
|
364
|
-
__publicField(this, "lifetime", new AbortController());
|
|
365
|
-
ctx.effect(() => () => {
|
|
366
|
-
this.lifetime.abort(/* @__PURE__ */ new Error("Model settings sync owner unloaded"));
|
|
367
|
-
});
|
|
368
|
-
}
|
|
369
|
-
watch(signal) {
|
|
370
|
-
return watchModelSettingsChanges(this.ctx, AbortSignal.any([this.lifetime.signal, signal]));
|
|
371
|
-
}
|
|
372
|
-
};
|
|
373
|
-
_init = __decoratorStart(_a);
|
|
374
|
-
__decorateElement(_init, 1, "watch", _watch_dec, ModelSettingsChangesController);
|
|
375
|
-
__decoratorMetadata(_init, ModelSettingsChangesController);
|
|
376
248
|
//#endregion
|
|
377
249
|
//#region src/cast.ts
|
|
378
250
|
/**
|
|
@@ -863,7 +735,7 @@ const Config = Schema.object({
|
|
|
863
735
|
}).volatile()
|
|
864
736
|
});
|
|
865
737
|
function apply(ctx) {
|
|
866
|
-
|
|
738
|
+
registerHubModelSettingsChanges(ctx);
|
|
867
739
|
const profile = ctx.get("profileContext");
|
|
868
740
|
const settings = ctx.settings;
|
|
869
741
|
const describe = () => settings.describe({ redactSecrets: true });
|
|
@@ -891,7 +763,8 @@ function apply(ctx) {
|
|
|
891
763
|
interpolate: false,
|
|
892
764
|
text: () => cast.promptText(() => ctx.get("subagentModelSelection")?.current())
|
|
893
765
|
});
|
|
894
|
-
const run = (
|
|
766
|
+
const run = async () => {
|
|
767
|
+
const reason = "requested";
|
|
895
768
|
let report;
|
|
896
769
|
try {
|
|
897
770
|
report = buildProbeReport(describe());
|
|
@@ -902,20 +775,33 @@ function apply(ctx) {
|
|
|
902
775
|
ctx.logger.info("model-hub: probe (%s): %d namespaces, %d with model fields; self-test extra-key=%s role=%s", reason, report.totalNamespaces, report.namespacesWithModelFields, report.selfTest.extraKey, report.selfTest.role);
|
|
903
776
|
if (profile?.dir) try {
|
|
904
777
|
const dir = join(profile.dir, "data", "model-hub");
|
|
905
|
-
|
|
906
|
-
|
|
778
|
+
await mkdir(dir, { recursive: true });
|
|
779
|
+
await writeFile(join(dir, "probe-report.json"), JSON.stringify(report, null, 2));
|
|
907
780
|
} catch (error) {
|
|
908
781
|
ctx.logger.warn("model-hub: could not write probe report: %s", error instanceof Error ? error.message : String(error));
|
|
909
782
|
}
|
|
910
783
|
};
|
|
911
|
-
run(
|
|
912
|
-
|
|
784
|
+
const diagnostics = createProbeDiagnostics(run, (error) => {
|
|
785
|
+
ctx.logger.warn("model-hub: diagnostics failed: %s", String(error));
|
|
786
|
+
});
|
|
787
|
+
ctx.effect(() => {
|
|
788
|
+
const off = ctx.on("settings/document-updated", () => diagnostics.invalidate());
|
|
789
|
+
diagnostics.request();
|
|
790
|
+
return async () => {
|
|
791
|
+
off();
|
|
792
|
+
await diagnostics.dispose();
|
|
793
|
+
};
|
|
794
|
+
});
|
|
913
795
|
ctx.effect(() => registerHostRpc(ctx, CHANNEL, async (endpoint, payload, signal) => {
|
|
914
796
|
try {
|
|
915
|
-
if (endpoint === "fields.list")
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
797
|
+
if (endpoint === "fields.list") {
|
|
798
|
+
const value = await hub.list(signal);
|
|
799
|
+
diagnostics.request();
|
|
800
|
+
return {
|
|
801
|
+
ok: true,
|
|
802
|
+
value
|
|
803
|
+
};
|
|
804
|
+
}
|
|
919
805
|
if (endpoint === "fields.set") return {
|
|
920
806
|
ok: true,
|
|
921
807
|
value: await hub.set(payload, signal)
|