dsh-claude-motion 2.12.0 → 2.12.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/lib/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// dsh-claude-motion 2.12.
|
|
1
|
+
// dsh-claude-motion 2.12.2: built from baoyu-design.
|
|
2
2
|
var define_PLUGIN_default = { name: "claude-motion", provider: "dsh-claude-motion", skills: [{ name: "claude-motion", description: "Use this for a local Motion film: a short animated video (10–30 s unless asked for more, 900 s at most), such as an explainer, product walkthrough or UI demo, launch teaser, logo sting, social clip, animated chart or title sequence, that plays in the bundled Motion player and exports from there to MP4 or GIF. A narrated one carries a voice track: a take a scene, made here with a speech provider of the user's or recorded by them, spoken and captioned by the player, the motion timed to its words. Everything on screen is code, a pure function of time, written scene by scene into the film's own store with this skill's script while the user watches it fill in. Read it when creating, continuing, finalizing or revising one. Not for editing real footage, subtitles or audio (that is a video editor), a still picture, a slide deck or a static HTML page.", scriptAlias: "A", comments: true, requests: true }] };
|
|
3
3
|
|
|
4
4
|
import { readFile } from "node:fs/promises";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-claude-motion",
|
|
3
|
-
"version": "2.12.
|
|
3
|
+
"version": "2.12.2",
|
|
4
4
|
"description": "DeepSeek Harness plugin: the claude-motion skill from baoyu-design. The agent writes short animated films as code, scene by scene, and plays them in a local Motion player that exports MP4 or GIF.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"dsh",
|
|
@@ -24,6 +24,18 @@
|
|
|
24
24
|
"icon": "./icon.svg",
|
|
25
25
|
"baoyuDesign": {
|
|
26
26
|
"releaseNotes": [
|
|
27
|
+
{
|
|
28
|
+
"version": "2.12.2",
|
|
29
|
+
"date": "2026-11-09",
|
|
30
|
+
"en": "### Features\n- **`claude-design`: Export → HTML for Figma.** Capturing the canvas, or the Standalone web page, with Figma's Chrome extension brought the artboards in as empty boxes, because each artboard is drawn inside a frame the extension does not look into. **HTML for Figma** (in the toolbar's Export, an artboard's Export and the Share panel's Export tab) saves `<title>.figma.html`: every artboard's rendered layers, placed where they are on the canvas, with their styles, fonts and images inside the file, and no frames and no scripts. Open it in Chrome and capture it with Figma's extension (**Capture page**, or **Select element** for one artboard). In an artboard's own Export it is that artboard alone. `SKILL.md` tells the agent how to answer when asked to bring a design into Figma (reported by @mufanmu, [#36](https://github.com/JimLiu/baoyu-design/issues/36)).\n\n### Fixes\n- **`claude-design`: PNG export no longer draws some icons as black or solid blocks.** An SVG icon drawn with `<use>` lost the `fill: none` and `stroke: currentColor` its class gave it, and came out filled in black; it now takes the colour of the `<use>`. An icon cut out with a CSS `mask-image` (on an element or on `::before` and `::after`) was drawn as a solid block because the mask's file was not in the exported image; masks are now embedded like background images (reported by @hh0592821, [#35](https://github.com/JimLiu/baoyu-design/issues/35)).\n- **`share` gives out the Wi-Fi's address first on a computer with a VPN, a proxy or a hotspot.** On Windows the links could start with the address of a proxy's virtual adapter (a sing-box TUN named `falemon-tun`, `172.19.0.1`), which nobody else on the network can reach. Addresses of adapters named like a tunnel (`falemon-tun`, OpenVPN's TAP, Wintun, anything with `vpn` in its name), of point-to-point links, and of networks this computer makes itself (the Mobile Hotspot's `192.168.137.1`, a virtual machine's or container's network) now come after the local network's. When a computer is on more than one network, `share` says that a link that does not open can be tried with another of the listed addresses (reported by @Bistard, [#37](https://github.com/JimLiu/baoyu-design/issues/37)).\n- **`open` no longer says the port is in use when a firewall or proxy filters `::1`.** A probe refused with `EACCES` or `EPERM` counted as an answer from something on the port, so `open` gave up on all 100 ports it tries.\n- A page whose skill folder was moved, renamed or removed while its server ran now says so, and names the folder to the owner, instead of telling them to reinstall the skill. A guest is told to ask whoever shared it.",
|
|
31
|
+
"zh": "### 新功能\n- **`claude-design`:新增 Export → HTML for Figma。** 以前用 Figma 的 Chrome 扩展捕捉画布,或捕捉导出的 Standalone web page,画板进到 Figma 里都是空框,因为每个画板都画在一个框架(iframe)里,扩展看不进去。现在工具栏的 Export、画板自己的 Export 和 Share 面板的 Export 标签里都有 **HTML for Figma**,保存成 `<标题>.figma.html`:每个画板渲染出来的图层,摆在它们在画布上的位置,样式、字体和图片都在文件里,没有框架,也没有脚本。用 Chrome 打开这个文件,再用 Figma 的扩展捕捉(**Capture page**,只要一个画板就用 **Select element**)。画板自己的 Export 里,导出的只是这一个画板。`SKILL.md` 也写了用户要把设计带进 Figma 时 Agent 该怎么答(@mufanmu 报告,[#36](https://github.com/JimLiu/baoyu-design/issues/36))。\n\n### 修复\n- **`claude-design`:PNG 导出不再把一部分图标画成黑色或实心块。** 用 `<use>` 画的 SVG 图标,会丢掉 class 给它的 `fill: none` 和 `stroke: currentColor`,导出来被涂成黑色,现在按 `<use>` 的颜色走。用 CSS `mask-image` 抠出来的图标(元素上的,或 `::before`、`::after` 上的)因为遮罩文件没进导出的图片,被画成一整块实心,现在遮罩像背景图一样嵌进去(@hh0592821 报告,[#35](https://github.com/JimLiu/baoyu-design/issues/35))。\n- **装了 VPN、代理或开了热点的电脑上,`share` 先给出 Wi-Fi 的地址。** 在 Windows 上,链接可能以代理虚拟网卡的地址开头(sing-box 的 TUN,叫 `falemon-tun`,`172.19.0.1`),网络上的其他人连不上。现在名字像隧道的网卡(`falemon-tun`、OpenVPN 的 TAP、Wintun、名字里带 `vpn` 的),点对点链路,以及这台电脑自己建的网络(移动热点的 `192.168.137.1`、虚拟机或容器的网络),地址都排在本地网络后面。电脑在多个网络上时,`share` 会提示:链接打不开,可以把地址换成列出的另一个再试(@Bistard 报告,[#37](https://github.com/JimLiu/baoyu-design/issues/37))。\n- **防火墙或代理拦着 `::1` 时,`open` 不再报端口被占用。** 探测被 `EACCES` 或 `EPERM` 拒绝,以前算成端口上有东西应答,`open` 试的 100 个端口全部放弃。\n- 技能文件夹在服务器运行期间被移动、改名或删除,页面现在会说明这一点,并把文件夹告诉主人,而不是让他重装技能;访客看到的是请分享的人重新打开。"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"version": "2.12.1",
|
|
35
|
+
"date": "2026-11-07",
|
|
36
|
+
"en": "### Fixes\n- **A long comment thread no longer runs off the bottom of the window.** The open card used to have no height limit, so the last replies and the reply box could be out of reach. In every editor it now stops at 60% of the window (never under 320px, and never taller than the room on the side it opens toward). The comments scroll inside it and the reply box stays below. After you reply, the thread follows to your reply; a long reply from the agent lines up at its top, and scrolling up stops the following (reported by @congee949, [#34](https://github.com/JimLiu/baoyu-design/issues/34)).\n- **`claude-design` and `claude-slides` opened on their own now keep the address bar on where you are.** Under `open` or DeepSeek Harness's browser there is no claude.ai frame to do it, so switching pages or slides left the address as it was, a pasted `#page-…` or `#slide-…` link did nothing once the page had loaded, and **Copy link to page** and **Copy link to slide** could not copy. In `claude-design` the address now names the page, switching to another page adds a history entry (up to 20), and Back and Forward move between them. In `claude-slides` the address follows the current slide without filling the history. Both follow a changed address to its place, and the copy shortcuts copy the page's address with the place in it and say **Link copied.** On claude.ai nothing changes. This is the address part of [#33](https://github.com/JimLiu/baoyu-design/issues/33), reported by @congee949; the previous/next page buttons and page keys it asks for are not in this release.",
|
|
37
|
+
"zh": "### 修复\n- **很长的评论串不再顶出窗口下沿。** 以前打开的评论卡片没有高度上限,最后几条回复和回复框可能够不到。现在所有编辑器里,卡片最高是窗口的 60%(不低于 320px,也不超过它朝向那一侧的空间),评论在卡片里滚动,回复框固定在下面。你回复之后,评论串会跟到你的回复;Agent 的长回复从它的开头对齐,往上滚就不再跟随(@congee949 报告,[#34](https://github.com/JimLiu/baoyu-design/issues/34))。\n- **单独打开的 `claude-design` 和 `claude-slides`,地址栏现在会跟着你所在的位置。** 用 `open` 或在 DeepSeek Harness 的浏览器里打开时,没有 claude.ai 的外层框架来做这件事:切页或切幻灯片,地址栏不变;贴一个 `#page-…` 或 `#slide-…` 的链接,页面加载之后没有反应;**Copy link to page**、**Copy link to slide** 复制不了。现在 `claude-design` 的地址栏写的是当前页,切到另一页会多一条历史记录(最多 20 条),后退、前进能在页之间来回;`claude-slides` 的地址栏跟着当前幻灯片走,但不往历史里添记录。地址被改成另一个位置时,两者都会跟过去;复制快捷键复制的是带着位置的本页地址,并提示 **Link copied.**。在 claude.ai 上没有变化。这是 [#33](https://github.com/JimLiu/baoyu-design/issues/33)(@congee949 报告)里地址栏的那部分,它要的上一页/下一页按钮和切页快捷键这个版本没有做。"
|
|
38
|
+
},
|
|
27
39
|
{
|
|
28
40
|
"version": "2.12.0",
|
|
29
41
|
"date": "2026-11-06",
|
|
@@ -59,18 +71,6 @@
|
|
|
59
71
|
"date": "2026-11-04",
|
|
60
72
|
"en": "### Fixes\n- DeepSeek Harness on Windows: the command the skills told the agent to run was written for a POSIX shell, and PowerShell reads a quoted path at the start of a line as a string, not a command. On Windows they now give `& '<node>' '<script>' <command>`, and say that PowerShell has no heredoc.",
|
|
61
73
|
"zh": "### 修复\n- Windows 上的 DeepSeek Harness:技能告诉 agent 运行的命令是按 POSIX shell 写的,而 PowerShell 会把行首带引号的路径当成字符串,不当成命令。现在 Windows 上给的是 `& '<node>' '<script>' <command>`,并说明 PowerShell 没有 heredoc。"
|
|
62
|
-
},
|
|
63
|
-
{
|
|
64
|
-
"version": "2.9.1",
|
|
65
|
-
"date": "2026-11-04",
|
|
66
|
-
"en": "### Fixes\n- DeepSeek Harness on Windows: the plugins only recognized a shell tool named `bash`, and on Windows it is named `pwsh`, so they never noticed an `open`. The folder stayed off the **Artifacts** page, **Send to Agent** never appeared, and comments did not reach the agent. They now recognize both names (by @leil894-collab, [#31](https://github.com/JimLiu/baoyu-design/pull/31); reported by @EmotionTowel, [#30](https://github.com/JimLiu/baoyu-design/issues/30)).",
|
|
67
|
-
"zh": "### 修复\n- Windows 上的 DeepSeek Harness:插件只认名叫 `bash` 的 shell 工具,而它在 Windows 上叫 `pwsh`,所以一直注意不到 `open`。文件夹不会出现在作品页,**Send to Agent** 不出现,评论也到不了 Agent。现在两个名字都认(by @leil894-collab,[#31](https://github.com/JimLiu/baoyu-design/pull/31);@EmotionTowel 报告,[#30](https://github.com/JimLiu/baoyu-design/issues/30))。"
|
|
68
|
-
},
|
|
69
|
-
{
|
|
70
|
-
"version": "2.9.0",
|
|
71
|
-
"date": "2026-11-03",
|
|
72
|
-
"en": "### Features\n- **ChatGPT plugins.** The skills now also come as plugins for the ChatGPT desktop app and Codex: Baoyu Slides, Baoyu Canvas, Baoyu Design System, Baoyu Dashboard, Baoyu Motion (with `motion-director` and `dataviz`) and Baoyu Dataviz. This repository is their marketplace: run `codex plugin marketplace add JimLiu/baoyu-design --sparse .agents/plugins --sparse chatgpt-plugins`, then install the ones you want. [chatgpt-plugins/README.md](chatgpt-plugins/README.md) has the steps.\n- DeepSeek Harness: each deck, canvas, design system, dashboard and film on the **Artifacts** page now has a real thumbnail, taken from its own editor and retaken when its files change. This needs the desktop app; in `dsh web` a card keeps a drawn picture of its type.\n- The **Artifacts** page's tiles and **+** menu start a new session with the input filled in, such as `/claude-slides Make me a slide deck about: `, and sending it loads that skill. Only plugins that are on get a tile.\n- The **Artifacts** page has grid and list views, search, sorting (last opened, last edited, date created, name) and filters (type, date opened, sharing, pinned).\n- Each card on the **Artifacts** page has a menu to pin, rename, copy the link or delete. Rename changes the title in the artifact itself, so its editor shows the new name. Delete moves the folder to `baoyu-design/trash/` in the app's data folder, with an Undo; a folder that also holds other files stays where it is and only leaves the list.\n\n### Fixes\n- In a sandbox that blocks local network, such as Codex's default one, `open` said `PORT_IN_USE`, as if every port were taken. It now says `NETWORK_BLOCKED` and how to run the command, and the skills say which commands need local network.",
|
|
73
|
-
"zh": "### 新功能\n- **ChatGPT 插件。** 这些技能也做成了 ChatGPT 桌面版和 Codex 的插件:Baoyu Slides、Baoyu Canvas、Baoyu Design System、Baoyu Dashboard、Baoyu Motion(带 `motion-director` 和 `dataviz`)和 Baoyu Dataviz。本仓库就是它们的 marketplace:运行 `codex plugin marketplace add JimLiu/baoyu-design --sparse .agents/plugins --sparse chatgpt-plugins`,再装你要的插件。步骤见 [chatgpt-plugins/README.zh-CN.md](chatgpt-plugins/README.zh-CN.md)。\n- DeepSeek Harness:**Artifacts** 页(中文界面是「作品」)上的幻灯片、画布、设计系统、仪表盘和影片现在都有真实的缩略图,从各自的编辑器里截取,文件改过后会重新截。这要在桌面版里;`dsh web` 的卡片仍然是画出来的类型示意图。\n- 作品页顶部的入口和 **+** 菜单会新开一个会话,并填好输入框,比如 `/claude-slides 帮我做一份幻灯片,主题是:`,发送时会加载对应的技能。只有开着的插件才有入口。\n- 作品页可以切换网格和列表,可以搜索、排序(最近打开、最近修改、创建时间、名称)和筛选(类型、打开时间、共享、已固定)。\n- 作品页的每张卡片都有菜单,可以固定、重命名、复制链接和删除。重命名改的是作品本身的标题,编辑器里也会显示新名字。删除会把文件夹移到应用数据目录的 `baoyu-design/trash/`,可以撤销;文件夹里还有别的文件时,文件夹留在原处,只从列表移除。\n\n### 修复\n- 在不允许访问本机网络的沙箱里(比如 Codex 的默认沙箱),`open` 会报 `PORT_IN_USE`,好像所有端口都被占了。现在它报 `NETWORK_BLOCKED`,并说明该怎么运行;技能说明里也写了哪些命令要访问本机网络。"
|
|
74
74
|
}
|
|
75
75
|
]
|
|
76
76
|
},
|
|
@@ -96,7 +96,7 @@
|
|
|
96
96
|
"dsh": ">=0.2.0-0"
|
|
97
97
|
},
|
|
98
98
|
"dependencies": {
|
|
99
|
-
"dsh-claude-artifacts": "^2.12.
|
|
99
|
+
"dsh-claude-artifacts": "^2.12.2"
|
|
100
100
|
},
|
|
101
101
|
"dsh": {
|
|
102
102
|
"bundle": {
|
|
@@ -104,13 +104,21 @@ function isTailnet(address) {
|
|
|
104
104
|
const m = /^100\.(\d{1,3})\./.exec(address);
|
|
105
105
|
return !!m && Number(m[1]) >= 64 && Number(m[1]) <= 127;
|
|
106
106
|
}
|
|
107
|
-
var isTunnel = (name) =>
|
|
107
|
+
var isTunnel = (name) => /(^|[^a-z0-9])(utun|tun|tap|wg|ppp|ipsec)\d*($|[^a-z0-9])/i.test(name) || /vpn|wintun|tunnel/i.test(name);
|
|
108
|
+
var ipv4Number = (address) => address.split(".").reduce((n, part) => n * 256 + Number(part), 0);
|
|
109
|
+
function isOwnNetwork(entry) {
|
|
110
|
+
if (!/^\d+\.\d+\.\d+\.\d+$/.test(entry.netmask)) return false;
|
|
111
|
+
const mask = ipv4Number(entry.netmask);
|
|
112
|
+
if (mask >= ipv4Number("255.255.255.252")) return true;
|
|
113
|
+
const address = ipv4Number(entry.address);
|
|
114
|
+
return ((address & mask) >>> 0) + 1 === address;
|
|
115
|
+
}
|
|
108
116
|
function lanAddresses() {
|
|
109
117
|
const out = /* @__PURE__ */ new Map();
|
|
110
118
|
for (const [name, list] of Object.entries(os.networkInterfaces())) {
|
|
111
119
|
for (const entry of list ?? []) {
|
|
112
120
|
if (entry.family !== "IPv4" || entry.internal || entry.address.startsWith("169.254.") || isBenchmarkRange(entry.address)) continue;
|
|
113
|
-
const rank = isTailnet(entry.address) ? 2 : isTunnel(name) ? 1 : 0;
|
|
121
|
+
const rank = isTailnet(entry.address) ? 2 : isTunnel(name) || isOwnNetwork(entry) ? 1 : 0;
|
|
114
122
|
out.set(entry.address, Math.min(rank, out.get(entry.address) ?? rank));
|
|
115
123
|
}
|
|
116
124
|
}
|
|
@@ -125,7 +133,10 @@ function answers(host, port) {
|
|
|
125
133
|
};
|
|
126
134
|
socket.setTimeout(300, () => done(false));
|
|
127
135
|
socket.once("connect", () => done(true));
|
|
128
|
-
socket.once(
|
|
136
|
+
socket.once(
|
|
137
|
+
"error",
|
|
138
|
+
(error) => done(!["ECONNREFUSED", "EADDRNOTAVAIL", "EAFNOSUPPORT", "ENETUNREACH", "EHOSTUNREACH", "EACCES", "EPERM"].includes(error.code ?? ""))
|
|
139
|
+
);
|
|
129
140
|
});
|
|
130
141
|
}
|
|
131
142
|
async function answersAnyPort(address) {
|
|
@@ -171,6 +182,7 @@ function serverOrigin(host, port) {
|
|
|
171
182
|
return `http://${shown2}:${port}`;
|
|
172
183
|
}
|
|
173
184
|
var pagePathOf = (kind, root) => `/${kind}/${createHash("sha256").update(path.resolve(root)).digest("base64url").slice(0, 22)}/`;
|
|
185
|
+
var pageGone = (dir, owner) => owner ? `This page's files are no longer in ${dir}: the skill was moved, renamed or removed while its server ran. Stop the server and open the artifact again (the agent that opened it can do both).` : "This page's files are gone from the computer that shares it. Ask whoever shared it to open it again.";
|
|
174
186
|
function sendJson(response, status, body, headers = {}) {
|
|
175
187
|
const text = JSON.stringify(body);
|
|
176
188
|
response.writeHead(status, {
|
|
@@ -2958,9 +2970,12 @@ async function shareCommand(o) {
|
|
|
2958
2970
|
const links = view.links;
|
|
2959
2971
|
const shown2 = (list) => Object.fromEntries(Object.entries(list).map(([role, link]) => [role, link.on ? link.url : "off"]));
|
|
2960
2972
|
const tailnet = view.lan ? view.tailnet : void 0;
|
|
2973
|
+
const addresses = view.lan ? lanUrls(view) : [];
|
|
2974
|
+
const local = view.lan && Array.isArray(view.addresses) ? view.addresses.filter((a) => !isTailnet(String(a))) : [];
|
|
2975
|
+
const others = local.length > 1 ? " This computer is on more than one network (addresses): if a link does not open for someone on the same Wi-Fi or LAN, give them the same link with another of those addresses." : "";
|
|
2961
2976
|
return {
|
|
2962
2977
|
lan: view.lan,
|
|
2963
|
-
...view.lan ? { addresses
|
|
2978
|
+
...view.lan ? { addresses } : {},
|
|
2964
2979
|
links: shown2(links),
|
|
2965
2980
|
...tailnet ? {
|
|
2966
2981
|
tailscale: shown2(tailnet.links),
|
|
@@ -2968,7 +2983,7 @@ async function shareCommand(o) {
|
|
|
2968
2983
|
} : {},
|
|
2969
2984
|
guests: view.guests,
|
|
2970
2985
|
...view.lan ? {
|
|
2971
|
-
note:
|
|
2986
|
+
note: `Send the link for the role you want to give: editor edits, commenter comments, viewer reads. Anyone on this network with a link joins under a name they type. The owner (this computer) shares from the Share button too.${others}`,
|
|
2972
2987
|
security: "It is plain http: others on the network can read what passes. A link is the permission: whoever has it gets its role, so send it only to the people meant to have it, and reset a role's link if it went further.",
|
|
2973
2988
|
stop: o.offCommand
|
|
2974
2989
|
} : { note: `Not shared on the network: the links work on this computer only. ${NOT_SHARED_HINT}` }
|
|
@@ -7792,7 +7807,8 @@ data: ${JSON.stringify(data)}
|
|
|
7792
7807
|
try {
|
|
7793
7808
|
html = fs19.readFileSync(path18.join(EDITOR_DIR, "index.html"), "utf8");
|
|
7794
7809
|
} catch {
|
|
7795
|
-
|
|
7810
|
+
log3(`the player's files are gone from ${EDITOR_DIR}: the skill was moved, renamed or removed while this server ran`);
|
|
7811
|
+
return json(res, 404, { code: "not_found", message: pageGone(EDITOR_DIR, viewer.role === "owner") });
|
|
7796
7812
|
}
|
|
7797
7813
|
const body = Buffer.from(share2.injectHead(html, viewer, at === void 0 ? "" : `?at=${at}`) ?? html);
|
|
7798
7814
|
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8", "Content-Length": body.length, "Cache-Control": "no-store", "X-Content-Type-Options": "nosniff" });
|