@ninkch/dsh-artcraft 0.2.8 → 0.2.10
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 +31 -16
- package/README.zh-CN.md +24 -12
- package/apps/catalog.json +293 -0
- package/artcraft.config.json.example +6 -1
- package/client.js +17 -9
- package/index.js +93 -19
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -14,18 +14,22 @@
|
|
|
14
14
|
|
|
15
15
|
## Why this exists
|
|
16
16
|
|
|
17
|
-
[ArtCraft](https://getartcraft.com/apps) is a family of free, fair-source reinventions
|
|
18
|
-
studio tools, written from scratch in pure Rust: **PhotoCraft** (Photoshop),
|
|
19
|
-
(Premiere Pro), **
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
[ArtCraft](https://getartcraft.com/apps) is a family of **twelve** free, fair-source reinventions
|
|
18
|
+
of Adobe's studio tools, written from scratch in pure Rust: **PhotoCraft** (Photoshop),
|
|
19
|
+
**VectorCraft** (Illustrator), **FilmCraft** (Premiere Pro), **LightCraft** (Lightroom),
|
|
20
|
+
**PdfCraft** (Acrobat), **EffectCraft** (After Effects), **DesignCraft** (InDesign),
|
|
21
|
+
**WordCraft** (Word), **DeckCraft** (PowerPoint), **GridCraft** (Excel), **CADCraft** (AutoCAD)
|
|
22
|
+
and **SoundCraft** (Pro Tools). They share one superpower that most desktop apps don't have:
|
|
23
|
+
**every menu item, slider and dialog is a command**, and the exact same commands can be driven
|
|
24
|
+
from a headless CLI, a JSON control channel, or an MCP server. The apps were built for agents
|
|
25
|
+
from day one.
|
|
23
26
|
|
|
24
27
|
This plugin brings that surface into DeepSeek Harness, so an AI agent can *operate* the apps —
|
|
25
28
|
not just talk about them:
|
|
26
29
|
|
|
27
|
-
- **In chat** —
|
|
28
|
-
send control-channel commands to a running app,
|
|
30
|
+
- **In chat** — eight agent tools let any Harness session check the toolchain, run CLI commands,
|
|
31
|
+
send control-channel commands to a running app, do bridged file operations, and consult a
|
|
32
|
+
per-app capability catalog.
|
|
29
33
|
- **In the browser** — a same-origin HTTP API (`/artcraft/api/*`) that any Harness web UI can call,
|
|
30
34
|
no CORS, no keys. It was built for [无限画布 / infinite-canvas](../dsh-infinite_canvas/README.md),
|
|
31
35
|
a node-based AI short-drama storyboard canvas, but any front end can use it.
|
|
@@ -140,10 +144,14 @@ artcraft_cli { bin:"photocraft", args:["batch","--actions","demo/craft/grade.js
|
|
|
140
144
|
|
|
141
145
|
| Tool | What it does |
|
|
142
146
|
|---|---|
|
|
143
|
-
| `artcraft_status` | Toolchain health check: which CLIs resolved, config location, control ports, running jobs |
|
|
144
|
-
| `artcraft_cli` | Run any CLI subcommand synchronously (`photocraft-cli run/batch`, `
|
|
145
|
-
| `artcraft_control` | One command over the JSON control channel of a *running*
|
|
147
|
+
| `artcraft_status` | Toolchain health check: which of the 12 CLIs resolved, config location, control ports, running jobs |
|
|
148
|
+
| `artcraft_cli` | Run any CLI subcommand synchronously (`photocraft-cli run/batch`, `wordcraft-cli convert`, …) |
|
|
149
|
+
| `artcraft_control` | One command over the JSON control channel of a *running* app (filmcraft 9876 / effectcraft 9877 / vectorcraft 7979 / lightcraft 7980, or pass `port`) |
|
|
146
150
|
| `artcraft_fs` | Bridged file ops — list / stat / read / write / mkdir at caller-decided absolute paths |
|
|
151
|
+
| `artcraft_discover` | Family install auto-discovery: fills missing paths, auto-corrects stale ones |
|
|
152
|
+
| `artcraft_apps` | Capability catalog for all 12 apps: CLI subcommands, control ports, MCP, repo/docs links |
|
|
153
|
+
| `artcraft_recipes` | Built-in expert recipes: 8 cross-app professional workflows |
|
|
154
|
+
| `artcraft_update` | The plugin's own update (check / apply) |
|
|
147
155
|
|
|
148
156
|
## Driving it from the browser
|
|
149
157
|
|
|
@@ -175,7 +183,10 @@ Full route list:
|
|
|
175
183
|
| `GET /artcraft/api/fs?op=list\|stat\|readtext&path=…` | Read directories, metadata, small text files |
|
|
176
184
|
| `GET /artcraft/api/file?path=…` | Download a file — streamed, up to 2 GB |
|
|
177
185
|
| `POST /artcraft/api/job` · `GET ?id=…` · `POST /artcraft/api/job/cancel` | Job lifecycle with output statting and tail logs |
|
|
178
|
-
| `POST /artcraft/api/control` | Synchronous control-channel call |
|
|
186
|
+
| `POST /artcraft/api/control` | Synchronous control-channel call (`app` or `port`) |
|
|
187
|
+
| `GET /artcraft/api/apps[?id=…]` | Family capability catalog (12 apps) |
|
|
188
|
+
| `POST /artcraft/api/discover` | Family install discovery + config self-repair |
|
|
189
|
+
| `GET /artcraft/api/update/check` · `POST /artcraft/api/update/apply` | The plugin's own update |
|
|
179
190
|
|
|
180
191
|
Uploads are capped at 320 MB per request (Blob direct, no base64 needed for the raw path);
|
|
181
192
|
downloads stream up to 2 GB. All path arguments are **absolute** (or `base` absolute directory +
|
|
@@ -209,10 +220,14 @@ POST /artcraft/api/control
|
|
|
209
220
|
Time accepts `seconds`, `frame` or `timecode` (internally FilmCraft counts ticks at
|
|
210
221
|
254,016,000,000/s). `filmcraft-cli commands` lists the 650+ engine commands; the protocol is
|
|
211
222
|
documented in [filmcraft/docs/control-protocol.md](https://github.com/storytold/filmcraft/blob/main/docs/control-protocol.md).
|
|
212
|
-
EffectCraft listens the same way on its own port (default 9877)
|
|
223
|
+
EffectCraft listens the same way on its own port (default 9877); VectorCraft defaults to 7979
|
|
224
|
+
and LightCraft to 7980 (both built into `artcraft_control`'s `app`). The remaining apps pick
|
|
225
|
+
dynamic ports: start them with `app --port PORT`, then pass `port` to `artcraft_control`. Each
|
|
226
|
+
app's control surface is described in the `artcraft_apps` catalog.
|
|
213
227
|
|
|
214
|
-
> PhotoCraft's control channel is an authenticated variant and is
|
|
215
|
-
> here —
|
|
228
|
+
> PhotoCraft's control channel is an authenticated variant and PdfCraft's is file-based
|
|
229
|
+
> (`--control FILE`); both are deliberately **not** proxied here — the headless CLI covers
|
|
230
|
+
> everything this plugin needs.
|
|
216
231
|
|
|
217
232
|
## Working with 无限画布 (infinite-canvas)
|
|
218
233
|
|
|
@@ -268,7 +283,7 @@ a web UI.
|
|
|
268
283
|
|
|
269
284
|
The HTTP surface has **no authentication** and rides on the Harness web server, which listens on
|
|
270
285
|
loopback only — treat the port as trusted-local and don't expose it to a network; put a reverse
|
|
271
|
-
proxy with auth in front if you must. Child processes are locked to the
|
|
286
|
+
proxy with auth in front if you must. Child processes are locked to the twelve allow-listed
|
|
272
287
|
family CLIs; the control channel only ever dials `127.0.0.1`.
|
|
273
288
|
|
|
274
289
|
## Publishing
|
package/README.zh-CN.md
CHANGED
|
@@ -15,16 +15,18 @@
|
|
|
15
15
|
## 为什么做这个
|
|
16
16
|
|
|
17
17
|
[ArtCraft](https://getartcraft.com/apps) 是一套用纯 Rust 从零重写的免费公平源代码(fair source)
|
|
18
|
-
Adobe
|
|
19
|
-
**
|
|
20
|
-
Effects
|
|
18
|
+
Adobe 对标工具,共 **12 个应用**:**PhotoCraft**(Photoshop)、**VectorCraft**(Illustrator)、
|
|
19
|
+
**FilmCraft**(Premiere Pro)、**LightCraft**(Lightroom)、**PdfCraft**(Acrobat)、
|
|
20
|
+
**EffectCraft**(After Effects)、**DesignCraft**(InDesign)、**WordCraft**(Word)、
|
|
21
|
+
**DeckCraft**(PowerPoint)、**GridCraft**(Excel)、**CADCraft**(AutoCAD)、**SoundCraft**
|
|
22
|
+
(Pro Tools)。它们有一个大多数桌面软件都不具备的共同基因:**每个菜单项、滑块、对话框都是一条
|
|
21
23
|
命令**,而同一套命令既能从无头 CLI 调用,也能走 JSON 控制通道或 MCP——这些 App 从第一天起
|
|
22
24
|
就是为 agent 设计的。
|
|
23
25
|
|
|
24
26
|
本插件把这套自动化面接进 DeepSeek Harness,让 AI 不只是"谈论"这些软件,而是真的**操作**它们:
|
|
25
27
|
|
|
26
|
-
- **对话里** ——
|
|
27
|
-
App
|
|
28
|
+
- **对话里** —— 八个 Agent 工具,任何 Harness 会话都能检查工具链、执行 CLI 命令、向运行中的
|
|
29
|
+
App 发控制通道命令、做桥接文件操作、查每个应用的能力目录。
|
|
28
30
|
- **浏览器里** —— 同源 HTTP API(`/artcraft/api/*`),任何 Harness 前端都能直接调用:无 CORS、
|
|
29
31
|
无密钥。它为 [无限画布 / infinite-canvas](../dsh-infinite_canvas/README.md)(节点式 AI 短剧
|
|
30
32
|
分镜画布)而建,但任何前端都可用。
|
|
@@ -129,10 +131,14 @@ artcraft_cli { bin:"photocraft", args:["batch","--actions","demo/craft/grade.js
|
|
|
129
131
|
|
|
130
132
|
| 工具 | 用途 |
|
|
131
133
|
|---|---|
|
|
132
|
-
| `artcraft_status` | 工具体检:CLI 是否找到、配置目录、控制端口、进行中的任务 |
|
|
133
|
-
| `artcraft_cli` | 同步执行任意 CLI 子命令(`photocraft-cli run/batch`、`
|
|
134
|
-
| `artcraft_control` | 向**运行中**的
|
|
134
|
+
| `artcraft_status` | 工具体检:12 个 CLI 是否找到、配置目录、控制端口、进行中的任务 |
|
|
135
|
+
| `artcraft_cli` | 同步执行任意 CLI 子命令(`photocraft-cli run/batch`、`wordcraft-cli convert` 等) |
|
|
136
|
+
| `artcraft_control` | 向**运行中**的 App 控制通道发一条命令(filmcraft 9876 / effectcraft 9877 / vectorcraft 7979 / lightcraft 7980,或 port 直连) |
|
|
135
137
|
| `artcraft_fs` | 桥接文件操作 —— list / stat / 读 / 写 / 建目录,路径由调用方绝对指定 |
|
|
138
|
+
| `artcraft_discover` | 家族安装自动探测:填充缺失路径、自动纠正失效路径 |
|
|
139
|
+
| `artcraft_apps` | 12 应用能力目录:每个应用的 CLI 子命令、控制端口、MCP、仓库/文档链接 |
|
|
140
|
+
| `artcraft_recipes` | 内置专家处理方案:8 套跨应用专业工作流配方 |
|
|
141
|
+
| `artcraft_update` | 插件自身更新(检查 / 应用) |
|
|
136
142
|
|
|
137
143
|
## 在浏览器里驱动
|
|
138
144
|
|
|
@@ -163,7 +169,10 @@ POST /artcraft/api/job/cancel { "id":"7f2c…" }
|
|
|
163
169
|
| `GET /artcraft/api/fs?op=list\|stat\|readtext&path=…` | 读目录、元数据、小文本 |
|
|
164
170
|
| `GET /artcraft/api/file?path=…` | 下载文件 —— 流式,上限 2 GB |
|
|
165
171
|
| `POST /artcraft/api/job` · `GET ?id=…` · `POST /artcraft/api/job/cancel` | 任务生命周期,含产物探测与日志尾部 |
|
|
166
|
-
| `POST /artcraft/api/control` |
|
|
172
|
+
| `POST /artcraft/api/control` | 控制通道同步调用(`app` 或 `port`) |
|
|
173
|
+
| `GET /artcraft/api/apps[?id=…]` | 家族能力目录(12 应用) |
|
|
174
|
+
| `POST /artcraft/api/discover` | 家族安装探测 + 配置自动修复 |
|
|
175
|
+
| `GET /artcraft/api/update/check` · `POST /artcraft/api/update/apply` | 插件自更新 |
|
|
167
176
|
|
|
168
177
|
上传单次上限 320 MB(原始路径 Blob 直传,无需 base64);下载流式上限 2 GB。
|
|
169
178
|
所有路径参数为**绝对路径**(或 `base` 绝对目录 + 相对 `rel`)—— 位置由调用方决定:
|
|
@@ -195,9 +204,12 @@ POST /artcraft/api/control
|
|
|
195
204
|
时间可传 `seconds` / `frame` / `timecode`(FilmCraft 内部以每秒 254,016,000,000 tick 计)。
|
|
196
205
|
`filmcraft-cli commands` 列出全部 650+ 引擎命令;协议详见
|
|
197
206
|
[filmcraft/docs/control-protocol.md](https://github.com/storytold/filmcraft/blob/main/docs/control-protocol.md)。
|
|
198
|
-
EffectCraft 同族协议,端口默认 9877
|
|
207
|
+
EffectCraft 同族协议,端口默认 9877;VectorCraft 默认 7979、LightCraft 默认 7980(`artcraft_control`
|
|
208
|
+
的 `app` 已内置)。其余应用端口动态:以 `app --port PORT` 启动后,`artcraft_control` 传 `port`
|
|
209
|
+
直连即可(协议同族)。每个应用的控制面详见 `artcraft_apps` 能力目录。
|
|
199
210
|
|
|
200
|
-
> PhotoCraft
|
|
211
|
+
> PhotoCraft 的控制通道是带鉴权的变体、PdfCraft 是文件式(`--control FILE`),本插件**有意不代理**
|
|
212
|
+
> —— 两者走无头 CLI 足够。
|
|
201
213
|
|
|
202
214
|
## 与无限画布(infinite-canvas)协作
|
|
203
215
|
|
|
@@ -250,7 +262,7 @@ NVENC 硬编)、ProRes、DNxHR,附 EBU R128 响度归一与字幕烧录。
|
|
|
250
262
|
## 安全与信任模型
|
|
251
263
|
|
|
252
264
|
HTTP 面无鉴权,挂在 Harness Web 服务之下(仅回环监听)—— 把端口当本机可信处理,**不要暴露
|
|
253
|
-
到网络**;确需远程请加带鉴权的反向代理。子进程锁定
|
|
265
|
+
到网络**;确需远程请加带鉴权的反向代理。子进程锁定 12 个白名单家族 CLI;控制通道只会拨
|
|
254
266
|
`127.0.0.1`。
|
|
255
267
|
|
|
256
268
|
## 发布
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"note": "ArtCraft 家族 12 应用的自动化能力目录。来源:官方 getartcraft.com/apps、各应用 GitHub 仓库(storytold/*)、本机 12 个 <app>-cli --help 实测(0.2.9 时点)。要拿某应用的实时命令注册表,用 artcraft_cli 跑该应用的 commands 子命令。",
|
|
4
|
+
"controlProtocol": "家族共用 JSON-lines 控制协议(127.0.0.1:<port>,请求 {\"id\",\"method\",\"params\"},方法如 engine.execute / engine.commands / ui.inspect / ui.screenshot)。App 需以 --control 启动。artcraft_control 已代理有固定默认端口的应用;其余应用端口动态(app --port 启动时指定),可用 artcraft_control 的 port 参数直连。",
|
|
5
|
+
"apps": [
|
|
6
|
+
{
|
|
7
|
+
"id": "photocraft",
|
|
8
|
+
"name": "PhotoCraft",
|
|
9
|
+
"tagline": "图像编辑",
|
|
10
|
+
"ref": "Adobe Photoshop",
|
|
11
|
+
"stage": "early alpha",
|
|
12
|
+
"repo": "https://github.com/storytold/photocraft",
|
|
13
|
+
"docs": "https://getartcraft.com/apps/photocraft",
|
|
14
|
+
"cli": "photocraft-cli",
|
|
15
|
+
"control": null,
|
|
16
|
+
"controlNote": "控制通道为令牌鉴权模式,artcraft_control 不代理;headless 用 serve/mcp",
|
|
17
|
+
"mcp": true,
|
|
18
|
+
"subcommands": [
|
|
19
|
+
{ "name": "convert", "usage": "convert <in> <out> [--format ext] [--quality 1-100] [--tiff-layers]", "summary": "格式互转(.pcraft/.psd/.png/.jpg/.tif/.webp/.exr…);TIFF 默认拼合,--tiff-layers 保留图层" },
|
|
20
|
+
{ "name": "info", "usage": "info <file> [--compact]", "summary": "文档 JSON(尺寸/颜色模式/位深/图层树)" },
|
|
21
|
+
{ "name": "run", "usage": "run (<file> | --new <json>) --cmd <id> [--params <json>]… [--out <file>] [--format] [--quality] [--tiff-layers]", "summary": "打开文件按序执行引擎命令后保存;每个 --params 归属前一个 --cmd" },
|
|
22
|
+
{ "name": "batch", "usage": "batch --actions <actions.json> --in <dir> --out <dir> [--format] [--quality] [--in-place] [--tiff-layers]", "summary": "动作列表批处理整个目录(录制动作/droplet 格式);--in-place 才允许覆盖原目录" },
|
|
23
|
+
{ "name": "droplet", "usage": "droplet <file.pcdroplet> <file-or-dir>… [--out <dir>]", "summary": "运行 Photoshop 式 droplet" },
|
|
24
|
+
{ "name": "commands", "usage": "commands [--json] [--filter <text>]", "summary": "列出引擎命令注册表" },
|
|
25
|
+
{ "name": "serve", "usage": "serve [--port <port>] [--control-token …] [--automation-read-root <dir>] [--automation-write-root <dir>]", "summary": "常驻 headless 会话:stdio 或 TCP JSON lines(engine.execute、doc.open/new/save/inspect/render/select/close、session.list、batch、methods)" },
|
|
26
|
+
{ "name": "mcp", "usage": "mcp [--bridge 127.0.0.1:port] [--control-token …] [--automation-read-root] [--automation-write-root]", "summary": "stdio MCP 服务器(headless 引擎,或 bridge 到运行中的 app)" }
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"id": "vectorcraft",
|
|
31
|
+
"name": "VectorCraft",
|
|
32
|
+
"tagline": "矢量插画",
|
|
33
|
+
"ref": "Adobe Illustrator",
|
|
34
|
+
"stage": "in development",
|
|
35
|
+
"repo": "https://github.com/storytold/vectorcraft",
|
|
36
|
+
"docs": "https://getartcraft.com/apps/vectorcraft",
|
|
37
|
+
"cli": "vectorcraft-cli",
|
|
38
|
+
"control": 7979,
|
|
39
|
+
"mcp": true,
|
|
40
|
+
"subcommands": [
|
|
41
|
+
{ "name": "run", "usage": "run [--in FILE] [--cmd ID [--params JSON]]… [--export FILE]… [--scale N]", "summary": "headless 批处理:打开或新建文档,按序执行命令,按扩展名导出" },
|
|
42
|
+
{ "name": "commands", "usage": "commands", "summary": "命令目录 JSON" },
|
|
43
|
+
{ "name": "convert", "usage": "convert IN OUT [--scale N] [--artboard I | --range R] [--outline-text] [--replace-lossy]", "summary": "转换/导出(SVG/PDF/PNG…);PDF 出全部画板;--outline-text 文字转路径" },
|
|
44
|
+
{ "name": "info", "usage": "info FILE", "summary": "JSON 摘要:导入警告、标题、颜色模式、单位、画板、对象统计、字体" },
|
|
45
|
+
{ "name": "bench", "usage": "bench FILE [--size WxH] [--iters N]", "summary": "渲染基准(ms/帧,多线程与单线程)" },
|
|
46
|
+
{ "name": "perf", "usage": "perf [--paths N]", "summary": "性能预算检查(渲染/平移/命中/存取/SVG/Pathfinder)" },
|
|
47
|
+
{ "name": "mcp", "usage": "mcp [--connect ADDR | --headless] [--automation-read-root DIR] [--automation-write-root DIR]", "summary": "stdio MCP(默认连运行中的 app 127.0.0.1:7979,回退 headless)" }
|
|
48
|
+
]
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"id": "filmcraft",
|
|
52
|
+
"name": "FilmCraft",
|
|
53
|
+
"tagline": "视频剪辑、调色和声音处理",
|
|
54
|
+
"ref": "Adobe Premiere Pro",
|
|
55
|
+
"stage": "in development",
|
|
56
|
+
"repo": "https://github.com/storytold/filmcraft",
|
|
57
|
+
"docs": "https://getartcraft.com/apps/filmcraft",
|
|
58
|
+
"cli": "filmcraft-cli",
|
|
59
|
+
"control": 9876,
|
|
60
|
+
"mcp": true,
|
|
61
|
+
"global": ["--project <p.fcproj>", "--demo", "--save", "--save-as <p.fcproj>"],
|
|
62
|
+
"subcommands": [
|
|
63
|
+
{ "name": "exec", "usage": "exec <id> [key=value …] | exec <id> '<json params>'", "summary": "运行单条命令,结果 JSON" },
|
|
64
|
+
{ "name": "run", "usage": "run <script.jsonl | ->", "summary": "脚本批处理:每行一个 {\"id\",\"params\"}(# 注释可用)" },
|
|
65
|
+
{ "name": "commands", "usage": "commands [filter] [--json]", "summary": "命令清单(id/label/快捷键/参数)" },
|
|
66
|
+
{ "name": "describe", "usage": "describe <id>", "summary": "单条命令 JSON(菜单/快捷键/参数/当前可用性)" },
|
|
67
|
+
{ "name": "inspect", "usage": "inspect [project|sequence]", "summary": "项目树或活动序列 JSON(默认两者)" },
|
|
68
|
+
{ "name": "import", "usage": "import <file>…", "summary": "导入媒体到项目" },
|
|
69
|
+
{ "name": "export", "usage": "export <out> [--preset name] [--format f] [--range entire|inOut|workArea|秒] [--settings json] [--gpu-rendering auto|off] [--scale f] [--quality 0-100] [--no-audio] [--queue]", "summary": "导出活动序列(h264/hevc/prores/dnxhr/apv/mjpeg/mxf-op1a/mxf-opatom/png/tiff/bmp/gif/wav/aiff/aac);--list-presets 列预设" },
|
|
70
|
+
{ "name": "render", "usage": "render --seconds S --out f.png [--scale 0.5]", "summary": "渲染 Program 单帧 PNG" },
|
|
71
|
+
{ "name": "probe", "usage": "probe <media> [--image-sequence]", "summary": "媒体信息 JSON(含 MXF/Ogg/BWF 细节;编号静帧序列取首帧)" },
|
|
72
|
+
{ "name": "bench-decode", "usage": "bench-decode <media> [--frames N]", "summary": "解码基准" },
|
|
73
|
+
{ "name": "mcp", "usage": "mcp", "summary": "stdio MCP(headless,或 --bridge 接运行中的 app)" }
|
|
74
|
+
]
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"id": "lightcraft",
|
|
78
|
+
"name": "LightCraft",
|
|
79
|
+
"tagline": "照片管理与 RAW 处理",
|
|
80
|
+
"ref": "Adobe Lightroom",
|
|
81
|
+
"stage": "in development",
|
|
82
|
+
"repo": "https://github.com/storytold/lightcraft",
|
|
83
|
+
"docs": "https://getartcraft.com/apps/lightcraft",
|
|
84
|
+
"cli": "lightcraft-cli",
|
|
85
|
+
"control": 7980,
|
|
86
|
+
"mcp": true,
|
|
87
|
+
"subcommands": [
|
|
88
|
+
{ "name": "run", "usage": "run [--demo | --library DIR | --import PATH… | --connect [ADDR] | --script FILE|- | --keep-going] COMMAND [k=v | '{json}']…", "summary": "命令批处理(每命令一行 JSON 结果):develop.set/auto、app.export 等控制协议方法;--library 模式编辑落盘" },
|
|
89
|
+
{ "name": "mcp", "usage": "mcp [--connect [ADDR] | --demo | --library DIR] [FILES/FOLDERS…]", "summary": "stdio MCP(headless 默认;--compact 只列辅助工具)" },
|
|
90
|
+
{ "name": "render", "usage": "render <IN> -o <OUT> [--set CONTROL=VALUE…] [--settings FILE] [--preset ID] [--size N] [--quality Q] [--opt KEY=VALUE…]", "summary": "单文件 RAW 冲洗导出(.jpg/.png/.tif/.webp/.avif/.dng);--opt 支持 colorSpace/bitDepth/percent/ppi/format=original" },
|
|
91
|
+
{ "name": "snapshot", "usage": "snapshot [FILES/FOLDERS…] [OPTIONS]", "summary": "无窗口 CPU 光栅化跑完整 UI 并输出 PNG(界面截图自动化)" }
|
|
92
|
+
]
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"id": "pdfcraft",
|
|
96
|
+
"name": "PdfCraft",
|
|
97
|
+
"tagline": "PDF 阅读、整理和保护",
|
|
98
|
+
"ref": "Adobe Acrobat",
|
|
99
|
+
"stage": "early alpha",
|
|
100
|
+
"repo": "https://github.com/storytold/pdfcraft",
|
|
101
|
+
"docs": "https://getartcraft.com/apps/pdfcraft",
|
|
102
|
+
"cli": "pdfcraft-cli",
|
|
103
|
+
"control": null,
|
|
104
|
+
"controlNote": "控制通道为文件式(--control FILE),不走 TCP,artcraft_control 不代理",
|
|
105
|
+
"mcp": true,
|
|
106
|
+
"subcommands": [
|
|
107
|
+
{ "name": "info", "usage": "info <file.pdf> [--password PW]", "summary": "文档摘要 JSON" },
|
|
108
|
+
{ "name": "render", "usage": "render <file.pdf> --page N [--dpi 96] --out x.png", "summary": "页面渲染(.png/.jpg/.tif/.pam)" },
|
|
109
|
+
{ "name": "text", "usage": "text <file.pdf> [--page N]", "summary": "提取文本(页间换页符分隔)" },
|
|
110
|
+
{ "name": "edit", "usage": "edit <in.pdf> --out out.pdf [--rotate 1,3:90] [--delete 2,4] [--move 5:1] [--insert-blank 1] [--title T] [--author A] [--full]", "summary": "页级编辑:旋转/删除/移动/插空白页/元数据" },
|
|
111
|
+
{ "name": "combine", "usage": "combine <a.pdf> <b.pdf> … --out combined.pdf", "summary": "合并多个 PDF" },
|
|
112
|
+
{ "name": "extract", "usage": "extract <in.pdf> --pages 1,3,5 --out out.pdf", "summary": "抽取指定页" },
|
|
113
|
+
{ "name": "split", "usage": "split <in.pdf> (--every N | --before 3,7) [--out-dir DIR]", "summary": "拆分(每 N 页一档 / 指定页前切)" },
|
|
114
|
+
{ "name": "check", "usage": "check <files or dirs…> [--timeout 20] [--dpi 36] [--json out.json]", "summary": "批量打开校验(损坏/加密扫描)" },
|
|
115
|
+
{ "name": "tools", "usage": "tools", "summary": "自动化工具与其 JSON Schema" },
|
|
116
|
+
{ "name": "run", "usage": "run <tool> [key=value …] [--root DIR] [--out image.png] | run --script steps.json [--root DIR]", "summary": "运行自动化工具(或脚本数组 [{\"tool\",\"args\"}…])" },
|
|
117
|
+
{ "name": "mcp", "usage": "mcp [--root DIR] [--compact]", "summary": "stdio MCP(--compact 精简工具集 + tool_search/tool_call)" },
|
|
118
|
+
{ "name": "ui", "usage": "ui --control FILE <method> [key=value …] [--out shot.png]", "summary": "驱动以 --control FILE 启动的运行中 app(engine.execute/ui.* 等)" }
|
|
119
|
+
]
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"id": "effectcraft",
|
|
123
|
+
"name": "EffectCraft",
|
|
124
|
+
"tagline": "动态图形与视觉特效",
|
|
125
|
+
"ref": "Adobe After Effects",
|
|
126
|
+
"stage": "in development",
|
|
127
|
+
"repo": "https://github.com/storytold/effectcraft",
|
|
128
|
+
"docs": "https://getartcraft.com/apps/effectcraft",
|
|
129
|
+
"cli": "effectcraft-cli",
|
|
130
|
+
"control": 9877,
|
|
131
|
+
"mcp": true,
|
|
132
|
+
"global": ["--project F.ecproj | --demo | --empty", "--save | --save-as F", "--bridge PORT", "--json", "--gpu"],
|
|
133
|
+
"subcommands": [
|
|
134
|
+
{ "name": "info", "usage": "info", "summary": "项目 + 引擎摘要" },
|
|
135
|
+
{ "name": "commands", "usage": "commands [--filter TEXT] [--enabled]", "summary": "引擎命令清单" },
|
|
136
|
+
{ "name": "exec", "usage": "exec <command-id> [--params JSON]", "summary": "运行单条引擎命令" },
|
|
137
|
+
{ "name": "run", "usage": "run <id> <json> [<id> <json> …]", "summary": "按序运行多条命令" },
|
|
138
|
+
{ "name": "props", "usage": "props <comp> <layer> [--flat] [--time S]", "summary": "图层属性树(含路径;<comp>/<layer> 可用 id/名称,'-' 为当前)" },
|
|
139
|
+
{ "name": "get", "usage": "get <comp> <layer> <path> [--time S]", "summary": "读属性" },
|
|
140
|
+
{ "name": "set", "usage": "set <comp> <layer> <path> <value> [--time S] [--expression E]", "summary": "写属性(可设表达式)" },
|
|
141
|
+
{ "name": "render-frame", "usage": "render-frame [--comp C] [--time S | --frame N] [--max-side PX | --scale K] [--out F.png] [--transparent]", "summary": "单帧渲染(可透明底)" },
|
|
142
|
+
{ "name": "render", "usage": "render [--comp C] --out FILE [--format h264|hevc|av1|prores|webm|png|jpeg|tiff|exr|gif|wav|aiff] [--start/--end/--work-area/--fps/--resolution/--quality/--channels/--bitrate/--prores PROFILE/--rate-control/--keyint/--webm-codec vp9|av1…] [--queue] | --template T.ectemplate --values V.json", "summary": "合成输出(编码参数齐全;模板渲染用 --template + --values)" },
|
|
143
|
+
{ "name": "bench", "usage": "bench [--comp C] [--time S] [--scale K] [--n N] [--play N] [--gpu] | bench --ops", "summary": "渲染基准(CPU/GPU 对比;--ops 大项目日常操作基准)" },
|
|
144
|
+
{ "name": "script", "usage": "script FILE.jsx [F.ecproj] | --eval CODE", "summary": "AE 风格 JS 对象模型(app.project/comps/layers/properties…),错误带 file:line:col" },
|
|
145
|
+
{ "name": "mcp", "usage": "mcp [--autosave | --bridge PORT] [--automation-read-root DIR] [--automation-write-root DIR]", "summary": "stdio MCP(--autosave 保留未保存的 headless 成果;脚本可被 root 限制拒绝)" }
|
|
146
|
+
]
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
"id": "designcraft",
|
|
150
|
+
"name": "DesignCraft",
|
|
151
|
+
"tagline": "页面排版与出版",
|
|
152
|
+
"ref": "Adobe InDesign",
|
|
153
|
+
"stage": "in development",
|
|
154
|
+
"repo": "https://github.com/storytold/designcraft",
|
|
155
|
+
"docs": "https://getartcraft.com/apps/designcraft",
|
|
156
|
+
"cli": "designcraft-cli",
|
|
157
|
+
"control": null,
|
|
158
|
+
"controlNote": "控制通道端口动态:app --port PORT 启动后用 artcraft_control 的 port 参数直连",
|
|
159
|
+
"mcp": true,
|
|
160
|
+
"subcommands": [
|
|
161
|
+
{ "name": "run", "usage": "run [--in FILE | --sample] [--cmd ID[=JSON]]… [--page N] [--scale S] [--pdf-options JSON] [--export OUT] [--all-pages DIR]", "summary": "headless 执行命令并导出(--page/--scale/--pdf-options 归属其后的导出)" },
|
|
162
|
+
{ "name": "commands", "usage": "commands [FILTER]", "summary": "命令清单" },
|
|
163
|
+
{ "name": "describe", "usage": "describe COMMAND", "summary": "单命令详情" },
|
|
164
|
+
{ "name": "script", "usage": "script [FILE|-] [--in FILE | --sample] [--connect PORT] [--save OUT] [--export OUT] [--keep-going]", "summary": "脚本批处理" },
|
|
165
|
+
{ "name": "app", "usage": "app [--port PORT] COMMAND [JSON] | --method METHOD [JSON]", "summary": "调用运行中 app 的控制通道(引擎命令或协议方法)" },
|
|
166
|
+
{ "name": "mcp", "usage": "mcp [--connect PORT] [--sample]", "summary": "stdio MCP" },
|
|
167
|
+
{ "name": "perf", "usage": "perf [--pages N] [--runs N] [--strict]", "summary": "性能预算" },
|
|
168
|
+
{ "name": "bench", "usage": "bench FILE [--runs N]", "summary": "渲染基准" },
|
|
169
|
+
{ "name": "links", "usage": "links", "summary": "社区/文档链接" }
|
|
170
|
+
]
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
"id": "wordcraft",
|
|
174
|
+
"name": "WordCraft",
|
|
175
|
+
"tagline": "写作与文档设计",
|
|
176
|
+
"ref": "Microsoft Word",
|
|
177
|
+
"stage": "in development",
|
|
178
|
+
"repo": "https://github.com/storytold/wordcraft",
|
|
179
|
+
"docs": "https://getartcraft.com/apps/wordcraft",
|
|
180
|
+
"cli": "wordcraft-cli",
|
|
181
|
+
"control": null,
|
|
182
|
+
"controlNote": "控制通道端口动态(mcp --connect HOST:PORT 桥接运行中的 app)",
|
|
183
|
+
"mcp": true,
|
|
184
|
+
"subcommands": [
|
|
185
|
+
{ "name": "convert", "usage": "convert <in> <out>", "summary": "格式互转:docx/doc(读)/pdf/odt/rtf/html/md/tex/txt/json/png" },
|
|
186
|
+
{ "name": "info", "usage": "info <file>", "summary": "页数/字数/段落/属性 JSON" },
|
|
187
|
+
{ "name": "text", "usage": "text <file>", "summary": "纯文本提取" },
|
|
188
|
+
{ "name": "inspect", "usage": "inspect <file>", "summary": "文档结构 JSON" },
|
|
189
|
+
{ "name": "render", "usage": "render <file> <out.png> [--page N] [--scale S]", "summary": "页面渲染 PNG" },
|
|
190
|
+
{ "name": "run", "usage": "run [--file F | --template T] --cmd 'id={json}' [--cmd …] [--save OUT] [--print] [--author NAME]", "summary": "headless 命令(--author 给修订/批注署名)" },
|
|
191
|
+
{ "name": "commands", "usage": "commands [--json]", "summary": "全部命令清单" },
|
|
192
|
+
{ "name": "parity", "usage": "parity [--markdown]", "summary": "特性目录对照报告" },
|
|
193
|
+
{ "name": "zotero", "usage": "zotero <command> <file> [--cmd …] [--save OUT] [--trace] [--port P]", "summary": "Zotero 文献命令(需 Zotero 运行中):addEditCitation/addEditBibliography/addNote/refresh/removeCodes/setDocPrefs" },
|
|
194
|
+
{ "name": "mcp", "usage": "mcp [--connect HOST:PORT | --author NAME]", "summary": "stdio MCP(headless 或桥接运行中的 app)" }
|
|
195
|
+
]
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
"id": "deckcraft",
|
|
199
|
+
"name": "DeckCraft",
|
|
200
|
+
"tagline": "演示文稿与幻灯片",
|
|
201
|
+
"ref": "Microsoft PowerPoint",
|
|
202
|
+
"stage": "in development",
|
|
203
|
+
"repo": "https://github.com/storytold/deckcraft",
|
|
204
|
+
"docs": "https://getartcraft.com/apps/deckcraft",
|
|
205
|
+
"cli": "deckcraft-cli",
|
|
206
|
+
"control": null,
|
|
207
|
+
"controlNote": "控制通道端口动态:app --port PORT 启动后用 artcraft_control 的 port 参数直连",
|
|
208
|
+
"mcp": true,
|
|
209
|
+
"subcommands": [
|
|
210
|
+
{ "name": "info", "usage": "info FILE", "summary": "演示文稿摘要" },
|
|
211
|
+
{ "name": "render", "usage": "render (FILE | --sample) [--slide N | --all] [--scale S] [--edit] OUT", "summary": "幻灯片渲染 PNG(单页/全部)" },
|
|
212
|
+
{ "name": "convert", "usage": "convert IN OUT", "summary": "格式转换" },
|
|
213
|
+
{ "name": "run", "usage": "run [--in FILE | --sample] [--cmd ID[=JSON]]… [--save OUT] [--export OUT] [--print]", "summary": "headless 命令批处理" },
|
|
214
|
+
{ "name": "commands", "usage": "commands [FILTER]", "summary": "命令清单" },
|
|
215
|
+
{ "name": "describe", "usage": "describe COMMAND", "summary": "单命令详情" },
|
|
216
|
+
{ "name": "app", "usage": "app [--port PORT] COMMAND [JSON] | --method METHOD [JSON]", "summary": "调用运行中 app 的控制通道" },
|
|
217
|
+
{ "name": "mcp", "usage": "mcp [--connect PORT] [--sample]", "summary": "stdio MCP" }
|
|
218
|
+
]
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
"id": "gridcraft",
|
|
222
|
+
"name": "GridCraft",
|
|
223
|
+
"tagline": "电子表格与数据处理",
|
|
224
|
+
"ref": "Microsoft Excel",
|
|
225
|
+
"stage": "in development",
|
|
226
|
+
"repo": "https://github.com/storytold/gridcraft",
|
|
227
|
+
"docs": "https://getartcraft.com/apps/gridcraft",
|
|
228
|
+
"cli": "gridcraft-cli",
|
|
229
|
+
"control": null,
|
|
230
|
+
"controlNote": "控制通道端口动态(send <port> 直发)",
|
|
231
|
+
"mcp": true,
|
|
232
|
+
"subcommands": [
|
|
233
|
+
{ "name": "info", "usage": "info <file> [--json]", "summary": "工作表/已用范围/表格/图表/名称" },
|
|
234
|
+
{ "name": "convert", "usage": "convert <in> <out> [--sheet NAME]", "summary": "xlsx/csv/tsv/json/html 按扩展名互转" },
|
|
235
|
+
{ "name": "eval", "usage": "eval <formula> [--in FILE] [--sheet S] [--cell A1] [--json]", "summary": "求值公式" },
|
|
236
|
+
{ "name": "cat", "usage": "cat <file> [--range A1:D20] [--sheet S] [--formulas] [--csv]", "summary": "读单元格区域(可含公式)" },
|
|
237
|
+
{ "name": "run", "usage": "run [--in FILE | --sample NAME] [--cmd 'id={json}']… [--script FILE.jsonl] [--out FILE] [--print RANGE] [--quiet]", "summary": "headless 命令批处理(可输出文件/打印区域)" },
|
|
238
|
+
{ "name": "commands", "usage": "commands [--json] [--search X]", "summary": "命令清单" },
|
|
239
|
+
{ "name": "functions", "usage": "functions [--json] [--search X] [--category C]", "summary": "函数库清单" },
|
|
240
|
+
{ "name": "send", "usage": "send <port> <method> [json]", "summary": "向运行中 app 的控制通道直发一条方法" },
|
|
241
|
+
{ "name": "mcp", "usage": "mcp [--connect PORT] [--in FILE | --sample NAME]", "summary": "stdio MCP" }
|
|
242
|
+
]
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
"id": "cadcraft",
|
|
246
|
+
"name": "CADCraft",
|
|
247
|
+
"tagline": "计算机辅助设计与制图",
|
|
248
|
+
"ref": "Autodesk AutoCAD",
|
|
249
|
+
"stage": "in development",
|
|
250
|
+
"repo": "https://github.com/storytold/cadcraft",
|
|
251
|
+
"docs": "https://getartcraft.com/apps/cadcraft",
|
|
252
|
+
"cli": "cadcraft-cli",
|
|
253
|
+
"control": null,
|
|
254
|
+
"controlNote": "控制通道端口动态(mcp --connect HOST:PORT 桥接运行中的 app)",
|
|
255
|
+
"mcp": true,
|
|
256
|
+
"subcommands": [
|
|
257
|
+
{ "name": "info", "usage": "info FILE.dxf", "summary": "图纸摘要" },
|
|
258
|
+
{ "name": "convert", "usage": "convert IN.dxf OUT.(dxf|dwg|svg|png|pdf) [FRAMING]", "summary": "格式转换/出图" },
|
|
259
|
+
{ "name": "run", "usage": "run [FILE | --sample | --metric] [--script TEXT | --script-file F.scr] [--cmd 'id {json}']… [--save OUT.dxf] [--export OUT.(png|svg|pdf)] [FRAMING]", "summary": "headless 执行(支持 AutoCAD 风格 .scr 脚本)后存/出图" },
|
|
260
|
+
{ "name": "commands", "usage": "commands [FILTER]", "summary": "命令清单" },
|
|
261
|
+
{ "name": "sample", "usage": "sample (bracket|floorplan) OUT.(dxf|dwg|svg|png)", "summary": "生成示例图(支架/户型平面)" },
|
|
262
|
+
{ "name": "perf", "usage": "perf [N]", "summary": "性能基准" },
|
|
263
|
+
{ "name": "mcp", "usage": "mcp [--connect HOST:PORT]", "summary": "stdio MCP" },
|
|
264
|
+
{ "name": "FRAMING", "usage": "--window x0,y0,x1,y1 | --view extents|current", "summary": "出图取景:指定矩形(图形单位)或范围/当前视图" }
|
|
265
|
+
]
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
"id": "soundcraft",
|
|
269
|
+
"name": "SoundCraft",
|
|
270
|
+
"tagline": "音频录制、编辑与混音",
|
|
271
|
+
"ref": "Avid Pro Tools",
|
|
272
|
+
"stage": "in development",
|
|
273
|
+
"repo": "https://github.com/storytold/soundcraft",
|
|
274
|
+
"docs": "https://getartcraft.com/apps/soundcraft",
|
|
275
|
+
"cli": "soundcraft-cli",
|
|
276
|
+
"control": null,
|
|
277
|
+
"controlNote": "控制通道端口动态:app --port P 启动后用 artcraft_control 的 port 参数直连",
|
|
278
|
+
"mcp": true,
|
|
279
|
+
"subcommands": [
|
|
280
|
+
{ "name": "info", "usage": "info FILE", "summary": "音频文件或 .scraft 工程摘要" },
|
|
281
|
+
{ "name": "convert", "usage": "convert IN OUT [--bit-depth 16|24|32f] [--rate HZ] [--normalize]", "summary": "音频转换(位深/采样率/响度归一)" },
|
|
282
|
+
{ "name": "run", "usage": "run [--in S.scraft | --demo] [--cmd ID[=JSON]]… [--bounce OUT] [--start T --end T] [--save S.scraft] [--inspect]", "summary": "headless 命令批处理并 bounce(区间可选)" },
|
|
283
|
+
{ "name": "script", "usage": "script FILE [--in S | --demo] [--save S] [--bounce OUT]", "summary": "脚本批处理(每行 `ID JSON`)" },
|
|
284
|
+
{ "name": "commands", "usage": "commands [FILTER]", "summary": "命令清单" },
|
|
285
|
+
{ "name": "describe", "usage": "describe ID", "summary": "单命令详情" },
|
|
286
|
+
{ "name": "app", "usage": "app [--port P] METHOD [JSON]", "summary": "调用运行中 app 的控制通道" },
|
|
287
|
+
{ "name": "parity", "usage": "parity [--write PATH]", "summary": "特性对照报告(markdown)" },
|
|
288
|
+
{ "name": "plugins", "usage": "plugins", "summary": "内置插件清单" },
|
|
289
|
+
{ "name": "mcp", "usage": "mcp [--connect PORT] [--demo]", "summary": "stdio MCP" }
|
|
290
|
+
]
|
|
291
|
+
}
|
|
292
|
+
]
|
|
293
|
+
}
|
|
@@ -6,7 +6,12 @@
|
|
|
6
6
|
"lightcraft": "C:/Program Files/LightCraft",
|
|
7
7
|
"pdfcraft": "C:/Program Files/PdfCraft",
|
|
8
8
|
"effectcraft": "C:/Program Files/EffectCraft",
|
|
9
|
-
"designcraft": "C:/Program Files/DesignCraft"
|
|
9
|
+
"designcraft": "C:/Program Files/DesignCraft",
|
|
10
|
+
"wordcraft": "C:/Program Files/WordCraft",
|
|
11
|
+
"deckcraft": "C:/Program Files/DeckCraft",
|
|
12
|
+
"gridcraft": "C:/Program Files/GridCraft",
|
|
13
|
+
"cadcraft": "C:/Program Files/CADCraft",
|
|
14
|
+
"soundcraft": "C:/Program Files/SoundCraft"
|
|
10
15
|
},
|
|
11
16
|
"control": {
|
|
12
17
|
"filmcraft": 9876,
|
package/client.js
CHANGED
|
@@ -15,7 +15,7 @@ window.__ModuleLoader__.load({
|
|
|
15
15
|
|
|
16
16
|
const NS = 'artcraft';
|
|
17
17
|
const API = '/artcraft/api';
|
|
18
|
-
const LABELS = { photocraft: 'PhotoCraft', vectorcraft: 'VectorCraft', filmcraft: 'FilmCraft', lightcraft: 'LightCraft', pdfcraft: 'PdfCraft', effectcraft: 'EffectCraft', designcraft: 'DesignCraft' };
|
|
18
|
+
const LABELS = { photocraft: 'PhotoCraft', vectorcraft: 'VectorCraft', filmcraft: 'FilmCraft', lightcraft: 'LightCraft', pdfcraft: 'PdfCraft', effectcraft: 'EffectCraft', designcraft: 'DesignCraft', wordcraft: 'WordCraft', deckcraft: 'DeckCraft', gridcraft: 'GridCraft', cadcraft: 'CADCraft', soundcraft: 'SoundCraft' };
|
|
19
19
|
|
|
20
20
|
const CSS = `
|
|
21
21
|
.dshac-card { border: 1px solid var(--dsw-border-primary, rgba(128,128,128,.35)); border-radius: 10px; padding: 12px; font-size: 13px; line-height: 1.5; }
|
|
@@ -83,9 +83,12 @@ window.__ModuleLoader__.load({
|
|
|
83
83
|
const u = await api('/update/check');
|
|
84
84
|
if (!alive.current) return;
|
|
85
85
|
setUpd(u);
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
86
|
+
// 待重启优先于"有新版本":新包已在磁盘、运行中的还是旧代码,重启前不再误导
|
|
87
|
+
setOut(u.pendingRestart
|
|
88
|
+
? `✅ 已更新到 v${u.pendingVersion ?? u.diskVersion ?? '?'},请重启 Harness 完成更新(运行中的仍是 v${u.current},页面刷新不够)`
|
|
89
|
+
: u.updateAvailable
|
|
90
|
+
? `有新版本:v${u.latest}(当前 v${u.current}),安装方式:${u.mode === 'git' ? 'git 仓库' : 'npm 安装'}`
|
|
91
|
+
: `已是最新${u.latest ? '(npm latest v' + u.latest + ')' : ''}${u.note ? ' · ' + u.note : ''}`);
|
|
89
92
|
} catch (e) { if (alive.current) setOut('检查失败:' + String(e.message || e)); }
|
|
90
93
|
finally { if (alive.current) setBusy(''); }
|
|
91
94
|
}, []);
|
|
@@ -99,7 +102,11 @@ window.__ModuleLoader__.load({
|
|
|
99
102
|
// 不自动刷新/重启任何东西:本插件是 Host 半侧代码,生效 = 重启 Harness 进程
|
|
100
103
|
if (r.needRestart) {
|
|
101
104
|
setDone(true);
|
|
102
|
-
|
|
105
|
+
// 立即把"待重启"写进 upd(服务端事实),后续任何 checkUpdate/重挂载都会保持常驻横幅
|
|
106
|
+
setUpd((u) => (u
|
|
107
|
+
? { ...u, pendingRestart: true, pendingVersion: r.latest ?? u.pendingVersion, diskVersion: r.latest ?? u.diskVersion, updateAvailable: false }
|
|
108
|
+
: u));
|
|
109
|
+
setOut((r.output || '') + '\n\n✅ 更新已写入磁盘(v' + (r.latest ?? '?') + ')。生效方式:重启 DeepSeek Harness(进程级重启,页面刷新不够)。何时重启由你决定。');
|
|
103
110
|
}
|
|
104
111
|
} catch (e) { if (alive.current) setOut('更新失败:' + String(e.message || e)); }
|
|
105
112
|
finally { if (alive.current) setBusy(''); }
|
|
@@ -134,6 +141,7 @@ window.__ModuleLoader__.load({
|
|
|
134
141
|
h('div', { className: 'dshac-row', style: { marginTop: '10px' } },
|
|
135
142
|
h('span', { className: 'dshac-muted' },
|
|
136
143
|
'当前 v' + (status?.version ?? upd?.current ?? '?') +
|
|
144
|
+
(upd?.pendingRestart ? '(磁盘已是 v' + (upd.pendingVersion ?? upd.diskVersion ?? '?') + ',待重启)' : '') +
|
|
137
145
|
(upd ? ' · npm latest v' + (upd.latest ?? '—') : '') +
|
|
138
146
|
(upd?.mode ? '(' + (upd.mode === 'git' ? 'git 仓库' + (upd.gitClean === false ? ' · 有本地改动' : '') : 'npm 安装') + ')' : '')),
|
|
139
147
|
h('button', { className: 'dshac-btn primary', onClick: checkUpdate, disabled: busy !== '' },
|
|
@@ -141,11 +149,11 @@ window.__ModuleLoader__.load({
|
|
|
141
149
|
h('button', {
|
|
142
150
|
className: 'dshac-btn',
|
|
143
151
|
onClick: applyUpdate,
|
|
144
|
-
disabled: busy !== '' || !upd?.updateAvailable,
|
|
145
|
-
title: upd?.updateAvailable ? '' : '有新版本时才可应用',
|
|
152
|
+
disabled: busy !== '' || !upd?.updateAvailable || upd?.pendingRestart,
|
|
153
|
+
title: upd?.pendingRestart ? '更新已写入磁盘,重启 Harness 后生效' : (upd?.updateAvailable ? '' : '有新版本时才可应用'),
|
|
146
154
|
}, busy === 'apply' ? '更新中…' : '一键更新')),
|
|
147
|
-
done ? h('div', { className: 'dshac-note' },
|
|
148
|
-
'
|
|
155
|
+
(upd?.pendingRestart || done) ? h('div', { className: 'dshac-note' },
|
|
156
|
+
'✅ 新版已写入磁盘,请重启 DeepSeek Harness 以完成更新(进程级重启,页面刷新不够)。重启后这里会显示新版本,何时重启由你决定 —— 更新不会打断正在运行的任务。') : null,
|
|
149
157
|
out ? h('div', { className: 'dshac-out' }, out) : null,
|
|
150
158
|
);
|
|
151
159
|
}
|
package/index.js
CHANGED
|
@@ -8,11 +8,12 @@
|
|
|
8
8
|
*
|
|
9
9
|
* 两种形态:
|
|
10
10
|
* 1) Agent Tools(对话内直接驱动):
|
|
11
|
-
* artcraft_status —— 检查
|
|
12
|
-
* artcraft_cli —— 运行
|
|
13
|
-
* artcraft_control —— 向运行中的 FilmCraft/EffectCraft JSON 控制通道发一条命令
|
|
11
|
+
* artcraft_status —— 检查 12 个家族 CLI 是否可用、配置目录、控制通道配置
|
|
12
|
+
* artcraft_cli —— 运行 12 个家族 CLI 任意命令(cwd / 文件参数由调用方给绝对路径)
|
|
13
|
+
* artcraft_control —— 向运行中的 FilmCraft/EffectCraft/VectorCraft/LightCraft JSON 控制通道发一条命令
|
|
14
14
|
* artcraft_fs —— 桥接文件操作(list/stat/readtext/write/mkdir,绝对路径)
|
|
15
15
|
* artcraft_update —— 插件自身更新(检查/应用)
|
|
16
|
+
* artcraft_apps —— 12 个家族应用的自动化能力目录(子命令/控制端口/MCP/仓库)
|
|
16
17
|
* 2) HTTP API(同源 /artcraft/api/*,供无限画布等前端调用,无 CORS 问题):
|
|
17
18
|
* GET /artcraft/api/status 环境自检
|
|
18
19
|
* GET /artcraft/api/fs list / stat / readtext
|
|
@@ -22,11 +23,14 @@
|
|
|
22
23
|
* POST /artcraft/api/job 启动长任务(渲染/导出/批处理)
|
|
23
24
|
* POST /artcraft/api/job/cancel 取消任务
|
|
24
25
|
* POST /artcraft/api/control 控制通道同步调用(engine.execute / ui.*)
|
|
26
|
+
* GET /artcraft/api/apps 家族能力目录(list / ?id= 单个)
|
|
25
27
|
*
|
|
26
28
|
* 安全约定:
|
|
27
|
-
* - 子进程只允许
|
|
29
|
+
* - 子进程只允许 12 个白名单键(家族 CLI),具体可执行文件由 artcraft.config.json 指定;
|
|
28
30
|
* - 控制通道只连 127.0.0.1,与 ArtCraft 官方协议一致(App 需以 --control 启动;
|
|
29
|
-
*
|
|
31
|
+
* 已知默认端口:filmcraft 9876 / effectcraft 9877 / vectorcraft 7979 / lightcraft 7980;
|
|
32
|
+
* PhotoCraft 控制通道为令牌鉴权模式、PdfCraft 为文件式(--control FILE),均不代理;
|
|
33
|
+
* 其余应用端口动态,用 port 参数直连);
|
|
30
34
|
* - 本插件与 infinite-canvas 零代码耦合,仅通过 HTTP + 调用方给定路径协作。
|
|
31
35
|
*
|
|
32
36
|
* 信任模型:HTTP API 无鉴权,随 DSH Web GUI 仅监听回环;不要把 GUI 端口暴露到局域网。
|
|
@@ -42,12 +46,15 @@ import crypto from 'node:crypto';
|
|
|
42
46
|
import { fileURLToPath } from 'node:url';
|
|
43
47
|
|
|
44
48
|
const NAME = 'artcraft';
|
|
45
|
-
const VERSION = '0.2.
|
|
49
|
+
const VERSION = '0.2.10';
|
|
46
50
|
const HERE = path.dirname(fileURLToPath(import.meta.url));
|
|
47
51
|
|
|
48
|
-
const BINS = [
|
|
52
|
+
const BINS = [
|
|
53
|
+
'photocraft', 'vectorcraft', 'filmcraft', 'lightcraft', 'pdfcraft', 'effectcraft',
|
|
54
|
+
'designcraft', 'wordcraft', 'deckcraft', 'gridcraft', 'cadcraft', 'soundcraft',
|
|
55
|
+
];
|
|
49
56
|
const PKG_NAME = '@ninkch/dsh-artcraft';
|
|
50
|
-
const DEFAULT_PORTS = { filmcraft: 9876, effectcraft: 9877 };
|
|
57
|
+
const DEFAULT_PORTS = { filmcraft: 9876, effectcraft: 9877, vectorcraft: 7979, lightcraft: 7980 };
|
|
51
58
|
|
|
52
59
|
const BODY_CAP = 2 * 1024 * 1024; // 普通 JSON 请求体上限
|
|
53
60
|
const WRITE_CAP = 320 * 1024 * 1024; // 上传(写盘)上限
|
|
@@ -66,13 +73,20 @@ const DEFAULT_CONFIG = {
|
|
|
66
73
|
pdfcraft: 'pdfcraft-cli',
|
|
67
74
|
effectcraft: 'effectcraft-cli',
|
|
68
75
|
designcraft: 'designcraft-cli',
|
|
76
|
+
wordcraft: 'wordcraft-cli',
|
|
77
|
+
deckcraft: 'deckcraft-cli',
|
|
78
|
+
gridcraft: 'gridcraft-cli',
|
|
79
|
+
cadcraft: 'cadcraft-cli',
|
|
80
|
+
soundcraft: 'soundcraft-cli',
|
|
69
81
|
},
|
|
70
82
|
control: { ...DEFAULT_PORTS },
|
|
71
83
|
};
|
|
72
84
|
|
|
73
85
|
const APP_DISPLAY = {
|
|
74
86
|
photocraft: 'PhotoCraft', vectorcraft: 'VectorCraft', filmcraft: 'FilmCraft',
|
|
75
|
-
lightcraft: 'LightCraft', pdfcraft: 'PdfCraft', effectcraft: 'EffectCraft',
|
|
87
|
+
lightcraft: 'LightCraft', pdfcraft: 'PdfCraft', effectcraft: 'EffectCraft',
|
|
88
|
+
designcraft: 'DesignCraft', wordcraft: 'WordCraft', deckcraft: 'DeckCraft',
|
|
89
|
+
gridcraft: 'GridCraft', cadcraft: 'CADCraft', soundcraft: 'SoundCraft',
|
|
76
90
|
};
|
|
77
91
|
|
|
78
92
|
/* ============================ 配置 ============================ */
|
|
@@ -606,10 +620,22 @@ async function updateCheck() {
|
|
|
606
620
|
const current = VERSION;
|
|
607
621
|
const { latest, note } = await fetchLatestVersion();
|
|
608
622
|
const info = await detectInstall();
|
|
623
|
+
// 磁盘版本 vs 运行版本:apply 已把新包写进磁盘(换目录 / git pull),但运行中的进程还是旧代码 ——
|
|
624
|
+
// 只对比 npm 版本号会让"一键更新后"看起来又回到有新版本。把"待重启"作为服务端事实返回,
|
|
625
|
+
// 前端据此常驻提示,卡片重挂载/页面刷新都不丢,真重启后(磁盘=运行)自动消失。
|
|
626
|
+
let diskVersion = null;
|
|
627
|
+
try {
|
|
628
|
+
const pj = JSON.parse(await fs.readFile(path.join(HERE, 'package.json'), 'utf8'));
|
|
629
|
+
diskVersion = typeof pj?.version === 'string' ? pj.version : null;
|
|
630
|
+
} catch { /* 非关键 */ }
|
|
631
|
+
const pendingRestart = !!(diskVersion && diskVersion !== current);
|
|
609
632
|
return {
|
|
610
633
|
current,
|
|
611
634
|
latest,
|
|
635
|
+
diskVersion,
|
|
612
636
|
updateAvailable: !!(latest && semverGt(latest, current)),
|
|
637
|
+
pendingRestart,
|
|
638
|
+
pendingVersion: pendingRestart ? diskVersion : null,
|
|
613
639
|
mode: info.mode,
|
|
614
640
|
repoDir: info.repoDir,
|
|
615
641
|
gitClean: info.gitClean,
|
|
@@ -731,7 +757,7 @@ export function apply(ctx) {
|
|
|
731
757
|
|
|
732
758
|
attempt({
|
|
733
759
|
name: 'artcraft_status',
|
|
734
|
-
description: '检查 ArtCraft 家族
|
|
760
|
+
description: '检查 ArtCraft 家族 12 个 CLI 是否可用,报告配置目录、控制通道端口与任务状态。本插件只是桥接,产物路径由调用方决定。',
|
|
735
761
|
schema: { type: 'object', properties: {}, additionalProperties: false },
|
|
736
762
|
async execute() {
|
|
737
763
|
const cfg = await loadConfig();
|
|
@@ -741,7 +767,7 @@ export function apply(ctx) {
|
|
|
741
767
|
|
|
742
768
|
attempt({
|
|
743
769
|
name: 'artcraft_cli',
|
|
744
|
-
description: '运行 ArtCraft 家族 CLI 的任意子命令(photocraft-cli /
|
|
770
|
+
description: '运行 ArtCraft 家族 CLI 的任意子命令(photocraft-cli / wordcraft-cli / soundcraft-cli 等 12 个,bin 参数的 enum 即完整清单)。长渲染请改用 HTTP POST /artcraft/api/job 后台执行。',
|
|
745
771
|
schema: {
|
|
746
772
|
type: 'object',
|
|
747
773
|
properties: {
|
|
@@ -765,24 +791,25 @@ export function apply(ctx) {
|
|
|
765
791
|
|
|
766
792
|
attempt({
|
|
767
793
|
name: 'artcraft_control',
|
|
768
|
-
description: '向运行中的
|
|
794
|
+
description: '向运行中的 ArtCraft JSON 控制通道发送一条命令(同族 JSON-lines 协议:engine.execute / engine.commands / ui.inspect / ui.screenshot…)。已知默认端口:filmcraft(--control 9876) / effectcraft(9877) / vectorcraft(7979) / lightcraft(7980);其余应用端口动态,可传 port 直连。PhotoCraft 控制通道为令牌鉴权模式、PdfCraft 为文件式,不在代理范围。',
|
|
769
795
|
schema: {
|
|
770
796
|
type: 'object',
|
|
771
797
|
properties: {
|
|
772
|
-
app: { type: 'string', enum: ['filmcraft', 'effectcraft'], description: '
|
|
773
|
-
|
|
798
|
+
app: { type: 'string', enum: ['filmcraft', 'effectcraft', 'vectorcraft', 'lightcraft'], description: '目标应用(决定默认端口)' },
|
|
799
|
+
port: { type: 'number', description: '可选:直接指定端口(覆盖 app 默认;用于端口动态的应用)' },
|
|
800
|
+
method: { type: 'string', description: '如 engine.execute / engine.commands / ui.inspect / ui.screenshot' },
|
|
774
801
|
params: { type: 'object', description: '命令参数' },
|
|
775
802
|
timeoutMs: { type: 'number' },
|
|
776
803
|
},
|
|
777
|
-
required: ['
|
|
804
|
+
required: ['method'],
|
|
778
805
|
additionalProperties: false,
|
|
779
806
|
},
|
|
780
807
|
async execute(args) {
|
|
781
808
|
const cfg = await loadConfig();
|
|
782
|
-
const port = cfg.control[String(args.app)];
|
|
783
|
-
if (!port) throw new Error(
|
|
809
|
+
const port = Number(args.port) > 0 ? Number(args.port) : cfg.control[String(args.app ?? '')];
|
|
810
|
+
if (!(Number(port) > 0)) throw new Error('需要 app (filmcraft|effectcraft|vectorcraft|lightcraft) 或 port');
|
|
784
811
|
const result = await controlCall(port, String(args.method), args.params ?? {}, { timeoutMs: args.timeoutMs });
|
|
785
|
-
return { app: args.app, port, method: args.method, result };
|
|
812
|
+
return { app: args.app ?? null, port, method: args.method, result };
|
|
786
813
|
},
|
|
787
814
|
});
|
|
788
815
|
|
|
@@ -918,6 +945,35 @@ export function apply(ctx) {
|
|
|
918
945
|
},
|
|
919
946
|
});
|
|
920
947
|
|
|
948
|
+
attempt({
|
|
949
|
+
name: 'artcraft_apps',
|
|
950
|
+
description: 'ArtCraft 家族 12 应用的自动化能力目录:每个应用的定位、对标软件、CLI 子命令用法、控制通道端口、MCP 可用性与仓库/文档链接。action=list 列出全部;action=get + id 取单个应用的完整能力卡。要拿某应用的实时命令注册表,用 artcraft_cli 跑该应用的 commands 子命令。',
|
|
951
|
+
schema: {
|
|
952
|
+
type: 'object',
|
|
953
|
+
properties: {
|
|
954
|
+
action: { type: 'string', enum: ['list', 'get'] },
|
|
955
|
+
id: { type: 'string', description: 'action=get 时的应用 id(如 wordcraft)' },
|
|
956
|
+
},
|
|
957
|
+
required: ['action'],
|
|
958
|
+
additionalProperties: false,
|
|
959
|
+
},
|
|
960
|
+
async execute(args) {
|
|
961
|
+
const catalogPath = path.join(HERE, 'apps', 'catalog.json');
|
|
962
|
+
const catalog = JSON.parse(await fs.readFile(catalogPath, 'utf8'));
|
|
963
|
+
if (String(args.action) === 'get') {
|
|
964
|
+
const a = catalog.apps.find((x) => x.id === String(args.id ?? ''));
|
|
965
|
+
if (!a) throw new Error('应用不存在: ' + args.id + '(可用: ' + catalog.apps.map((x) => x.id).join(', ') + ')');
|
|
966
|
+
return a;
|
|
967
|
+
}
|
|
968
|
+
return {
|
|
969
|
+
version: catalog.version,
|
|
970
|
+
controlProtocol: catalog.controlProtocol,
|
|
971
|
+
apps: catalog.apps.map((a) => ({ id: a.id, name: a.name, tagline: a.tagline, ref: a.ref, cli: a.cli, control: a.control, mcp: a.mcp, stage: a.stage })),
|
|
972
|
+
hint: 'action=get + id 取完整能力卡(子命令用法 + 控制端口 + 仓库/文档链接)',
|
|
973
|
+
};
|
|
974
|
+
},
|
|
975
|
+
});
|
|
976
|
+
|
|
921
977
|
return () => {
|
|
922
978
|
for (const d of disposers) { try { d(); } catch { /* ignore */ } }
|
|
923
979
|
};
|
|
@@ -1094,12 +1150,30 @@ export function apply(ctx) {
|
|
|
1094
1150
|
});
|
|
1095
1151
|
}),
|
|
1096
1152
|
|
|
1153
|
+
makeRoute(`/${NAME}/api/apps`, async (req, res) => {
|
|
1154
|
+
if (req.method !== 'GET') throw new Error('仅支持 GET');
|
|
1155
|
+
const url = new URL(req.url, 'http://x');
|
|
1156
|
+
const id = url.searchParams.get('id');
|
|
1157
|
+
const catalog = JSON.parse(await fs.readFile(path.join(HERE, 'apps', 'catalog.json'), 'utf8'));
|
|
1158
|
+
if (id) {
|
|
1159
|
+
const a = catalog.apps.find((x) => x.id === id);
|
|
1160
|
+
if (!a) throw new Error('应用不存在: ' + id + '(可用: ' + catalog.apps.map((x) => x.id).join(', ') + ')');
|
|
1161
|
+
sendJson(res, 200, a);
|
|
1162
|
+
return;
|
|
1163
|
+
}
|
|
1164
|
+
sendJson(res, 200, {
|
|
1165
|
+
version: catalog.version,
|
|
1166
|
+
controlProtocol: catalog.controlProtocol,
|
|
1167
|
+
apps: catalog.apps.map((a) => ({ id: a.id, name: a.name, tagline: a.tagline, ref: a.ref, cli: a.cli, control: a.control, mcp: a.mcp, stage: a.stage })),
|
|
1168
|
+
});
|
|
1169
|
+
}),
|
|
1170
|
+
|
|
1097
1171
|
makeRoute(`/${NAME}/api/control`, async (req, res) => {
|
|
1098
1172
|
if (req.method !== 'POST') throw new Error('仅支持 POST');
|
|
1099
1173
|
const cfg = await loadConfig();
|
|
1100
1174
|
const body = await readJson(req);
|
|
1101
1175
|
const port = body.port ?? cfg.control[String(body.app ?? '')];
|
|
1102
|
-
if (!(Number(port) > 0)) throw new Error('需要 app (filmcraft|effectcraft) 或 port');
|
|
1176
|
+
if (!(Number(port) > 0)) throw new Error('需要 app (filmcraft|effectcraft|vectorcraft|lightcraft) 或 port');
|
|
1103
1177
|
const result = await controlCall(
|
|
1104
1178
|
Number(port),
|
|
1105
1179
|
String(body.method),
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ninkch/dsh-artcraft",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.10",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"description": "Drive the open-source ArtCraft studio apps
|
|
5
|
+
"description": "Drive the open-source ArtCraft studio suite (12 family apps: PhotoCraft, VectorCraft, FilmCraft, LightCraft, PdfCraft, EffectCraft, DesignCraft, WordCraft, DeckCraft, GridCraft, CADCraft, SoundCraft) from DeepSeek Harness: agent tools, a same-origin HTTP API, and plugins-page status with self-update.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"deepseek-harness",
|
|
8
8
|
"dsh-plugin",
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
"client.js",
|
|
36
36
|
"cordis.patch.yml",
|
|
37
37
|
"artcraft.config.json.example",
|
|
38
|
+
"apps",
|
|
38
39
|
"recipes",
|
|
39
40
|
"README.md",
|
|
40
41
|
"README.zh-CN.md",
|