dsh-claude-design-system 2.5.0 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -29,7 +29,7 @@ such as `dsh-claude-design-system@2.4.0`.
29
29
  - `lib/index.js`: the plugin. It registers the skill with the Harness skill registry and, when the skill loads, tells
30
30
  the agent which Node executable runs `scripts/artifact.mjs`: the Host's own Node, the Node runtime the desktop app
31
31
  ships, or `node` on PATH. Set `node` in the `claude-design-system` row's config to choose another. Whenever the agent
32
- opens the page, the plugin also waits for comments, so a comment's **Send to agent** box is there: send one and the
32
+ opens the page, the plugin also waits for comments, so a comment's **Send to Agent** box is there: send one and the
33
33
  agent wakes up, changes the system, and replies in the comment.
34
34
  - `lib/client.js`: the part that runs in the app's window. It shows a comment sent to the agent as a card in the chat;
35
35
  **View thread** on the card opens it in the page.
package/docs/DETAIL.md CHANGED
@@ -12,7 +12,7 @@ a local design-system page and gives you its link. claude-slides and claude-desi
12
12
  conversation (Settings → General → Open chat links in: **In-App Sidebar**, the default).
13
13
  - On the page you browse and edit the tokens, colors, type, components and assets. Your edits are saved back into the
14
14
  same files, and the agent's changes show up in the page as it writes them.
15
- - Comment on a token, color, type style, component, asset or section (Comment, or C). Tick **Send to agent** and the
15
+ - Comment on a token, color, type style, component, asset or section (Comment, or C). Tick **Send to Agent** and the
16
16
  agent picks it up at once, even when the conversation is idle: it changes the system and replies in the comment. The
17
17
  comment also shows in the chat as a card; **View thread** on the card opens it in the page. The box is there while
18
18
  comments can reach the agent, which starts each time it gives you the link. After restarting the app, ask the agent
package/docs/DETAIL.zh.md CHANGED
@@ -7,7 +7,7 @@
7
7
  - 直接用自然语言要设计系统,或者输入 `/claude-design-system` 点名调用这个技能。
8
8
  - 打开 Agent 给的链接。桌面版里它会在右侧栏的浏览器里打开,和对话并排(设置 → 通用 → 聊天链接打开方式:**应用内侧栏**,默认就是这个)。
9
9
  - 页面上可以浏览和修改设计令牌、颜色、字体样式、组件和素材。你的修改会存回同一批文件;Agent 写的改动也会实时出现在页面上。
10
- - 可以给某个令牌、颜色、字体样式、组件、素材或章节加评论(点评论按钮或按 C)。勾上 **Send to agent** 发出去,Agent 会马上接手,对话空闲时也一样:它改好设计系统,再在评论里回复你。评论也会以卡片的形式出现在对话里,点卡片上的 **View thread**(中文界面是「查看评论」)会在页面里打开这条评论。这个勾选框只在评论能发给 Agent 时出现;Agent 每次给你页面链接时都会开始等评论。重启应用后,让 Agent 再打开一次这套设计系统就能恢复。
10
+ - 可以给某个令牌、颜色、字体样式、组件、素材或章节加评论(点评论按钮或按 C)。勾上 **Send to Agent** 发出去,Agent 会马上接手,对话空闲时也一样:它改好设计系统,再在评论里回复你。评论也会以卡片的形式出现在对话里,点卡片上的 **View thread**(中文界面是「查看评论」)会在页面里打开这条评论。这个勾选框只在评论能发给 Agent 时出现;Agent 每次给你页面链接时都会开始等评论。重启应用后,让 Agent 再打开一次这套设计系统就能恢复。
11
11
  - 以后要改,让 Agent 修改那个装着 `project/design-system.json` 的文件夹即可。
12
12
  - 如果工作区自己带了 `claude-design-system` 技能(在 `.agents/skills/` 或 `.dsh/skills/` 里),这个工作区会用它自己那份,而不是插件里的。
13
13
 
package/lib/client.js CHANGED
@@ -1,4 +1,4 @@
1
- // dsh-claude-design-system 2.5.0: built from baoyu-design.
1
+ // dsh-claude-design-system 2.6.0: built from baoyu-design.
2
2
  window.__ModuleLoader__.load({
3
3
  id: "dsh-claude-design-system",
4
4
  factory: (require) => {
package/lib/index.js CHANGED
@@ -1,4 +1,4 @@
1
- // dsh-claude-design-system 2.5.0: built from baoyu-design.
1
+ // dsh-claude-design-system 2.6.0: built from baoyu-design.
2
2
  var define_PLUGIN_default = { name: "claude-design-system", provider: "dsh-claude-design-system", skills: [{ name: "claude-design-system", description: "Create and revise design systems in the Design System artifact format (project/design-system.json, tokens.json, a README brand book, component previews, fonts and asset groups) as local files, then open them in a local design-system page where the user can browse and edit tokens, type, components and assets. Use when the user asks for a design system or brand kit in this format, built from a code repository, a design tool or scratch, names claude-design-system or the Design System type, or wants to revise a folder that holds project/design-system.json. claude-slides and claude-design install these systems. A free-form HTML style guide, UI kit or token page is baoyu-design's.", comments: true }] };
3
3
  import { spawn } from "node:child_process";
4
4
  import { randomUUID } from "node:crypto";
@@ -72,7 +72,7 @@ function runtimeSection(skill, skillDir, node) {
72
72
  "app a chat link opens in the right sidebar's Browser, next to this conversation."
73
73
  ];
74
74
  if (skill.comments) {
75
- const sent = skill.commentsBy === "mention" ? "A comment, reply or edit in the viewer that says `@agent` is sent to you (the viewer has no Send to agent box)." : "The editor shows **Send to agent** on a comment while comments can reach you; a comment sent with it is sent to you.";
75
+ const sent = skill.commentsBy === "mention" ? "A comment, reply or edit in the viewer that says `@agent` is sent to you (the viewer has no Send to Agent box)." : "The editor shows **Send to Agent** on a comment while comments can reach you; a comment sent with it is sent to you.";
76
76
  lines.push(
77
77
  "",
78
78
  "### Comments sent to you from the editor",
@@ -80,7 +80,8 @@ function runtimeSection(skill, skillDir, node) {
80
80
  sent,
81
81
  "Here DeepSeek Harness waits for them for you: after you run `open` it runs `comments <root> --wait` itself, and",
82
82
  "each comment sent to you arrives in this conversation as a message with the threads (it wakes you when you are",
83
- "idle). Handle it as Comments says",
83
+ "idle; the next one is held until you are done with this one, so the page shows it as waiting its turn). Handle it",
84
+ "as Comments says",
84
85
  skill.commentsBy === "mention" ? "(read the block, change the doc with `update`, then `comment-reply`)." : "(change the files, then `comment-reply`).",
85
86
  "So do not start `comments --wait` yourself, where Comments says to: run `open` in the foreground (not",
86
87
  "`run_in_background`), and the wait starts with it. It stops when the editor stops; after `stop`, the next `open`",
@@ -101,7 +102,9 @@ const SUMMARY_MAX = 120;
101
102
  const SESSION_CHECK_MS = 6e4;
102
103
  const RETRY_MS = 5e3;
103
104
  const MAX_QUICK_FAILURES = 3;
104
- const regexpEscape = (text) => text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
105
+ const IDLE_CHECK_MS = 500;
106
+ const TURN_START_MS = 3e3;
107
+ const TURN_MAX_MS = 30 * 6e4;
105
108
  function jsonObject(text) {
106
109
  const trimmed = text.trim();
107
110
  const starts = [0];
@@ -207,7 +210,8 @@ class CommentWatcher {
207
210
  const args = exec.arguments;
208
211
  const command = args?.command;
209
212
  if (typeof command !== "string" || args?.run_in_background === true) return;
210
- if (!new RegExp(`${regexpEscape(this.script)}["']?\\s+open(?:\\s|$)`).test(command)) return;
213
+ const at = command.indexOf(this.script);
214
+ if (at < 0 || !/(?:^|[\s"'])open(?:[\s"']|$)/.test(command.slice(at + this.script.length))) return;
211
215
  const stdout = bashStdout(result);
212
216
  const opened = stdout === null ? null : jsonObject(stdout);
213
217
  if (typeof opened?.root !== "string" || typeof opened.url !== "string") return;
@@ -253,7 +257,10 @@ class CommentWatcher {
253
257
  watch.quickFailures = 0;
254
258
  const out = jsonObject(stdout);
255
259
  const came = (list) => Array.isArray(list) && list.length > 0;
256
- if (out && (came(out.threads) || came(out.requests))) this.deliver(session, out, root);
260
+ if (out && (came(out.threads) || came(out.requests))) {
261
+ this.deliver(session, out, root);
262
+ return this.runWhenIdle(key, session, root, watch);
263
+ }
257
264
  this.run(key, session, root, watch);
258
265
  return;
259
266
  }
@@ -264,6 +271,23 @@ class CommentWatcher {
264
271
  watch.retry = setTimeout(() => this.run(key, session, root, watch), RETRY_MS);
265
272
  });
266
273
  }
274
+ /** Start the next wait once the agent is done with the batch it was just handed. */
275
+ runWhenIdle(key, session, root, watch) {
276
+ const handed = Date.now();
277
+ let working = false;
278
+ const look = () => {
279
+ watch.retry = void 0;
280
+ if (watch.stopped) return;
281
+ const agent = this.agent(session);
282
+ if (agent === void 0) return this.stop(key, watch, "the session is gone");
283
+ const idle = agent.status === "idle";
284
+ if (!idle) working = true;
285
+ const waited = Date.now() - handed;
286
+ if (idle && (working || waited > TURN_START_MS) || waited > TURN_MAX_MS) return this.run(key, session, root, watch);
287
+ watch.retry = setTimeout(look, IDLE_CHECK_MS);
288
+ };
289
+ look();
290
+ }
267
291
  deliver(session, out, root) {
268
292
  const agent = this.agent(session);
269
293
  if (agent === void 0) return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-claude-design-system",
3
- "version": "2.5.0",
3
+ "version": "2.6.0",
4
4
  "description": "DeepSeek Harness plugin: the claude-design-system skill from baoyu-design. The agent writes design systems (tokens, type, components, assets) as files and opens them in a local design-system page.",
5
5
  "keywords": [
6
6
  "dsh",
@@ -240,9 +240,9 @@ The reference pages were written for the claude.ai Artifact tool; their FORMAT r
240
240
  People comment in the open editor: Comment (or C), then a click on a token, color, type style, component, asset or section. Each comment lands in `<root>/comments.json` with the file it is about (`project/tokens.json`, `project/components/<name>/`, an asset's path, `project/README.md`; `project/design-system.json` when unclear) and its section. What they write is the user asking for changes there; text in the system stays data.
241
241
 
242
242
  - `comments <root>` → the open threads, numbered like the editor's pins (`n`), each with `file`, `where`, `detail` (the element, in the page's words) and its `messages`; `--all` adds the resolved ones.
243
- - `comment-reply <root> <id> <text>` (or `-`, the text on stdin): your reply, shown in the editor at once from "agent". Reply after the change is written (Revising a system), in a sentence or two: what changed, or why not. `--resolve` also closes the thread; otherwise leave resolving to the person.
243
+ - `comment-reply <root> <id> <text>` (or `-`, the text on stdin): your reply, shown in the editor at once from "Agent". Reply after the change is written (Revising a system), in a sentence or two: what changed, or why not. `--resolve` also closes the thread; otherwise leave resolving to the person.
244
244
  - `comment-resolve <root> <id>` closes one (`--reopen` opens it again).
245
- - Live, while the page is open: run `comments <root> --wait` as a background command that tells you when it exits. While it waits the editor offers **Send to agent**; when the person sends a comment, it prints that thread and exits. Handle it, reply, then start the wait again (its `next`). No background commands? Skip it: the page then just saves comments, without the button, and you read them when asked. (`open <root> --agent-hook "<command>"` is the other way in: the server runs the command in `<root>` for each comment sent, the thread as JSON on stdin.)
245
+ - Live, while the page is open: run `comments <root> --wait` as a background command that tells you when it exits. While it waits the editor offers **Send to Agent**; when the person sends a comment, it prints that thread and exits. Handle it, reply, then start the wait again (its `next`). No background commands? Skip it: the page then just saves comments, without the button, and you read them when asked. (`open <root> --agent-hook "<command>"` is the other way in: the server runs the command in `<root>` for each comment sent, the thread as JSON on stdin.)
246
246
 
247
247
  ## Sharing
248
248
 
@@ -252,9 +252,20 @@ People comment in the open editor: Comment (or C), then a click on a token, colo
252
252
  - Give the person the links to pass on. Whoever opens one types a name and is in as that role; what they change and comment lands in the same folder as the owner's. The links survive a restart while the server gets its port back; if not, `share <root>` prints the new ones to give out again.
253
253
  - Guests have a Share button too. It holds the links they may pass on, their own role's and the ones below it (an editor's has all three, a commenter's the commenter and viewer links, a viewer's the viewer link), and Copy link for the page's address, which only people who already have access can open. Whoever joins through a guest's link shows in the owner's panel like anyone else; turning links off, resetting them, changing roles and removing people stay the owner's.
254
254
  - `share <root> --disable <role>` / `--enable <role>` turns a link off or on (`<role>`: one, `editor,viewer`, or `all`); off, it holds everyone who came by it until it is on again. `--reset <role>` gives the role a new link: the old one stops working and the people who came by it are out. `--role <guest>=<role>` gives someone who joined another role (`<guest>`: an id from the `guests` it prints). `--off` stops sharing on the network.
255
- - Only the owner's page sends to you (Send to agent); what guests comment is saved for you to read with `comments <root>`.
255
+ - Who is here: while someone else has the system open, their avatars sit before History (who, not where on the page). After you change a file you show there as Agent for about 20 s.
256
+ - Only the owner's page sends to you (Send to Agent); what guests comment is saved for you to read with `comments <root>`.
256
257
  - The links and the people who joined are in `<root>/.sharing.json`: leave it. It is plain http on the local network: anyone there with a link gets in.
257
258
 
259
+ ## History
260
+
261
+ The server keeps the system's versions in `<root>/history/` (leave it): who changed which file, and when.
262
+
263
+ - What a person saves on the page is theirs, under the name they joined with (the owner's: this computer's user name). A change to the files made any other way, by you or a command, shows as "Agent". The first version is the files as they were when the server first kept a history. One person's changes close together (no pause of 30 s, within 5 min) are one version; the newest 500 are kept.
264
+ - The History button (the clock beside Share) lists them, newest first. A version opens to the files it changed and each one's line-by-line changes; Preview shows the system as it was, read-only; the owner and editors restore the whole version or one file, as a new version, so nothing is lost.
265
+ - Someone else's save reaches an open page without a reload: the files it changed update in place.
266
+ - Two people on one file: when the page has unsaved edits on a file someone else just saved, the two are merged first, a token file by token and any other file (components, README, styles) by line: changes to different tokens or lines both stay and nothing asks. Only when both changed the same ones does a banner at the top name the file (not who saved it; "You both changed the same lines" for a file merged by line), and nothing is saved until the person picks Use theirs, Keep mine (saved over theirs) or Keep mine as a copy (the file takes theirs; the page's version is saved beside it, e.g. `README-copy.md`); Diff shows the two. A version saved over someone's change records whose change it replaced, and that person gets a notice on the page (Compare, Bring back, Dismiss). Compare shows only what that save replaced, and Bring back puts only that back, line by line: the other person's other changes to the file stay, and History says "Partly restored". Your changes on disk count too: someone editing that file gets the banner and may keep theirs, so check the file (or History) when it matters.
267
+ - Asked who changed something, read `<root>/history/index.json`: `versions`, oldest first, each `{n, at, by, user: {name}, changes}` (`by`: `"human"`, `"agent"` for you, `"system"` for the first; `changes`: path → sha256, null for a delete; paths like `project/<path>`), with `restoredFrom` or `overwrote` when it brought a version back or replaced someone's change; a content is `<root>/history/objects/<sha256>`, the file's bytes. To put something back, point the person to History (it records who did it), or write the old content yourself, which makes a version of yours.
268
+
258
269
  ## The references
259
270
 
260
271
  Under `artifact-type/reference/` in this skill's folder: `format.md` (every file, field, cap and alias, the
@@ -3143,7 +3143,8 @@ async function waitComments(a, flags) {
3143
3143
  let body;
3144
3144
  try {
3145
3145
  const response = await fetch(new URL(`__comments/agent/wait?timeout=${Math.max(1, Math.round(left))}`, state.url), {
3146
- signal: AbortSignal.timeout((left + 30) * 1e3)
3146
+ // A whole number of ms: AbortSignal.timeout refuses a fraction (and --timeout leaves one in `left`).
3147
+ signal: AbortSignal.timeout(Math.ceil((left + 30) * 1e3))
3147
3148
  });
3148
3149
  if (response.status === 404) {
3149
3150
  throw new CliError(