@lmzhen/dsh-evolution-core 0.1.0-rc.55 → 0.1.0-rc.57
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 +14 -7
- package/lib/types/skill-store.d.ts +1 -1
- package/lib/types/usage.d.ts +2 -0
- package/package.json +5 -5
package/lib/index.js
CHANGED
|
@@ -197,7 +197,11 @@ function emptyRecord() {
|
|
|
197
197
|
archived_at: null
|
|
198
198
|
};
|
|
199
199
|
}
|
|
200
|
-
|
|
200
|
+
/** A timestamp passes only when `Date.parse` yields a finite epoch (N-3): a bare
|
|
201
|
+
* string check let garbage like "not-a-date" propagate as Invalid Date → NaN
|
|
202
|
+
* into quality math and lifecycle comparisons. */
|
|
203
|
+
const validTimestamp = (value) => typeof value === "string" && Number.isFinite(Date.parse(value));
|
|
204
|
+
const nullableTimestamp = (value) => value === null || validTimestamp(value);
|
|
201
205
|
/**
|
|
202
206
|
* Field-level normalization for one sidecar record (rc.42 audit P2-3): the
|
|
203
207
|
* spread used to copy any junk through verbatim, so a corrupted file could
|
|
@@ -205,6 +209,8 @@ const isTimestamp = (value) => value === null || typeof value === "string";
|
|
|
205
209
|
* NaN. Every field falls back to its `emptyRecord()` baseline unless it has
|
|
206
210
|
* exactly the declared type; an invalid `created_at` anchors the age clock at
|
|
207
211
|
* now (first-sight defer semantics for a record whose age is unknowable).
|
|
212
|
+
* Timestamps additionally require a parseable date (N-3): `"not-a-date"`
|
|
213
|
+
* would otherwise survive the type check as Invalid Date.
|
|
208
214
|
* Pure — exported for unit tests; `loadUsage` is the production caller.
|
|
209
215
|
*/
|
|
210
216
|
function normalizeUsageRecord(record) {
|
|
@@ -218,13 +224,13 @@ function normalizeUsageRecord(record) {
|
|
|
218
224
|
use_count: num(raw.use_count, base.use_count),
|
|
219
225
|
view_count: num(raw.view_count, base.view_count),
|
|
220
226
|
patch_count: num(raw.patch_count, base.patch_count),
|
|
221
|
-
last_used_at:
|
|
222
|
-
last_viewed_at:
|
|
223
|
-
last_patched_at:
|
|
224
|
-
created_at:
|
|
227
|
+
last_used_at: nullableTimestamp(raw.last_used_at) ? raw.last_used_at : base.last_used_at,
|
|
228
|
+
last_viewed_at: nullableTimestamp(raw.last_viewed_at) ? raw.last_viewed_at : base.last_viewed_at,
|
|
229
|
+
last_patched_at: nullableTimestamp(raw.last_patched_at) ? raw.last_patched_at : base.last_patched_at,
|
|
230
|
+
created_at: validTimestamp(raw.created_at) ? raw.created_at : base.created_at,
|
|
225
231
|
state: raw.state === "stale" || raw.state === "archived" ? raw.state : "active",
|
|
226
232
|
pinned: bool(raw.pinned, base.pinned),
|
|
227
|
-
archived_at:
|
|
233
|
+
archived_at: nullableTimestamp(raw.archived_at) ? raw.archived_at : base.archived_at,
|
|
228
234
|
quality_score: typeof raw.quality_score === "number" && Number.isFinite(raw.quality_score) ? raw.quality_score : void 0,
|
|
229
235
|
quality_warn: typeof raw.quality_warn === "boolean" ? raw.quality_warn : void 0
|
|
230
236
|
};
|
|
@@ -2308,6 +2314,7 @@ var SkillLibrary = class {
|
|
|
2308
2314
|
if (await this.io.exists(dest)) {
|
|
2309
2315
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[-:T]/g, "").slice(0, 14);
|
|
2310
2316
|
dest = join(archiveRoot, `${name.trim()}-${stamp}`);
|
|
2317
|
+
while (await this.io.exists(dest)) dest = join(archiveRoot, `${name.trim()}-${stamp}-${Math.random().toString(36).slice(2, 8)}`);
|
|
2311
2318
|
}
|
|
2312
2319
|
if (this.io.isSymlink) {
|
|
2313
2320
|
if (await this.io.isSymlink(dir) === true) return {
|
|
@@ -2623,7 +2630,7 @@ var SkillLibrary = class {
|
|
|
2623
2630
|
return null;
|
|
2624
2631
|
}
|
|
2625
2632
|
}
|
|
2626
|
-
/** Keep only the newest N snapshots (Hermes keep=5 parity);
|
|
2633
|
+
/** Keep only the newest N snapshots (Hermes keep=5 parity); older ones are removed outright. */
|
|
2627
2634
|
async retainSnapshots(keep) {
|
|
2628
2635
|
const snapshots = await this.listSnapshots();
|
|
2629
2636
|
for (const snapshot of snapshots.slice(keep)) try {
|
|
@@ -167,7 +167,7 @@ export declare class SkillLibrary {
|
|
|
167
167
|
snapshotAll(reason?: string, extras?: SnapshotExtra[]): Promise<string>;
|
|
168
168
|
/** Read and normalize a snapshot manifest; null when the file is missing or unparsable. */
|
|
169
169
|
readSnapshotManifest(path: string): Promise<SnapshotManifest | null>;
|
|
170
|
-
/** Keep only the newest N snapshots (Hermes keep=5 parity);
|
|
170
|
+
/** Keep only the newest N snapshots (Hermes keep=5 parity); older ones are removed outright. */
|
|
171
171
|
private retainSnapshots;
|
|
172
172
|
listSnapshots(): Promise<Array<{
|
|
173
173
|
path: string;
|
package/lib/types/usage.d.ts
CHANGED
|
@@ -29,6 +29,8 @@ export declare function emptyRecord(): UsageRecord;
|
|
|
29
29
|
* NaN. Every field falls back to its `emptyRecord()` baseline unless it has
|
|
30
30
|
* exactly the declared type; an invalid `created_at` anchors the age clock at
|
|
31
31
|
* now (first-sight defer semantics for a record whose age is unknowable).
|
|
32
|
+
* Timestamps additionally require a parseable date (N-3): `"not-a-date"`
|
|
33
|
+
* would otherwise survive the type check as Invalid Date.
|
|
32
34
|
* Pure — exported for unit tests; `loadUsage` is the production caller.
|
|
33
35
|
*/
|
|
34
36
|
export declare function normalizeUsageRecord(record: unknown): UsageRecord;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lmzhen/dsh-evolution-core",
|
|
3
3
|
"description": "Shared stores, prompts, signals and lifecycle logic for the dsh-evolution plugin family (community build)",
|
|
4
|
-
"version": "0.1.0-rc.
|
|
4
|
+
"version": "0.1.0-rc.57",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -32,13 +32,13 @@
|
|
|
32
32
|
],
|
|
33
33
|
"license": "MIT",
|
|
34
34
|
"peerDependencies": {
|
|
35
|
-
"@deepseek-ai/dsh-invariants": "^0.1.
|
|
35
|
+
"@deepseek-ai/dsh-invariants": "^0.1.1-rc.2",
|
|
36
36
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
37
|
-
"@deepseek-ai/dsh-session": "^0.1.
|
|
37
|
+
"@deepseek-ai/dsh-session": "^0.1.1-rc.2"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
|
-
"@deepseek-ai/dsh-invariants": "^0.1.
|
|
40
|
+
"@deepseek-ai/dsh-invariants": "^0.1.1-rc.2",
|
|
41
41
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
42
|
-
"@deepseek-ai/dsh-session": "^0.1.
|
|
42
|
+
"@deepseek-ai/dsh-session": "^0.1.1-rc.2"
|
|
43
43
|
}
|
|
44
44
|
}
|