@lmzhen/dsh-evolution-skill-history 0.13.0 → 0.13.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/lib/client.js +44 -26
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -35,11 +35,11 @@ The row is **inert without a web server** (`ctx.get('webServer')`, not a declare
|
|
|
35
35
|
|
|
36
36
|
**The left column** lists the skills that recorded versions, one row per skill: its name, how many versions it has, its own one-line description (the listing already carried it) and the management state the marker probe reported. A **search box** filters that list by name or description — client state only, no route behind it.
|
|
37
37
|
|
|
38
|
-
**The right pane** shows the selected skill's versions as two groups: **Body versions** (restorable) and **File versions** (history only, because a restore rewrites `SKILL.md`). A body row reads like a sentence rather than a dump — `v3 targeted edit 2026-09-27 18:20 · 3 hours ago (+1363 chars)` — with a *current* capsule on the live content, **Restore this version** (an inline two-click confirmation) on the others, and **Diff** expanding that version against its predecessor (lines added and removed, plus the changed region, marked truncated when it is long). After a restore the rows are read again — the restore itself is a new version — while the curator's result sentence stays on screen. **Refresh** re-reads the skill list and the open skill.
|
|
38
|
+
**The right pane** shows the selected skill's versions as two groups: **Body versions** (restorable) and **File versions** (history only, because a restore rewrites `SKILL.md`). A body row reads like a sentence rather than a dump — `v3 targeted edit 2026-09-27 18:20 · 3 hours ago (+1363 chars)` — with a *current* capsule on the live content, **Restore this version** (an inline two-click confirmation, with a **Cancel** beside it once it is armed) on the others, and **Diff** expanding that version against its predecessor (lines added and removed, plus the changed region, marked truncated when it is long). After a restore the rows are read again — the restore itself is a new version — while the curator's result sentence stays on screen. **Refresh** re-reads the skill list and the open skill.
|
|
39
39
|
|
|
40
40
|
**The panel owns no rule and no arithmetic.** The host reports every row with its whole verdict — `undoable` (evolution-core's artifact classification against the live bytes), `actionKind` (a closed vocabulary key), `age` (a bucket plus a count), `charsDelta`, `summary` — and this half substitutes words from its locale dictionary and renders. The time, the action words and the sentences are therefore localized; the facts are computed once, host-side, so the panel and the slash commands cannot drift.
|
|
41
41
|
|
|
42
|
-
**Appearance follows the platform's tokens, not its modules.** The panel carries its own stylesheet (`src/client/styles.ts`, injected once behind `data-plugin-css`) and copies its metrics from the platform's own components — the command card's `<pre>` for the diff block, the sidebar row's hover and focus ring for the controls — while every size is a `--dsh-content-font-size*` token or a `calc()` over one, so the panel follows the deployment's content size the way the platform's panels do. Importing the platform's control package is NOT possible from here without splitting this package's compiler faces: the specifier is path-mapped to source, and `tsc -b` then refuses the foreign project (host/client face split, `react` devDependencies and a CI graph change would all be needed). The roll call of what the panel deliberately does not do is in `## Known limitations and deferred work`.
|
|
42
|
+
**Appearance follows the platform's tokens, not its modules.** The panel carries its own stylesheet (`src/client/styles.ts`, injected once behind `data-plugin-css`) and copies its metrics from the platform's own components — the command card's `<pre>` for the diff block, the sidebar row's hover and focus ring for the controls, and the theme's semantic state pair (`--dsw-alias-state-success-primary` / `--dsw-alias-state-error-primary`) for the diff's added and removed lines — while every size is a `--dsh-content-font-size*` token or a `calc()` over one, so the panel follows the deployment's content size the way the platform's panels do. Importing the platform's control package is NOT possible from here without splitting this package's compiler faces: the specifier is path-mapped to source, and `tsc -b` then refuses the foreign project (host/client face split, `react` devDependencies and a CI graph change would all be needed). The roll call of what the panel deliberately does not do is in `## Known limitations and deferred work`.
|
|
43
43
|
|
|
44
44
|
## Build
|
|
45
45
|
|
package/lib/client.js
CHANGED
|
@@ -68,8 +68,7 @@ window.__ModuleLoader__.load({
|
|
|
68
68
|
const zh = {
|
|
69
69
|
"entry.label": "技能历史",
|
|
70
70
|
title: "技能历史",
|
|
71
|
-
hint: "每次技能写入留下的内容版本。回退只改 SKILL.md
|
|
72
|
-
"hint.current": "内容相同的版本会同时标「当前」。",
|
|
71
|
+
hint: "每次技能写入留下的内容版本。回退只改 SKILL.md 正文,标记、使用计数与策展状态不变。内容相同的版本会同时标「当前」。",
|
|
73
72
|
search: "按名字或描述筛选",
|
|
74
73
|
"search.none": "没有匹配的技能。",
|
|
75
74
|
"group.content": "正文版本",
|
|
@@ -130,8 +129,7 @@ window.__ModuleLoader__.load({
|
|
|
130
129
|
const en = {
|
|
131
130
|
"entry.label": "Skill history",
|
|
132
131
|
title: "Skill history",
|
|
133
|
-
hint: "The content versions every skill write leaves behind. Restoring changes the SKILL.md body only: markers, usage counts and curation state stay as they are.",
|
|
134
|
-
"hint.current": "Versions holding the same content are all marked “current”.",
|
|
132
|
+
hint: "The content versions every skill write leaves behind. Restoring changes the SKILL.md body only: markers, usage counts and curation state stay as they are. Versions holding the same content are all marked “current”.",
|
|
135
133
|
search: "Filter by name or description",
|
|
136
134
|
"search.none": "No skill matches.",
|
|
137
135
|
"group.content": "Body versions",
|
|
@@ -242,7 +240,7 @@ window.__ModuleLoader__.load({
|
|
|
242
240
|
".evo-hist-skill-line{display:flex;align-items:baseline;gap:6px}",
|
|
243
241
|
".evo-hist-skill-name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}",
|
|
244
242
|
".evo-hist-skill-count{flex:none;margin-left:auto;color:var(--dsw-alias-label-tertiary)}",
|
|
245
|
-
".evo-hist-skill-desc{margin-top:2px;color:var(--dsw-alias-label-tertiary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}",
|
|
243
|
+
".evo-hist-skill-desc{display:block;margin-top:2px;color:var(--dsw-alias-label-tertiary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}",
|
|
246
244
|
".evo-hist-main{flex:1 1 auto;min-width:0;min-height:0;overflow-y:auto;padding:12px 14px}",
|
|
247
245
|
".evo-hist-head{display:flex;align-items:center;gap:10px;margin:0 0 4px}",
|
|
248
246
|
".evo-hist-title{flex:1 1 auto;margin:0;font-size:inherit;font-weight:600}",
|
|
@@ -262,7 +260,7 @@ window.__ModuleLoader__.load({
|
|
|
262
260
|
".evo-hist-button:focus-visible{outline:2px solid var(--dsw-alias-label-primary);outline-offset:-2px}",
|
|
263
261
|
".evo-hist-button[data-tone=\"primary\"]{border-color:var(--dsw-alias-brand-primary);color:var(--dsw-alias-brand-primary)}",
|
|
264
262
|
".evo-hist-pre{margin:6px 0 2px;padding:12px 16px;max-height:260px;overflow:auto;border:.5px solid var(--dsw-alias-border-l1);border-radius:12px;background:var(--dsw-alias-markdown-code-block);color:var(--dsw-alias-label-primary);font:var(--dsw-font-markdown-code-block-small);white-space:pre-wrap}",
|
|
265
|
-
".evo-hist-pre-add{color:var(--dsw-alias-
|
|
263
|
+
".evo-hist-pre-add{color:var(--dsw-alias-state-success-primary)}",
|
|
266
264
|
".evo-hist-pre-del{color:var(--dsw-alias-state-error-primary)}"
|
|
267
265
|
].join("\n");
|
|
268
266
|
//#endregion
|
|
@@ -333,7 +331,7 @@ window.__ModuleLoader__.load({
|
|
|
333
331
|
return (0, react.createElement)("pre", { className: "evo-hist-pre" }, rows.length === 0 ? "±" : rows);
|
|
334
332
|
}
|
|
335
333
|
/** One version row: what happened, when, how big, and what it is against. */
|
|
336
|
-
function versionRow(face, row, confirming, openDiff, diff, restore, toggleDiff) {
|
|
334
|
+
function versionRow(face, row, confirming, openDiff, diff, restore, cancelRestore, toggleDiff) {
|
|
337
335
|
const parts = [
|
|
338
336
|
(0, react.createElement)("span", {
|
|
339
337
|
key: "v",
|
|
@@ -355,15 +353,25 @@ window.__ModuleLoader__.load({
|
|
|
355
353
|
key: "current",
|
|
356
354
|
className: "evo-hist-capsule"
|
|
357
355
|
}, face.t("current")));
|
|
358
|
-
if (row.undoable === true)
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
356
|
+
if (row.undoable === true) {
|
|
357
|
+
if (confirming === row.v) actions.push((0, react.createElement)("button", {
|
|
358
|
+
key: "cancel",
|
|
359
|
+
type: "button",
|
|
360
|
+
className: "evo-hist-button",
|
|
361
|
+
onClick: () => {
|
|
362
|
+
cancelRestore();
|
|
363
|
+
}
|
|
364
|
+
}, face.t("undo.no")));
|
|
365
|
+
actions.push((0, react.createElement)("button", {
|
|
366
|
+
key: "undo",
|
|
367
|
+
type: "button",
|
|
368
|
+
className: "evo-hist-button",
|
|
369
|
+
"data-tone": confirming === row.v ? "primary" : void 0,
|
|
370
|
+
onClick: () => {
|
|
371
|
+
restore(row.v);
|
|
372
|
+
}
|
|
373
|
+
}, confirming === row.v ? face.t("undo.confirm") : face.t("undo")));
|
|
374
|
+
}
|
|
367
375
|
if (row.undoable === true || row.charsDelta !== void 0) actions.push((0, react.createElement)("button", {
|
|
368
376
|
key: "diff",
|
|
369
377
|
type: "button",
|
|
@@ -389,7 +397,7 @@ window.__ModuleLoader__.load({
|
|
|
389
397
|
/** One group: a heading, an optional note, and its rows. */
|
|
390
398
|
function group(face, title, entries, noteText, state) {
|
|
391
399
|
if (entries.length === 0) return null;
|
|
392
|
-
return (0, react.createElement)("section", { key: title }, (0, react.createElement)("h3", { className: "evo-hist-group" }, title), noteText === void 0 ? null : (0, react.createElement)("p", { className: "evo-hist-hint" }, noteText), ...entries.map((entry) => versionRow(face, entry, state.confirming, state.openDiff, state.diffs.get(entry.v), state.restore, state.toggleDiff)));
|
|
400
|
+
return (0, react.createElement)("section", { key: title }, (0, react.createElement)("h3", { className: "evo-hist-group" }, title), noteText === void 0 ? null : (0, react.createElement)("p", { className: "evo-hist-hint" }, noteText), ...entries.map((entry) => versionRow(face, entry, state.confirming, state.openDiff, state.diffs.get(entry.v), state.restore, state.cancelRestore, state.toggleDiff)));
|
|
393
401
|
}
|
|
394
402
|
/**
|
|
395
403
|
* The panel body.
|
|
@@ -499,11 +507,16 @@ window.__ModuleLoader__.load({
|
|
|
499
507
|
const needle = query.trim().toLowerCase();
|
|
500
508
|
const visible = (0, react.useMemo)(() => needle === "" ? skills : skills.filter((skill) => skill.name.toLowerCase().includes(needle) || skill.description.toLowerCase().includes(needle)), [skills, needle]);
|
|
501
509
|
const loaded = payload !== void 0;
|
|
510
|
+
/** Drop the pending confirmation: the button that opened it must not be the only way out. */
|
|
511
|
+
const cancelRestore = () => {
|
|
512
|
+
setPending(void 0);
|
|
513
|
+
};
|
|
502
514
|
const rowState = {
|
|
503
515
|
confirming: pending,
|
|
504
516
|
openDiff,
|
|
505
517
|
diffs,
|
|
506
518
|
restore,
|
|
519
|
+
cancelRestore,
|
|
507
520
|
toggleDiff
|
|
508
521
|
};
|
|
509
522
|
return (0, react.createElement)("div", { className: "evo-hist-root" }, (0, react.createElement)("aside", { className: "evo-hist-aside" }, (0, react.createElement)("div", { className: "evo-hist-search" }, (0, react.createElement)("input", {
|
|
@@ -526,7 +539,7 @@ window.__ModuleLoader__.load({
|
|
|
526
539
|
type: "button",
|
|
527
540
|
className: "evo-hist-button",
|
|
528
541
|
onClick: refresh
|
|
529
|
-
}, face.t("refresh"))), (0, react.createElement)("p", { className: "evo-hist-hint" }, face.t("hint")
|
|
542
|
+
}, face.t("refresh"))), (0, react.createElement)("p", { className: "evo-hist-hint" }, face.t("hint")), noteText === void 0 ? null : (0, react.createElement)("p", {
|
|
530
543
|
className: "evo-hist-note",
|
|
531
544
|
"data-error": noteError ? "true" : void 0
|
|
532
545
|
}, noteText), selected === void 0 ? null : loaded ? null : (0, react.createElement)("p", { className: "evo-hist-hint" }, face.t("loading")), loaded ? (0, react.createElement)("div", null, group(face, face.t("group.content"), payload.content, void 0, rowState), group(face, face.t("group.support"), payload.support, face.t("group.support.note"), rowState), payload.content.length === 0 && payload.support.length === 0 ? (0, react.createElement)("p", { className: "evo-hist-hint" }, face.t("empty.versions")) : null) : null));
|
|
@@ -551,18 +564,23 @@ window.__ModuleLoader__.load({
|
|
|
551
564
|
/** Row order inside the global panel list (beside the platform's own rows). */
|
|
552
565
|
const PANEL_ORDER = 35;
|
|
553
566
|
/**
|
|
554
|
-
* The row's icon: a platform-style line glyph
|
|
567
|
+
* The row's icon: a platform-style line glyph, sized by the SIDEBAR's own contract.
|
|
555
568
|
*
|
|
556
|
-
*
|
|
557
|
-
*
|
|
558
|
-
*
|
|
559
|
-
*
|
|
569
|
+
* The platform hands every `sidebar.panellist` occupant `{ size, active }` (`SidebarRoot.tsx`
|
|
570
|
+
* `renderSlot('sidebar.panellist', { size: wide ? 16 : 18, active }, …)`) and its own icons render at
|
|
571
|
+
* that size (`IconGlobeOutline14 size={size}` in the sidebar's own spec). The neighbouring rows in a
|
|
572
|
+
* shipped GUI take the OTHER route — they inject their entry into the sidebar's DOM with their own
|
|
573
|
+
* `svg { width: 18px; height: 18px }` CSS — so 18px is the size a row glyph is expected to occupy.
|
|
574
|
+
* A glyph that sizes itself from CSS (`width: 100%`) resolves against an unsized flex box and fills
|
|
575
|
+
* the column: the size must come from the prop, with the neighbours' 18 as the fallback. The label
|
|
576
|
+
* carries the accessible name, so the glyph stays decoration.
|
|
560
577
|
*/
|
|
561
|
-
function PanelIcon() {
|
|
578
|
+
function PanelIcon(props = {}) {
|
|
579
|
+
const size = typeof props.size === "number" && props.size > 0 ? props.size : 18;
|
|
562
580
|
return (0, react.createElement)("svg", {
|
|
563
581
|
"aria-hidden": "true",
|
|
564
|
-
width:
|
|
565
|
-
height:
|
|
582
|
+
width: String(size),
|
|
583
|
+
height: String(size),
|
|
566
584
|
viewBox: "0 0 16 16",
|
|
567
585
|
fill: "none",
|
|
568
586
|
stroke: "currentColor",
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lmzhen/dsh-evolution-skill-history",
|
|
3
3
|
"description": "Web surface for skill content history: loopback host routes plus the sidebar panel (community build)",
|
|
4
|
-
"version": "0.13.
|
|
4
|
+
"version": "0.13.2",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -30,21 +30,21 @@
|
|
|
30
30
|
],
|
|
31
31
|
"license": "MIT",
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@lmzhen/dsh-evolution-core": "^0.13.
|
|
33
|
+
"@lmzhen/dsh-evolution-core": "^0.13.2"
|
|
34
34
|
},
|
|
35
35
|
"peerDependencies": {
|
|
36
36
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
37
37
|
"@deepseek-ai/dsh-host-webserver": "^0.1.5-rc.2",
|
|
38
38
|
"react": "^18.2.0",
|
|
39
|
-
"@lmzhen/dsh-evolution-curator": "^0.13.
|
|
39
|
+
"@lmzhen/dsh-evolution-curator": "^0.13.2"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
43
43
|
"@deepseek-ai/dsh-host-webserver": "^0.1.5-rc.2",
|
|
44
|
-
"@lmzhen/dsh-evolution-core": "^0.13.
|
|
45
|
-
"@lmzhen/dsh-evolution-curator": "^0.13.
|
|
46
|
-
"@lmzhen/dsh-evolution-io": "^0.13.
|
|
47
|
-
"@lmzhen/dsh-evolution-io-node": "^0.13.
|
|
44
|
+
"@lmzhen/dsh-evolution-core": "^0.13.2",
|
|
45
|
+
"@lmzhen/dsh-evolution-curator": "^0.13.2",
|
|
46
|
+
"@lmzhen/dsh-evolution-io": "^0.13.2",
|
|
47
|
+
"@lmzhen/dsh-evolution-io-node": "^0.13.2"
|
|
48
48
|
},
|
|
49
49
|
"dsh": {
|
|
50
50
|
"client": {
|