@lmzhen/dsh-evolution-skill-history 0.13.1 → 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.
Files changed (3) hide show
  1. package/README.md +2 -2
  2. package/lib/client.js +31 -18
  3. 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-brand-primary)}",
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) actions.push((0, react.createElement)("button", {
359
- key: "undo",
360
- type: "button",
361
- className: "evo-hist-button",
362
- "data-tone": confirming === row.v ? "primary" : void 0,
363
- onClick: () => {
364
- restore(row.v);
365
- }
366
- }, confirming === row.v ? face.t("undo.confirm") : face.t("undo")));
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") + " " + face.t("hint.current")), noteText === void 0 ? null : (0, react.createElement)("p", {
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));
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.1",
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.1"
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.1"
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.1",
45
- "@lmzhen/dsh-evolution-curator": "^0.13.1",
46
- "@lmzhen/dsh-evolution-io": "^0.13.1",
47
- "@lmzhen/dsh-evolution-io-node": "^0.13.1"
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": {