dsh-daoing-memory 0.1.9 → 0.1.10

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/lib/index.js CHANGED
@@ -1,7 +1,9 @@
1
- import { mkdirSync } from "node:fs";
1
+ import { createRequire } from "node:module";
2
+ import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
3
  import { join, resolve } from "node:path";
3
4
  import { DatabaseSync } from "node:sqlite";
4
5
  import { createHash, randomUUID } from "node:crypto";
6
+ import "@deepseek-ai/cordis";
5
7
  import { Remote, TypertRemoteService } from "@deepseek-ai/dsh-typert-protocol";
6
8
  //#region lib/types/store.js
7
9
  /**
@@ -12,7 +14,7 @@ import { Remote, TypertRemoteService } from "@deepseek-ai/dsh-typert-protocol";
12
14
  * @module dsh-daoing-memory/store
13
15
  */
14
16
  /** Monotone store schema version. v1→v2 is an additive ALTER migration (see open()). */
15
- const MEMORY_SCHEMA_VERSION = 5;
17
+ const MEMORY_SCHEMA_VERSION = 6;
16
18
  /** Half-life (ms) of the recency weighting applied to verification samples. */
17
19
  const TRUST_HALF_LIFE_MS = 4320 * 60 * 60 * 1e3;
18
20
  /** Hash one ledger block's content, chained to the previous hash. */
@@ -182,7 +184,7 @@ var MemoryStore = class {
182
184
  );
183
185
  `);
184
186
  const row = db.prepare("SELECT value FROM memory_meta WHERE key = ?").get("schema_version");
185
- if (row === void 0) db.prepare("INSERT INTO memory_meta (key, value) VALUES (?, ?)").run("schema_version", String(5));
187
+ if (row === void 0) db.prepare("INSERT INTO memory_meta (key, value) VALUES (?, ?)").run("schema_version", String(6));
186
188
  else {
187
189
  let v = Number(row.value);
188
190
  if (v === 1) {
@@ -201,8 +203,30 @@ var MemoryStore = class {
201
203
  db.exec(`ALTER TABLE concerns ADD COLUMN background TEXT NOT NULL DEFAULT '';`);
202
204
  v = 5;
203
205
  }
204
- if (v !== 5) throw new Error(`memory store schema version ${row.value} does not match 5; refusing to open`);
205
- db.prepare("UPDATE memory_meta SET value = ? WHERE key = ?").run(String(5), "schema_version");
206
+ if (v === 5 && true) {
207
+ db.exec(`
208
+ CREATE TABLE IF NOT EXISTS skill_artifacts (
209
+ id TEXT PRIMARY KEY,
210
+ parent_experience_id TEXT NOT NULL,
211
+ form TEXT NOT NULL,
212
+ status TEXT NOT NULL,
213
+ draft_path TEXT,
214
+ published_path TEXT,
215
+ version INTEGER NOT NULL DEFAULT 1,
216
+ use_count INTEGER NOT NULL DEFAULT 0,
217
+ optimize_count INTEGER NOT NULL DEFAULT 0,
218
+ last_feedback TEXT,
219
+ content_hash TEXT,
220
+ created_at INTEGER NOT NULL,
221
+ updated_at INTEGER NOT NULL
222
+ );
223
+ CREATE INDEX IF NOT EXISTS idx_skill_parent ON skill_artifacts (parent_experience_id);
224
+ CREATE INDEX IF NOT EXISTS idx_skill_status ON skill_artifacts (status);
225
+ `);
226
+ v = 6;
227
+ }
228
+ if (v !== 6) throw new Error(`memory store schema version ${row.value} does not match 6; refusing to open`);
229
+ db.prepare("UPDATE memory_meta SET value = ? WHERE key = ?").run(String(6), "schema_version");
206
230
  }
207
231
  db.exec("CREATE INDEX IF NOT EXISTS idx_exp_context ON experiences (context);");
208
232
  db.exec("CREATE INDEX IF NOT EXISTS idx_concern_parent ON concerns (parent_id);");
@@ -857,6 +881,60 @@ var MemoryStore = class {
857
881
  if (row.superseded_by !== null) fact.supersededBy = row.superseded_by;
858
882
  return fact;
859
883
  }
884
+ /** Insert or update a skill artifact. */
885
+ upsertSkillArtifact(artifact) {
886
+ this.db.prepare(`
887
+ INSERT INTO skill_artifacts (id, parent_experience_id, form, status, draft_path, published_path,
888
+ version, use_count, optimize_count, last_feedback, content_hash, created_at, updated_at)
889
+ VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)
890
+ ON CONFLICT(id) DO UPDATE SET
891
+ status=excluded.status, draft_path=excluded.draft_path, published_path=excluded.published_path,
892
+ version=excluded.version, use_count=excluded.use_count, optimize_count=excluded.optimize_count,
893
+ last_feedback=excluded.last_feedback, content_hash=excluded.content_hash, updated_at=excluded.updated_at
894
+ `).run(artifact.id, artifact.parentExperienceId, artifact.form, artifact.status, artifact.draftPath ?? null, artifact.publishedPath ?? null, artifact.version, artifact.useCount, artifact.optimizeCount, artifact.lastFeedback ?? null, artifact.contentHash ?? null, artifact.createdAt, artifact.updatedAt);
895
+ }
896
+ /** Get a skill artifact by id. */
897
+ getSkillArtifact(id) {
898
+ const row = this.db.prepare("SELECT * FROM skill_artifacts WHERE id = ?").get(id);
899
+ return row ? this.rowToSkillArtifact(row) : void 0;
900
+ }
901
+ /** List skill artifacts, optionally filtered by parent experience or status. */
902
+ listSkillArtifacts(filter) {
903
+ const clauses = ["1 = 1"];
904
+ const params = [];
905
+ if (filter?.parentExperienceId !== void 0) {
906
+ clauses.push("parent_experience_id = ?");
907
+ params.push(filter.parentExperienceId);
908
+ }
909
+ if (filter?.status !== void 0) {
910
+ clauses.push("status = ?");
911
+ params.push(filter.status);
912
+ }
913
+ return this.db.prepare(`SELECT * FROM skill_artifacts WHERE ${clauses.join(" AND ")} ORDER BY created_at DESC`).all(...params).map((r) => this.rowToSkillArtifact(r));
914
+ }
915
+ /** Count skill artifacts by status. */
916
+ countSkillArtifacts(status) {
917
+ if (status === void 0) return this.db.prepare("SELECT COUNT(*) AS n FROM skill_artifacts").get().n;
918
+ return this.db.prepare("SELECT COUNT(*) AS n FROM skill_artifacts WHERE status = ?").get(status).n;
919
+ }
920
+ rowToSkillArtifact(row) {
921
+ const artifact = {
922
+ id: row.id,
923
+ parentExperienceId: row.parent_experience_id,
924
+ form: row.form,
925
+ status: row.status,
926
+ version: row.version,
927
+ useCount: row.use_count,
928
+ optimizeCount: row.optimize_count,
929
+ createdAt: row.created_at,
930
+ updatedAt: row.updated_at
931
+ };
932
+ if (row.draft_path !== null) artifact.draftPath = row.draft_path;
933
+ if (row.published_path !== null) artifact.publishedPath = row.published_path;
934
+ if (row.last_feedback !== null) artifact.lastFeedback = row.last_feedback;
935
+ if (row.content_hash !== null) artifact.contentHash = row.content_hash;
936
+ return artifact;
937
+ }
860
938
  };
861
939
  //#endregion
862
940
  //#region lib/types/types.js
@@ -1967,10 +2045,8 @@ var MemoryCore = class MemoryCore {
1967
2045
  }, "deletion-feedback summarization");
1968
2046
  return next;
1969
2047
  }
1970
- const id = crypto.randomUUID();
1971
2048
  const exp = {
1972
- id,
1973
- familyId: id,
2049
+ id: crypto.randomUUID(),
1974
2050
  revision: 1,
1975
2051
  kind: "positive",
1976
2052
  source: "system",
@@ -1989,6 +2065,9 @@ var MemoryCore = class MemoryCore {
1989
2065
  status: "live",
1990
2066
  alpha: 5,
1991
2067
  beta: 2,
2068
+ samples: 7,
2069
+ trust: 6 / 9,
2070
+ weightedTrust: 6 / 9,
1992
2071
  pinned: false,
1993
2072
  tokensSaved: 0,
1994
2073
  tokensSpent: 0,
@@ -2014,6 +2093,110 @@ var MemoryCore = class MemoryCore {
2014
2093
  getDeletionFeedback() {
2015
2094
  return this.store.findExperienceByFamily(MemoryCore.DELETION_FEEDBACK_FAMILY);
2016
2095
  }
2096
+ /**
2097
+ * Create a skill artifact draft from LLM-generated content.
2098
+ * @param experienceId - parent experience family_id.
2099
+ * @param form - output form (skill_md or script_mjs).
2100
+ * @param content - the LLM-generated skill/script content.
2101
+ * @param draftPath - file path where the draft is saved.
2102
+ * @param actor - who triggered the generation.
2103
+ * @returns the created skill artifact.
2104
+ */
2105
+ createSkillDraft(experienceId, form, content, draftPath, actor) {
2106
+ const experience = this.store.getActiveRevision(experienceId);
2107
+ if (experience === void 0) throw new Error(`memory: experience not found: ${experienceId}`);
2108
+ const now = Date.now();
2109
+ const id = crypto.randomUUID();
2110
+ const artifact = {
2111
+ id,
2112
+ parentExperienceId: experienceId,
2113
+ form,
2114
+ status: "draft",
2115
+ draftPath,
2116
+ version: 1,
2117
+ useCount: 0,
2118
+ optimizeCount: 0,
2119
+ contentHash: createHash("sha256").update(content).digest("hex"),
2120
+ createdAt: now,
2121
+ updatedAt: now
2122
+ };
2123
+ this.store.upsertSkillArtifact(artifact);
2124
+ this.ledger("skill-draft", "experience", experienceId, actor, {
2125
+ skillId: id,
2126
+ form,
2127
+ gist: experience.gist.slice(0, 80)
2128
+ }, `skill draft generated from experience`);
2129
+ return artifact;
2130
+ }
2131
+ /**
2132
+ * Review a skill artifact: approve or reject.
2133
+ */
2134
+ reviewSkill(request, actor) {
2135
+ const artifact = this.store.getSkillArtifact(request.id);
2136
+ if (artifact === void 0) throw new Error(`memory: skill artifact not found: ${request.id}`);
2137
+ if (artifact.status !== "draft" && artifact.status !== "pending_review" && artifact.status !== "revising") throw new Error(`memory: skill artifact ${request.id} is in status "${artifact.status}", cannot review`);
2138
+ const now = Date.now();
2139
+ const updated = {
2140
+ ...artifact,
2141
+ status: request.decision === "approve" ? "approved" : "rejected",
2142
+ lastFeedback: JSON.stringify({
2143
+ decision: request.decision,
2144
+ reason: request.reason,
2145
+ ts: now
2146
+ }),
2147
+ updatedAt: now
2148
+ };
2149
+ this.store.upsertSkillArtifact(updated);
2150
+ this.ledger(request.decision === "approve" ? "skill-approve" : "skill-reject", "experience", artifact.parentExperienceId, actor, {
2151
+ skillId: request.id,
2152
+ form: artifact.form,
2153
+ version: artifact.version
2154
+ }, request.reason);
2155
+ return updated;
2156
+ }
2157
+ /**
2158
+ * Publish a skill artifact: copy draft to $DSH_HOME/skills/ and mark as published.
2159
+ * The actual file copy is done by the service layer; this method updates the DB record.
2160
+ */
2161
+ publishSkill(request, publishedPath, actor) {
2162
+ const artifact = this.store.getSkillArtifact(request.id);
2163
+ if (artifact === void 0) throw new Error(`memory: skill artifact not found: ${request.id}`);
2164
+ if (artifact.status !== "approved") throw new Error(`memory: skill artifact ${request.id} must be approved before publishing (current: ${artifact.status})`);
2165
+ const now = Date.now();
2166
+ const updated = {
2167
+ ...artifact,
2168
+ status: "published",
2169
+ publishedPath,
2170
+ updatedAt: now
2171
+ };
2172
+ this.store.upsertSkillArtifact(updated);
2173
+ this.ledger("skill-publish", "experience", artifact.parentExperienceId, actor, {
2174
+ skillId: request.id,
2175
+ form: artifact.form,
2176
+ publishedPath
2177
+ }, request.reason);
2178
+ return updated;
2179
+ }
2180
+ /** List skill artifacts, optionally filtered. */
2181
+ listSkillArtifacts(filter) {
2182
+ return this.store.listSkillArtifacts(filter);
2183
+ }
2184
+ /** Get a single skill artifact. */
2185
+ getSkillArtifact(id) {
2186
+ return this.store.getSkillArtifact(id);
2187
+ }
2188
+ /**
2189
+ * Check if an experience is a candidate for skill conversion.
2190
+ * Criteria: live status, enough recall events, complex path (≥3 steps).
2191
+ */
2192
+ isSkillCandidate(experienceId) {
2193
+ const exp = this.store.getActiveRevision(experienceId);
2194
+ if (exp === void 0 || exp.status !== "live") return false;
2195
+ if (exp.path.length < 3) return false;
2196
+ if (exp.verifiedCount < 2) return false;
2197
+ if (this.store.listSkillArtifacts({ parentExperienceId: experienceId }).some((a) => a.status === "published" || a.status === "approved" || a.status === "pending_review")) return false;
2198
+ return true;
2199
+ }
2017
2200
  /** Human pin/unpin: pinned cards keep the trust floor and escape budgets. */
2018
2201
  humanPin(request, actor) {
2019
2202
  const current = this.store.getActiveRevision(request.id);
@@ -2403,6 +2586,955 @@ var MemoryCore = class MemoryCore {
2403
2586
  }
2404
2587
  };
2405
2588
  //#endregion
2589
+ //#region ../../llm/llm/src/brand.ts
2590
+ /**
2591
+ * Brand a message identifier.
2592
+ * @param id - the opaque message identifier.
2593
+ * @returns the same string, branded; no validation is performed.
2594
+ */
2595
+ function MessageId(id) {
2596
+ return id;
2597
+ }
2598
+ //#endregion
2599
+ //#region ../../llm/llm/src/call-config.ts
2600
+ /**
2601
+ * Deep-freeze a value in place with an iterative traversal, guarding cycles,
2602
+ * so later mutation throws without imposing a JavaScript call-stack depth cap.
2603
+ * {@link AbortSignal} objects are deliberately skipped because they are the
2604
+ * request's live cancellation channel and freezing them breaks abort.
2605
+ * @param value - the value to freeze in place.
2606
+ * @returns the same value, frozen.
2607
+ */
2608
+ function deepFreeze(value) {
2609
+ const seen = /* @__PURE__ */ new WeakSet();
2610
+ const pending = [{
2611
+ kind: "visit",
2612
+ node: value
2613
+ }];
2614
+ while (pending.length > 0) {
2615
+ const task = pending.pop();
2616
+ /* v8 ignore next -- the loop condition guarantees one pending task. */
2617
+ if (task === void 0) continue;
2618
+ if (task.kind === "property") {
2619
+ pending.push({
2620
+ kind: "visit",
2621
+ node: task.source[task.key]
2622
+ });
2623
+ continue;
2624
+ }
2625
+ const node = task.node;
2626
+ if (node === null || typeof node !== "object") continue;
2627
+ if (node instanceof AbortSignal) continue;
2628
+ if (seen.has(node)) continue;
2629
+ seen.add(node);
2630
+ Object.freeze(node);
2631
+ const keys = Object.keys(node);
2632
+ for (let index = keys.length - 1; index >= 0; index--) {
2633
+ const key = keys[index];
2634
+ /* v8 ignore next -- the loop is bounded by the captured key count. */
2635
+ if (key === void 0) continue;
2636
+ pending.push({
2637
+ kind: "property",
2638
+ source: node,
2639
+ key
2640
+ });
2641
+ }
2642
+ }
2643
+ return value;
2644
+ }
2645
+ //#endregion
2646
+ //#region ../../llm/llm/src/message.ts
2647
+ /** Message value types, identity, and immutable construction helpers. */
2648
+ /**
2649
+ * Detach and deep-freeze a message whose identity already exists.
2650
+ * @param message - complete message, including its stable identity.
2651
+ * @returns an immutable snapshot that preserves the identity.
2652
+ */
2653
+ function freezeMessage(message) {
2654
+ return deepFreeze(structuredClone(message));
2655
+ }
2656
+ /**
2657
+ * Create one identified message and freeze it before publication.
2658
+ * @param input - complete role, content, and source for a new message.
2659
+ * @returns an immutable message with a fresh stable identity.
2660
+ */
2661
+ function createMessage(input) {
2662
+ return freezeMessage({
2663
+ ...input,
2664
+ id: MessageId(crypto.randomUUID())
2665
+ });
2666
+ }
2667
+ /**
2668
+ * Create one identified user-role message and freeze it before publication.
2669
+ * @param input - complete content and source for a new user message.
2670
+ * @returns an immutable user message with a fresh stable identity.
2671
+ */
2672
+ function createUserMessage(input) {
2673
+ return createMessage({
2674
+ ...input,
2675
+ role: "user"
2676
+ });
2677
+ }
2678
+ //#endregion
2679
+ //#region ../../../vendor/cosmokit/src/misc.ts
2680
+ /** Return true when a value is `null` or `undefined`. */
2681
+ function isNullable(value) {
2682
+ return value === null || value === void 0;
2683
+ }
2684
+ /** Return true for non-array object values. */
2685
+ function isPlainObject(data) {
2686
+ return data && typeof data === "object" && !Array.isArray(data);
2687
+ }
2688
+ /** Filter object entries and return a new object. */
2689
+ function filterKeys(object, filter) {
2690
+ return Object.fromEntries(Object.entries(object).filter(([key, value]) => filter(key, value)));
2691
+ }
2692
+ /** Map object values while preserving the original key set. */
2693
+ function mapValues(object, transform) {
2694
+ return Object.fromEntries(Object.entries(object).map(([key, value]) => [key, transform(value, key)]));
2695
+ }
2696
+ /** Pick selected keys from an object, optionally including `undefined` values. */
2697
+ function pick(source, keys, forced) {
2698
+ if (!keys) return { ...source };
2699
+ const result = {};
2700
+ for (const key of keys) if (forced || source[key] !== void 0) result[key] = source[key];
2701
+ return result;
2702
+ }
2703
+ //#endregion
2704
+ //#region ../../../vendor/cosmokit/src/types.ts
2705
+ /** Test values using `instanceof` with a `toStringTag` fallback. */
2706
+ function is(type, value) {
2707
+ if (arguments.length === 1) return (value) => is(type, value);
2708
+ return type in globalThis && value instanceof globalThis[type] || Object.prototype.toString.call(value).slice(8, -1) === type;
2709
+ }
2710
+ function isArrayBufferLike(value) {
2711
+ return is("ArrayBuffer", value) || is("SharedArrayBuffer", value);
2712
+ }
2713
+ function isArrayBufferSource(value) {
2714
+ return isArrayBufferLike(value) || ArrayBuffer.isView(value);
2715
+ }
2716
+ let Binary;
2717
+ (function(_Binary) {
2718
+ _Binary.is = isArrayBufferLike;
2719
+ _Binary.isSource = isArrayBufferSource;
2720
+ function fromSource(source) {
2721
+ if (ArrayBuffer.isView(source)) return source.buffer.slice(source.byteOffset, source.byteOffset + source.byteLength);
2722
+ else return source;
2723
+ }
2724
+ _Binary.fromSource = fromSource;
2725
+ function toBase64(source) {
2726
+ source = fromSource(source);
2727
+ if (typeof Buffer !== "undefined") return Buffer.from(source).toString("base64");
2728
+ let binary = "";
2729
+ const bytes = new Uint8Array(source);
2730
+ for (let i = 0; i < bytes.byteLength; i++) binary += String.fromCharCode(bytes[i]);
2731
+ return btoa(binary);
2732
+ }
2733
+ _Binary.toBase64 = toBase64;
2734
+ function fromBase64(source) {
2735
+ if (typeof Buffer !== "undefined") return fromSource(Buffer.from(source, "base64"));
2736
+ return Uint8Array.from(atob(source), (c) => c.charCodeAt(0));
2737
+ }
2738
+ _Binary.fromBase64 = fromBase64;
2739
+ function toHex(source) {
2740
+ source = fromSource(source);
2741
+ if (typeof Buffer !== "undefined") return Buffer.from(source).toString("hex");
2742
+ return Array.from(new Uint8Array(source), (byte) => byte.toString(16).padStart(2, "0")).join("");
2743
+ }
2744
+ _Binary.toHex = toHex;
2745
+ function fromHex(source) {
2746
+ if (typeof Buffer !== "undefined") return fromSource(Buffer.from(source, "hex"));
2747
+ const hex = source.length % 2 === 0 ? source : source.slice(0, source.length - 1);
2748
+ const buffer = [];
2749
+ for (let i = 0; i < hex.length; i += 2) buffer.push(parseInt(`${hex[i]}${hex[i + 1]}`, 16));
2750
+ return Uint8Array.from(buffer).buffer;
2751
+ }
2752
+ _Binary.fromHex = fromHex;
2753
+ })(Binary || (Binary = {}));
2754
+ Binary.fromBase64;
2755
+ Binary.toBase64;
2756
+ Binary.fromHex;
2757
+ Binary.toHex;
2758
+ /** Deep-clone common JavaScript values while preserving prototypes and cycles. */
2759
+ function clone(source, refs = /* @__PURE__ */ new Map()) {
2760
+ if (!source || typeof source !== "object") return source;
2761
+ if (is("Date", source)) return new Date(source.valueOf());
2762
+ if (is("RegExp", source)) return new RegExp(source.source, source.flags);
2763
+ if (isArrayBufferLike(source)) return source.slice(0);
2764
+ if (ArrayBuffer.isView(source)) return source.buffer.slice(source.byteOffset, source.byteOffset + source.byteLength);
2765
+ const cached = refs.get(source);
2766
+ if (cached) return cached;
2767
+ if (Array.isArray(source)) {
2768
+ const result = [];
2769
+ refs.set(source, result);
2770
+ source.forEach((value, index) => {
2771
+ result[index] = Reflect.apply(clone, null, [value, refs]);
2772
+ });
2773
+ return result;
2774
+ }
2775
+ const result = Object.create(Object.getPrototypeOf(source));
2776
+ refs.set(source, result);
2777
+ for (const key of Reflect.ownKeys(source)) {
2778
+ const descriptor = { ...Reflect.getOwnPropertyDescriptor(source, key) };
2779
+ if ("value" in descriptor) descriptor.value = Reflect.apply(clone, null, [descriptor.value, refs]);
2780
+ Reflect.defineProperty(result, key, descriptor);
2781
+ }
2782
+ return result;
2783
+ }
2784
+ /** Deeply compare arrays, dates, regexps, buffers, and plain object fields. */
2785
+ function deepEqual(a, b, strict) {
2786
+ if (a === b) return true;
2787
+ if (!strict && isNullable(a) && isNullable(b)) return true;
2788
+ if (typeof a !== typeof b) return false;
2789
+ if (typeof a !== "object") return false;
2790
+ if (!a || !b) return false;
2791
+ function check(test, then) {
2792
+ return test(a) ? test(b) ? then(a, b) : false : test(b) ? false : void 0;
2793
+ }
2794
+ 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) => {
2795
+ if (a.byteLength !== b.byteLength) return false;
2796
+ const viewA = new Uint8Array(a);
2797
+ const viewB = new Uint8Array(b);
2798
+ for (let i = 0; i < viewA.length; i++) if (viewA[i] !== viewB[i]) return false;
2799
+ return true;
2800
+ }) ?? Object.keys({
2801
+ ...a,
2802
+ ...b
2803
+ }).every((key) => deepEqual(a[key], b[key], strict));
2804
+ }
2805
+ //#endregion
2806
+ //#region ../../../vendor/cosmokit/src/time.ts
2807
+ let Time;
2808
+ (function(_Time) {
2809
+ _Time.millisecond = 1;
2810
+ const second = _Time.second = 1e3;
2811
+ const minute = _Time.minute = second * 60;
2812
+ const hour = _Time.hour = minute * 60;
2813
+ const day = _Time.day = hour * 24;
2814
+ const week = _Time.week = day * 7;
2815
+ let timezoneOffset = (/* @__PURE__ */ new Date()).getTimezoneOffset();
2816
+ function setTimezoneOffset(offset) {
2817
+ timezoneOffset = offset;
2818
+ }
2819
+ _Time.setTimezoneOffset = setTimezoneOffset;
2820
+ function getTimezoneOffset() {
2821
+ return timezoneOffset;
2822
+ }
2823
+ _Time.getTimezoneOffset = getTimezoneOffset;
2824
+ function getDateNumber(date = /* @__PURE__ */ new Date(), offset) {
2825
+ if (typeof date === "number") date = new Date(date);
2826
+ if (offset === void 0) offset = timezoneOffset;
2827
+ return Math.floor((date.valueOf() / minute - offset) / 1440);
2828
+ }
2829
+ _Time.getDateNumber = getDateNumber;
2830
+ function fromDateNumber(value, offset) {
2831
+ const date = new Date(value * day);
2832
+ if (offset === void 0) offset = timezoneOffset;
2833
+ return new Date(+date + offset * minute);
2834
+ }
2835
+ _Time.fromDateNumber = fromDateNumber;
2836
+ const numeric = /\d+(?:\.\d+)?/.source;
2837
+ const timeRegExp = new RegExp(`^${[
2838
+ "w(?:eek(?:s)?)?",
2839
+ "d(?:ay(?:s)?)?",
2840
+ "h(?:our(?:s)?)?",
2841
+ "m(?:in(?:ute)?(?:s)?)?",
2842
+ "s(?:ec(?:ond)?(?:s)?)?"
2843
+ ].map((unit) => `(${numeric}${unit})?`).join("")}$`);
2844
+ function parseTime(source) {
2845
+ const capture = timeRegExp.exec(source);
2846
+ if (!capture) return 0;
2847
+ return (parseFloat(capture[1]) * week || 0) + (parseFloat(capture[2]) * day || 0) + (parseFloat(capture[3]) * hour || 0) + (parseFloat(capture[4]) * minute || 0) + (parseFloat(capture[5]) * second || 0);
2848
+ }
2849
+ _Time.parseTime = parseTime;
2850
+ function parseDate(date) {
2851
+ const parsed = parseTime(date);
2852
+ if (parsed) date = Date.now() + parsed;
2853
+ else if (/^\d{1,2}(:\d{1,2}){1,2}$/.test(date)) date = `${(/* @__PURE__ */ new Date()).toLocaleDateString()}-${date}`;
2854
+ else if (/^\d{1,2}-\d{1,2}-\d{1,2}(:\d{1,2}){1,2}$/.test(date)) date = `${(/* @__PURE__ */ new Date()).getFullYear()}-${date}`;
2855
+ return date ? new Date(date) : /* @__PURE__ */ new Date();
2856
+ }
2857
+ _Time.parseDate = parseDate;
2858
+ function format(ms) {
2859
+ const abs = Math.abs(ms);
2860
+ if (abs >= day - hour / 2) return Math.round(ms / day) + "d";
2861
+ else if (abs >= hour - minute / 2) return Math.round(ms / hour) + "h";
2862
+ else if (abs >= minute - second / 2) return Math.round(ms / minute) + "m";
2863
+ else if (abs >= second) return Math.round(ms / second) + "s";
2864
+ return ms + "ms";
2865
+ }
2866
+ _Time.format = format;
2867
+ function toDigits(source, length = 2) {
2868
+ return source.toString().padStart(length, "0");
2869
+ }
2870
+ _Time.toDigits = toDigits;
2871
+ function template(template, time = /* @__PURE__ */ new Date()) {
2872
+ 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));
2873
+ }
2874
+ _Time.template = template;
2875
+ })(Time || (Time = {}));
2876
+ //#endregion
2877
+ //#region ../../../vendor/schemastery/src/index.ts
2878
+ const kSchema = Symbol.for("schemastery");
2879
+ const kValidationError = Symbol.for("ValidationError");
2880
+ globalThis.__schemastery_index__ ??= 0;
2881
+ globalThis.__schemastery_refs__ = void 0;
2882
+ var ValidationError = class extends TypeError {
2883
+ options;
2884
+ name = "ValidationError";
2885
+ constructor(message, options) {
2886
+ let prefix = "$";
2887
+ for (const segment of options.path || []) if (typeof segment === "string") prefix += "." + segment;
2888
+ else if (typeof segment === "number") prefix += "[" + segment + "]";
2889
+ else if (typeof segment === "symbol") prefix += `[Symbol(${segment.toString()})]`;
2890
+ if (prefix.startsWith(".")) prefix = prefix.slice(1);
2891
+ super((prefix === "$" ? "" : `${prefix} `) + message);
2892
+ this.options = options;
2893
+ }
2894
+ static is(error) {
2895
+ return !!error?.[kValidationError];
2896
+ }
2897
+ };
2898
+ Object.defineProperty(ValidationError.prototype, kValidationError, { value: true });
2899
+ const Schema = function(options) {
2900
+ const schema = function(data, options = {}) {
2901
+ return Schema.resolve(data, schema, options)[0];
2902
+ };
2903
+ if (options.refs) {
2904
+ const refs = mapValues(options.refs, (options) => new Schema(options));
2905
+ const getRef = (uid) => refs[uid];
2906
+ for (const key in refs) {
2907
+ const options = refs[key];
2908
+ options.sKey = getRef(options.sKey);
2909
+ options.inner = getRef(options.inner);
2910
+ options.list = options.list && options.list.map(getRef);
2911
+ options.dict = options.dict && mapValues(options.dict, getRef);
2912
+ }
2913
+ return refs[options.uid];
2914
+ }
2915
+ Object.assign(schema, options);
2916
+ if (typeof schema.callback === "string") try {
2917
+ schema.callback = new Function("return " + schema.callback)();
2918
+ } catch {}
2919
+ Object.defineProperty(schema, "uid", { value: globalThis.__schemastery_index__++ });
2920
+ Object.setPrototypeOf(schema, Schema.prototype);
2921
+ schema.meta ||= {};
2922
+ schema.toString = schema.toString.bind(schema);
2923
+ return schema;
2924
+ };
2925
+ Schema.prototype = Object.create(Function.prototype);
2926
+ Schema.prototype[kSchema] = true;
2927
+ Object.defineProperty(Schema.prototype, "~standard", { get() {
2928
+ return {
2929
+ version: 1,
2930
+ vendor: "schemastery",
2931
+ validate: (value) => {
2932
+ try {
2933
+ return { value: Schema.resolve(value, this, {})[0] };
2934
+ } catch (error) {
2935
+ if (ValidationError.is(error)) return { issues: [{
2936
+ message: error.message,
2937
+ path: error.options.path
2938
+ }] };
2939
+ throw error;
2940
+ }
2941
+ }
2942
+ };
2943
+ } });
2944
+ Schema.ValidationError = ValidationError;
2945
+ Schema.prototype.toJSON = function toJSON() {
2946
+ if (globalThis.__schemastery_refs__) {
2947
+ globalThis.__schemastery_refs__[this.uid] ??= JSON.parse(JSON.stringify({ ...this }));
2948
+ return this.uid;
2949
+ }
2950
+ globalThis.__schemastery_refs__ = { [this.uid]: { ...this } };
2951
+ globalThis.__schemastery_refs__[this.uid] = JSON.parse(JSON.stringify({ ...this }));
2952
+ const result = {
2953
+ uid: this.uid,
2954
+ refs: globalThis.__schemastery_refs__
2955
+ };
2956
+ globalThis.__schemastery_refs__ = void 0;
2957
+ return result;
2958
+ };
2959
+ Schema.prototype.set = function set(key, value) {
2960
+ this.dict[key] = value;
2961
+ return this;
2962
+ };
2963
+ Schema.prototype.push = function push(value) {
2964
+ this.list.push(value);
2965
+ return this;
2966
+ };
2967
+ function mergeDesc(original, messages) {
2968
+ const result = typeof original === "string" ? { "": original } : { ...original };
2969
+ for (const locale in messages) {
2970
+ const value = messages[locale];
2971
+ if (value?.$description || value?.$desc) result[locale] = value.$description || value.$desc;
2972
+ else if (typeof value === "string") result[locale] = value;
2973
+ }
2974
+ return result;
2975
+ }
2976
+ function getInner(value) {
2977
+ return value?.$value ?? value?.$inner;
2978
+ }
2979
+ function extractKeys(data) {
2980
+ return filterKeys(data ?? {}, (key) => !key.startsWith("$"));
2981
+ }
2982
+ Schema.prototype.i18n = function i18n(messages) {
2983
+ const schema = Schema(this);
2984
+ const desc = mergeDesc(schema.meta.description, messages);
2985
+ if (Object.keys(desc).length) schema.meta.description = desc;
2986
+ if (schema.dict) schema.dict = mapValues(schema.dict, (inner, key) => {
2987
+ return inner.i18n(mapValues(messages, (data) => getInner(data)?.[key] ?? data?.[key]));
2988
+ });
2989
+ if (schema.list) schema.list = schema.list.map((inner, index) => {
2990
+ return inner.i18n(mapValues(messages, (data = {}) => {
2991
+ if (Array.isArray(getInner(data))) return getInner(data)[index];
2992
+ if (Array.isArray(data)) return data[index];
2993
+ return extractKeys(data);
2994
+ }));
2995
+ });
2996
+ if (schema.inner) schema.inner = schema.inner.i18n(mapValues(messages, (data) => {
2997
+ if (getInner(data)) return getInner(data);
2998
+ return extractKeys(data);
2999
+ }));
3000
+ if (schema.sKey) schema.sKey = schema.sKey.i18n(mapValues(messages, (data) => data?.$key));
3001
+ return schema;
3002
+ };
3003
+ Schema.prototype.extra = function extra(key, value) {
3004
+ const schema = Schema(this);
3005
+ schema.meta = {
3006
+ ...schema.meta,
3007
+ [key]: value
3008
+ };
3009
+ return schema;
3010
+ };
3011
+ for (const key of [
3012
+ "required",
3013
+ "disabled",
3014
+ "collapse",
3015
+ "hidden",
3016
+ "loose"
3017
+ ]) Object.assign(Schema.prototype, { [key](value = true) {
3018
+ const schema = Schema(this);
3019
+ schema.meta = {
3020
+ ...schema.meta,
3021
+ [key]: value
3022
+ };
3023
+ return schema;
3024
+ } });
3025
+ Schema.prototype.deprecated = function deprecated() {
3026
+ const schema = Schema(this);
3027
+ schema.meta.badges ||= [];
3028
+ schema.meta.badges.push({
3029
+ text: "deprecated",
3030
+ type: "danger"
3031
+ });
3032
+ return schema;
3033
+ };
3034
+ Schema.prototype.experimental = function experimental() {
3035
+ const schema = Schema(this);
3036
+ schema.meta.badges ||= [];
3037
+ schema.meta.badges.push({
3038
+ text: "experimental",
3039
+ type: "warning"
3040
+ });
3041
+ return schema;
3042
+ };
3043
+ Schema.prototype.pattern = function pattern(regexp) {
3044
+ const schema = Schema(this);
3045
+ const pattern = pick(regexp, ["source", "flags"]);
3046
+ schema.meta = {
3047
+ ...schema.meta,
3048
+ pattern
3049
+ };
3050
+ return schema;
3051
+ };
3052
+ Schema.prototype.simplify = function simplify(value) {
3053
+ if (deepEqual(value, this.meta.default, this.type === "dict")) return null;
3054
+ if (isNullable(value)) return value;
3055
+ if (this.type === "object" || this.type === "dict") {
3056
+ const result = {};
3057
+ for (const key in value) {
3058
+ const item = (this.type === "object" ? this.dict[key] : this.inner)?.simplify(value[key]);
3059
+ if (this.type === "dict" || !isNullable(item)) result[key] = item;
3060
+ }
3061
+ if (deepEqual(result, this.meta.default, this.type === "dict")) return null;
3062
+ return result;
3063
+ } else if (this.type === "array" || this.type === "tuple") {
3064
+ const result = [];
3065
+ value.forEach((value, index) => {
3066
+ const schema = this.type === "array" ? this.inner : this.list[index];
3067
+ const item = schema ? schema.simplify(value) : value;
3068
+ result.push(item);
3069
+ });
3070
+ return result;
3071
+ } else if (this.type === "intersect") {
3072
+ const result = {};
3073
+ for (const item of this.list) Object.assign(result, item.simplify(value));
3074
+ return result;
3075
+ } else if (this.type === "union") for (const schema of this.list) try {
3076
+ Schema.resolve(value, schema, {});
3077
+ return schema.simplify(value);
3078
+ } catch {}
3079
+ return value;
3080
+ };
3081
+ Schema.prototype.toString = function toString(inline) {
3082
+ return formatters[this.type]?.(this, inline) ?? `Schema<${this.type}>`;
3083
+ };
3084
+ Schema.prototype.role = function role(role, extra) {
3085
+ const schema = Schema(this);
3086
+ schema.meta = {
3087
+ ...schema.meta,
3088
+ role,
3089
+ extra
3090
+ };
3091
+ return schema;
3092
+ };
3093
+ for (const key of [
3094
+ "default",
3095
+ "link",
3096
+ "comment",
3097
+ "description",
3098
+ "max",
3099
+ "min",
3100
+ "step"
3101
+ ]) Object.assign(Schema.prototype, { [key](value) {
3102
+ const schema = Schema(this);
3103
+ schema.meta = {
3104
+ ...schema.meta,
3105
+ [key]: value
3106
+ };
3107
+ return schema;
3108
+ } });
3109
+ const resolvers = {};
3110
+ Schema.extend = function extend(type, resolve) {
3111
+ resolvers[type] = resolve;
3112
+ };
3113
+ Schema.resolve = function resolve(data, schema, options = {}, strict = false) {
3114
+ if (!schema) return [data];
3115
+ if (options.ignore?.(data, schema)) return [data];
3116
+ if (isNullable(data) && schema.type !== "lazy") {
3117
+ if (schema.meta.required) throw new ValidationError(`missing required value`, options);
3118
+ let current = schema;
3119
+ let fallback = schema.meta.default;
3120
+ while (current?.type === "intersect" && isNullable(fallback)) {
3121
+ current = current.list[0];
3122
+ fallback = current?.meta.default;
3123
+ }
3124
+ if (isNullable(fallback)) return [data];
3125
+ data = clone(fallback);
3126
+ }
3127
+ const callback = resolvers[schema.type];
3128
+ if (!callback) throw new ValidationError(`unsupported type "${schema.type}"`, options);
3129
+ try {
3130
+ return callback(data, schema, options, strict);
3131
+ } catch (error) {
3132
+ if (!schema.meta.loose) throw error;
3133
+ return [schema.meta.default];
3134
+ }
3135
+ };
3136
+ Schema.from = function from(source) {
3137
+ if (isNullable(source)) return Schema.any();
3138
+ else if ([
3139
+ "string",
3140
+ "number",
3141
+ "boolean"
3142
+ ].includes(typeof source)) return Schema.const(source).required();
3143
+ else if (source[kSchema]) return source;
3144
+ else if (typeof source === "function") switch (source) {
3145
+ case String: return Schema.string().required();
3146
+ case Number: return Schema.number().required();
3147
+ case Boolean: return Schema.boolean().required();
3148
+ case Function: return Schema.function().required();
3149
+ default: return Schema.is(source).required();
3150
+ }
3151
+ else throw new TypeError(`cannot infer schema from ${source}`);
3152
+ };
3153
+ Schema.lazy = function lazy(builder) {
3154
+ const toJSON = () => {
3155
+ if (!schema.inner[kSchema]) {
3156
+ schema.inner = schema.builder();
3157
+ schema.inner.meta = {
3158
+ ...schema.meta,
3159
+ ...schema.inner.meta
3160
+ };
3161
+ }
3162
+ return schema.inner.toJSON();
3163
+ };
3164
+ const schema = new Schema({
3165
+ type: "lazy",
3166
+ builder,
3167
+ inner: { toJSON }
3168
+ });
3169
+ return schema;
3170
+ };
3171
+ Schema.natural = function natural() {
3172
+ return Schema.number().step(1).min(0);
3173
+ };
3174
+ Schema.percent = function percent() {
3175
+ return Schema.number().step(.01).min(0).max(1).role("slider");
3176
+ };
3177
+ Schema.date = function date() {
3178
+ return Schema.union([Schema.is(Date), Schema.transform(Schema.string().role("datetime"), (value, options) => {
3179
+ const date = new Date(value);
3180
+ if (isNaN(+date)) throw new ValidationError(`invalid date "${value}"`, options);
3181
+ return date;
3182
+ }, true)]);
3183
+ };
3184
+ Schema.regExp = function regExp(flag = "") {
3185
+ return Schema.union([Schema.is(RegExp), Schema.transform(Schema.string().role("regexp", { flag }), (value, options) => {
3186
+ try {
3187
+ return new RegExp(value, flag);
3188
+ } catch (e) {
3189
+ throw new ValidationError(e.message, options);
3190
+ }
3191
+ }, true)]);
3192
+ };
3193
+ Schema.arrayBuffer = function arrayBuffer(encoding) {
3194
+ return Schema.union([
3195
+ Schema.is(ArrayBuffer),
3196
+ Schema.is(SharedArrayBuffer),
3197
+ Schema.transform(Schema.any(), (value, options) => {
3198
+ if (Binary.isSource(value)) return Binary.fromSource(value);
3199
+ throw new ValidationError(`expected ArrayBufferSource but got ${value}`, options);
3200
+ }, true),
3201
+ ...encoding ? [Schema.transform(Schema.string(), (value, options) => {
3202
+ try {
3203
+ return encoding === "base64" ? Binary.fromBase64(value) : Binary.fromHex(value);
3204
+ } catch (e) {
3205
+ throw new ValidationError(e.message, options);
3206
+ }
3207
+ }, true)] : []
3208
+ ]);
3209
+ };
3210
+ Schema.extend("lazy", (data, schema, options, strict) => {
3211
+ if (!schema.inner[kSchema]) {
3212
+ schema.inner = schema.builder();
3213
+ schema.inner.meta = {
3214
+ ...schema.meta,
3215
+ ...schema.inner.meta
3216
+ };
3217
+ }
3218
+ return Schema.resolve(data, schema.inner, options, strict);
3219
+ });
3220
+ Schema.extend("any", (data) => {
3221
+ return [data];
3222
+ });
3223
+ Schema.extend("never", (data, _, options) => {
3224
+ throw new ValidationError(`expected nullable but got ${data}`, options);
3225
+ });
3226
+ Schema.extend("const", (data, { value }, options) => {
3227
+ if (deepEqual(data, value)) return [value];
3228
+ throw new ValidationError(`expected ${value} but got ${data}`, options);
3229
+ });
3230
+ function checkWithinRange(data, meta, description, options, skipMin = false) {
3231
+ const { max = Infinity, min = -Infinity } = meta;
3232
+ if (data > max) throw new ValidationError(`expected ${description} <= ${max} but got ${data}`, options);
3233
+ if (data < min && !skipMin) throw new ValidationError(`expected ${description} >= ${min} but got ${data}`, options);
3234
+ }
3235
+ Schema.extend("string", (data, { meta }, options) => {
3236
+ if (typeof data !== "string") throw new ValidationError(`expected string but got ${data}`, options);
3237
+ if (meta.pattern) {
3238
+ const regexp = new RegExp(meta.pattern.source, meta.pattern.flags);
3239
+ if (!regexp.test(data)) throw new ValidationError(`expect string to match regexp ${regexp}`, options);
3240
+ }
3241
+ checkWithinRange(data.length, meta, "string length", options);
3242
+ return [data];
3243
+ });
3244
+ function decimalShift(data, digits) {
3245
+ const str = data.toString();
3246
+ if (str.includes("e")) return data * Math.pow(10, digits);
3247
+ const index = str.indexOf(".");
3248
+ if (index === -1) return data * Math.pow(10, digits);
3249
+ const frac = str.slice(index + 1);
3250
+ const integer = str.slice(0, index);
3251
+ if (frac.length <= digits) return +(integer + frac.padEnd(digits, "0"));
3252
+ return +(integer + frac.slice(0, digits) + "." + frac.slice(digits));
3253
+ }
3254
+ function isMultipleOf(data, min, step) {
3255
+ step = Math.abs(step);
3256
+ if (!/^\d+\.\d+$/.test(step.toString())) return (data - min) % step === 0;
3257
+ const index = step.toString().indexOf(".");
3258
+ const digits = step.toString().slice(index + 1).length;
3259
+ return Math.abs(decimalShift(data, digits) - decimalShift(min, digits)) % decimalShift(step, digits) === 0;
3260
+ }
3261
+ Schema.extend("number", (data, { meta }, options) => {
3262
+ if (typeof data !== "number") throw new ValidationError(`expected number but got ${data}`, options);
3263
+ checkWithinRange(data, meta, "number", options);
3264
+ const { step } = meta;
3265
+ if (step && !isMultipleOf(data, meta.min ?? 0, step)) throw new ValidationError(`expected number multiple of ${step} but got ${data}`, options);
3266
+ return [data];
3267
+ });
3268
+ Schema.extend("boolean", (data, _, options) => {
3269
+ if (typeof data === "boolean") return [data];
3270
+ throw new ValidationError(`expected boolean but got ${data}`, options);
3271
+ });
3272
+ Schema.extend("bitset", (data, { bits, meta }, options) => {
3273
+ let value = 0, keys = [];
3274
+ if (typeof data === "number") {
3275
+ value = data;
3276
+ for (const key in bits) if (data & bits[key]) keys.push(key);
3277
+ } else if (Array.isArray(data)) {
3278
+ keys = data;
3279
+ for (const key of keys) {
3280
+ if (typeof key !== "string") throw new ValidationError(`expected string but got ${key}`, options);
3281
+ if (key in bits) value |= bits[key];
3282
+ }
3283
+ } else throw new ValidationError(`expected number or array but got ${data}`, options);
3284
+ if (value === meta.default) return [value];
3285
+ return [value, keys];
3286
+ });
3287
+ Schema.extend("function", (data, _, options) => {
3288
+ if (typeof data === "function") return [data];
3289
+ throw new ValidationError(`expected function but got ${data}`, options);
3290
+ });
3291
+ Schema.extend("is", (data, { constructor }, options) => {
3292
+ if (typeof constructor === "function") {
3293
+ if (data instanceof constructor) return [data];
3294
+ throw new ValidationError(`expected ${constructor.name} but got ${data}`, options);
3295
+ } else {
3296
+ if (isNullable(data)) throw new ValidationError(`expected ${constructor} but got ${data}`, options);
3297
+ let prototype = Object.getPrototypeOf(data);
3298
+ while (prototype) {
3299
+ if (prototype.constructor?.name === constructor) return [data];
3300
+ prototype = Object.getPrototypeOf(prototype);
3301
+ }
3302
+ throw new ValidationError(`expected ${constructor} but got ${data}`, options);
3303
+ }
3304
+ });
3305
+ function property(data, key, schema, options) {
3306
+ try {
3307
+ const [value, adapted] = Schema.resolve(data[key], schema, {
3308
+ ...options,
3309
+ path: [...options.path || [], key]
3310
+ });
3311
+ if (adapted !== void 0) data[key] = adapted;
3312
+ return value;
3313
+ } catch (e) {
3314
+ if (!options?.autofix) throw e;
3315
+ delete data[key];
3316
+ return schema.meta.default;
3317
+ }
3318
+ }
3319
+ Schema.extend("array", (data, { inner, meta }, options) => {
3320
+ if (!Array.isArray(data)) throw new ValidationError(`expected array but got ${data}`, options);
3321
+ checkWithinRange(data.length, meta, "array length", options, !isNullable(inner.meta.default));
3322
+ return [data.map((_, index) => property(data, index, inner, options))];
3323
+ });
3324
+ Schema.extend("dict", (data, { inner, sKey }, options, strict) => {
3325
+ if (!isPlainObject(data)) throw new ValidationError(`expected object but got ${data}`, options);
3326
+ const result = {};
3327
+ for (const key in data) {
3328
+ let rKey;
3329
+ try {
3330
+ rKey = Schema.resolve(key, sKey, options)[0];
3331
+ } catch (error) {
3332
+ if (strict) continue;
3333
+ throw error;
3334
+ }
3335
+ result[rKey] = property(data, key, inner, options);
3336
+ data[rKey] = data[key];
3337
+ if (key !== rKey) delete data[key];
3338
+ }
3339
+ return [result];
3340
+ });
3341
+ Schema.extend("tuple", (data, { list }, options, strict) => {
3342
+ if (!Array.isArray(data)) throw new ValidationError(`expected array but got ${data}`, options);
3343
+ const result = list.map((inner, index) => property(data, index, inner, options));
3344
+ if (strict) return [result];
3345
+ result.push(...data.slice(list.length));
3346
+ return [result];
3347
+ });
3348
+ function merge(result, data) {
3349
+ for (const key in data) {
3350
+ if (key in result) continue;
3351
+ result[key] = data[key];
3352
+ }
3353
+ }
3354
+ Schema.extend("object", (data, { dict }, options, strict) => {
3355
+ if (!isPlainObject(data)) throw new ValidationError(`expected object but got ${data}`, options);
3356
+ const result = {};
3357
+ for (const key in dict) {
3358
+ const value = property(data, key, dict[key], options);
3359
+ if (!isNullable(value) || key in data) result[key] = value;
3360
+ }
3361
+ if (!strict) merge(result, data);
3362
+ return [result];
3363
+ });
3364
+ Schema.extend("union", (data, { list, toString }, options, strict) => {
3365
+ const messages = [];
3366
+ for (const inner of list) try {
3367
+ return Schema.resolve(data, inner, options, strict);
3368
+ } catch (error) {
3369
+ messages.push(error);
3370
+ }
3371
+ throw new ValidationError(`expected ${toString()} but got ${JSON.stringify(data)}`, options);
3372
+ });
3373
+ Schema.extend("intersect", (data, { list, toString }, options, strict) => {
3374
+ if (!list.length) return [data];
3375
+ let result;
3376
+ for (const inner of list) {
3377
+ const value = Schema.resolve(data, inner, options, true)[0];
3378
+ if (isNullable(value)) continue;
3379
+ if (isNullable(result)) result = value;
3380
+ else if (typeof result !== typeof value) throw new ValidationError(`expected ${toString()} but got ${JSON.stringify(data)}`, options);
3381
+ else if (typeof value === "object") merge(result ??= {}, value);
3382
+ else if (result !== value) throw new ValidationError(`expected ${toString()} but got ${JSON.stringify(data)}`, options);
3383
+ }
3384
+ if (!strict && isPlainObject(data)) merge(result, data);
3385
+ return [result];
3386
+ });
3387
+ Schema.extend("transform", (data, { inner, callback, preserve }, options) => {
3388
+ const [result, adapted = data] = Schema.resolve(data, inner, options, true);
3389
+ if (preserve) return [callback(result)];
3390
+ else return [callback(result), callback(adapted)];
3391
+ });
3392
+ const formatters = {};
3393
+ function defineMethod(name, keys, format) {
3394
+ formatters[name] = format;
3395
+ Object.assign(Schema, { [name](...args) {
3396
+ const schema = new Schema({ type: name });
3397
+ keys.forEach((key, index) => {
3398
+ switch (key) {
3399
+ case "sKey":
3400
+ schema.sKey = args[index] ?? Schema.string();
3401
+ break;
3402
+ case "inner":
3403
+ schema.inner = Schema.from(args[index]);
3404
+ break;
3405
+ case "list":
3406
+ schema.list = args[index].map(Schema.from);
3407
+ break;
3408
+ case "dict":
3409
+ schema.dict = mapValues(args[index], Schema.from);
3410
+ break;
3411
+ case "bits":
3412
+ schema.bits = {};
3413
+ for (const key in args[index]) {
3414
+ if (typeof args[index][key] !== "number") continue;
3415
+ schema.bits[key] = args[index][key];
3416
+ }
3417
+ break;
3418
+ case "callback": {
3419
+ const callback = schema.callback = args[index];
3420
+ callback["toJSON"] ||= () => callback.toString();
3421
+ break;
3422
+ }
3423
+ case "constructor": {
3424
+ const constructor = schema.constructor = args[index];
3425
+ if (typeof constructor === "function") constructor["toJSON"] ||= () => constructor["name"];
3426
+ break;
3427
+ }
3428
+ default: schema[key] = args[index];
3429
+ }
3430
+ });
3431
+ if (name === "object" || name === "dict") schema.meta.default = {};
3432
+ else if (name === "array" || name === "tuple") schema.meta.default = [];
3433
+ else if (name === "bitset") schema.meta.default = 0;
3434
+ return schema;
3435
+ } });
3436
+ }
3437
+ defineMethod("is", ["constructor"], ({ constructor }) => {
3438
+ if (typeof constructor === "function") return constructor.name;
3439
+ else return constructor;
3440
+ });
3441
+ defineMethod("any", [], () => "any");
3442
+ defineMethod("never", [], () => "never");
3443
+ defineMethod("const", ["value"], ({ value }) => typeof value === "string" ? JSON.stringify(value) : value);
3444
+ defineMethod("string", [], () => "string");
3445
+ defineMethod("number", [], () => "number");
3446
+ defineMethod("boolean", [], () => "boolean");
3447
+ defineMethod("bitset", ["bits"], () => "bitset");
3448
+ defineMethod("function", [], () => "function");
3449
+ defineMethod("array", ["inner"], ({ inner }) => `${inner.toString(true)}[]`);
3450
+ defineMethod("dict", ["inner", "sKey"], ({ inner, sKey }) => `{ [key: ${sKey.toString()}]: ${inner.toString()} }`);
3451
+ defineMethod("tuple", ["list"], ({ list }) => `[${list.map((inner) => inner.toString()).join(", ")}]`);
3452
+ defineMethod("object", ["dict"], ({ dict }) => {
3453
+ if (Object.keys(dict).length === 0) return "{}";
3454
+ return `{ ${Object.entries(dict).map(([key, inner]) => {
3455
+ return `${key}${inner.meta.required ? "" : "?"}: ${inner.toString()}`;
3456
+ }).join(", ")} }`;
3457
+ });
3458
+ defineMethod("union", ["list"], ({ list }, inline) => {
3459
+ const result = list.map(({ toString: format }) => format()).join(" | ");
3460
+ return inline ? `(${result})` : result;
3461
+ });
3462
+ defineMethod("intersect", ["list"], ({ list }) => {
3463
+ return `${list.map((inner) => inner.toString(true)).join(" & ")}`;
3464
+ });
3465
+ defineMethod("transform", [
3466
+ "inner",
3467
+ "callback",
3468
+ "preserve"
3469
+ ], ({ inner }, isInner) => inner.toString(isInner));
3470
+ //#endregion
3471
+ //#region ../../util/timeout/src/index.ts
3472
+ /** Largest delay Node schedules without clamping it to one millisecond. */
3473
+ const MAX_TIMER_DELAY_MS = 2147483647;
3474
+ //#endregion
3475
+ //#region ../../llm/llm/src/error.ts
3476
+ /**
3477
+ * Canonical provider-neutral code for a response that completed normally but
3478
+ * carried no content blocks at all. Providers occasionally emit a degenerate
3479
+ * completion (a terminal stop with zero output); adapters classify it as this
3480
+ * failure instead of yielding an empty assistant message, because an empty
3481
+ * message silently ends the turn with nothing for the user or the loop to act
3482
+ * on. The attempt produced nothing durable, so retry policy treats it as safe
3483
+ * to repeat.
3484
+ */
3485
+ const EMPTY_RESPONSE_CODE = "EMPTY_RESPONSE";
3486
+ new RegExp(String.raw`(?:^|[^a-z0-9])context[\s_-](?:length|window)[\s_-]` + String.raw`(?:exceed(?:ed|s)?|overflow(?:ed)?|limit[\s_-]exceeded)(?:$|[^a-z0-9])`, "i");
3487
+ new RegExp(String.raw`\b(?:request|prompt|input|messages?)\s+(?:is\s+|are\s+)?` + String.raw`too\s+(?:large|long)\s+for\s+(?:(?:this|the)\s+)?` + String.raw`(?:model(?:'s)?\s+)?context(?:\s+window)?\b`, "i");
3488
+ new RegExp(String.raw`\b(?:input|prompt|request|messages?)\b.{0,40}` + String.raw`\b(?:exceed(?:s|ed)?|overflows?|is\s+larger\s+than)\b.{0,40}` + String.raw`\b(?:the\s+)?(?:model(?:'s)?\s+)?context(?:\s+(?:length|window))?\b`, "i");
3489
+ //#endregion
3490
+ //#region ../../llm/llm/src/retry-policy.ts
3491
+ /**
3492
+ * Provider-owned request-retry policy configuration and resolution.
3493
+ *
3494
+ * Adapters expose one resolved policy per registered provider route; the
3495
+ * optional dsh-llm-retry plugin executes it on the agent's failed-step extension point.
3496
+ *
3497
+ * @module @deepseek-ai/dsh-llm/retry-policy
3498
+ */
3499
+ const DEFAULT_MAX_RETRIES = 2;
3500
+ const DEFAULT_INITIAL_DELAY_MS = 500;
3501
+ const DEFAULT_MAX_DELAY_MS = 1e4;
3502
+ const DEFAULT_JITTER_RATIO = .1;
3503
+ const DEFAULT_RETRYABLE_CODES = Object.freeze([
3504
+ EMPTY_RESPONSE_CODE,
3505
+ "RATE_LIMIT",
3506
+ "SERVER",
3507
+ "TIMEOUT",
3508
+ "TRANSPORT"
3509
+ ]);
3510
+ const backoffSchema = Schema.object({
3511
+ initialDelayMs: Schema.number().max(MAX_TIMER_DELAY_MS).default(DEFAULT_INITIAL_DELAY_MS),
3512
+ maxDelayMs: Schema.number().max(MAX_TIMER_DELAY_MS).default(DEFAULT_MAX_DELAY_MS),
3513
+ jitterRatio: Schema.number().min(0).max(1).default(DEFAULT_JITTER_RATIO)
3514
+ });
3515
+ const normalPolicySchema = Schema.object({
3516
+ mode: Schema.const("normal").required(),
3517
+ maxRetries: Schema.number().step(1).min(0).max(Number.MAX_SAFE_INTEGER).default(DEFAULT_MAX_RETRIES),
3518
+ retryableCodes: Schema.array(Schema.string()).default([...DEFAULT_RETRYABLE_CODES]),
3519
+ backoff: backoffSchema
3520
+ });
3521
+ const alwaysPolicySchema = Schema.object({
3522
+ mode: Schema.const("always").required(),
3523
+ backoff: backoffSchema
3524
+ });
3525
+ Schema.union([normalPolicySchema, alwaysPolicySchema]);
3526
+ //#endregion
3527
+ //#region ../../llm/llm/src/attribution.ts
3528
+ /**
3529
+ * Centralize the non-secret product identity every provider request sends as `User-Agent`, keeping
3530
+ * adapters from drifting. See
3531
+ * `.agents/notes/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.md`.
3532
+ *
3533
+ * App-attribution vocabulary for provider requests.
3534
+ * @module @deepseek-ai/dsh-llm/attribution
3535
+ */
3536
+ const { version } = createRequire(import.meta.url)("../package.json");
3537
+ //#endregion
2406
3538
  //#region lib/types/service.js
2407
3539
  /**
2408
3540
  * Memory library Typert Remote service: the wire face over MemoryCore.
@@ -2506,6 +3638,12 @@ let MemoryService = (() => {
2506
3638
  let _humanAckDiary_decorators;
2507
3639
  let _humanSetConcernStatus_decorators;
2508
3640
  let _humanDeleteConcern_decorators;
3641
+ let _generateSkillDraft_decorators;
3642
+ let _reviewSkill_decorators;
3643
+ let _publishSkill_decorators;
3644
+ let _listSkillArtifacts_decorators;
3645
+ let _getSkillArtifact_decorators;
3646
+ let _isSkillCandidate_decorators;
2509
3647
  return class MemoryService extends _classSuper {
2510
3648
  static {
2511
3649
  const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
@@ -2554,6 +3692,12 @@ let MemoryService = (() => {
2554
3692
  _humanAckDiary_decorators = [Remote("humanAckDiary")];
2555
3693
  _humanSetConcernStatus_decorators = [Remote("humanSetConcernStatus")];
2556
3694
  _humanDeleteConcern_decorators = [Remote("humanDeleteConcern")];
3695
+ _generateSkillDraft_decorators = [Remote("generateSkillDraft")];
3696
+ _reviewSkill_decorators = [Remote("reviewSkill")];
3697
+ _publishSkill_decorators = [Remote("publishSkill")];
3698
+ _listSkillArtifacts_decorators = [Remote("listSkillArtifacts")];
3699
+ _getSkillArtifact_decorators = [Remote("getSkillArtifact")];
3700
+ _isSkillCandidate_decorators = [Remote("isSkillCandidate")];
2557
3701
  __esDecorate(this, null, _refine_decorators, {
2558
3702
  kind: "method",
2559
3703
  name: "refine",
@@ -3049,6 +4193,72 @@ let MemoryService = (() => {
3049
4193
  },
3050
4194
  metadata: _metadata
3051
4195
  }, null, _instanceExtraInitializers);
4196
+ __esDecorate(this, null, _generateSkillDraft_decorators, {
4197
+ kind: "method",
4198
+ name: "generateSkillDraft",
4199
+ static: false,
4200
+ private: false,
4201
+ access: {
4202
+ has: (obj) => "generateSkillDraft" in obj,
4203
+ get: (obj) => obj.generateSkillDraft
4204
+ },
4205
+ metadata: _metadata
4206
+ }, null, _instanceExtraInitializers);
4207
+ __esDecorate(this, null, _reviewSkill_decorators, {
4208
+ kind: "method",
4209
+ name: "reviewSkill",
4210
+ static: false,
4211
+ private: false,
4212
+ access: {
4213
+ has: (obj) => "reviewSkill" in obj,
4214
+ get: (obj) => obj.reviewSkill
4215
+ },
4216
+ metadata: _metadata
4217
+ }, null, _instanceExtraInitializers);
4218
+ __esDecorate(this, null, _publishSkill_decorators, {
4219
+ kind: "method",
4220
+ name: "publishSkill",
4221
+ static: false,
4222
+ private: false,
4223
+ access: {
4224
+ has: (obj) => "publishSkill" in obj,
4225
+ get: (obj) => obj.publishSkill
4226
+ },
4227
+ metadata: _metadata
4228
+ }, null, _instanceExtraInitializers);
4229
+ __esDecorate(this, null, _listSkillArtifacts_decorators, {
4230
+ kind: "method",
4231
+ name: "listSkillArtifacts",
4232
+ static: false,
4233
+ private: false,
4234
+ access: {
4235
+ has: (obj) => "listSkillArtifacts" in obj,
4236
+ get: (obj) => obj.listSkillArtifacts
4237
+ },
4238
+ metadata: _metadata
4239
+ }, null, _instanceExtraInitializers);
4240
+ __esDecorate(this, null, _getSkillArtifact_decorators, {
4241
+ kind: "method",
4242
+ name: "getSkillArtifact",
4243
+ static: false,
4244
+ private: false,
4245
+ access: {
4246
+ has: (obj) => "getSkillArtifact" in obj,
4247
+ get: (obj) => obj.getSkillArtifact
4248
+ },
4249
+ metadata: _metadata
4250
+ }, null, _instanceExtraInitializers);
4251
+ __esDecorate(this, null, _isSkillCandidate_decorators, {
4252
+ kind: "method",
4253
+ name: "isSkillCandidate",
4254
+ static: false,
4255
+ private: false,
4256
+ access: {
4257
+ has: (obj) => "isSkillCandidate" in obj,
4258
+ get: (obj) => obj.isSkillCandidate
4259
+ },
4260
+ metadata: _metadata
4261
+ }, null, _instanceExtraInitializers);
3052
4262
  if (_metadata) Object.defineProperty(this, Symbol.metadata, {
3053
4263
  enumerable: true,
3054
4264
  configurable: true,
@@ -3147,8 +4357,7 @@ let MemoryService = (() => {
3147
4357
  2. 每条规则说明:什么类型的记忆应该避免提取,以及为什么
3148
4358
  3. 规则要具体可操作,不要泛泛而谈
3149
4359
  4. 如果删除原因都很相似,合并为更精炼的规则`;
3150
- const messages = [{
3151
- role: "user",
4360
+ const messages = [createUserMessage({
3152
4361
  content: [{
3153
4362
  type: "text",
3154
4363
  text: `以下是近期被用户删除的记忆及其删除原因:
@@ -3156,8 +4365,12 @@ let MemoryService = (() => {
3156
4365
  ${deletionList}
3157
4366
 
3158
4367
  请总结成提取反馈规则。`
3159
- }]
3160
- }];
4368
+ }],
4369
+ source: {
4370
+ kind: "plugin",
4371
+ plugin: "dsh-daoing-memory"
4372
+ }
4373
+ })];
3161
4374
  let text = "";
3162
4375
  const options = {
3163
4376
  provider,
@@ -3341,6 +4554,105 @@ ${deletionList}
3341
4554
  this.core.humanDeleteConcern(request, "human");
3342
4555
  return { deleted: true };
3343
4556
  }
4557
+ /** Generate a skill draft from an experience using LLM. */
4558
+ async generateSkillDraft(agent, request) {
4559
+ const experience = this.core["store"].getActiveRevision(request.experienceId);
4560
+ if (experience === void 0) throw new Error(`memory: experience not found: ${request.experienceId}`);
4561
+ const content = await this.generateSkillContentWithLlm(agent, experience, request.form);
4562
+ if (content.length === 0) throw new Error("memory: LLM generated empty skill content");
4563
+ const draftDir = join(process.env.DSH_HOME ?? join(process.cwd(), ".dsh"), "dsh-daoing-memory", "skills");
4564
+ mkdirSync(draftDir, { recursive: true });
4565
+ const ext = request.form === "skill_md" ? ".md" : ".mjs";
4566
+ const draftPath = join(draftDir, `${randomUUID()}${ext}`);
4567
+ writeFileSync(draftPath, content, "utf8");
4568
+ return this.core.createSkillDraft(request.experienceId, request.form, content, draftPath, actorOf(agent));
4569
+ }
4570
+ /** Review (approve/reject) a skill artifact. */
4571
+ reviewSkill(agent, request) {
4572
+ return this.core.reviewSkill(request, actorOf(agent));
4573
+ }
4574
+ /** Publish an approved skill (copy to $DSH_HOME/skills/). */
4575
+ publishSkill(agent, request) {
4576
+ const artifact = this.core.getSkillArtifact(request.id);
4577
+ if (artifact === void 0) throw new Error(`memory: skill artifact not found: ${request.id}`);
4578
+ if (artifact.draftPath === void 0) throw new Error("memory: skill artifact has no draft path");
4579
+ const publishDir = join(process.env.DSH_HOME ?? join(process.cwd(), ".dsh"), "skills");
4580
+ mkdirSync(publishDir, { recursive: true });
4581
+ const ext = artifact.form === "skill_md" ? ".md" : ".mjs";
4582
+ const publishedPath = join(publishDir, `${artifact.id}${ext}`);
4583
+ writeFileSync(publishedPath, readFileSync(artifact.draftPath, "utf8"), "utf8");
4584
+ return this.core.publishSkill(request, publishedPath, actorOf(agent));
4585
+ }
4586
+ /** List skill artifacts. */
4587
+ listSkillArtifacts(agent, parentExperienceId, status) {
4588
+ const filter = {};
4589
+ if (parentExperienceId !== "") filter.parentExperienceId = parentExperienceId;
4590
+ if (status !== "") filter.status = status;
4591
+ return this.core.listSkillArtifacts(filter);
4592
+ }
4593
+ /** Get a single skill artifact. */
4594
+ getSkillArtifact(agent, id) {
4595
+ return this.core.getSkillArtifact(id) ?? null;
4596
+ }
4597
+ /** Check if an experience is a skill conversion candidate. */
4598
+ isSkillCandidate(agent, experienceId) {
4599
+ return this.core.isSkillCandidate(experienceId);
4600
+ }
4601
+ /**
4602
+ * Generate skill content from an experience using LLM.
4603
+ */
4604
+ async generateSkillContentWithLlm(agent, experience, form) {
4605
+ const header = agent.session.requestHeader()?.config;
4606
+ if (header === void 0) return "";
4607
+ const provider = header.provider;
4608
+ const model = header.model;
4609
+ if (provider === void 0 || model === void 0) return "";
4610
+ const isScript = form === "script_mjs";
4611
+ const systemPrompt = isScript ? `你是一个技能脚本生成器。根据给定的经验(gist、路径步骤、判断背景、限制条件),生成一个可直接执行的 Node.js (.mjs) 脚本。
4612
+
4613
+ 要求:
4614
+ 1. 脚本必须自包含,不依赖外部包(只用 Node.js 内置模块)
4615
+ 2. 脚本顶部用注释说明用途和使用方法
4616
+ 3. 脚本要有错误处理
4617
+ 4. 脚本要跨平台兼容(Windows/macOS/Linux)
4618
+ 5. 只输出脚本代码,不要其他解释` : `你是一个 DSH skill 文档生成器。根据给定的经验(gist、路径步骤、判断背景、限制条件),生成一个 DSH skill 格式的 Markdown 文档。
4619
+
4620
+ 要求:
4621
+ 1. 使用 DSH skill 标准格式(标题、描述、触发条件、步骤)
4622
+ 2. 步骤要具体可操作
4623
+ 3. 包含适用场景和不适用场景
4624
+ 4. 只输出 Markdown 内容,不要其他解释`;
4625
+ const messages = [createUserMessage({
4626
+ content: [{
4627
+ type: "text",
4628
+ text: `经验摘要:${experience.gist}
4629
+
4630
+ 路径步骤:
4631
+ ${experience.path.map((s, i) => `${i + 1}. ${s.action}`).join("\n")}
4632
+
4633
+ 判断背景:${experience.reasoning}
4634
+
4635
+ 限制条件:
4636
+ ${experience.limits.map((l) => `- ${l}`).join("\n")}
4637
+
4638
+ 请生成${isScript ? "可执行脚本" : "skill 文档"}。`
4639
+ }],
4640
+ source: {
4641
+ kind: "plugin",
4642
+ plugin: "dsh-daoing-memory"
4643
+ }
4644
+ })];
4645
+ let text = "";
4646
+ for await (const chunk of this.ctx.llm.stream({
4647
+ provider,
4648
+ model,
4649
+ messages,
4650
+ system: systemPrompt,
4651
+ maxTokens: 4e3,
4652
+ sessionId: agent.session.id
4653
+ })) if (chunk.type === "text-delta") text += chunk.text;
4654
+ return text.trim();
4655
+ }
3344
4656
  };
3345
4657
  })();
3346
4658
  //#endregion