@linxin666/dsh-client-ui-task-board 0.3.23 → 0.4.0
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/icon.svg +3 -0
- package/lib/client.js +351 -85
- package/lib/client.js.map +1 -1
- package/lib/index.js +174 -916
- package/lib/types/client/PluginSettingsCard.d.ts +4 -0
- package/lib/types/client/TaskBoardSettingsCard.d.ts +5 -5
- package/lib/types/client/board/TaskForm.d.ts +6 -1
- package/lib/types/client/board/parse-model-pref.d.ts +4 -0
- package/lib/types/client/index.d.ts +43 -10
- package/lib/types/client/locales.d.ts +1 -0
- package/lib/types/client/main-session.d.ts +32 -0
- package/lib/types/client/plugin-card-seat.d.ts +103 -0
- package/lib/types/client/settings-form.d.ts +17 -17
- package/lib/types/core/controller.d.ts +10 -8
- package/lib/types/core/session-reuse.d.ts +4 -2
- package/lib/types/host-ledger.d.ts +15 -0
- package/lib/types/http.d.ts +18 -1
- package/lib/types/index.d.ts +72 -17
- package/package.json +30 -24
- package/src/client/PluginSettingsCard.tsx +7 -2
- package/src/client/TaskBoardSettingsCard.tsx +7 -5
- package/src/client/board/NewTaskModal.tsx +33 -7
- package/src/client/board/TaskForm.tsx +13 -0
- package/src/client/board/parse-model-pref.ts +35 -0
- package/src/client/board.module.css +31 -12
- package/src/client/index.ts +121 -38
- package/src/client/locales.ts +2 -0
- package/src/client/main-session.ts +43 -0
- package/src/client/plugin-card-seat.ts +192 -0
- package/src/client/settings-form.ts +34 -31
- package/src/client/sidebar-entry-core.ts +3 -3
- package/src/client/sidebar-entry.ts +2 -2
- package/src/core/controller.ts +12 -8
- package/src/core/session-reuse.ts +14 -5
- package/src/host-ledger.ts +59 -11
- package/src/http.ts +23 -1
- package/src/index.ts +97 -52
package/lib/index.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
|
-
import z from "schemastery";
|
|
2
|
+
import z from "@deepseek-ai/schemastery";
|
|
3
3
|
import { spawn, spawnSync } from "node:child_process";
|
|
4
4
|
import { createHash, timingSafeEqual } from "node:crypto";
|
|
5
5
|
import { chmodSync, closeSync, existsSync, fsyncSync, mkdirSync, openSync, readFileSync, readdirSync, renameSync, statSync, unlinkSync, writeFileSync } from "node:fs";
|
|
6
6
|
import { dirname, isAbsolute, join, win32 } from "node:path";
|
|
7
7
|
import { homedir } from "node:os";
|
|
8
8
|
import { isAbsolute as isAbsolute$1, join as join$1 } from "node:path/posix";
|
|
9
|
-
import { Service } from "@deepseek-ai/cordis";
|
|
9
|
+
import { Context, Service } from "@deepseek-ai/cordis";
|
|
10
10
|
//#region src/core/schedule.ts
|
|
11
11
|
/** Inclusive ranges per field, in cron order. */
|
|
12
12
|
const FIELD_RANGES = [
|
|
@@ -181,8 +181,10 @@ function isDigits(value) {
|
|
|
181
181
|
* Pick the session a new execution of this task may continue in, or undefined
|
|
182
182
|
* to mint a fresh conversation. Reuse requires ALL of:
|
|
183
183
|
* - the task opted in (`reuseSession === true`);
|
|
184
|
-
* - the task's newest execution carries a session id
|
|
185
|
-
*
|
|
184
|
+
* - the task's newest SETTLED execution carries a session id (issue #1587: the
|
|
185
|
+
* launch path calls this after `startExecution` appended this run's own open
|
|
186
|
+
* record, so reading the array tail always found an unsettled row and reuse
|
|
187
|
+
* never happened);
|
|
186
188
|
* - the roster is known and that session is present and idle.
|
|
187
189
|
*
|
|
188
190
|
* An unknown roster (session/list unavailable) never reuses: minting a fresh
|
|
@@ -194,8 +196,15 @@ function isDigits(value) {
|
|
|
194
196
|
*/
|
|
195
197
|
function reusableSessionId(task, idleSessionIds) {
|
|
196
198
|
if (task.reuseSession !== true || idleSessionIds === void 0) return void 0;
|
|
197
|
-
|
|
198
|
-
|
|
199
|
+
let last;
|
|
200
|
+
for (let index = task.executions.length - 1; index >= 0; index -= 1) {
|
|
201
|
+
const candidate = task.executions[index];
|
|
202
|
+
if (candidate.sessionId !== void 0 && candidate.endedAt !== void 0) {
|
|
203
|
+
last = candidate;
|
|
204
|
+
break;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
if (last === void 0 || last.sessionId === void 0) return void 0;
|
|
199
208
|
return idleSessionIds.has(last.sessionId) ? last.sessionId : void 0;
|
|
200
209
|
}
|
|
201
210
|
//#endregion
|
|
@@ -1406,6 +1415,11 @@ function processIsAlive(pid) {
|
|
|
1406
1415
|
}
|
|
1407
1416
|
}
|
|
1408
1417
|
const PROCESS_PROBE_TIMEOUT_MS = 3e3;
|
|
1418
|
+
/**
|
|
1419
|
+
* The CIM fallback pays a WMI cold start, so it gets a wider budget than the
|
|
1420
|
+
* direct `Get-Process` read it backs up.
|
|
1421
|
+
*/
|
|
1422
|
+
const CIM_PROBE_TIMEOUT_MS = 8e3;
|
|
1409
1423
|
let ownStartTime;
|
|
1410
1424
|
let ownStartTimeResolved = false;
|
|
1411
1425
|
/**
|
|
@@ -1430,6 +1444,52 @@ function linuxStartTimeMs(pid) {
|
|
|
1430
1444
|
return;
|
|
1431
1445
|
}
|
|
1432
1446
|
}
|
|
1447
|
+
/** Default probe: one hidden, profile-free PowerShell process per script. */
|
|
1448
|
+
const runPowerShellProbe = (script, timeoutMs) => {
|
|
1449
|
+
const probe = spawnSync("powershell", [
|
|
1450
|
+
"-NoProfile",
|
|
1451
|
+
"-NonInteractive",
|
|
1452
|
+
"-Command",
|
|
1453
|
+
script
|
|
1454
|
+
], {
|
|
1455
|
+
timeout: timeoutMs,
|
|
1456
|
+
windowsHide: true
|
|
1457
|
+
});
|
|
1458
|
+
if (probe.status !== 0 || probe.stdout.length === 0) return void 0;
|
|
1459
|
+
return probe.stdout.toString("utf8").trim();
|
|
1460
|
+
};
|
|
1461
|
+
/** The epoch-millisecond reading a probe printed, or undefined when unusable. */
|
|
1462
|
+
function parseProbeEpochMs(raw) {
|
|
1463
|
+
if (raw === void 0 || raw.trim() === "") return void 0;
|
|
1464
|
+
const started = Number(raw.trim());
|
|
1465
|
+
return Number.isFinite(started) ? started : void 0;
|
|
1466
|
+
}
|
|
1467
|
+
/** Start time through Get-Process: precise, but empty for protected processes. */
|
|
1468
|
+
function getProcessStartScript(pid) {
|
|
1469
|
+
return "[DateTimeOffset]::FromFileTime((Get-Process -Id " + String(pid) + " -ErrorAction SilentlyContinue).StartTime.ToUniversalTime().ToFileTime()).ToUnixTimeMilliseconds()";
|
|
1470
|
+
}
|
|
1471
|
+
/** Start time through Win32_Process: readable for System/svchost too. */
|
|
1472
|
+
function cimStartScript(pid) {
|
|
1473
|
+
return "$p=Get-CimInstance Win32_Process -Filter \"ProcessId=" + String(pid) + "\" -ErrorAction SilentlyContinue;if($p -ne $null){[DateTimeOffset]::FromFileTime($p.CreationDate.ToUniversalTime().ToFileTime()).ToUnixTimeMilliseconds()}";
|
|
1474
|
+
}
|
|
1475
|
+
/**
|
|
1476
|
+
* Windows start time (Unix epoch ms) of a live process.
|
|
1477
|
+
*
|
|
1478
|
+
* `Get-Process` is the precise first choice, but an unprivileged caller cannot
|
|
1479
|
+
* read `.StartTime` for a protected process (System, svchost): the property is
|
|
1480
|
+
* empty, so the probe returns nothing. Without a fallback, a crash leftover
|
|
1481
|
+
* lock whose PID was reused by such a process could never be proven stale and
|
|
1482
|
+
* blocked every startup until the lock was deleted by hand (issue #1629).
|
|
1483
|
+
* Win32_Process through CIM reports the same CreationDate for those processes
|
|
1484
|
+
* at the same millisecond precision, so it is the second identity source. The
|
|
1485
|
+
* probe is injectable so the fallback chain is testable off Windows.
|
|
1486
|
+
*/
|
|
1487
|
+
function win32StartTimeMs(pid, probe = runPowerShellProbe) {
|
|
1488
|
+
if (!Number.isSafeInteger(pid) || pid <= 0) return void 0;
|
|
1489
|
+
const direct = parseProbeEpochMs(probe(getProcessStartScript(pid), PROCESS_PROBE_TIMEOUT_MS));
|
|
1490
|
+
if (direct !== void 0) return direct;
|
|
1491
|
+
return parseProbeEpochMs(probe(cimStartScript(pid), CIM_PROBE_TIMEOUT_MS));
|
|
1492
|
+
}
|
|
1433
1493
|
/**
|
|
1434
1494
|
* Best-effort start time (Unix epoch ms) of a live process. Used to prove
|
|
1435
1495
|
* whether the ledger lock really belongs to the PID recorded in it, so a
|
|
@@ -1439,20 +1499,7 @@ function linuxStartTimeMs(pid) {
|
|
|
1439
1499
|
*/
|
|
1440
1500
|
function processStartTimeMs(pid) {
|
|
1441
1501
|
if (process.platform === "linux") return linuxStartTimeMs(pid);
|
|
1442
|
-
if (process.platform === "win32")
|
|
1443
|
-
const probe = spawnSync("powershell", [
|
|
1444
|
-
"-NoProfile",
|
|
1445
|
-
"-NonInteractive",
|
|
1446
|
-
"-Command",
|
|
1447
|
-
"[DateTimeOffset]::FromFileTime((Get-Process -Id " + String(pid) + " -ErrorAction SilentlyContinue).StartTime.ToUniversalTime().ToFileTime()).ToUnixTimeMilliseconds()"
|
|
1448
|
-
], {
|
|
1449
|
-
timeout: PROCESS_PROBE_TIMEOUT_MS,
|
|
1450
|
-
windowsHide: true
|
|
1451
|
-
});
|
|
1452
|
-
if (probe.status !== 0 || probe.stdout.length === 0) return void 0;
|
|
1453
|
-
const started = Number(probe.stdout.toString("utf8").trim());
|
|
1454
|
-
return Number.isFinite(started) ? started : void 0;
|
|
1455
|
-
}
|
|
1502
|
+
if (process.platform === "win32") return win32StartTimeMs(pid);
|
|
1456
1503
|
const env = {
|
|
1457
1504
|
...process.env,
|
|
1458
1505
|
LC_ALL: "C"
|
|
@@ -3032,7 +3079,7 @@ function safeConsoleError(message, ...args) {
|
|
|
3032
3079
|
} catch {}
|
|
3033
3080
|
}
|
|
3034
3081
|
//#endregion
|
|
3035
|
-
//#region ../../node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.
|
|
3082
|
+
//#region ../../node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.7-rc.1_@deepseek-ai+cordis@4.0.4/node_modules/@deepseek-ai/dsh-typert-protocol/lib/index.js
|
|
3036
3083
|
/** The one Remote failure class shared by owners, the Gateway, and consumers. */
|
|
3037
3084
|
/**
|
|
3038
3085
|
* One Remote call failure: a real Error carrying its stable code and typed
|
|
@@ -3076,7 +3123,10 @@ function isTypertRemoteSegment(value) {
|
|
|
3076
3123
|
}
|
|
3077
3124
|
const REMOTE_METHOD_DESCRIPTOR = "@deepseek-ai/dsh-typert-protocol/remote-methods";
|
|
3078
3125
|
/**
|
|
3079
|
-
* Bind one visible Service field to a Cordis key and Remote namespace.
|
|
3126
|
+
* Bind one visible Service field to a Cordis key and Remote namespace. A
|
|
3127
|
+
* service that owns a Cordis Context also gives its tree `ctx.invocation`,
|
|
3128
|
+
* `undefined` outside a Remote call, so no `TypertRemoteService` is needed for
|
|
3129
|
+
* a Host composition to read it.
|
|
3080
3130
|
* @param service - owning Service instance, normally `this`.
|
|
3081
3131
|
* @param serviceKey - exact Cordis service key.
|
|
3082
3132
|
* @param options - optional distinct wire namespace.
|
|
@@ -3086,6 +3136,8 @@ function bindTypertRemote(service, serviceKey, options = {}) {
|
|
|
3086
3136
|
validateName("service key", serviceKey);
|
|
3087
3137
|
const namespace = options.namespace ?? serviceKey;
|
|
3088
3138
|
validateName("namespace", namespace);
|
|
3139
|
+
const ctx = Reflect.get(service, "ctx");
|
|
3140
|
+
if (ctx instanceof Context) provideInvocationAccessor(ctx);
|
|
3089
3141
|
return Object.freeze({
|
|
3090
3142
|
service,
|
|
3091
3143
|
serviceKey,
|
|
@@ -3107,6 +3159,16 @@ var TypertRemoteService = class extends Service {
|
|
|
3107
3159
|
this.typertRemote = bindTypertRemote(this, this.name, options);
|
|
3108
3160
|
}
|
|
3109
3161
|
};
|
|
3162
|
+
/**
|
|
3163
|
+
* Make `ctx.invocation` read as `undefined` outside a Remote call instead of the
|
|
3164
|
+
* reflect service's "cannot get property" error; a call-derived Context shadows
|
|
3165
|
+
* the accessor with its own property. The first Remote Service constructed in a
|
|
3166
|
+
* tree registers it on the root, where it outlives any one Service.
|
|
3167
|
+
*/
|
|
3168
|
+
function provideInvocationAccessor(ctx) {
|
|
3169
|
+
if (Object.hasOwn(ctx.root.reflect.props, "invocation")) return;
|
|
3170
|
+
ctx.root.accessor("invocation", { get: () => void 0 });
|
|
3171
|
+
}
|
|
3110
3172
|
function Remote(methodExportOrOptions, context) {
|
|
3111
3173
|
if (typeof methodExportOrOptions === "string") {
|
|
3112
3174
|
validateName("Remote export name", methodExportOrOptions);
|
|
@@ -3177,7 +3239,7 @@ function validateName(subject, value) {
|
|
|
3177
3239
|
if (!isTypertRemoteSegment(value)) throw new TypeError(`typert-protocol: ${subject} must contain only RPC endpoint segment characters`);
|
|
3178
3240
|
}
|
|
3179
3241
|
//#endregion
|
|
3180
|
-
//#region ../../node_modules/.pnpm/@deepseek-ai+dsh-util-values@0.1.
|
|
3242
|
+
//#region ../../node_modules/.pnpm/@deepseek-ai+dsh-util-values@0.1.7-rc.1_@deepseek-ai+cordis@4.0.4/node_modules/@deepseek-ai/dsh-util-values/lib/index.js
|
|
3181
3243
|
/**
|
|
3182
3244
|
* Deep-freeze an object graph in place while leaving live AbortSignal objects mutable.
|
|
3183
3245
|
* @param value - value to freeze.
|
|
@@ -3221,7 +3283,7 @@ function deepFreeze(value) {
|
|
|
3221
3283
|
return value;
|
|
3222
3284
|
}
|
|
3223
3285
|
//#endregion
|
|
3224
|
-
//#region ../../node_modules/.pnpm/@deepseek-ai+dsh-util-crypto@0.1.
|
|
3286
|
+
//#region ../../node_modules/.pnpm/@deepseek-ai+dsh-util-crypto@0.1.7-rc.1_@deepseek-ai+cordis@4.0.4/node_modules/@deepseek-ai/dsh-util-crypto/lib/index.js
|
|
3225
3287
|
/**
|
|
3226
3288
|
* Random v4 UUID, minted from `crypto.getRandomValues`.
|
|
3227
3289
|
* @returns the UUID string.
|
|
@@ -3234,7 +3296,7 @@ function randomUUID() {
|
|
|
3234
3296
|
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
3235
3297
|
}
|
|
3236
3298
|
//#endregion
|
|
3237
|
-
//#region ../../node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.
|
|
3299
|
+
//#region ../../node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.7-rc.1_@deepseek-ai+cordis@4.0.4/node_modules/@deepseek-ai/dsh-brand/lib/index.js
|
|
3238
3300
|
/**
|
|
3239
3301
|
* Duplicate-install-safe nominal primitive helpers.
|
|
3240
3302
|
*
|
|
@@ -3257,801 +3319,11 @@ function brandString(value) {
|
|
|
3257
3319
|
return value;
|
|
3258
3320
|
}
|
|
3259
3321
|
//#endregion
|
|
3260
|
-
//#region ../../node_modules/.pnpm/@deepseek-ai+
|
|
3261
|
-
/** Return true when a value is `null` or `undefined`. */
|
|
3262
|
-
function isNullable(value) {
|
|
3263
|
-
return value === null || value === void 0;
|
|
3264
|
-
}
|
|
3265
|
-
/** Return true for non-array object values. */
|
|
3266
|
-
function isPlainObject(data) {
|
|
3267
|
-
return data && typeof data === "object" && !Array.isArray(data);
|
|
3268
|
-
}
|
|
3269
|
-
/** Filter object entries and return a new object. */
|
|
3270
|
-
function filterKeys(object, filter) {
|
|
3271
|
-
return Object.fromEntries(Object.entries(object).filter(([key, value]) => filter(key, value)));
|
|
3272
|
-
}
|
|
3273
|
-
/** Map object values while preserving the original key set. */
|
|
3274
|
-
function mapValues(object, transform) {
|
|
3275
|
-
return Object.fromEntries(Object.entries(object).map(([key, value]) => [key, transform(value, key)]));
|
|
3276
|
-
}
|
|
3277
|
-
/** Pick selected keys from an object, optionally including `undefined` values. */
|
|
3278
|
-
function pick(source, keys, forced) {
|
|
3279
|
-
if (!keys) return { ...source };
|
|
3280
|
-
const result = {};
|
|
3281
|
-
for (const key of keys) if (forced || source[key] !== void 0) result[key] = source[key];
|
|
3282
|
-
return result;
|
|
3283
|
-
}
|
|
3284
|
-
/** Test values using `instanceof` with a `toStringTag` fallback. */
|
|
3285
|
-
function is(type, value) {
|
|
3286
|
-
if (arguments.length === 1) return (value) => is(type, value);
|
|
3287
|
-
return type in globalThis && value instanceof globalThis[type] || Object.prototype.toString.call(value).slice(8, -1) === type;
|
|
3288
|
-
}
|
|
3289
|
-
function isArrayBufferLike(value) {
|
|
3290
|
-
return is("ArrayBuffer", value) || is("SharedArrayBuffer", value);
|
|
3291
|
-
}
|
|
3292
|
-
function isArrayBufferSource(value) {
|
|
3293
|
-
return isArrayBufferLike(value) || ArrayBuffer.isView(value);
|
|
3294
|
-
}
|
|
3295
|
-
/** Binary source detection and base64/hex conversion helpers. */
|
|
3296
|
-
var Binary;
|
|
3297
|
-
(function(Binary) {
|
|
3298
|
-
Binary.is = isArrayBufferLike;
|
|
3299
|
-
Binary.isSource = isArrayBufferSource;
|
|
3300
|
-
function fromSource(source) {
|
|
3301
|
-
if (ArrayBuffer.isView(source)) return source.buffer.slice(source.byteOffset, source.byteOffset + source.byteLength);
|
|
3302
|
-
else return source;
|
|
3303
|
-
}
|
|
3304
|
-
Binary.fromSource = fromSource;
|
|
3305
|
-
function toBase64(source) {
|
|
3306
|
-
source = fromSource(source);
|
|
3307
|
-
if (typeof Buffer !== "undefined") return Buffer.from(source).toString("base64");
|
|
3308
|
-
let binary = "";
|
|
3309
|
-
const bytes = new Uint8Array(source);
|
|
3310
|
-
for (let i = 0; i < bytes.byteLength; i++) binary += String.fromCharCode(bytes[i]);
|
|
3311
|
-
return btoa(binary);
|
|
3312
|
-
}
|
|
3313
|
-
Binary.toBase64 = toBase64;
|
|
3314
|
-
function fromBase64(source) {
|
|
3315
|
-
if (typeof Buffer !== "undefined") return fromSource(Buffer.from(source, "base64"));
|
|
3316
|
-
return Uint8Array.from(atob(source), (c) => c.charCodeAt(0));
|
|
3317
|
-
}
|
|
3318
|
-
Binary.fromBase64 = fromBase64;
|
|
3319
|
-
function toHex(source) {
|
|
3320
|
-
source = fromSource(source);
|
|
3321
|
-
if (typeof Buffer !== "undefined") return Buffer.from(source).toString("hex");
|
|
3322
|
-
return Array.from(new Uint8Array(source), (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
3323
|
-
}
|
|
3324
|
-
Binary.toHex = toHex;
|
|
3325
|
-
function fromHex(source) {
|
|
3326
|
-
if (typeof Buffer !== "undefined") return fromSource(Buffer.from(source, "hex"));
|
|
3327
|
-
const hex = source.length % 2 === 0 ? source : source.slice(0, source.length - 1);
|
|
3328
|
-
const buffer = [];
|
|
3329
|
-
for (let i = 0; i < hex.length; i += 2) buffer.push(parseInt(`${hex[i]}${hex[i + 1]}`, 16));
|
|
3330
|
-
return Uint8Array.from(buffer).buffer;
|
|
3331
|
-
}
|
|
3332
|
-
Binary.fromHex = fromHex;
|
|
3333
|
-
})(Binary || (Binary = {}));
|
|
3334
|
-
Binary.fromBase64;
|
|
3335
|
-
Binary.toBase64;
|
|
3336
|
-
Binary.fromHex;
|
|
3337
|
-
Binary.toHex;
|
|
3338
|
-
/** Deep-clone common JavaScript values while preserving prototypes and cycles. */
|
|
3339
|
-
function clone(source, refs = /* @__PURE__ */ new Map()) {
|
|
3340
|
-
if (!source || typeof source !== "object") return source;
|
|
3341
|
-
if (is("Date", source)) return new Date(source.valueOf());
|
|
3342
|
-
if (is("RegExp", source)) return new RegExp(source.source, source.flags);
|
|
3343
|
-
if (isArrayBufferLike(source)) return source.slice(0);
|
|
3344
|
-
if (ArrayBuffer.isView(source)) return source.buffer.slice(source.byteOffset, source.byteOffset + source.byteLength);
|
|
3345
|
-
const cached = refs.get(source);
|
|
3346
|
-
if (cached) return cached;
|
|
3347
|
-
if (Array.isArray(source)) {
|
|
3348
|
-
const result = [];
|
|
3349
|
-
refs.set(source, result);
|
|
3350
|
-
source.forEach((value, index) => {
|
|
3351
|
-
result[index] = Reflect.apply(clone, null, [value, refs]);
|
|
3352
|
-
});
|
|
3353
|
-
return result;
|
|
3354
|
-
}
|
|
3355
|
-
const result = Object.create(Object.getPrototypeOf(source));
|
|
3356
|
-
refs.set(source, result);
|
|
3357
|
-
for (const key of Reflect.ownKeys(source)) {
|
|
3358
|
-
const descriptor = { ...Reflect.getOwnPropertyDescriptor(source, key) };
|
|
3359
|
-
if ("value" in descriptor) descriptor.value = Reflect.apply(clone, null, [descriptor.value, refs]);
|
|
3360
|
-
Reflect.defineProperty(result, key, descriptor);
|
|
3361
|
-
}
|
|
3362
|
-
return result;
|
|
3363
|
-
}
|
|
3364
|
-
/** Deeply compare arrays, dates, regexps, buffers, and plain object fields. */
|
|
3365
|
-
function deepEqual(a, b, strict) {
|
|
3366
|
-
if (a === b) return true;
|
|
3367
|
-
if (!strict && isNullable(a) && isNullable(b)) return true;
|
|
3368
|
-
if (typeof a !== typeof b) return false;
|
|
3369
|
-
if (typeof a !== "object") return false;
|
|
3370
|
-
if (!a || !b) return false;
|
|
3371
|
-
function check(test, then) {
|
|
3372
|
-
return test(a) ? test(b) ? then(a, b) : false : test(b) ? false : void 0;
|
|
3373
|
-
}
|
|
3374
|
-
return check(Array.isArray, (a, b) => a.length === b.length && a.every((item, index) => deepEqual(item, b[index]))) ?? check(is("Date"), (a, b) => a.valueOf() === b.valueOf()) ?? check(is("RegExp"), (a, b) => a.source === b.source && a.flags === b.flags) ?? check(isArrayBufferLike, (a, b) => {
|
|
3375
|
-
if (a.byteLength !== b.byteLength) return false;
|
|
3376
|
-
const viewA = new Uint8Array(a);
|
|
3377
|
-
const viewB = new Uint8Array(b);
|
|
3378
|
-
for (let i = 0; i < viewA.length; i++) if (viewA[i] !== viewB[i]) return false;
|
|
3379
|
-
return true;
|
|
3380
|
-
}) ?? Object.keys({
|
|
3381
|
-
...a,
|
|
3382
|
-
...b
|
|
3383
|
-
}).every((key) => deepEqual(a[key], b[key], strict));
|
|
3384
|
-
}
|
|
3385
|
-
/** Time constants plus parsing and formatting helpers. */
|
|
3386
|
-
var Time;
|
|
3387
|
-
(function(Time) {
|
|
3388
|
-
Time.millisecond = 1;
|
|
3389
|
-
Time.second = 1e3;
|
|
3390
|
-
Time.minute = Time.second * 60;
|
|
3391
|
-
Time.hour = Time.minute * 60;
|
|
3392
|
-
Time.day = Time.hour * 24;
|
|
3393
|
-
Time.week = Time.day * 7;
|
|
3394
|
-
let timezoneOffset = (/* @__PURE__ */ new Date()).getTimezoneOffset();
|
|
3395
|
-
function setTimezoneOffset(offset) {
|
|
3396
|
-
timezoneOffset = offset;
|
|
3397
|
-
}
|
|
3398
|
-
Time.setTimezoneOffset = setTimezoneOffset;
|
|
3399
|
-
function getTimezoneOffset() {
|
|
3400
|
-
return timezoneOffset;
|
|
3401
|
-
}
|
|
3402
|
-
Time.getTimezoneOffset = getTimezoneOffset;
|
|
3403
|
-
function getDateNumber(date = /* @__PURE__ */ new Date(), offset) {
|
|
3404
|
-
if (typeof date === "number") date = new Date(date);
|
|
3405
|
-
if (offset === void 0) offset = timezoneOffset;
|
|
3406
|
-
return Math.floor((date.valueOf() / Time.minute - offset) / 1440);
|
|
3407
|
-
}
|
|
3408
|
-
Time.getDateNumber = getDateNumber;
|
|
3409
|
-
function fromDateNumber(value, offset) {
|
|
3410
|
-
const date = new Date(value * Time.day);
|
|
3411
|
-
if (offset === void 0) offset = timezoneOffset;
|
|
3412
|
-
return new Date(+date + offset * Time.minute);
|
|
3413
|
-
}
|
|
3414
|
-
Time.fromDateNumber = fromDateNumber;
|
|
3415
|
-
const numeric = /\d+(?:\.\d+)?/.source;
|
|
3416
|
-
const timeRegExp = new RegExp(`^${[
|
|
3417
|
-
"w(?:eek(?:s)?)?",
|
|
3418
|
-
"d(?:ay(?:s)?)?",
|
|
3419
|
-
"h(?:our(?:s)?)?",
|
|
3420
|
-
"m(?:in(?:ute)?(?:s)?)?",
|
|
3421
|
-
"s(?:ec(?:ond)?(?:s)?)?"
|
|
3422
|
-
].map((unit) => `(${numeric}${unit})?`).join("")}$`);
|
|
3423
|
-
function parseTime(source) {
|
|
3424
|
-
const capture = timeRegExp.exec(source);
|
|
3425
|
-
if (!capture) return 0;
|
|
3426
|
-
return (parseFloat(capture[1]) * Time.week || 0) + (parseFloat(capture[2]) * Time.day || 0) + (parseFloat(capture[3]) * Time.hour || 0) + (parseFloat(capture[4]) * Time.minute || 0) + (parseFloat(capture[5]) * Time.second || 0);
|
|
3427
|
-
}
|
|
3428
|
-
Time.parseTime = parseTime;
|
|
3429
|
-
function parseDate(date) {
|
|
3430
|
-
const parsed = parseTime(date);
|
|
3431
|
-
if (parsed) date = Date.now() + parsed;
|
|
3432
|
-
else if (/^\d{1,2}(:\d{1,2}){1,2}$/.test(date)) date = `${(/* @__PURE__ */ new Date()).toLocaleDateString()}-${date}`;
|
|
3433
|
-
else if (/^\d{1,2}-\d{1,2}-\d{1,2}(:\d{1,2}){1,2}$/.test(date)) date = `${(/* @__PURE__ */ new Date()).getFullYear()}-${date}`;
|
|
3434
|
-
return date ? new Date(date) : /* @__PURE__ */ new Date();
|
|
3435
|
-
}
|
|
3436
|
-
Time.parseDate = parseDate;
|
|
3437
|
-
function format(ms) {
|
|
3438
|
-
const abs = Math.abs(ms);
|
|
3439
|
-
if (abs >= Time.day - Time.hour / 2) return Math.round(ms / Time.day) + "d";
|
|
3440
|
-
else if (abs >= Time.hour - Time.minute / 2) return Math.round(ms / Time.hour) + "h";
|
|
3441
|
-
else if (abs >= Time.minute - Time.second / 2) return Math.round(ms / Time.minute) + "m";
|
|
3442
|
-
else if (abs >= Time.second) return Math.round(ms / Time.second) + "s";
|
|
3443
|
-
return ms + "ms";
|
|
3444
|
-
}
|
|
3445
|
-
Time.format = format;
|
|
3446
|
-
function toDigits(source, length = 2) {
|
|
3447
|
-
return source.toString().padStart(length, "0");
|
|
3448
|
-
}
|
|
3449
|
-
Time.toDigits = toDigits;
|
|
3450
|
-
function template(template, time = /* @__PURE__ */ new Date()) {
|
|
3451
|
-
return template.replace("yyyy", time.getFullYear().toString()).replace("yy", time.getFullYear().toString().slice(2)).replace("MM", toDigits(time.getMonth() + 1)).replace("dd", toDigits(time.getDate())).replace("hh", toDigits(time.getHours())).replace("mm", toDigits(time.getMinutes())).replace("ss", toDigits(time.getSeconds())).replace("SSS", toDigits(time.getMilliseconds(), 3));
|
|
3452
|
-
}
|
|
3453
|
-
Time.template = template;
|
|
3454
|
-
})(Time || (Time = {}));
|
|
3455
|
-
//#endregion
|
|
3456
|
-
//#region ../../node_modules/.pnpm/@deepseek-ai+schemastery@3.18.2/node_modules/@deepseek-ai/schemastery/lib/index.mjs
|
|
3457
|
-
const kSchema = Symbol.for("schemastery");
|
|
3458
|
-
const kValidationError = Symbol.for("ValidationError");
|
|
3459
|
-
globalThis.__schemastery_index__ ??= 0;
|
|
3460
|
-
globalThis.__schemastery_refs__ = void 0;
|
|
3461
|
-
var ValidationError = class extends TypeError {
|
|
3462
|
-
options;
|
|
3463
|
-
name = "ValidationError";
|
|
3464
|
-
constructor(message, options) {
|
|
3465
|
-
let prefix = "$";
|
|
3466
|
-
for (const segment of options.path || []) if (typeof segment === "string") prefix += "." + segment;
|
|
3467
|
-
else if (typeof segment === "number") prefix += "[" + segment + "]";
|
|
3468
|
-
else if (typeof segment === "symbol") prefix += `[Symbol(${segment.toString()})]`;
|
|
3469
|
-
if (prefix.startsWith(".")) prefix = prefix.slice(1);
|
|
3470
|
-
super((prefix === "$" ? "" : `${prefix} `) + message);
|
|
3471
|
-
this.options = options;
|
|
3472
|
-
}
|
|
3473
|
-
static is(error) {
|
|
3474
|
-
return !!error?.[kValidationError];
|
|
3475
|
-
}
|
|
3476
|
-
};
|
|
3477
|
-
Object.defineProperty(ValidationError.prototype, kValidationError, { value: true });
|
|
3478
|
-
const Schema = function(options) {
|
|
3479
|
-
const schema = function(data, options = {}) {
|
|
3480
|
-
return Schema.resolve(data, schema, options)[0];
|
|
3481
|
-
};
|
|
3482
|
-
if (options.refs) {
|
|
3483
|
-
const refs = mapValues(options.refs, (options) => new Schema(options));
|
|
3484
|
-
const getRef = (uid) => refs[uid];
|
|
3485
|
-
for (const key in refs) {
|
|
3486
|
-
const options = refs[key];
|
|
3487
|
-
options.sKey = getRef(options.sKey);
|
|
3488
|
-
options.inner = getRef(options.inner);
|
|
3489
|
-
options.list = options.list && options.list.map(getRef);
|
|
3490
|
-
options.dict = options.dict && mapValues(options.dict, getRef);
|
|
3491
|
-
}
|
|
3492
|
-
return refs[options.uid];
|
|
3493
|
-
}
|
|
3494
|
-
Object.assign(schema, options);
|
|
3495
|
-
if (typeof schema.callback === "string") try {
|
|
3496
|
-
schema.callback = new Function("return " + schema.callback)();
|
|
3497
|
-
} catch {}
|
|
3498
|
-
Object.defineProperty(schema, "uid", { value: globalThis.__schemastery_index__++ });
|
|
3499
|
-
Object.setPrototypeOf(schema, Schema.prototype);
|
|
3500
|
-
schema.meta ||= {};
|
|
3501
|
-
schema.toString = schema.toString.bind(schema);
|
|
3502
|
-
return schema;
|
|
3503
|
-
};
|
|
3504
|
-
Schema.prototype = Object.create(Function.prototype);
|
|
3505
|
-
Schema.prototype[kSchema] = true;
|
|
3506
|
-
Object.defineProperty(Schema.prototype, "~standard", { get() {
|
|
3507
|
-
return {
|
|
3508
|
-
version: 1,
|
|
3509
|
-
vendor: "schemastery",
|
|
3510
|
-
validate: (value) => {
|
|
3511
|
-
try {
|
|
3512
|
-
return { value: Schema.resolve(value, this, {})[0] };
|
|
3513
|
-
} catch (error) {
|
|
3514
|
-
if (ValidationError.is(error)) return { issues: [{
|
|
3515
|
-
message: error.message,
|
|
3516
|
-
path: error.options.path
|
|
3517
|
-
}] };
|
|
3518
|
-
throw error;
|
|
3519
|
-
}
|
|
3520
|
-
}
|
|
3521
|
-
};
|
|
3522
|
-
} });
|
|
3523
|
-
Schema.ValidationError = ValidationError;
|
|
3524
|
-
Schema.prototype.toJSON = function toJSON() {
|
|
3525
|
-
if (globalThis.__schemastery_refs__) {
|
|
3526
|
-
globalThis.__schemastery_refs__[this.uid] ??= JSON.parse(JSON.stringify({ ...this }));
|
|
3527
|
-
return this.uid;
|
|
3528
|
-
}
|
|
3529
|
-
globalThis.__schemastery_refs__ = { [this.uid]: { ...this } };
|
|
3530
|
-
globalThis.__schemastery_refs__[this.uid] = JSON.parse(JSON.stringify({ ...this }));
|
|
3531
|
-
const result = {
|
|
3532
|
-
uid: this.uid,
|
|
3533
|
-
refs: globalThis.__schemastery_refs__
|
|
3534
|
-
};
|
|
3535
|
-
globalThis.__schemastery_refs__ = void 0;
|
|
3536
|
-
return result;
|
|
3537
|
-
};
|
|
3538
|
-
Schema.prototype.set = function set(key, value) {
|
|
3539
|
-
this.dict[key] = value;
|
|
3540
|
-
return this;
|
|
3541
|
-
};
|
|
3542
|
-
Schema.prototype.push = function push(value) {
|
|
3543
|
-
this.list.push(value);
|
|
3544
|
-
return this;
|
|
3545
|
-
};
|
|
3546
|
-
function mergeDesc(original, messages) {
|
|
3547
|
-
const result = typeof original === "string" ? { "": original } : { ...original };
|
|
3548
|
-
for (const locale in messages) {
|
|
3549
|
-
const value = messages[locale];
|
|
3550
|
-
if (value?.$description || value?.$desc) result[locale] = value.$description || value.$desc;
|
|
3551
|
-
else if (typeof value === "string") result[locale] = value;
|
|
3552
|
-
}
|
|
3553
|
-
return result;
|
|
3554
|
-
}
|
|
3555
|
-
function getInner(value) {
|
|
3556
|
-
return value?.$value ?? value?.$inner;
|
|
3557
|
-
}
|
|
3558
|
-
function extractKeys(data) {
|
|
3559
|
-
return filterKeys(data ?? {}, (key) => !key.startsWith("$"));
|
|
3560
|
-
}
|
|
3561
|
-
Schema.prototype.i18n = function i18n(messages) {
|
|
3562
|
-
const schema = Schema(this);
|
|
3563
|
-
const desc = mergeDesc(schema.meta.description, messages);
|
|
3564
|
-
if (Object.keys(desc).length) schema.meta.description = desc;
|
|
3565
|
-
if (schema.dict) schema.dict = mapValues(schema.dict, (inner, key) => {
|
|
3566
|
-
return inner.i18n(mapValues(messages, (data) => getInner(data)?.[key] ?? data?.[key]));
|
|
3567
|
-
});
|
|
3568
|
-
if (schema.list) schema.list = schema.list.map((inner, index) => {
|
|
3569
|
-
return inner.i18n(mapValues(messages, (data = {}) => {
|
|
3570
|
-
if (Array.isArray(getInner(data))) return getInner(data)[index];
|
|
3571
|
-
if (Array.isArray(data)) return data[index];
|
|
3572
|
-
return extractKeys(data);
|
|
3573
|
-
}));
|
|
3574
|
-
});
|
|
3575
|
-
if (schema.inner) schema.inner = schema.inner.i18n(mapValues(messages, (data) => {
|
|
3576
|
-
if (getInner(data)) return getInner(data);
|
|
3577
|
-
return extractKeys(data);
|
|
3578
|
-
}));
|
|
3579
|
-
if (schema.sKey) schema.sKey = schema.sKey.i18n(mapValues(messages, (data) => data?.$key));
|
|
3580
|
-
return schema;
|
|
3581
|
-
};
|
|
3582
|
-
Schema.prototype.extra = function extra(key, value) {
|
|
3583
|
-
const schema = Schema(this);
|
|
3584
|
-
schema.meta = {
|
|
3585
|
-
...schema.meta,
|
|
3586
|
-
[key]: value
|
|
3587
|
-
};
|
|
3588
|
-
return schema;
|
|
3589
|
-
};
|
|
3590
|
-
for (const key of [
|
|
3591
|
-
"required",
|
|
3592
|
-
"disabled",
|
|
3593
|
-
"collapse",
|
|
3594
|
-
"hidden",
|
|
3595
|
-
"loose"
|
|
3596
|
-
]) Object.assign(Schema.prototype, { [key](value = true) {
|
|
3597
|
-
const schema = Schema(this);
|
|
3598
|
-
schema.meta = {
|
|
3599
|
-
...schema.meta,
|
|
3600
|
-
[key]: value
|
|
3601
|
-
};
|
|
3602
|
-
return schema;
|
|
3603
|
-
} });
|
|
3604
|
-
Schema.prototype.deprecated = function deprecated() {
|
|
3605
|
-
const schema = Schema(this);
|
|
3606
|
-
schema.meta.badges ||= [];
|
|
3607
|
-
schema.meta.badges.push({
|
|
3608
|
-
text: "deprecated",
|
|
3609
|
-
type: "danger"
|
|
3610
|
-
});
|
|
3611
|
-
return schema;
|
|
3612
|
-
};
|
|
3613
|
-
Schema.prototype.experimental = function experimental() {
|
|
3614
|
-
const schema = Schema(this);
|
|
3615
|
-
schema.meta.badges ||= [];
|
|
3616
|
-
schema.meta.badges.push({
|
|
3617
|
-
text: "experimental",
|
|
3618
|
-
type: "warning"
|
|
3619
|
-
});
|
|
3620
|
-
return schema;
|
|
3621
|
-
};
|
|
3622
|
-
Schema.prototype.pattern = function pattern(regexp) {
|
|
3623
|
-
const schema = Schema(this);
|
|
3624
|
-
const pattern = pick(regexp, ["source", "flags"]);
|
|
3625
|
-
schema.meta = {
|
|
3626
|
-
...schema.meta,
|
|
3627
|
-
pattern
|
|
3628
|
-
};
|
|
3629
|
-
return schema;
|
|
3630
|
-
};
|
|
3631
|
-
Schema.prototype.simplify = function simplify(value) {
|
|
3632
|
-
if (deepEqual(value, this.meta.default, this.type === "dict")) return null;
|
|
3633
|
-
if (isNullable(value)) return value;
|
|
3634
|
-
if (this.type === "object" || this.type === "dict") {
|
|
3635
|
-
const result = {};
|
|
3636
|
-
for (const key in value) {
|
|
3637
|
-
const item = (this.type === "object" ? this.dict[key] : this.inner)?.simplify(value[key]);
|
|
3638
|
-
if (this.type === "dict" || !isNullable(item)) result[key] = item;
|
|
3639
|
-
}
|
|
3640
|
-
if (deepEqual(result, this.meta.default, this.type === "dict")) return null;
|
|
3641
|
-
return result;
|
|
3642
|
-
} else if (this.type === "array" || this.type === "tuple") {
|
|
3643
|
-
const result = [];
|
|
3644
|
-
value.forEach((value, index) => {
|
|
3645
|
-
const schema = this.type === "array" ? this.inner : this.list[index];
|
|
3646
|
-
const item = schema ? schema.simplify(value) : value;
|
|
3647
|
-
result.push(item);
|
|
3648
|
-
});
|
|
3649
|
-
return result;
|
|
3650
|
-
} else if (this.type === "intersect") {
|
|
3651
|
-
const result = {};
|
|
3652
|
-
for (const item of this.list) Object.assign(result, item.simplify(value));
|
|
3653
|
-
return result;
|
|
3654
|
-
} else if (this.type === "union") for (const schema of this.list) try {
|
|
3655
|
-
Schema.resolve(value, schema, {});
|
|
3656
|
-
return schema.simplify(value);
|
|
3657
|
-
} catch {}
|
|
3658
|
-
return value;
|
|
3659
|
-
};
|
|
3660
|
-
Schema.prototype.toString = function toString(inline) {
|
|
3661
|
-
return formatters[this.type]?.(this, inline) ?? `Schema<${this.type}>`;
|
|
3662
|
-
};
|
|
3663
|
-
Schema.prototype.role = function role(role, extra) {
|
|
3664
|
-
const schema = Schema(this);
|
|
3665
|
-
schema.meta = {
|
|
3666
|
-
...schema.meta,
|
|
3667
|
-
role,
|
|
3668
|
-
extra
|
|
3669
|
-
};
|
|
3670
|
-
return schema;
|
|
3671
|
-
};
|
|
3672
|
-
for (const key of [
|
|
3673
|
-
"default",
|
|
3674
|
-
"link",
|
|
3675
|
-
"comment",
|
|
3676
|
-
"description",
|
|
3677
|
-
"max",
|
|
3678
|
-
"min",
|
|
3679
|
-
"step"
|
|
3680
|
-
]) Object.assign(Schema.prototype, { [key](value) {
|
|
3681
|
-
const schema = Schema(this);
|
|
3682
|
-
schema.meta = {
|
|
3683
|
-
...schema.meta,
|
|
3684
|
-
[key]: value
|
|
3685
|
-
};
|
|
3686
|
-
return schema;
|
|
3687
|
-
} });
|
|
3688
|
-
const resolvers = {};
|
|
3689
|
-
Schema.extend = function extend(type, resolve) {
|
|
3690
|
-
resolvers[type] = resolve;
|
|
3691
|
-
};
|
|
3692
|
-
Schema.resolve = function resolve(data, schema, options = {}, strict = false) {
|
|
3693
|
-
if (!schema) return [data];
|
|
3694
|
-
if (options.ignore?.(data, schema)) return [data];
|
|
3695
|
-
if (isNullable(data) && schema.type !== "lazy") {
|
|
3696
|
-
if (schema.meta.required) throw new ValidationError(`missing required value`, options);
|
|
3697
|
-
let current = schema;
|
|
3698
|
-
let fallback = schema.meta.default;
|
|
3699
|
-
while (current?.type === "intersect" && isNullable(fallback)) {
|
|
3700
|
-
current = current.list[0];
|
|
3701
|
-
fallback = current?.meta.default;
|
|
3702
|
-
}
|
|
3703
|
-
if (isNullable(fallback)) return [data];
|
|
3704
|
-
data = clone(fallback);
|
|
3705
|
-
}
|
|
3706
|
-
const callback = resolvers[schema.type];
|
|
3707
|
-
if (!callback) throw new ValidationError(`unsupported type "${schema.type}"`, options);
|
|
3708
|
-
try {
|
|
3709
|
-
return callback(data, schema, options, strict);
|
|
3710
|
-
} catch (error) {
|
|
3711
|
-
if (!schema.meta.loose) throw error;
|
|
3712
|
-
return [schema.meta.default];
|
|
3713
|
-
}
|
|
3714
|
-
};
|
|
3715
|
-
Schema.from = function from(source) {
|
|
3716
|
-
if (isNullable(source)) return Schema.any();
|
|
3717
|
-
else if ([
|
|
3718
|
-
"string",
|
|
3719
|
-
"number",
|
|
3720
|
-
"boolean"
|
|
3721
|
-
].includes(typeof source)) return Schema.const(source).required();
|
|
3722
|
-
else if (source[kSchema]) return source;
|
|
3723
|
-
else if (typeof source === "function") switch (source) {
|
|
3724
|
-
case String: return Schema.string().required();
|
|
3725
|
-
case Number: return Schema.number().required();
|
|
3726
|
-
case Boolean: return Schema.boolean().required();
|
|
3727
|
-
case Function: return Schema.function().required();
|
|
3728
|
-
default: return Schema.is(source).required();
|
|
3729
|
-
}
|
|
3730
|
-
else throw new TypeError(`cannot infer schema from ${source}`);
|
|
3731
|
-
};
|
|
3732
|
-
Schema.lazy = function lazy(builder) {
|
|
3733
|
-
const toJSON = () => {
|
|
3734
|
-
if (!schema.inner[kSchema]) {
|
|
3735
|
-
schema.inner = schema.builder();
|
|
3736
|
-
schema.inner.meta = {
|
|
3737
|
-
...schema.meta,
|
|
3738
|
-
...schema.inner.meta
|
|
3739
|
-
};
|
|
3740
|
-
}
|
|
3741
|
-
return schema.inner.toJSON();
|
|
3742
|
-
};
|
|
3743
|
-
const schema = new Schema({
|
|
3744
|
-
type: "lazy",
|
|
3745
|
-
builder,
|
|
3746
|
-
inner: { toJSON }
|
|
3747
|
-
});
|
|
3748
|
-
return schema;
|
|
3749
|
-
};
|
|
3750
|
-
Schema.natural = function natural() {
|
|
3751
|
-
return Schema.number().step(1).min(0);
|
|
3752
|
-
};
|
|
3753
|
-
Schema.percent = function percent() {
|
|
3754
|
-
return Schema.number().step(.01).min(0).max(1).role("slider");
|
|
3755
|
-
};
|
|
3756
|
-
Schema.date = function date() {
|
|
3757
|
-
return Schema.union([Schema.is(Date), Schema.transform(Schema.string().role("datetime"), (value, options) => {
|
|
3758
|
-
const date = new Date(value);
|
|
3759
|
-
if (isNaN(+date)) throw new ValidationError(`invalid date "${value}"`, options);
|
|
3760
|
-
return date;
|
|
3761
|
-
}, true)]);
|
|
3762
|
-
};
|
|
3763
|
-
Schema.regExp = function regExp(flag = "") {
|
|
3764
|
-
return Schema.union([Schema.is(RegExp), Schema.transform(Schema.string().role("regexp", { flag }), (value, options) => {
|
|
3765
|
-
try {
|
|
3766
|
-
return new RegExp(value, flag);
|
|
3767
|
-
} catch (e) {
|
|
3768
|
-
throw new ValidationError(e.message, options);
|
|
3769
|
-
}
|
|
3770
|
-
}, true)]);
|
|
3771
|
-
};
|
|
3772
|
-
Schema.arrayBuffer = function arrayBuffer(encoding) {
|
|
3773
|
-
return Schema.union([
|
|
3774
|
-
Schema.is(ArrayBuffer),
|
|
3775
|
-
Schema.is(SharedArrayBuffer),
|
|
3776
|
-
Schema.transform(Schema.any(), (value, options) => {
|
|
3777
|
-
if (Binary.isSource(value)) return Binary.fromSource(value);
|
|
3778
|
-
throw new ValidationError(`expected ArrayBufferSource but got ${value}`, options);
|
|
3779
|
-
}, true),
|
|
3780
|
-
...encoding ? [Schema.transform(Schema.string(), (value, options) => {
|
|
3781
|
-
try {
|
|
3782
|
-
return encoding === "base64" ? Binary.fromBase64(value) : Binary.fromHex(value);
|
|
3783
|
-
} catch (e) {
|
|
3784
|
-
throw new ValidationError(e.message, options);
|
|
3785
|
-
}
|
|
3786
|
-
}, true)] : []
|
|
3787
|
-
]);
|
|
3788
|
-
};
|
|
3789
|
-
Schema.extend("lazy", (data, schema, options, strict) => {
|
|
3790
|
-
if (!schema.inner[kSchema]) {
|
|
3791
|
-
schema.inner = schema.builder();
|
|
3792
|
-
schema.inner.meta = {
|
|
3793
|
-
...schema.meta,
|
|
3794
|
-
...schema.inner.meta
|
|
3795
|
-
};
|
|
3796
|
-
}
|
|
3797
|
-
return Schema.resolve(data, schema.inner, options, strict);
|
|
3798
|
-
});
|
|
3799
|
-
Schema.extend("any", (data) => {
|
|
3800
|
-
return [data];
|
|
3801
|
-
});
|
|
3802
|
-
Schema.extend("never", (data, _, options) => {
|
|
3803
|
-
throw new ValidationError(`expected nullable but got ${data}`, options);
|
|
3804
|
-
});
|
|
3805
|
-
Schema.extend("const", (data, { value }, options) => {
|
|
3806
|
-
if (deepEqual(data, value)) return [value];
|
|
3807
|
-
throw new ValidationError(`expected ${value} but got ${data}`, options);
|
|
3808
|
-
});
|
|
3809
|
-
function checkWithinRange(data, meta, description, options, skipMin = false) {
|
|
3810
|
-
const { max = Infinity, min = -Infinity } = meta;
|
|
3811
|
-
if (data > max) throw new ValidationError(`expected ${description} <= ${max} but got ${data}`, options);
|
|
3812
|
-
if (data < min && !skipMin) throw new ValidationError(`expected ${description} >= ${min} but got ${data}`, options);
|
|
3813
|
-
}
|
|
3814
|
-
Schema.extend("string", (data, { meta }, options) => {
|
|
3815
|
-
if (typeof data !== "string") throw new ValidationError(`expected string but got ${data}`, options);
|
|
3816
|
-
if (meta.pattern) {
|
|
3817
|
-
const regexp = new RegExp(meta.pattern.source, meta.pattern.flags);
|
|
3818
|
-
if (!regexp.test(data)) throw new ValidationError(`expect string to match regexp ${regexp}`, options);
|
|
3819
|
-
}
|
|
3820
|
-
checkWithinRange(data.length, meta, "string length", options);
|
|
3821
|
-
return [data];
|
|
3822
|
-
});
|
|
3823
|
-
function decimalShift(data, digits) {
|
|
3824
|
-
const str = data.toString();
|
|
3825
|
-
if (str.includes("e")) return data * Math.pow(10, digits);
|
|
3826
|
-
const index = str.indexOf(".");
|
|
3827
|
-
if (index === -1) return data * Math.pow(10, digits);
|
|
3828
|
-
const frac = str.slice(index + 1);
|
|
3829
|
-
const integer = str.slice(0, index);
|
|
3830
|
-
if (frac.length <= digits) return +(integer + frac.padEnd(digits, "0"));
|
|
3831
|
-
return +(integer + frac.slice(0, digits) + "." + frac.slice(digits));
|
|
3832
|
-
}
|
|
3833
|
-
function isMultipleOf(data, min, step) {
|
|
3834
|
-
step = Math.abs(step);
|
|
3835
|
-
if (!/^\d+\.\d+$/.test(step.toString())) return (data - min) % step === 0;
|
|
3836
|
-
const index = step.toString().indexOf(".");
|
|
3837
|
-
const digits = step.toString().slice(index + 1).length;
|
|
3838
|
-
return Math.abs(decimalShift(data, digits) - decimalShift(min, digits)) % decimalShift(step, digits) === 0;
|
|
3839
|
-
}
|
|
3840
|
-
Schema.extend("number", (data, { meta }, options) => {
|
|
3841
|
-
if (typeof data !== "number") throw new ValidationError(`expected number but got ${data}`, options);
|
|
3842
|
-
checkWithinRange(data, meta, "number", options);
|
|
3843
|
-
const { step } = meta;
|
|
3844
|
-
if (step && !isMultipleOf(data, meta.min ?? 0, step)) throw new ValidationError(`expected number multiple of ${step} but got ${data}`, options);
|
|
3845
|
-
return [data];
|
|
3846
|
-
});
|
|
3847
|
-
Schema.extend("boolean", (data, _, options) => {
|
|
3848
|
-
if (typeof data === "boolean") return [data];
|
|
3849
|
-
throw new ValidationError(`expected boolean but got ${data}`, options);
|
|
3850
|
-
});
|
|
3851
|
-
Schema.extend("bitset", (data, { bits, meta }, options) => {
|
|
3852
|
-
let value = 0, keys = [];
|
|
3853
|
-
if (typeof data === "number") {
|
|
3854
|
-
value = data;
|
|
3855
|
-
for (const key in bits) if (data & bits[key]) keys.push(key);
|
|
3856
|
-
} else if (Array.isArray(data)) {
|
|
3857
|
-
keys = data;
|
|
3858
|
-
for (const key of keys) {
|
|
3859
|
-
if (typeof key !== "string") throw new ValidationError(`expected string but got ${key}`, options);
|
|
3860
|
-
if (key in bits) value |= bits[key];
|
|
3861
|
-
}
|
|
3862
|
-
} else throw new ValidationError(`expected number or array but got ${data}`, options);
|
|
3863
|
-
if (value === meta.default) return [value];
|
|
3864
|
-
return [value, keys];
|
|
3865
|
-
});
|
|
3866
|
-
Schema.extend("function", (data, _, options) => {
|
|
3867
|
-
if (typeof data === "function") return [data];
|
|
3868
|
-
throw new ValidationError(`expected function but got ${data}`, options);
|
|
3869
|
-
});
|
|
3870
|
-
Schema.extend("is", (data, { constructor }, options) => {
|
|
3871
|
-
if (typeof constructor === "function") {
|
|
3872
|
-
if (data instanceof constructor) return [data];
|
|
3873
|
-
throw new ValidationError(`expected ${constructor.name} but got ${data}`, options);
|
|
3874
|
-
} else {
|
|
3875
|
-
if (isNullable(data)) throw new ValidationError(`expected ${constructor} but got ${data}`, options);
|
|
3876
|
-
let prototype = Object.getPrototypeOf(data);
|
|
3877
|
-
while (prototype) {
|
|
3878
|
-
if (prototype.constructor?.name === constructor) return [data];
|
|
3879
|
-
prototype = Object.getPrototypeOf(prototype);
|
|
3880
|
-
}
|
|
3881
|
-
throw new ValidationError(`expected ${constructor} but got ${data}`, options);
|
|
3882
|
-
}
|
|
3883
|
-
});
|
|
3884
|
-
function property(data, key, schema, options) {
|
|
3885
|
-
try {
|
|
3886
|
-
const [value, adapted] = Schema.resolve(data[key], schema, {
|
|
3887
|
-
...options,
|
|
3888
|
-
path: [...options.path || [], key]
|
|
3889
|
-
});
|
|
3890
|
-
if (adapted !== void 0) data[key] = adapted;
|
|
3891
|
-
return value;
|
|
3892
|
-
} catch (e) {
|
|
3893
|
-
if (!options?.autofix) throw e;
|
|
3894
|
-
delete data[key];
|
|
3895
|
-
return schema.meta.default;
|
|
3896
|
-
}
|
|
3897
|
-
}
|
|
3898
|
-
Schema.extend("array", (data, { inner, meta }, options) => {
|
|
3899
|
-
if (!Array.isArray(data)) throw new ValidationError(`expected array but got ${data}`, options);
|
|
3900
|
-
checkWithinRange(data.length, meta, "array length", options, !isNullable(inner.meta.default));
|
|
3901
|
-
return [data.map((_, index) => property(data, index, inner, options))];
|
|
3902
|
-
});
|
|
3903
|
-
Schema.extend("dict", (data, { inner, sKey }, options, strict) => {
|
|
3904
|
-
if (!isPlainObject(data)) throw new ValidationError(`expected object but got ${data}`, options);
|
|
3905
|
-
const result = {};
|
|
3906
|
-
for (const key in data) {
|
|
3907
|
-
let rKey;
|
|
3908
|
-
try {
|
|
3909
|
-
rKey = Schema.resolve(key, sKey, options)[0];
|
|
3910
|
-
} catch (error) {
|
|
3911
|
-
if (strict) continue;
|
|
3912
|
-
throw error;
|
|
3913
|
-
}
|
|
3914
|
-
result[rKey] = property(data, key, inner, options);
|
|
3915
|
-
data[rKey] = data[key];
|
|
3916
|
-
if (key !== rKey) delete data[key];
|
|
3917
|
-
}
|
|
3918
|
-
return [result];
|
|
3919
|
-
});
|
|
3920
|
-
Schema.extend("tuple", (data, { list }, options, strict) => {
|
|
3921
|
-
if (!Array.isArray(data)) throw new ValidationError(`expected array but got ${data}`, options);
|
|
3922
|
-
const result = list.map((inner, index) => property(data, index, inner, options));
|
|
3923
|
-
if (strict) return [result];
|
|
3924
|
-
result.push(...data.slice(list.length));
|
|
3925
|
-
return [result];
|
|
3926
|
-
});
|
|
3927
|
-
function merge(result, data) {
|
|
3928
|
-
for (const key in data) {
|
|
3929
|
-
if (key in result) continue;
|
|
3930
|
-
result[key] = data[key];
|
|
3931
|
-
}
|
|
3932
|
-
}
|
|
3933
|
-
Schema.extend("object", (data, { dict }, options, strict) => {
|
|
3934
|
-
if (!isPlainObject(data)) throw new ValidationError(`expected object but got ${data}`, options);
|
|
3935
|
-
const result = {};
|
|
3936
|
-
for (const key in dict) {
|
|
3937
|
-
const value = property(data, key, dict[key], options);
|
|
3938
|
-
if (!isNullable(value) || key in data) result[key] = value;
|
|
3939
|
-
}
|
|
3940
|
-
if (!strict) merge(result, data);
|
|
3941
|
-
return [result];
|
|
3942
|
-
});
|
|
3943
|
-
Schema.extend("union", (data, { list, toString }, options, strict) => {
|
|
3944
|
-
const messages = [];
|
|
3945
|
-
for (const inner of list) try {
|
|
3946
|
-
return Schema.resolve(data, inner, options, strict);
|
|
3947
|
-
} catch (error) {
|
|
3948
|
-
messages.push(error);
|
|
3949
|
-
}
|
|
3950
|
-
throw new ValidationError(`expected ${toString()} but got ${JSON.stringify(data)}`, options);
|
|
3951
|
-
});
|
|
3952
|
-
Schema.extend("intersect", (data, { list, toString }, options, strict) => {
|
|
3953
|
-
if (!list.length) return [data];
|
|
3954
|
-
let result;
|
|
3955
|
-
for (const inner of list) {
|
|
3956
|
-
const value = Schema.resolve(data, inner, options, true)[0];
|
|
3957
|
-
if (isNullable(value)) continue;
|
|
3958
|
-
if (isNullable(result)) result = value;
|
|
3959
|
-
else if (typeof result !== typeof value) throw new ValidationError(`expected ${toString()} but got ${JSON.stringify(data)}`, options);
|
|
3960
|
-
else if (typeof value === "object") merge(result ??= {}, value);
|
|
3961
|
-
else if (result !== value) throw new ValidationError(`expected ${toString()} but got ${JSON.stringify(data)}`, options);
|
|
3962
|
-
}
|
|
3963
|
-
if (!strict && isPlainObject(data)) merge(result, data);
|
|
3964
|
-
return [result];
|
|
3965
|
-
});
|
|
3966
|
-
Schema.extend("transform", (data, { inner, callback, preserve }, options) => {
|
|
3967
|
-
const [result, adapted = data] = Schema.resolve(data, inner, options, true);
|
|
3968
|
-
if (preserve) return [callback(result)];
|
|
3969
|
-
else return [callback(result), callback(adapted)];
|
|
3970
|
-
});
|
|
3971
|
-
const formatters = {};
|
|
3972
|
-
function defineMethod(name, keys, format) {
|
|
3973
|
-
formatters[name] = format;
|
|
3974
|
-
Object.assign(Schema, { [name](...args) {
|
|
3975
|
-
const schema = new Schema({ type: name });
|
|
3976
|
-
keys.forEach((key, index) => {
|
|
3977
|
-
switch (key) {
|
|
3978
|
-
case "sKey":
|
|
3979
|
-
schema.sKey = args[index] ?? Schema.string();
|
|
3980
|
-
break;
|
|
3981
|
-
case "inner":
|
|
3982
|
-
schema.inner = Schema.from(args[index]);
|
|
3983
|
-
break;
|
|
3984
|
-
case "list":
|
|
3985
|
-
schema.list = args[index].map(Schema.from);
|
|
3986
|
-
break;
|
|
3987
|
-
case "dict":
|
|
3988
|
-
schema.dict = mapValues(args[index], Schema.from);
|
|
3989
|
-
break;
|
|
3990
|
-
case "bits":
|
|
3991
|
-
schema.bits = {};
|
|
3992
|
-
for (const key in args[index]) {
|
|
3993
|
-
if (typeof args[index][key] !== "number") continue;
|
|
3994
|
-
schema.bits[key] = args[index][key];
|
|
3995
|
-
}
|
|
3996
|
-
break;
|
|
3997
|
-
case "callback": {
|
|
3998
|
-
const callback = schema.callback = args[index];
|
|
3999
|
-
callback["toJSON"] ||= () => callback.toString();
|
|
4000
|
-
break;
|
|
4001
|
-
}
|
|
4002
|
-
case "constructor": {
|
|
4003
|
-
const constructor = schema.constructor = args[index];
|
|
4004
|
-
if (typeof constructor === "function") constructor["toJSON"] ||= () => constructor["name"];
|
|
4005
|
-
break;
|
|
4006
|
-
}
|
|
4007
|
-
default: schema[key] = args[index];
|
|
4008
|
-
}
|
|
4009
|
-
});
|
|
4010
|
-
if (name === "object" || name === "dict") schema.meta.default = {};
|
|
4011
|
-
else if (name === "array" || name === "tuple") schema.meta.default = [];
|
|
4012
|
-
else if (name === "bitset") schema.meta.default = 0;
|
|
4013
|
-
return schema;
|
|
4014
|
-
} });
|
|
4015
|
-
}
|
|
4016
|
-
defineMethod("is", ["constructor"], ({ constructor }) => {
|
|
4017
|
-
if (typeof constructor === "function") return constructor.name;
|
|
4018
|
-
else return constructor;
|
|
4019
|
-
});
|
|
4020
|
-
defineMethod("any", [], () => "any");
|
|
4021
|
-
defineMethod("never", [], () => "never");
|
|
4022
|
-
defineMethod("const", ["value"], ({ value }) => typeof value === "string" ? JSON.stringify(value) : value);
|
|
4023
|
-
defineMethod("string", [], () => "string");
|
|
4024
|
-
defineMethod("number", [], () => "number");
|
|
4025
|
-
defineMethod("boolean", [], () => "boolean");
|
|
4026
|
-
defineMethod("bitset", ["bits"], () => "bitset");
|
|
4027
|
-
defineMethod("function", [], () => "function");
|
|
4028
|
-
defineMethod("array", ["inner"], ({ inner }) => `${inner.toString(true)}[]`);
|
|
4029
|
-
defineMethod("dict", ["inner", "sKey"], ({ inner, sKey }) => `{ [key: ${sKey.toString()}]: ${inner.toString()} }`);
|
|
4030
|
-
defineMethod("tuple", ["list"], ({ list }) => `[${list.map((inner) => inner.toString()).join(", ")}]`);
|
|
4031
|
-
defineMethod("object", ["dict"], ({ dict }) => {
|
|
4032
|
-
if (Object.keys(dict).length === 0) return "{}";
|
|
4033
|
-
return `{ ${Object.entries(dict).map(([key, inner]) => {
|
|
4034
|
-
return `${key}${inner.meta.required ? "" : "?"}: ${inner.toString()}`;
|
|
4035
|
-
}).join(", ")} }`;
|
|
4036
|
-
});
|
|
4037
|
-
defineMethod("union", ["list"], ({ list }, inline) => {
|
|
4038
|
-
const result = list.map(({ toString: format }) => format()).join(" | ");
|
|
4039
|
-
return inline ? `(${result})` : result;
|
|
4040
|
-
});
|
|
4041
|
-
defineMethod("intersect", ["list"], ({ list }) => {
|
|
4042
|
-
return `${list.map((inner) => inner.toString(true)).join(" & ")}`;
|
|
4043
|
-
});
|
|
4044
|
-
defineMethod("transform", [
|
|
4045
|
-
"inner",
|
|
4046
|
-
"callback",
|
|
4047
|
-
"preserve"
|
|
4048
|
-
], ({ inner }, isInner) => inner.toString(isInner));
|
|
4049
|
-
//#endregion
|
|
4050
|
-
//#region ../../node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.5-rc.1_@deepseek-ai+cordis@4.0.2/node_modules/@deepseek-ai/dsh-timeout/lib/index.js
|
|
3322
|
+
//#region ../../node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.7-rc.1_@deepseek-ai+cordis@4.0.4/node_modules/@deepseek-ai/dsh-timeout/lib/index.js
|
|
4051
3323
|
/** Largest delay Node schedules without clamping it to one millisecond. */
|
|
4052
3324
|
const MAX_TIMER_DELAY_MS = 2147483647;
|
|
4053
3325
|
//#endregion
|
|
4054
|
-
//#region ../../node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.
|
|
3326
|
+
//#region ../../node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.7-rc.1_@deepseek-ai+cordis@4.0.4/node_modules/@deepseek-ai/dsh-llm/lib/index.js
|
|
4055
3327
|
/**
|
|
4056
3328
|
* Detach and deep-freeze a message whose identity already exists.
|
|
4057
3329
|
* @param message - complete message, including its stable identity.
|
|
@@ -4066,10 +3338,10 @@ function freezeMessage(message) {
|
|
|
4066
3338
|
* @returns an immutable message with a fresh stable identity.
|
|
4067
3339
|
*/
|
|
4068
3340
|
function createMessage(input) {
|
|
4069
|
-
return
|
|
3341
|
+
return deepFreeze(structuredClone({
|
|
4070
3342
|
...input,
|
|
4071
3343
|
id: brandString(randomUUID())
|
|
4072
|
-
});
|
|
3344
|
+
}));
|
|
4073
3345
|
}
|
|
4074
3346
|
/**
|
|
4075
3347
|
* Create one identified user-role message and freeze it before publication.
|
|
@@ -4134,22 +3406,22 @@ const DEFAULT_RETRYABLE_CODES = Object.freeze([
|
|
|
4134
3406
|
"TIMEOUT",
|
|
4135
3407
|
"TRANSPORT"
|
|
4136
3408
|
]);
|
|
4137
|
-
const backoffSchema =
|
|
4138
|
-
initialDelayMs:
|
|
4139
|
-
maxDelayMs:
|
|
4140
|
-
jitterRatio:
|
|
3409
|
+
const backoffSchema = z.object({
|
|
3410
|
+
initialDelayMs: z.number().max(MAX_TIMER_DELAY_MS).default(DEFAULT_INITIAL_DELAY_MS),
|
|
3411
|
+
maxDelayMs: z.number().max(MAX_TIMER_DELAY_MS).default(DEFAULT_MAX_DELAY_MS),
|
|
3412
|
+
jitterRatio: z.number().min(0).max(1).default(DEFAULT_JITTER_RATIO)
|
|
4141
3413
|
});
|
|
4142
|
-
const normalPolicySchema =
|
|
4143
|
-
mode:
|
|
4144
|
-
maxRetries:
|
|
4145
|
-
retryableCodes:
|
|
3414
|
+
const normalPolicySchema = z.object({
|
|
3415
|
+
mode: z.const("normal").required(),
|
|
3416
|
+
maxRetries: z.number().step(1).min(0).max(Number.MAX_SAFE_INTEGER).default(DEFAULT_MAX_RETRIES),
|
|
3417
|
+
retryableCodes: z.array(z.string()).default([...DEFAULT_RETRYABLE_CODES]),
|
|
4146
3418
|
backoff: backoffSchema
|
|
4147
3419
|
});
|
|
4148
|
-
const alwaysPolicySchema =
|
|
4149
|
-
mode:
|
|
3420
|
+
const alwaysPolicySchema = z.object({
|
|
3421
|
+
mode: z.const("always").required(),
|
|
4150
3422
|
backoff: backoffSchema
|
|
4151
3423
|
});
|
|
4152
|
-
|
|
3424
|
+
z.union([normalPolicySchema, alwaysPolicySchema]);
|
|
4153
3425
|
const NORMAL_POLICY_KEYS = /* @__PURE__ */ new Set([
|
|
4154
3426
|
"mode",
|
|
4155
3427
|
"maxRetries",
|
|
@@ -4293,13 +3565,15 @@ function failureSnapshot(value) {
|
|
|
4293
3565
|
const status = candidate.status;
|
|
4294
3566
|
const providerRetryAfterMs = candidate.providerRetryAfterMs;
|
|
4295
3567
|
const requestId = candidate.requestId;
|
|
4296
|
-
|
|
3568
|
+
const offloadImages = candidate.offloadImages;
|
|
3569
|
+
if (typeof message !== "string" || message.length === 0 || typeof code !== "string" || code.length === 0 || status !== void 0 && (!Number.isInteger(status) || status < 100 || status > 599) || providerRetryAfterMs !== void 0 && (!Number.isFinite(providerRetryAfterMs) || providerRetryAfterMs <= 0) || requestId !== void 0 && (typeof requestId !== "string" || requestId.length === 0) || offloadImages !== void 0 && (!Number.isSafeInteger(offloadImages) || offloadImages <= 0)) return void 0;
|
|
4297
3570
|
return Object.freeze({
|
|
4298
3571
|
message,
|
|
4299
3572
|
code,
|
|
4300
3573
|
...status === void 0 ? {} : { status },
|
|
4301
3574
|
...providerRetryAfterMs === void 0 ? {} : { providerRetryAfterMs },
|
|
4302
|
-
...requestId === void 0 ? {} : { requestId }
|
|
3575
|
+
...requestId === void 0 ? {} : { requestId },
|
|
3576
|
+
...offloadImages === void 0 ? {} : { offloadImages }
|
|
4303
3577
|
});
|
|
4304
3578
|
} catch (_sdkFailureGetter) {
|
|
4305
3579
|
return;
|
|
@@ -4329,25 +3603,23 @@ function textOnlyImageText(ref) {
|
|
|
4329
3603
|
return `[image omitted because this model accepts text only; attachment sha256:${String(ref.attachmentId).slice(7, 15)}]`;
|
|
4330
3604
|
}
|
|
4331
3605
|
/**
|
|
4332
|
-
* True when typed model content contains an image block
|
|
4333
|
-
*
|
|
4334
|
-
*
|
|
4335
|
-
* survey), so a consumer cannot silently diverge on nesting depth.
|
|
3606
|
+
* True when typed model content contains an image block. This is the one image
|
|
3607
|
+
* walk shared by every image policy (capability gating, text-only
|
|
3608
|
+
* serialization, compaction survey), so a consumer cannot silently diverge.
|
|
4336
3609
|
* @param content - typed model content blocks.
|
|
4337
|
-
* @returns whether any
|
|
3610
|
+
* @returns whether any block is an image.
|
|
4338
3611
|
*/
|
|
4339
3612
|
function contentHasImage(content) {
|
|
4340
|
-
return content.some((block) => block.type === "image"
|
|
3613
|
+
return content.some((block) => block.type === "image");
|
|
4341
3614
|
}
|
|
4342
3615
|
/**
|
|
4343
|
-
* True when typed model content contains a file block
|
|
4344
|
-
* tool-result content on the same recursion every file policy shares.
|
|
3616
|
+
* True when typed model content contains a file block.
|
|
4345
3617
|
* Reads current content on every call without retaining scan results.
|
|
4346
3618
|
* @param content - typed model content blocks.
|
|
4347
|
-
* @returns whether any
|
|
3619
|
+
* @returns whether any block is a file.
|
|
4348
3620
|
*/
|
|
4349
3621
|
function contentHasFile(content) {
|
|
4350
|
-
for (const block of content) if (block.type === "file"
|
|
3622
|
+
for (const block of content) if (block.type === "file") return true;
|
|
4351
3623
|
return false;
|
|
4352
3624
|
}
|
|
4353
3625
|
/**
|
|
@@ -4364,7 +3636,7 @@ function fileHandleText(ref, readonlyPath) {
|
|
|
4364
3636
|
if (readonlyPath === void 0) return `[${identity} was uploaded, but the current execution environment cannot access a readable path. Report that limitation if its contents are needed; do not claim to have read it.]`;
|
|
4365
3637
|
return `[${identity}: verbatim read-only copy saved at ${quoted(readonlyPath)}. Read that path with your file tools when its contents are needed; copy it to a writable location before modifying it. When delegating file work, include this saved path in the delegation prompt; only subagents sharing this execution environment can read it.]`;
|
|
4366
3638
|
}
|
|
4367
|
-
/** Replace every file occurrence
|
|
3639
|
+
/** Replace every file occurrence with handle text. */
|
|
4368
3640
|
function replaceFilesWithHandles(blocks, resolvePath) {
|
|
4369
3641
|
let next;
|
|
4370
3642
|
for (const [index, block] of blocks.entries()) {
|
|
@@ -4376,29 +3648,10 @@ function replaceFilesWithHandles(blocks, resolvePath) {
|
|
|
4376
3648
|
});
|
|
4377
3649
|
continue;
|
|
4378
3650
|
}
|
|
4379
|
-
if (block.type === "tool-result") {
|
|
4380
|
-
const content = replaceFilesWithHandles(block.content, resolvePath);
|
|
4381
|
-
if (content !== block.content) {
|
|
4382
|
-
next ??= blocks.slice(0, index);
|
|
4383
|
-
next.push({
|
|
4384
|
-
...block,
|
|
4385
|
-
content
|
|
4386
|
-
});
|
|
4387
|
-
continue;
|
|
4388
|
-
}
|
|
4389
|
-
}
|
|
4390
3651
|
next?.push(block);
|
|
4391
3652
|
}
|
|
4392
3653
|
return next ?? blocks;
|
|
4393
3654
|
}
|
|
4394
|
-
/**
|
|
4395
|
-
* Project durable file history into deterministic handle text for every model
|
|
4396
|
-
* route. Unlike images, no provider receives file blocks natively, so this
|
|
4397
|
-
* projection is unconditional in request assembly.
|
|
4398
|
-
* @param messages - complete request history.
|
|
4399
|
-
* @param resolvePath - resolve one reference's current execution-world read path.
|
|
4400
|
-
* @returns the original list without files, otherwise shallow message copies with handle text.
|
|
4401
|
-
*/
|
|
4402
3655
|
function projectFilesToText(messages, resolvePath) {
|
|
4403
3656
|
if (!messages.some((message) => contentHasFile(message.content))) return messages;
|
|
4404
3657
|
return messages.map((message) => {
|
|
@@ -4409,7 +3662,7 @@ function projectFilesToText(messages, resolvePath) {
|
|
|
4409
3662
|
};
|
|
4410
3663
|
});
|
|
4411
3664
|
}
|
|
4412
|
-
/** Replace every image occurrence
|
|
3665
|
+
/** Replace every image occurrence for a text-only model. */
|
|
4413
3666
|
function replaceImagesForTextModel(blocks) {
|
|
4414
3667
|
let next;
|
|
4415
3668
|
for (const [index, block] of blocks.entries()) {
|
|
@@ -4421,26 +3674,10 @@ function replaceImagesForTextModel(blocks) {
|
|
|
4421
3674
|
});
|
|
4422
3675
|
continue;
|
|
4423
3676
|
}
|
|
4424
|
-
if (block.type === "tool-result") {
|
|
4425
|
-
const content = replaceImagesForTextModel(block.content);
|
|
4426
|
-
if (content !== block.content) {
|
|
4427
|
-
next ??= blocks.slice(0, index);
|
|
4428
|
-
next.push({
|
|
4429
|
-
...block,
|
|
4430
|
-
content
|
|
4431
|
-
});
|
|
4432
|
-
continue;
|
|
4433
|
-
}
|
|
4434
|
-
}
|
|
4435
3677
|
next?.push(block);
|
|
4436
3678
|
}
|
|
4437
3679
|
return next ?? blocks;
|
|
4438
3680
|
}
|
|
4439
|
-
/**
|
|
4440
|
-
* Project durable image history into deterministic text for an exact text-only model.
|
|
4441
|
-
* @param messages - complete request history.
|
|
4442
|
-
* @returns the original list without images, otherwise shallow message copies with stable placeholders.
|
|
4443
|
-
*/
|
|
4444
3681
|
function projectImagesForTextModel(messages) {
|
|
4445
3682
|
if (!messages.some((message) => contentHasImage(message.content))) return messages;
|
|
4446
3683
|
return messages.map((message) => {
|
|
@@ -4530,7 +3767,8 @@ var LlmError = class extends HarnessError {
|
|
|
4530
3767
|
code,
|
|
4531
3768
|
...options?.status === void 0 ? {} : { status: options.status },
|
|
4532
3769
|
...options?.providerRetryAfterMs === void 0 ? {} : { providerRetryAfterMs: options.providerRetryAfterMs },
|
|
4533
|
-
...options?.requestId === void 0 ? {} : { requestId: options.requestId }
|
|
3770
|
+
...options?.requestId === void 0 ? {} : { requestId: options.requestId },
|
|
3771
|
+
...options?.offloadImages === void 0 ? {} : { offloadImages: options.offloadImages }
|
|
4534
3772
|
});
|
|
4535
3773
|
}
|
|
4536
3774
|
};
|
|
@@ -4798,7 +4036,8 @@ var LlmError = class extends HarnessError {
|
|
|
4798
4036
|
id: model.id,
|
|
4799
4037
|
...model.name === void 0 ? {} : { name: model.name },
|
|
4800
4038
|
...model.contextWindow === void 0 ? {} : { contextWindow: model.contextWindow },
|
|
4801
|
-
...model.maxTokens === void 0 ? {} : { maxTokens: model.maxTokens }
|
|
4039
|
+
...model.maxTokens === void 0 ? {} : { maxTokens: model.maxTokens },
|
|
4040
|
+
...model.inputModalities === void 0 ? {} : { inputModalities: [...model.inputModalities] }
|
|
4802
4041
|
});
|
|
4803
4042
|
}
|
|
4804
4043
|
return models;
|
|
@@ -5027,8 +4266,9 @@ var LlmError = class extends HarnessError {
|
|
|
5027
4266
|
/** Remove replay state whose historical route is owned by another adapter. */
|
|
5028
4267
|
forAdapter(options, adapter) {
|
|
5029
4268
|
const messages = options.messages.map((message) => {
|
|
4269
|
+
if (message.role !== "assistant") return message;
|
|
5030
4270
|
const source = message.source;
|
|
5031
|
-
if (
|
|
4271
|
+
if (source.replayState === void 0) return message;
|
|
5032
4272
|
if (this.adapters.get(source.provider)?.adapter === adapter) return message;
|
|
5033
4273
|
return freezeMessage({
|
|
5034
4274
|
...message,
|
|
@@ -5684,19 +4924,35 @@ const inject = [
|
|
|
5684
4924
|
/** Model-facing announcement: plugin presence, capabilities, and limits. */
|
|
5685
4925
|
const TASK_BOARD_GUIDANCE = "本机已安装 dsh-task-board 插件(DSH Web GUI 的任务看板):侧边栏「任务看板」入口;在 dsh-web 插件全家桶仓库(packages/dsh-task-board)统一维护,经聚合包 web-ui-all 一键安装。能力:多列看板管理任务;Host 权威账本;关闭浏览器后仍由 Host 执行和结算;任务可钉住工作区、agent 预设和权限;支持 Host 本地时区的 5 段 cron,错过的触发点不补跑;可选且默认关闭的空闲系统睡眠保护允许屏幕熄灭,但不承诺拦截合盖、手动睡眠、休眠、关机或唤醒已睡眠机器。执行消耗 API 额度。用户提到「任务看板 / 看板 / 定时任务」时即指本插件,请据此协作。若你同时用 todo_write 维护会话顶部的可见计划列表,最终回复前必须再次调用 todo_write 收尾:没有剩余工作时不要保留 in_progress,已完成的最后一步要标为 completed。";
|
|
5686
4926
|
/**
|
|
5687
|
-
*
|
|
5688
|
-
*
|
|
5689
|
-
*
|
|
4927
|
+
* The schema is left to inference rather than annotated with `z<Config>`: a
|
|
4928
|
+
* volatile field's parsed output is a `Volatile` reference while its accepted
|
|
4929
|
+
* input stays the plain value, so the two sides no longer share one shape and
|
|
4930
|
+
* the annotation would reject the schema the Host must be given.
|
|
5690
4931
|
*/
|
|
5691
|
-
const TASK_BOARD_SETTINGS_NAMESPACE = "task-board";
|
|
5692
4932
|
const Config = z.object({
|
|
5693
|
-
announceToAgent: z.boolean().default(false),
|
|
5694
|
-
enabled: z.boolean().default(true),
|
|
5695
|
-
preventIdleSleep: z.boolean().default(false),
|
|
4933
|
+
announceToAgent: z.boolean().default(false).volatile(),
|
|
4934
|
+
enabled: z.boolean().default(true).volatile(),
|
|
4935
|
+
preventIdleSleep: z.boolean().default(false).volatile(),
|
|
5696
4936
|
trustedProxyHosts: z.array(z.string()).default([]),
|
|
5697
4937
|
proxyTokenEnv: z.string().min(1).default(DEFAULT_PROXY_TOKEN_ENV),
|
|
5698
4938
|
sessionDefaultPermission: z.union(TASK_PERMISSIONS).default(DEFAULT_SESSION_PERMISSION)
|
|
5699
4939
|
});
|
|
4940
|
+
/**
|
|
4941
|
+
* Read one config field's current value.
|
|
4942
|
+
*
|
|
4943
|
+
* The Loader hands schema-volatile fields as stable references it commits in
|
|
4944
|
+
* place, so a live value must be read at use time rather than captured when
|
|
4945
|
+
* the plugin activates; a plain value (a programmatic mount, or a field the
|
|
4946
|
+
* schema does not mark volatile) is returned as it stands.
|
|
4947
|
+
* @param field - the config field as the Loader handed it.
|
|
4948
|
+
* @param fallback - value to use when the field is absent.
|
|
4949
|
+
* @returns the effective field value.
|
|
4950
|
+
*/
|
|
4951
|
+
function readConfigField(field, fallback) {
|
|
4952
|
+
if (field === void 0) return fallback;
|
|
4953
|
+
if (typeof field === "object" && field !== null && typeof field.get === "function") return field.get();
|
|
4954
|
+
return field;
|
|
4955
|
+
}
|
|
5700
4956
|
/** Resolve proxy access without ever placing the token value in plugin config. */
|
|
5701
4957
|
function resolveProxyAccess(config, env = process.env) {
|
|
5702
4958
|
const trustedProxyHosts = config?.trustedProxyHosts ?? [];
|
|
@@ -5728,15 +4984,26 @@ function resolveLlmRuntime(ctx) {
|
|
|
5728
4984
|
}
|
|
5729
4985
|
}
|
|
5730
4986
|
/**
|
|
5731
|
-
*
|
|
5732
|
-
*
|
|
5733
|
-
*
|
|
5734
|
-
*
|
|
4987
|
+
* Activate the board's host half: ledger, routes, cron scheduler, power
|
|
4988
|
+
* inhibitor, and the model-facing announcement.
|
|
4989
|
+
*
|
|
4990
|
+
* The effective settings are the config the Host hands this row. The three
|
|
4991
|
+
* fields the browser card edits are schema-volatile, so the Loader commits an
|
|
4992
|
+
* edit into the running fiber's references instead of remounting the row —
|
|
4993
|
+
* `sync` therefore reads them at use time and follows
|
|
4994
|
+
* `loader/volatile-update`, the event the Loader emits once it has committed
|
|
4995
|
+
* them. Every other field reloads the row, which re-runs this activation.
|
|
5735
4996
|
* @param ctx - the plugin context (systemPrompt injected).
|
|
5736
4997
|
* @param config - resolved plugin config (schema defaults applied by the loader).
|
|
5737
4998
|
*/
|
|
5738
4999
|
const apply = mountOnce("@linxin666/dsh-client-ui-task-board", applyImpl);
|
|
5739
5000
|
function applyImpl(ctx, config) {
|
|
5001
|
+
/** Current master switch (the browser half reads the same field from its own form). */
|
|
5002
|
+
const enabled = () => readConfigField(config?.enabled, true);
|
|
5003
|
+
/** Current announcement flag. */
|
|
5004
|
+
const announceToAgent = () => readConfigField(config?.announceToAgent, DEFAULT_ANNOUNCE);
|
|
5005
|
+
/** Current idle-sleep protection flag. */
|
|
5006
|
+
const preventIdleSleep = () => readConfigField(config?.preventIdleSleep, false);
|
|
5740
5007
|
const host = new TaskBoardHostService(ctx.typertGateway, {
|
|
5741
5008
|
workspaceRegistry: ctx.workspaceRegistry,
|
|
5742
5009
|
sessionDefaultPermission: config?.sessionDefaultPermission ?? "read-only",
|
|
@@ -5746,7 +5013,7 @@ function applyImpl(ctx, config) {
|
|
|
5746
5013
|
return (await ctx.commands.execute(agent, line, [], signal))?.result;
|
|
5747
5014
|
} }
|
|
5748
5015
|
});
|
|
5749
|
-
host.setConfiguration(
|
|
5016
|
+
host.setConfiguration(enabled(), preventIdleSleep());
|
|
5750
5017
|
host.start();
|
|
5751
5018
|
ctx.effect(() => {
|
|
5752
5019
|
const disposers = [];
|
|
@@ -5767,41 +5034,32 @@ function applyImpl(ctx, config) {
|
|
|
5767
5034
|
host.dispose();
|
|
5768
5035
|
};
|
|
5769
5036
|
}, "task-board: host ledger, scheduler, and routes");
|
|
5770
|
-
let current = () => config ?? {};
|
|
5771
5037
|
let disposeSection;
|
|
5038
|
+
let applied;
|
|
5772
5039
|
const sync = () => {
|
|
5040
|
+
const next = {
|
|
5041
|
+
enabled: enabled(),
|
|
5042
|
+
announceToAgent: announceToAgent(),
|
|
5043
|
+
preventIdleSleep: preventIdleSleep()
|
|
5044
|
+
};
|
|
5045
|
+
if (applied !== void 0 && applied.enabled === next.enabled && applied.announceToAgent === next.announceToAgent && applied.preventIdleSleep === next.preventIdleSleep) return;
|
|
5046
|
+
applied = next;
|
|
5047
|
+
host.setConfiguration(next.enabled, next.preventIdleSleep);
|
|
5773
5048
|
if (disposeSection !== void 0) {
|
|
5774
5049
|
disposeSection();
|
|
5775
5050
|
disposeSection = void 0;
|
|
5776
5051
|
}
|
|
5777
|
-
|
|
5778
|
-
host.setConfiguration(active, current().preventIdleSleep ?? false);
|
|
5779
|
-
if (!active) return;
|
|
5780
|
-
if ((current().announceToAgent ?? DEFAULT_ANNOUNCE) === false) return;
|
|
5052
|
+
if (!next.enabled || !next.announceToAgent) return;
|
|
5781
5053
|
disposeSection = ctx.systemPrompt.section({
|
|
5782
5054
|
name: "plugin:task-board",
|
|
5783
5055
|
order: SECTION_ORDER,
|
|
5784
5056
|
text: TASK_BOARD_GUIDANCE
|
|
5785
5057
|
});
|
|
5786
5058
|
};
|
|
5787
|
-
ctx.
|
|
5788
|
-
|
|
5789
|
-
if (typeof settingsCtx.settings?.installSection === "function") settingsCtx.settings.installSection(ctx, TASK_BOARD_SETTINGS_NAMESPACE, Config, config ?? {}, {
|
|
5790
|
-
setSource: (source) => {
|
|
5791
|
-
current = source;
|
|
5792
|
-
},
|
|
5793
|
-
onChange: sync
|
|
5794
|
-
});
|
|
5795
|
-
else if (typeof settingsCtx.settings?.register === "function") {
|
|
5796
|
-
const scope = settingsCtx.settings.register(TASK_BOARD_SETTINGS_NAMESPACE, Config, { base: config ?? {} });
|
|
5797
|
-
current = () => scope?.get?.() ?? config ?? {};
|
|
5798
|
-
scope?.watch?.(() => {
|
|
5799
|
-
sync();
|
|
5800
|
-
});
|
|
5801
|
-
}
|
|
5802
|
-
} catch {}
|
|
5059
|
+
ctx.on("loader/volatile-update", () => {
|
|
5060
|
+
sync();
|
|
5803
5061
|
});
|
|
5804
5062
|
sync();
|
|
5805
5063
|
}
|
|
5806
5064
|
//#endregion
|
|
5807
|
-
export { Config, DEFAULT_PROXY_TOKEN_ENV, TASK_BOARD_GUIDANCE,
|
|
5065
|
+
export { Config, DEFAULT_PROXY_TOKEN_ENV, TASK_BOARD_GUIDANCE, apply, inject, readConfigField, resolveLlmRuntime, resolveProxyAccess };
|