paintress 0.2.2 → 0.3.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 +27 -7
- package/README.zh-CN.md +27 -7
- package/dist/cli.js +137 -39
- package/package.json +1 -1
- package/ui/dist/assets/index-WQnLS4sD.js +6 -0
- package/ui/dist/index.html +1 -1
- package/ui/dist/assets/index-CMZ78plm.js +0 -6
package/README.md
CHANGED
|
@@ -42,8 +42,8 @@ paintress install pi cursor # or only the ones you name
|
|
|
42
42
|
## CLI
|
|
43
43
|
|
|
44
44
|
```text
|
|
45
|
-
paintress mcp
|
|
46
|
-
paintress
|
|
45
|
+
paintress mcp start the stdio MCP server
|
|
46
|
+
paintress info <file> document summary
|
|
47
47
|
paintress query <file> [--type t] [--name n|--regex] find nodes
|
|
48
48
|
paintress get <file> <id> [--depth n] read a node subtree
|
|
49
49
|
paintress update <file> <id> '<patch-json>' shallow-merge attributes
|
|
@@ -84,8 +84,10 @@ Canvas navigation: wheel zooms at the pointer, space / middle button / empty are
|
|
|
84
84
|
| Claude Desktop | `~/.config/Claude/claude_desktop_config.json` | `mcpServers` |
|
|
85
85
|
| Cursor | `~/.cursor/mcp.json` | `mcpServers` |
|
|
86
86
|
| VS Code | `~/.config/Code/User/mcp.json` | `servers` (with `"type": "stdio"`) |
|
|
87
|
+
| Windsurf | `~/.codeium/windsurf/mcp_config.json` | `mcpServers` |
|
|
87
88
|
| Codex | `~/.codex/config.toml` | `[mcp_servers.paintress]` |
|
|
88
89
|
| pi | `~/.pi/agent/mcp.json` | `mcpServers` |
|
|
90
|
+
| OpenCode | `~/.config/opencode/opencode.json` | `mcp.servers` (current) or `mcp` (older; `command` is an array) |
|
|
89
91
|
|
|
90
92
|
```bash
|
|
91
93
|
paintress mcp-config cursor # print the exact snippet instead of editing files
|
|
@@ -129,6 +131,12 @@ Rules:
|
|
|
129
131
|
- Report the resolved path and version (`paintress ping` prints the daemon version when the viewer runs; `npm ls -g --depth=0 paintress` prints the package version).
|
|
130
132
|
- Only when every check is empty do you install (step 1).
|
|
131
133
|
|
|
134
|
+
If the install succeeded but `command -v paintress` still finds nothing (some version managers need a new shell), call it by full path — do not install a second copy:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
"$(npm prefix -g)/bin/paintress" doctor
|
|
138
|
+
```
|
|
139
|
+
|
|
132
140
|
### 1. Install (only if step 0 found nothing)
|
|
133
141
|
|
|
134
142
|
```bash
|
|
@@ -152,7 +160,9 @@ paintress install --dry-run # preview the writes
|
|
|
152
160
|
paintress install <client-id> # write only the client you are running in
|
|
153
161
|
```
|
|
154
162
|
|
|
155
|
-
Client ids: `claude`, `cursor`, `vscode`, `codex`, `pi`. Use `paintress install` without arguments to cover every detected client.
|
|
163
|
+
Client ids: `claude`, `cursor`, `vscode`, `windsurf`, `codex`, `pi`, `opencode`. Use `paintress install` without arguments to cover every detected client.
|
|
164
|
+
|
|
165
|
+
OpenCode has two config layouts in the wild. `install` follows whatever the existing file already uses and falls back to the current `mcp.servers` shape for a new file; force it with `--opencode-layout legacy` or `--opencode-layout v2`.
|
|
156
166
|
|
|
157
167
|
What the write does:
|
|
158
168
|
|
|
@@ -162,17 +172,27 @@ What the write does:
|
|
|
162
172
|
- is idempotent: an identical entry reports `noop` and nothing is written;
|
|
163
173
|
- uses the bare command `paintress` when it resolves on PATH, otherwise the absolute path of the binary.
|
|
164
174
|
|
|
165
|
-
If
|
|
175
|
+
### If your client is not in that list
|
|
176
|
+
|
|
177
|
+
The entry is small and nearly the same everywhere, so adapt it by hand:
|
|
178
|
+
|
|
179
|
+
1. Find where the client keeps its MCP servers — its own docs, an `/mcp` command, or a "configure MCP servers" menu item.
|
|
180
|
+
2. Match the shape. Most clients use a `mcpServers` object holding `command` + `args`; VS Code uses `servers` with `"type": "stdio"`; OpenCode puts a single `command` **array** under `mcp.servers` (older builds: under `mcp`) with `"type": "local"`; Codex uses a TOML table.
|
|
181
|
+
3. Print the closest snippet and edit it:
|
|
166
182
|
|
|
167
183
|
```bash
|
|
168
|
-
paintress mcp-config cursor
|
|
169
|
-
paintress mcp-config vscode
|
|
170
|
-
paintress mcp-config
|
|
184
|
+
paintress mcp-config cursor # JSON with mcpServers
|
|
185
|
+
paintress mcp-config vscode # JSON with servers + type: stdio
|
|
186
|
+
paintress mcp-config opencode # JSON with mcp.servers + command array
|
|
187
|
+
paintress mcp-config codex # TOML table
|
|
171
188
|
```
|
|
172
189
|
|
|
190
|
+
To make a client first-class (so `doctor` and `install` cover it), add one spec to `src/integrations/clients.ts` — `id`, `label`, `format`, `rootPath`, optional `typeValue` / `commandForm` / `extraFields`, and `configPath(home, platform, env)` — plus one test in `test/integrations.spec.ts`. No other file needs to change.
|
|
191
|
+
|
|
173
192
|
### 3. Install the skill (recommended)
|
|
174
193
|
|
|
175
194
|
```bash
|
|
195
|
+
mkdir -p <your-skill-dir>/paintress
|
|
176
196
|
cp "$(npm root -g)/paintress/skills/paintress/SKILL.md" <your-skill-dir>/paintress/SKILL.md
|
|
177
197
|
```
|
|
178
198
|
|
package/README.zh-CN.md
CHANGED
|
@@ -42,8 +42,8 @@ paintress install pi cursor # 或只写指定的客户端
|
|
|
42
42
|
## CLI
|
|
43
43
|
|
|
44
44
|
```text
|
|
45
|
-
paintress mcp
|
|
46
|
-
paintress
|
|
45
|
+
paintress mcp 启动 stdio MCP server
|
|
46
|
+
paintress info <file> 文档摘要
|
|
47
47
|
paintress query <file> [--type t] [--name n|--regex] 条件查询节点
|
|
48
48
|
paintress get <file> <id> [--depth n] 读取节点子树
|
|
49
49
|
paintress update <file> <id> '<patch-json>' 浅合并更新属性
|
|
@@ -84,8 +84,10 @@ paintress watch demo ./demo
|
|
|
84
84
|
| Claude Desktop | `~/.config/Claude/claude_desktop_config.json` | `mcpServers` |
|
|
85
85
|
| Cursor | `~/.cursor/mcp.json` | `mcpServers` |
|
|
86
86
|
| VS Code | `~/.config/Code/User/mcp.json` | `servers`(条目需 `"type": "stdio"`) |
|
|
87
|
+
| Windsurf | `~/.codeium/windsurf/mcp_config.json` | `mcpServers` |
|
|
87
88
|
| Codex | `~/.codex/config.toml` | `[mcp_servers.paintress]` |
|
|
88
89
|
| pi | `~/.pi/agent/mcp.json` | `mcpServers` |
|
|
90
|
+
| OpenCode | `~/.config/opencode/opencode.json` | `mcp.servers`(当前版)或 `mcp`(旧版;`command` 是数组) |
|
|
89
91
|
|
|
90
92
|
```bash
|
|
91
93
|
paintress mcp-config cursor # 只打印片段,不改文件
|
|
@@ -129,6 +131,12 @@ MIT
|
|
|
129
131
|
- 向用户报告解析到的路径与版本(查看器运行时 `paintress ping` 会打印版本;包版本用 `npm ls -g --depth=0 paintress`)。
|
|
130
132
|
- 只有在全部检查都为空时,才执行第 1 步。
|
|
131
133
|
|
|
134
|
+
如果安装成功但 `command -v paintress` 仍然找不到(某些版本管理器需要新开 shell),用完整路径调用,**不要因此再装一份**:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
"$(npm prefix -g)/bin/paintress" doctor
|
|
138
|
+
```
|
|
139
|
+
|
|
132
140
|
### 1. 安装(仅在检测全空时)
|
|
133
141
|
|
|
134
142
|
```bash
|
|
@@ -152,7 +160,9 @@ paintress install --dry-run # 预览将要写入的内容
|
|
|
152
160
|
paintress install <client-id> # 只写当前所在的客户端
|
|
153
161
|
```
|
|
154
162
|
|
|
155
|
-
客户端 id:`claude`、`cursor`、`vscode`、`codex`、`pi`。不带参数执行 `paintress install` 会覆盖所有检测到的客户端。
|
|
163
|
+
客户端 id:`claude`、`cursor`、`vscode`、`windsurf`、`codex`、`pi`、`opencode`。不带参数执行 `paintress install` 会覆盖所有检测到的客户端。
|
|
164
|
+
|
|
165
|
+
OpenCode 现在有两套配置布局:`install` 会跟随文件里既有的布局,新文件按官方当前的 `mcp.servers`;需要强制时用 `--opencode-layout legacy` 或 `--opencode-layout v2`。
|
|
156
166
|
|
|
157
167
|
写入行为:
|
|
158
168
|
|
|
@@ -162,17 +172,27 @@ paintress install <client-id> # 只写当前所在的客户端
|
|
|
162
172
|
- 幂等:条目已一致时返回 `noop`,不写磁盘;
|
|
163
173
|
- 当 `paintress` 能在 PATH 上解析时写裸命令,否则写可执行文件的绝对路径。
|
|
164
174
|
|
|
165
|
-
如果当前 agent
|
|
175
|
+
### 如果当前 agent 不在列表里
|
|
176
|
+
|
|
177
|
+
条目很小,各家格式几乎一致,直接照抄改写即可:
|
|
178
|
+
|
|
179
|
+
1. 先找到该客户端放 MCP server 的位置——查它自己的文档、`/mcp` 命令,或「配置 MCP 服务器」菜单项。
|
|
180
|
+
2. 对照格式:多数是 `mcpServers` 对象,里面 `command` + `args`;VS Code 是 `servers` 加 `"type": "stdio"`;OpenCode 的 `command` 是**数组**,放在 `mcp.servers` 下(旧版放 `mcp` 下)并带 `"type": "local"`;Codex 是 TOML 表。
|
|
181
|
+
3. 打印最接近的片段再改:
|
|
166
182
|
|
|
167
183
|
```bash
|
|
168
|
-
paintress mcp-config cursor
|
|
169
|
-
paintress mcp-config vscode
|
|
170
|
-
paintress mcp-config
|
|
184
|
+
paintress mcp-config cursor # JSON,顶层 mcpServers
|
|
185
|
+
paintress mcp-config vscode # JSON,顶层 servers + type: stdio
|
|
186
|
+
paintress mcp-config opencode # JSON,mcp.servers + command 数组
|
|
187
|
+
paintress mcp-config codex # TOML 表
|
|
171
188
|
```
|
|
172
189
|
|
|
190
|
+
想让某个客户端成为内置支持(`doctor`、`install` 都能覆盖),只需在 `src/integrations/clients.ts` 里加一条配置:`id`、`label`、`format`、`rootPath`,以及可选的 `typeValue` / `commandForm` / `extraFields` 和 `configPath(home, platform, env)`,再在 `test/integrations.spec.ts` 加一个测试。其他文件都不用动。
|
|
191
|
+
|
|
173
192
|
### 3. 安装 skill(建议)
|
|
174
193
|
|
|
175
194
|
```bash
|
|
195
|
+
mkdir -p <技能目录>/paintress
|
|
176
196
|
cp "$(npm root -g)/paintress/skills/paintress/SKILL.md" <技能目录>/paintress/SKILL.md
|
|
177
197
|
```
|
|
178
198
|
|
package/dist/cli.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { a as isDaemonRunning, c as pidPath, d as sanitizeProjectName, f as socketPath, i as attachPersistent, l as resolveProjectDir, m as encodeLine, n as runStdioServer, o as sendRequest, p as LineDecoder, r as TOOLS, s as lockPath, u as safeJoin } from "./server-C4TC8Bw3.js";
|
|
3
3
|
import { Wt as VERSION, t as renderDocument, w as loadDoc } from "./render-CbYe9rII.js";
|
|
4
4
|
import "./index.js";
|
|
5
|
-
import { closeSync, copyFileSync, existsSync, mkdirSync, openSync, readFileSync, readdirSync, realpathSync, renameSync, statSync, unlinkSync, writeFileSync } from "node:fs";
|
|
5
|
+
import { chmodSync, closeSync, copyFileSync, existsSync, mkdirSync, openSync, readFileSync, readdirSync, realpathSync, renameSync, statSync, unlinkSync, writeFileSync } from "node:fs";
|
|
6
6
|
import { homedir } from "node:os";
|
|
7
7
|
import { fileURLToPath } from "node:url";
|
|
8
8
|
import { dirname, extname, join, relative, resolve } from "node:path";
|
|
@@ -845,14 +845,21 @@ async function startDaemon(opts = {}) {
|
|
|
845
845
|
};
|
|
846
846
|
}
|
|
847
847
|
// src/integrations/clients.ts
|
|
848
|
+
/**
|
|
849
|
+
* 多客户端接入(阶段 5):把「paintress mcp」这条 stdio 命令写进各家 agent 的配置。
|
|
850
|
+
*
|
|
851
|
+
* 设计要点:
|
|
852
|
+
* - 只认「已知客户端 + 已知路径」,不做全盘扫描;
|
|
853
|
+
* - 生成条目与写入分离:解析/生成是纯函数(可单测),落盘只在 apply 阶段发生;
|
|
854
|
+
* - 路径由 home / platform / env 注入,测试不依赖真实文件系统。
|
|
855
|
+
*/
|
|
848
856
|
const posixHome = (home) => home.replace(/\/+$/, "");
|
|
849
857
|
const CLIENTS = [
|
|
850
858
|
{
|
|
851
859
|
id: "claude",
|
|
852
860
|
label: "Claude Desktop",
|
|
853
861
|
format: "json",
|
|
854
|
-
|
|
855
|
-
needsType: false,
|
|
862
|
+
rootPath: ["mcpServers"],
|
|
856
863
|
configPath: (home, platform, env) => {
|
|
857
864
|
if (platform === "darwin") return `${posixHome(home)}/Library/Application Support/Claude/claude_desktop_config.json`;
|
|
858
865
|
if (platform === "win32") return `${env["APPDATA"] ?? posixHome(home)}/Claude/claude_desktop_config.json`;
|
|
@@ -863,43 +870,68 @@ const CLIENTS = [
|
|
|
863
870
|
id: "cursor",
|
|
864
871
|
label: "Cursor",
|
|
865
872
|
format: "json",
|
|
866
|
-
|
|
867
|
-
needsType: false,
|
|
873
|
+
rootPath: ["mcpServers"],
|
|
868
874
|
configPath: (home) => `${posixHome(home)}/.cursor/mcp.json`
|
|
869
875
|
},
|
|
870
876
|
{
|
|
871
877
|
id: "vscode",
|
|
872
878
|
label: "VS Code",
|
|
873
879
|
format: "json",
|
|
874
|
-
|
|
875
|
-
|
|
880
|
+
rootPath: ["servers"],
|
|
881
|
+
typeValue: "stdio",
|
|
876
882
|
configPath: (home, platform, env) => {
|
|
877
883
|
if (platform === "darwin") return `${posixHome(home)}/Library/Application Support/Code/User/mcp.json`;
|
|
878
884
|
if (platform === "win32") return `${env["APPDATA"] ?? posixHome(home)}/Code/User/mcp.json`;
|
|
879
885
|
return `${posixHome(home)}/.config/Code/User/mcp.json`;
|
|
880
886
|
}
|
|
881
887
|
},
|
|
888
|
+
{
|
|
889
|
+
id: "windsurf",
|
|
890
|
+
label: "Windsurf",
|
|
891
|
+
format: "json",
|
|
892
|
+
rootPath: ["mcpServers"],
|
|
893
|
+
configPath: (home, platform, env) => {
|
|
894
|
+
return `${platform === "win32" ? env["USERPROFILE"] ?? posixHome(home) : posixHome(home)}/.codeium/windsurf/mcp_config.json`;
|
|
895
|
+
}
|
|
896
|
+
},
|
|
882
897
|
{
|
|
883
898
|
id: "codex",
|
|
884
899
|
label: "Codex",
|
|
885
900
|
format: "toml",
|
|
886
|
-
|
|
887
|
-
needsType: false,
|
|
901
|
+
rootPath: ["mcp_servers"],
|
|
888
902
|
configPath: (home) => `${posixHome(home)}/.codex/config.toml`
|
|
889
903
|
},
|
|
890
904
|
{
|
|
891
905
|
id: "pi",
|
|
892
906
|
label: "pi",
|
|
893
907
|
format: "json",
|
|
894
|
-
|
|
895
|
-
needsType: false,
|
|
908
|
+
rootPath: ["mcpServers"],
|
|
896
909
|
configPath: (home) => `${posixHome(home)}/.pi/agent/mcp.json`
|
|
910
|
+
},
|
|
911
|
+
{
|
|
912
|
+
id: "opencode",
|
|
913
|
+
label: "OpenCode",
|
|
914
|
+
format: "json",
|
|
915
|
+
rootPath: ["mcp", "servers"],
|
|
916
|
+
typeValue: "local",
|
|
917
|
+
commandForm: "command-array",
|
|
918
|
+
configPath: (home, _platform, env) => {
|
|
919
|
+
return `${env["XDG_CONFIG_HOME"] ?? `${posixHome(home)}/.config`}/opencode/opencode.json`;
|
|
920
|
+
}
|
|
897
921
|
}
|
|
898
922
|
];
|
|
899
923
|
function findClient(id) {
|
|
900
924
|
return CLIENTS.find((c) => c.id === id);
|
|
901
925
|
}
|
|
902
926
|
/**
|
|
927
|
+
* 客户端是否已在本机出现过:配置目录存在即视为已安装/已使用。
|
|
928
|
+
* 不依赖可执行文件是否在 PATH(GUI 客户端通常不在 PATH),也不扫全盘。
|
|
929
|
+
*/
|
|
930
|
+
function isClientDetected(spec, home, platform, env, exists) {
|
|
931
|
+
const path = spec.configPath(home, platform, env);
|
|
932
|
+
return exists(path) || exists(dirname(path));
|
|
933
|
+
}
|
|
934
|
+
/**
|
|
903
935
|
* 决定写进配置的启动命令。
|
|
904
936
|
*
|
|
905
937
|
* - 若 `paintress` 已经在 PATH 上指向当前可执行文件(全局安装的常见情形)→ 用裸命令,
|
|
@@ -937,33 +969,84 @@ function resolveLaunchCommand(opts) {
|
|
|
937
969
|
args: ["mcp"]
|
|
938
970
|
};
|
|
939
971
|
}
|
|
940
|
-
/**
|
|
941
|
-
function buildEntry(spec, launch) {
|
|
942
|
-
const
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
972
|
+
/** 单个客户端的配置条目;OpenCode 旧布局还需要 enabled: true */
|
|
973
|
+
function buildEntry(spec, launch, layout = "auto") {
|
|
974
|
+
const entry = {};
|
|
975
|
+
if (spec.typeValue !== void 0) entry["type"] = spec.typeValue;
|
|
976
|
+
if (spec.commandForm === "command-array") entry["command"] = [launch.command, ...launch.args];
|
|
977
|
+
else {
|
|
978
|
+
entry["command"] = launch.command;
|
|
979
|
+
entry["args"] = launch.args;
|
|
980
|
+
}
|
|
981
|
+
if (spec.extraFields !== void 0) Object.assign(entry, spec.extraFields);
|
|
982
|
+
if (spec.id === "opencode" && layout === "legacy") entry["enabled"] = true;
|
|
983
|
+
return entry;
|
|
984
|
+
}
|
|
985
|
+
function isRecord$1(value) {
|
|
986
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
987
|
+
}
|
|
988
|
+
/**
|
|
989
|
+
* 解析 server 表在配置里的路径。
|
|
990
|
+
*
|
|
991
|
+
* OpenCode 有两套布局:V2 把 server 放在 `mcp.servers` 下,旧布局直接放在 `mcp` 下。
|
|
992
|
+
* 已有文件按实际内容判断(避免把条目写到当前版本不读的位置),新文件用官方当前的 V2。
|
|
993
|
+
*/
|
|
994
|
+
function resolveRootPath(spec, existingRoot, layout = "auto") {
|
|
995
|
+
if (spec.id !== "opencode") return spec.rootPath;
|
|
996
|
+
if (layout === "legacy") return ["mcp"];
|
|
997
|
+
if (layout === "v2") return ["mcp", "servers"];
|
|
998
|
+
const mcp = existingRoot?.["mcp"];
|
|
999
|
+
if (isRecord$1(mcp)) {
|
|
1000
|
+
if (isRecord$1(mcp["servers"])) return ["mcp", "servers"];
|
|
1001
|
+
if (Object.values(mcp).some((v) => isRecord$1(v) && (typeof v["type"] === "string" || "command" in v))) return ["mcp"];
|
|
1002
|
+
}
|
|
1003
|
+
return ["mcp", "servers"];
|
|
950
1004
|
}
|
|
951
1005
|
/** Codex 用的 TOML 片段(改 TOML 风险高,只输出不写入) */
|
|
952
1006
|
function tomlSnippet(launch, name = "paintress") {
|
|
953
|
-
const args = launch.args.map((a) =>
|
|
954
|
-
return `[mcp_servers.${name}]\ncommand =
|
|
1007
|
+
const args = launch.args.map((a) => JSON.stringify(a)).join(", ");
|
|
1008
|
+
return `[mcp_servers.${name}]\ncommand = ${JSON.stringify(launch.command)}\nargs = [${args}]\n`;
|
|
955
1009
|
}
|
|
956
|
-
/** JSON
|
|
1010
|
+
/** JSON 客户端用的片段(含嵌套路径,OpenCode 按默认布局) */
|
|
957
1011
|
function jsonSnippet(spec, launch, name = "paintress") {
|
|
958
|
-
|
|
1012
|
+
const path = resolveRootPath(spec, null);
|
|
1013
|
+
const entry = buildEntry(spec, launch, path.length === 1 ? "legacy" : "v2");
|
|
1014
|
+
let cursor = { [name]: entry };
|
|
1015
|
+
for (const key of [...path].reverse()) cursor = { [key]: cursor };
|
|
1016
|
+
return JSON.stringify(cursor, null, 2);
|
|
959
1017
|
}
|
|
960
1018
|
// src/integrations/install.ts
|
|
961
1019
|
/**
|
|
962
1020
|
* 配置写入:解析 → 合并 → 备份 → 原子落盘。
|
|
963
1021
|
* 只动 `rootKey` 下名为 `paintress` 的那一条,其余内容与顺序保持不变(JSON 重新序列化)。
|
|
964
1022
|
*/
|
|
1023
|
+
function isRecord(value) {
|
|
1024
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1025
|
+
}
|
|
1026
|
+
/** 按路径取出 server 表(不存在或类型不对时返回空对象) */
|
|
1027
|
+
function readTable(root, path) {
|
|
1028
|
+
let cursor = root;
|
|
1029
|
+
for (const key of path) {
|
|
1030
|
+
if (!isRecord(cursor)) return {};
|
|
1031
|
+
cursor = cursor[key];
|
|
1032
|
+
}
|
|
1033
|
+
return isRecord(cursor) ? { ...cursor } : {};
|
|
1034
|
+
}
|
|
1035
|
+
/** 按路径写回 server 表,沿途缺失的层级补建,其余键原样保留 */
|
|
1036
|
+
function writeTable(root, path, table) {
|
|
1037
|
+
let cursor = root;
|
|
1038
|
+
path.forEach((key, index) => {
|
|
1039
|
+
if (index === path.length - 1) {
|
|
1040
|
+
cursor[key] = table;
|
|
1041
|
+
return;
|
|
1042
|
+
}
|
|
1043
|
+
const next = isRecord(cursor[key]) ? { ...cursor[key] } : {};
|
|
1044
|
+
cursor[key] = next;
|
|
1045
|
+
cursor = next;
|
|
1046
|
+
});
|
|
1047
|
+
}
|
|
965
1048
|
/** 纯函数:把 paintress 条目并入现有配置文本 */
|
|
966
|
-
function planJsonMerge(spec, path, existing, launch) {
|
|
1049
|
+
function planJsonMerge(spec, path, existing, launch, options = {}) {
|
|
967
1050
|
const base = {
|
|
968
1051
|
spec,
|
|
969
1052
|
path,
|
|
@@ -972,14 +1055,14 @@ function planJsonMerge(spec, path, existing, launch) {
|
|
|
972
1055
|
detail: ""
|
|
973
1056
|
};
|
|
974
1057
|
if (spec.format === "toml") {
|
|
975
|
-
const snippet =
|
|
1058
|
+
const snippet = tomlSnippet(launch);
|
|
976
1059
|
if (existing === null) return {
|
|
977
1060
|
...base,
|
|
978
1061
|
status: "create",
|
|
979
1062
|
next: snippet,
|
|
980
1063
|
detail: "将创建配置文件并写入条目"
|
|
981
1064
|
};
|
|
982
|
-
if (
|
|
1065
|
+
if (/^\s*\[\s*mcp_servers\s*\.\s*(?:paintress|"paintress"|'paintress')\s*\]\s*$/m.test(existing)) return {
|
|
983
1066
|
...base,
|
|
984
1067
|
status: "noop",
|
|
985
1068
|
detail: "条目已存在(TOML 不自动改写)"
|
|
@@ -1008,9 +1091,10 @@ function planJsonMerge(spec, path, existing, launch) {
|
|
|
1008
1091
|
detail: "配置文件不是合法 JSON,未改动"
|
|
1009
1092
|
};
|
|
1010
1093
|
}
|
|
1011
|
-
const
|
|
1012
|
-
const
|
|
1013
|
-
const
|
|
1094
|
+
const rootPath = resolveRootPath(spec, root, options.opencodeLayout ?? "auto");
|
|
1095
|
+
const layout = spec.id === "opencode" && rootPath.length === 1 ? "legacy" : "v2";
|
|
1096
|
+
const table = readTable(root, rootPath);
|
|
1097
|
+
const entry = buildEntry(spec, launch, layout);
|
|
1014
1098
|
const current = table["paintress"];
|
|
1015
1099
|
if (JSON.stringify(current) === JSON.stringify(entry)) return {
|
|
1016
1100
|
...base,
|
|
@@ -1020,7 +1104,7 @@ function planJsonMerge(spec, path, existing, launch) {
|
|
|
1020
1104
|
};
|
|
1021
1105
|
const existed = current !== void 0;
|
|
1022
1106
|
table["paintress"] = entry;
|
|
1023
|
-
root
|
|
1107
|
+
writeTable(root, rootPath, table);
|
|
1024
1108
|
return {
|
|
1025
1109
|
...base,
|
|
1026
1110
|
status: existed ? "update" : existing === null ? "create" : "update",
|
|
@@ -1039,6 +1123,7 @@ function applyPlan(path, content, dryRun) {
|
|
|
1039
1123
|
}
|
|
1040
1124
|
const tmp = join(dirname(path), `.paintress-tmp-${process.pid}`);
|
|
1041
1125
|
writeFileSync(tmp, content, "utf8");
|
|
1126
|
+
if (existsSync(path)) chmodSync(tmp, statSync(path).mode & 511);
|
|
1042
1127
|
renameSync(tmp, path);
|
|
1043
1128
|
return { backup };
|
|
1044
1129
|
}
|
|
@@ -1059,6 +1144,13 @@ const FLAG_KEYS = /* @__PURE__ */ new Set([
|
|
|
1059
1144
|
"port",
|
|
1060
1145
|
"idle",
|
|
1061
1146
|
"daemon",
|
|
1147
|
+
"dry-run",
|
|
1148
|
+
"opencode-layout"
|
|
1149
|
+
]);
|
|
1150
|
+
const BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
|
|
1151
|
+
"regex",
|
|
1152
|
+
"reusable",
|
|
1153
|
+
"daemon",
|
|
1062
1154
|
"dry-run"
|
|
1063
1155
|
]);
|
|
1064
1156
|
/** 纯函数:argv → 命令 + 位置参数 + 标志(可单测) */
|
|
@@ -1073,7 +1165,7 @@ function parseArgv(argv) {
|
|
|
1073
1165
|
const key = tok.slice(2);
|
|
1074
1166
|
if (!FLAG_KEYS.has(key)) return null;
|
|
1075
1167
|
const next = rest[i + 1];
|
|
1076
|
-
if (key
|
|
1168
|
+
if (BOOLEAN_FLAGS.has(key)) flags[key] = true;
|
|
1077
1169
|
else if (typeof next === "string" && !next.startsWith("--")) {
|
|
1078
1170
|
flags[key] = next;
|
|
1079
1171
|
i++;
|
|
@@ -1199,22 +1291,29 @@ async function main(argv) {
|
|
|
1199
1291
|
if (cmd === "install" || cmd === "doctor") {
|
|
1200
1292
|
const home = homedir();
|
|
1201
1293
|
const launch = currentLaunchCommand();
|
|
1202
|
-
const
|
|
1294
|
+
const detected = (spec) => isClientDetected(spec, home, process.platform, process.env, existsSync);
|
|
1295
|
+
let ids;
|
|
1296
|
+
if (positionals.length > 0) ids = positionals;
|
|
1297
|
+
else if (cmd === "doctor") ids = CLIENTS.map((c) => c.id);
|
|
1298
|
+
else ids = CLIENTS.filter(detected).map((c) => c.id);
|
|
1203
1299
|
const unknown = ids.filter((id) => findClient(id) === void 0);
|
|
1204
1300
|
if (unknown.length > 0) throw new Error(`未知客户端:${unknown.join(", ")}(可选:${CLIENTS.map((c) => c.id).join(" / ")})`);
|
|
1205
1301
|
const dryRun = cmd === "doctor" || flags["dry-run"] === true;
|
|
1302
|
+
const layoutFlag = flagStr(flags, "opencode-layout") ?? "auto";
|
|
1303
|
+
if (layoutFlag !== "auto" && layoutFlag !== "legacy" && layoutFlag !== "v2") throw new Error(`--opencode-layout 只接受 auto / legacy / v2,收到:${layoutFlag}`);
|
|
1206
1304
|
const results = [];
|
|
1207
1305
|
for (const id of ids) {
|
|
1208
1306
|
const spec = findClient(id);
|
|
1209
1307
|
if (spec === void 0) continue;
|
|
1210
1308
|
const path = spec.configPath(home, process.platform, process.env);
|
|
1211
1309
|
const existing = readConfig(path);
|
|
1212
|
-
const plan = planJsonMerge(spec, path, existing, launch);
|
|
1310
|
+
const plan = planJsonMerge(spec, path, existing, launch, { opencodeLayout: layoutFlag });
|
|
1213
1311
|
if (cmd === "doctor") {
|
|
1214
1312
|
results.push({
|
|
1215
1313
|
client: spec.id,
|
|
1216
1314
|
label: spec.label,
|
|
1217
1315
|
path,
|
|
1316
|
+
detected: detected(spec),
|
|
1218
1317
|
exists: existing !== null,
|
|
1219
1318
|
status: plan.status,
|
|
1220
1319
|
detail: plan.detail
|
|
@@ -1404,11 +1503,10 @@ async function main(argv) {
|
|
|
1404
1503
|
return 1;
|
|
1405
1504
|
}
|
|
1406
1505
|
}
|
|
1407
|
-
function isDirectExecution() {
|
|
1408
|
-
const entry = process.argv[1];
|
|
1506
|
+
function isDirectExecution(entry = process.argv[1], moduleUrl = import.meta.url) {
|
|
1409
1507
|
if (entry === void 0) return false;
|
|
1410
1508
|
try {
|
|
1411
|
-
return realpathSync(entry) === realpathSync(fileURLToPath(
|
|
1509
|
+
return realpathSync(entry) === realpathSync(fileURLToPath(moduleUrl));
|
|
1412
1510
|
} catch {
|
|
1413
1511
|
return false;
|
|
1414
1512
|
}
|
|
@@ -1416,4 +1514,4 @@ function isDirectExecution() {
|
|
|
1416
1514
|
if (isDirectExecution()) main(process.argv.slice(2)).then((code) => {
|
|
1417
1515
|
if (code !== 0) process.exitCode = code;
|
|
1418
1516
|
});
|
|
1419
|
-
export { main, parseArgv };
|
|
1517
|
+
export { isDirectExecution, main, parseArgv };
|
package/package.json
CHANGED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),t.credentials=e.crossOrigin===`use-credentials`?`include`:e.crossOrigin===`anonymous`?`omit`:`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var e={context:void 0,registry:void 0,effects:void 0,done:!1,getContextId(){return t(this.context.count)},getNextContextId(){return t(this.context.count++)}};function t(t){let n=String(t),r=n.length-1;return e.context.id+(r?String.fromCharCode(96+r):``)+n}function n(t){e.context=t}var r=(e,t)=>e===t,i=Symbol(`solid-track`),a={equals:r},o=null,s=N,c=1,l=2,u={owned:null,cleanups:null,context:null,owner:null},d=null,f=null,p=null,m=null,h=null,g=0;function _(e,t){let n=p,r=d,i=e.length===0,a=t===void 0?r:t,o=i?u:{owned:null,cleanups:null,context:a?a.context:null,owner:a},s=i?e:()=>e(v(o));d=o,p=null;try{return M(s,!0)}finally{p=n,d=r}}function v(e){return()=>C(()=>I(e))}function y(e,t){t=t?Object.assign({},a,t):a;let n={value:e,observers:null,observerSlots:null,comparator:t.equals||void 0};return[re.bind(n),e=>(typeof e==`function`&&(e=f&&f.running&&f.sources.has(n)?e(n.tValue):e(n.value)),O(n,e))]}function b(e,t,n){k(A(e,t,!1,c))}function x(e,t,n){s=oe;let r=A(e,t,!1,c),i=D&&ne(D);i&&(r.suspense=i),n&&n.render||(r.user=!0),h?h.push(r):k(r)}function S(e,t,n){n=n?Object.assign({},a,n):a;let r=A(e,t,!0,0);return r.observers=null,r.observerSlots=null,r.comparator=n.equals||void 0,k(r),re.bind(r)}function C(e){if(p===null)return e();let t=p;p=null;try{return e()}finally{p=t}}function w(e,t,n){let r=Array.isArray(e),i,a=n&&n.defer;return n=>{let o;if(r){o=Array(e.length);for(let t=0;t<e.length;t++)o[t]=e[t]()}else o=e();if(a)return a=!1,n;let s=C(()=>t(o,i,n));return i=o,s}}function ee(e){x(()=>C(e))}function T(e){return d===null||(d.cleanups===null?d.cleanups=[e]:d.cleanups.push(e)),e}var[te,E]=y(!1);function ne(e){let t;return d&&d.context&&(t=d.context[e.id])!==void 0?t:e.defaultValue}var D;function re(){let e=f&&f.running;if(this.sources&&(e?this.tState:this.state)){if((e?this.tState:this.state)===c)k(this);else{let e=m;m=null,M(()=>P(this),!1),m=e}}if(p){let e=this.observers;if(!e||e[e.length-1]!==p){let t=e?e.length:0;p.sources?(p.sources.push(this),p.sourceSlots.push(t)):(p.sources=[this],p.sourceSlots=[t]),e?(e.push(p),this.observerSlots.push(p.sources.length-1)):(this.observers=[p],this.observerSlots=[p.sources.length-1])}}return e&&f.sources.has(this)?this.tValue:this.value}function O(e,t,n){let r=f&&f.running&&f.sources.has(e)?e.tValue:e.value;if(!e.comparator||!e.comparator(r,t)){if(f){let r=f.running;(r||!n&&f.sources.has(e))&&(f.sources.add(e),e.tValue=t),r||(e.value=t)}else e.value=t;e.observers&&e.observers.length&&M(()=>{for(let t=0;t<e.observers.length;t+=1){let n=e.observers[t],r=f&&f.running;r&&f.disposed.has(n)||((r?!n.tState:!n.state)&&(n.pure?m.push(n):h.push(n),n.observers&&F(n)),r?n.tState=c:n.state=c)}if(m.length>1e6)throw m=[],Error()},!1)}return t}function k(e){if(!e.fn)return;I(e);let t=g;ie(e,f&&f.running&&f.sources.has(e)?e.tValue:e.value,t),f&&!f.running&&f.sources.has(e)&&queueMicrotask(()=>{M(()=>{f&&(f.running=!0),p=d=e,ie(e,e.tValue,t),p=d=null},!1)})}function ie(e,t,n){let r,i=d,a=p;p=d=e;try{r=e.fn(t)}catch(t){return e.pure&&(f&&f.running?(e.tState=c,e.tOwned&&e.tOwned.forEach(I),e.tOwned=void 0):(e.state=c,e.owned&&e.owned.forEach(I),e.owned=null)),e.updatedAt=n+1,z(t)}finally{p=a,d=i}(!e.updatedAt||e.updatedAt<=n)&&(e.updatedAt!=null&&`observers`in e?O(e,r,!0):f&&f.running&&e.pure?(f.sources.has(e)||(e.value=r),f.sources.add(e),e.tValue=r):e.value=r,e.updatedAt=n)}function A(e,t,n,r=c,i){let a={fn:e,state:r,updatedAt:null,owned:null,sources:null,sourceSlots:null,cleanups:null,value:t,owner:d,context:d?d.context:null,pure:n};return f&&f.running&&(a.state=0,a.tState=r),d===null||d!==u&&(f&&f.running&&d.pure?d.tOwned?d.tOwned.push(a):d.tOwned=[a]:d.owned?d.owned.push(a):d.owned=[a]),a}function j(e){let t=f&&f.running;if((t?e.tState:e.state)===0)return;if((t?e.tState:e.state)===l)return P(e);if(e.suspense&&C(e.suspense.inFallback))return e.suspense.effects.push(e);let n=[e];for(;(e=e.owner)&&(!e.updatedAt||e.updatedAt<g);){if(t&&f.disposed.has(e))return;(t?e.tState:e.state)&&n.push(e)}for(let r=n.length-1;r>=0;r--){if(e=n[r],t){let t=e,i=n[r+1];for(;(t=t.owner)&&t!==i;)if(f.disposed.has(t))return}if((t?e.tState:e.state)===c)k(e);else if((t?e.tState:e.state)===l){let t=m;m=null,M(()=>P(e,n[0]),!1),m=t}}}function M(e,t){if(m)return e();let n=!1;t||(m=[]),h?n=!0:h=[],g++;try{let t=e();return ae(n),t}catch(e){n||(h=null),m=null,z(e)}}function ae(e){if(m&&=(N(m),null),e)return;let t;if(f){if(!f.promises.size&&!f.queue.size){let e=f.sources,n=f.disposed;h.push.apply(h,f.effects),t=f.resolve;for(let e of h)`tState`in e&&(e.state=e.tState),delete e.tState;f=null,M(()=>{for(let e of n)I(e);for(let t of e){if(t.value=t.tValue,t.owned)for(let e=0,n=t.owned.length;e<n;e++)I(t.owned[e]);t.tOwned&&(t.owned=t.tOwned),delete t.tValue,delete t.tOwned,t.tState=0}E(!1)},!1)}else if(f.running){f.running=!1,f.effects.push.apply(f.effects,h),h=null,E(!0);return}}let n=h;h=null,n.length&&M(()=>s(n),!1),t&&t()}function N(e){for(let t=0;t<e.length;t++)j(e[t])}function oe(t){let r,i=0;for(r=0;r<t.length;r++){let e=t[r];e.user?t[i++]=e:j(e)}if(e.context){if(e.count){e.effects||=[],e.effects.push(...t.slice(0,i));return}n()}for(e.effects&&(e.done||!e.count)&&(t=[...e.effects,...t],i+=e.effects.length,delete e.effects),r=0;r<i;r++)j(t[r])}function P(e,t){let n=f&&f.running;n?e.tState=0:e.state=0;for(let r=0;r<e.sources.length;r+=1){let i=e.sources[r];if(i.sources){let e=n?i.tState:i.state;e===c?i!==t&&(!i.updatedAt||i.updatedAt<g)&&j(i):e===l&&P(i,t)}}}function F(e){let t=f&&f.running;for(let n=0;n<e.observers.length;n+=1){let r=e.observers[n];(t?!r.tState:!r.state)&&(t?r.tState=l:r.state=l,r.pure?m.push(r):h.push(r),r.observers&&F(r))}}function I(e){let t;if(e.sources)for(;e.sources.length;){let t=e.sources.pop(),n=e.sourceSlots.pop(),r=t.observers;if(r&&r.length){let e=r.pop(),i=t.observerSlots.pop();n<r.length&&(e.sourceSlots[i]=n,r[n]=e,t.observerSlots[n]=i)}}if(e.tOwned){for(t=e.tOwned.length-1;t>=0;t--)I(e.tOwned[t]);delete e.tOwned}if(f&&f.running&&e.pure)L(e,!0);else if(e.owned){for(t=e.owned.length-1;t>=0;t--)I(e.owned[t]);e.owned=null}if(e.cleanups){for(t=e.cleanups.length-1;t>=0;t--)e.cleanups[t]();e.cleanups=null}f&&f.running?e.tState=0:e.state=0}function L(e,t){if(t||(e.tState=0,f.disposed.add(e)),e.owned)for(let t=0;t<e.owned.length;t++)L(e.owned[t])}function se(e){return e instanceof Error?e:Error(typeof e==`string`?e:`Unknown error`,{cause:e})}function R(e,t,n){try{for(let n of t)n(e)}catch(e){z(e,n&&n.owner||null)}}function z(e,t=d){let n=o&&t&&t.context&&t.context[o],r=se(e);if(!n)throw r;h?h.push({fn(){R(r,n,t)},state:c}):R(r,n,t)}var ce=Symbol(`fallback`);function B(e){for(let t=0;t<e.length;t++)e[t]()}function le(e,t,n={}){let r=[],a=[],o=[],s=0,c=t.length>1?[]:null;return T(()=>B(o)),()=>{let l=e()||[],u=l.length,d,f;return l[i],C(()=>{let e,t,i,m,h,g,v,y,b;if(u===0)s!==0&&(B(o),o=[],r=[],a=[],s=0,c&&=[]),n.fallback&&(r=[ce],a[0]=_(e=>(o[0]=e,n.fallback())),s=1);else if(s===0){for(a=Array(u),f=0;f<u;f++)r[f]=l[f],a[f]=_(p);s=u}else{for(i=Array(u),m=Array(u),c&&(h=Array(u)),g=0,v=Math.min(s,u);g<v&&r[g]===l[g];g++);for(v=s-1,y=u-1;v>=g&&y>=g&&r[v]===l[y];v--,y--)i[y]=a[v],m[y]=o[v],c&&(h[y]=c[v]);for(e=new Map,t=Array(y+1),f=y;f>=g;f--)b=l[f],d=e.get(b),t[f]=d===void 0?-1:d,e.set(b,f);for(d=g;d<=v;d++)b=r[d],f=e.get(b),f!==void 0&&f!==-1?(i[f]=a[d],m[f]=o[d],c&&(h[f]=c[d]),f=t[f],e.set(b,f)):o[d]();for(f=g;f<u;f++)f in i?(a[f]=i[f],o[f]=m[f],c&&(c[f]=h[f],c[f](f))):a[f]=_(p);a=a.slice(0,s=u),r=l.slice(0)}return a});function p(e){if(o[f]=e,c){let[e,n]=y(f);return c[f]=n,t(l[f],e)}return t(l[f])}}}function V(e,t){return C(()=>e(t||{}))}var ue=e=>`Stale read from <${e}>.`;function H(e){let t=`fallback`in e&&{fallback:()=>e.fallback};return S(le(()=>e.each,e.children,t||void 0))}function U(e){let t=e.keyed,n=S(()=>e.when,void 0,void 0),r=t?n:S(n,void 0,{equals:(e,t)=>!e==!t});return S(()=>{let i=r();if(i){let a=e.children;return typeof a==`function`&&a.length>0?C(()=>a(t?i:()=>{if(!C(r))throw ue(`Show`);return n()})):a}return e.fallback},void 0,void 0)}var de=e=>S(()=>e());function fe(e,t,n){let r=n.length,i=t.length,a=r,o=0,s=0,c=t[i-1].nextSibling,l=null;for(;o<i||s<a;)if(t[o]===n[s])o++,s++;else{for(;t[i-1]===n[a-1];)i--,a--;if(i===o){let t=a<r?s?n[s-1].nextSibling:n[a-s]:c;for(;s<a;)e.insertBefore(n[s++],t)}else if(a===s)for(;o<i;)l&&l.has(t[o])||t[o].remove(),o++;else if(t[o]===n[a-1]&&n[s]===t[i-1]){let r=t[--i].nextSibling;e.insertBefore(n[s++],t[o++].nextSibling),e.insertBefore(n[--a],r),t[i]=n[a]}else{if(!l){l=new Map;let e=s;for(;e<a;)l.set(n[e],e++)}let r=l.get(t[o]);if(r!=null){if(s<r&&r<a){let c=o,u=1,d;for(;++c<i&&c<a&&(d=l.get(t[c]))!=null&&d===r+u;)u++;if(u>r-s){let i=t[o];for(;s<r;)e.insertBefore(n[s++],i)}else e.replaceChild(n[s++],t[o++])}else o++}else t[o++].remove()}}}var pe=`_$DX_DELEGATE`;function me(e,t,n,r={}){let i;return _(r=>{i=r,t===document?e():G(t,e(),!n&&t.firstChild?null:void 0,n)},r.owner),()=>{i(),t.textContent=``}}function W(e,t,n,r){let i,a=()=>{let t=r?document.createElementNS(`http://www.w3.org/1998/Math/MathML`,`template`):document.createElement(`template`);return t.innerHTML=e,n?t.content.firstChild.firstChild:r?t.firstChild:t.content.firstChild},o=t?()=>C(()=>document.importNode(i||=a(),!0)):()=>(i||=a()).cloneNode(!0);return o.cloneNode=o,o}function he(e,t=window.document){let n=t[pe]||(t[pe]=new Set);for(let r=0,i=e.length;r<i;r++){let i=e[r];n.has(i)||(n.add(i),t.addEventListener(i,ye))}}function ge(e,t,n){ve(e)||(n==null?e.removeAttribute(t):e.setAttribute(t,n))}function _e(e,t,n){return C(()=>e(t,n))}function G(e,t,n,r){if(n!==void 0&&!r&&(r=[]),typeof t!=`function`)return K(e,t,r,n);b(r=>K(e,t(),r,n),r)}function ve(t){return!!e.context&&!e.done&&(!t||t.isConnected)}function ye(t){if(e.registry&&e.events&&e.events.find(([e,n])=>n===t))return;let n=t.target,r=`$$${t.type}`,i=t.target,a=t.currentTarget,o=e=>Object.defineProperty(t,"target",{configurable:!0,value:e}),s=()=>{let e=n[r];if(e&&!n.disabled){let i=n[`${r}Data`];if(i===void 0?e.call(n,t):e.call(n,i,t),t.cancelBubble)return}return n.host&&typeof n.host!=`string`&&!n.host._$host&&n.contains(t.target)&&o(n.host),!0},c=()=>{for(;s()&&(n=n._$host||n.parentNode||n.host););};Object.defineProperty(t,"currentTarget",{configurable:!0,get(){return n||document}}),e.registry&&!e.done&&(e.done=_$HY.done=!0);try{if(t.composedPath){let e=t.composedPath();o(e[0]);for(let t=0;t<e.length-2&&(n=e[t],s());t++){if(n._$host){n=n._$host,c();break}if(n.parentNode===a)break}}else c();o(i)}finally{t=n=null}}function K(e,t,n,r,i){let a=ve(e);if(a){!n&&(n=[...e.childNodes]);let t=[];for(let e=0;e<n.length;e++){let r=n[e];r.nodeType===8&&r.data.slice(0,2)===`!$`?r.remove():t.push(r)}n=t}for(;typeof n==`function`;)n=n();if(t===n)return n;let o=typeof t,s=r!==void 0;if(e=s&&n[0]&&n[0].parentNode||e,o===`string`||o===`number`){if(a||o===`number`&&(t=t.toString(),t===n))return n;if(s){let i=n[0];i&&i.nodeType===3?i.data!==t&&(i.data=t):i=document.createTextNode(t),n=Y(e,n,r,i)}else n=n!==``&&typeof n==`string`?e.firstChild.data=t:e.textContent=t}else if(t==null||o===`boolean`){if(a)return n;n=Y(e,n,r)}else if(o===`function`)return b(()=>{let i=t();for(;typeof i==`function`;)i=i();n=K(e,i,n,r)}),()=>n;else if(Array.isArray(t)){let o=[],c=n&&Array.isArray(n);if(q(o,t,n,i))return b(()=>n=K(e,o,n,r,!0)),()=>n;if(a){if(!o.length)return n;if(r===void 0)return n=[...e.childNodes];let t=o[0];if(t.parentNode!==e)return n;let i=[t];for(;(t=t.nextSibling)!==r;)i.push(t);return n=i}if(o.length===0){if(n=Y(e,n,r),s)return n}else c?n.length===0?J(e,o,r):fe(e,n,o):(n&&Y(e),J(e,o));n=o}else if(t.nodeType){if(a&&t.parentNode)return n=s?[t]:t;if(Array.isArray(n)){if(s)return n=Y(e,n,r,t);Y(e,n,null,t)}else n==null||n===``||!e.firstChild?e.appendChild(t):e.replaceChild(t,e.firstChild);n=t}return n}function q(e,t,n,r){let i=!1;for(let a=0,o=t.length;a<o;a++){let o=t[a],s=n&&n[e.length],c;if(o!=null&&o!==!0&&o!==!1){if((c=typeof o)==`object`&&o.nodeType)e.push(o);else if(Array.isArray(o))i=q(e,o,s)||i;else if(c===`function`){if(r){for(;typeof o==`function`;)o=o();i=q(e,Array.isArray(o)?o:[o],Array.isArray(s)?s:[s])||i}else e.push(o),i=!0}else{let t=String(o);s&&s.nodeType===3&&s.data===t?e.push(s):e.push(document.createTextNode(t))}}}return i}function J(e,t,n=null){for(let r=0,i=t.length;r<i;r++)e.insertBefore(t[r],n)}function Y(e,t,n,r){if(n===void 0)return e.textContent=``;let i=r||document.createTextNode(``);if(t.length){let r=!1;for(let a=t.length-1;a>=0;a--){let o=t[a];if(i!==o){let t=o.parentNode===e;!r&&!a?t?e.replaceChild(i,o):e.insertBefore(i,n):t&&o.remove()}else r=!0}}else e.insertBefore(i,n);return[i]}async function X(e){let t=await fetch(e,{headers:{accept:`application/json`}});if(!t.ok){let e=await t.text().catch(()=>``);throw Error(`HTTP ${t.status}${e?`: ${e.slice(0,200)}`:``}`)}return await t.json()}function be(){return X(`/api/projects`)}function xe(e){return X(`/api/projects/${encodeURIComponent(e)}/files`)}function Se(e,t){return`/render/${encodeURIComponent(e)}/${t.split(`/`).map(encodeURIComponent).join(`/`)}?embed=1`}function Ce(e,t){return`/events?project=${encodeURIComponent(e)}&path=${encodeURIComponent(t)}`}function we(e){return X(`/api/marks?project=${encodeURIComponent(e)}`)}async function Te(e){let t=await fetch(`/api/marks`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify(e)});if(!t.ok)throw Error(`HTTP ${t.status}`);let n=await t.json();if(!n.ok)throw Error(n.error??`添加标记失败`);return n.mark}async function Ee(e){let t=await fetch(`/api/marks?project=${encodeURIComponent(e)}`,{method:`DELETE`});if(!t.ok)throw Error(`HTTP ${t.status}`);return(await t.json()).cleared}function De(e,t){return X(`/api/changes?project=${encodeURIComponent(e)}&path=${encodeURIComponent(t)}`)}var Z=.1,Oe=.02;function ke(e,t){return t===0||Math.abs(e)>=Math.abs(t)?null:t>0?-1:1}function Q(e,t=Z){return Math.min(4,Math.max(t,e))}function Ae(e,t,n,r,i=Z){let a=Q(e.z*t,i);if(a===e.z)return e;let o=a/e.z;return{z:a,tx:n-(n-e.tx)*o,ty:r-(r-e.ty)*o}}function je(e,t,n,r=Z){return Ae(e,Q(t,r)/e.z,n.width/2,n.height/2,r)}function Me(e,t,n=24){let r=Math.max(1,e.w),i=Math.max(1,e.h),a=Math.max(1,t.width-n*2),o=Math.max(1,t.height-n*2),s=Q(Math.min(a/r,o/i),Oe);return{z:s,tx:(t.width-r*s)/2-e.x*s,ty:(t.height-i*s)/2-e.y*s}}function Ne(e,t,n){return{z:e.z,tx:e.tx+t,ty:e.ty+n}}function Pe(e){return`translate(${e.tx}px, ${e.ty}px) scale(${e.z})`}function Fe(e){if(e===null||e===``)return null;let t;try{t=JSON.parse(e)}catch{return null}if(typeof t!=`object`||!t)return null;let{z:n,tx:r,ty:i}=t;return typeof n!=`number`||typeof r!=`number`||typeof i!=`number`||!Number.isFinite(n)||!Number.isFinite(r)||!Number.isFinite(i)||n<=0?null:{z:Q(n,Oe),tx:r,ty:i}}var Ie=3,Le=.0015;function Re({doc:e,onChange:t,onLevelStep:n}){let r=e.querySelector(`.ptr-canvas`);if(r===null)return null;let i=r;i.style.transformOrigin=`0 0`;let a={z:1,tx:0,ty:0},o=!1,s=!1,c=!1,l=null,u=()=>({width:e.documentElement.clientWidth||1,height:e.documentElement.clientHeight||1});function d(){i.style.transform=Pe(a),t?.(a)}function f(e){a=e,d()}function p(){i.style.transition=``}function m(e){i.style.transition=`transform 180ms ease-out`,f(e),setTimeout(p,220)}function h(t){e.documentElement.style.cursor=t}function g(e){if(e.preventDefault(),e.altKey&&n!==void 0){let t=ke(e.deltaX,e.deltaY);t!==null&&n(t,{x:e.clientX,y:e.clientY});return}p();let t=1;e.deltaMode===1?t=16:e.deltaMode===2&&(t=u().height);let r=a.z<.1?Oe:Z;f(Ae(a,Math.exp(-e.deltaY*t*Le),e.clientX,e.clientY,r))}function _(t){return t.button===1?!0:t.button===0?o?!0:t.target===i||t.target===e.body||t.target===e.documentElement:!1}function v(e){_(e)&&(e.preventDefault(),l={lastX:e.clientX,lastY:e.clientY,startX:e.clientX,startY:e.clientY},s=!1)}function y(t){if(!l)return;if(!s){if(Math.hypot(t.clientX-l.startX,t.clientY-l.startY)<Ie)return;s=!0,p(),e.body.style.userSelect=`none`,h(`grabbing`)}let n=t.clientX-l.lastX,r=t.clientY-l.lastY;l.lastX=t.clientX,l.lastY=t.clientY,f(Ne(a,n,r))}function b(){l&&(l=null,s&&(s=!1,c=!0,e.body.style.userSelect=``,h(o?`grab`:``)))}function x(e){o!==e&&(o=e,s||h(e?`grab`:``))}function S(e){if(e.key===` `&&!e.metaKey&&!e.ctrlKey&&!e.altKey){let t=e.target,n=t?.tagName??``;if(n===`INPUT`||n===`TEXTAREA`||t?.isContentEditable===!0)return;x(!0),e.preventDefault()}else ee(e)&&e.preventDefault()}function C(e){e.key===` `&&x(!1)}function w(){x(!1),b()}function ee(e){return(e.ctrlKey||e.metaKey)&&(e.key===`0`||e.key===`)`||e.code===`Digit0`||e.code===`Numpad0`)?(f(je(a,1,u())),!0):e.shiftKey&&!e.ctrlKey&&!e.metaKey&&(e.key===`!`||e.code===`Digit1`)?(T(),!0):!1}function T(){f(Me({x:0,y:0,w:i.offsetWidth,h:i.offsetHeight},u()))}function te(e){let t=u();m({z:a.z,tx:t.width/2-(e.x+e.w/2)*a.z,ty:t.height/2-(e.y+e.h/2)*a.z})}return e.addEventListener(`wheel`,g,{passive:!1}),e.addEventListener(`mousedown`,v,!0),e.addEventListener(`mousemove`,y,!0),e.addEventListener(`mouseup`,b,!0),e.addEventListener(`keydown`,S),e.addEventListener(`keyup`,C),e.defaultView?.addEventListener(`blur`,w),{get:()=>a,set:f,fitAll:T,centerOn:te,focusBox:e=>m(Me(e,u())),zoomToPercent:e=>f(je(a,e,u())),consumeDragClick:()=>{let e=c;return c=!1,e},handleKey:ee,setSpace:x,destroy:()=>{e.removeEventListener(`wheel`,g),e.removeEventListener(`mousedown`,v,!0),e.removeEventListener(`mousemove`,y,!0),e.removeEventListener(`mouseup`,b,!0),e.removeEventListener(`keydown`,S),e.removeEventListener(`keyup`,C),e.defaultView?.removeEventListener(`blur`,w)}}}var ze=W(`<span class=badge>v`),Be=W(`<ul class=list>`),Ve=W(`<section class="section files"><h2>设计稿 <span class=hint>depth `),He=W(`<section class="section marks"><h2>标记<button class="ghost tiny">清空</button></h2><ul class=list>`),Ue=W(`<span class=hint>pid `),We=W(`<div class=error>`),Ge=W(`<code>/`),Ke=W(`<div class=toolbar><div class=crumbs></div><div class=tools><span class="hint zoom">%</span><button class="ghost tiny"title=适应窗口(Shift+1)>适应</button><button class="ghost tiny"title=100%(Ctrl/Cmd+0)>1:1</button><button class=ghost>重新渲染`),qe=W(`<div class=boardbar><button class=board>全部`),Je=W(`<iframe class=preview title="design preview"sandbox="allow-same-origin allow-scripts">`),Ye=W(`<div class=app><aside class=sidebar><header class=sidebar-head><img class=brand-mark src=/logo.svg alt><h1>paintress</h1></header><section class=section><h2>项目</h2></section><footer class=sidebar-foot><label class=toggle><input type=checkbox>实时刷新</label><button class=ghost>刷新列表</button></footer></aside><main class=stage>`),Xe=W(`<p class=empty>还没有注册项目<br><code>paintress watch <name> <dir>`),Ze=W(`<li><button class=item><span class=item-name></span><span class=item-meta> 个设计稿`),Qe=W(`<p class=empty>没有 .ptr / .pen 文件`),$e=W(`<li><button class=item><span class=item-name>`),et=W(`<li><button class=item><span class=item-name><b class=mark-no>#</b> </span><span class=item-meta>`),tt=W(`<p>从左侧选择一个设计稿`),nt=W(`<div class=placeholder>`),rt=W(`<p>从左侧选择项目`),it=W(`<span class=sep>/`),at=W(`<button class=crumb>`),ot=W(`<button class=board><span class=board-size>×`);function $(e){return typeof CSS<`u`&&typeof CSS.escape==`function`?CSS.escape(e):e.replace(/["\\]/g,`\\$&`)}function st(){let[e,t]=y([]),[n,r]=y(null),[i,a]=y([]),[o,s]=y(null),[c,l]=y([]),[u,d]=y(null),[f,p]=y([]),[m,h]=y(null),[g,_]=y({}),[v,S]=y(0),[C,te]=y(!0),[E,ne]=y(``),[D,re]=y([]),[O,k]=y(null),[ie,A]=y(1),j,M=null,ae;function N(){let e=new URLSearchParams,t=n(),r=o();t&&e.set(`project`,t),r&&e.set(`file`,r);let i=e.toString();history.replaceState(null,``,i?`?${i}`:location.pathname)}async function oe(){try{let e=await be();t(e.projects),_({pid:e.pid,version:e.version}),h(null)}catch(e){h(e instanceof Error?e.message:String(e))}}async function P(e){try{l((await we(e)).marks)}catch{l([])}}async function F(e){r(e),s(null),d(null),p([]);try{let t=await xe(e);a(t.files),h(null)}catch(e){a([]),h(e instanceof Error?e.message:String(e))}P(e),N()}function I(e){s(e),d(null),p([]),N()}ee(()=>{let e=e=>{let t=e.target;return t?.tagName===`INPUT`||t?.tagName===`TEXTAREA`||t?.isContentEditable===!0},t=t=>{e(t)||(t.key===` `&&!t.ctrlKey&&!t.metaKey&&!t.altKey?(M?.setSpace(!0),t.preventDefault()):M?.handleKey(t)===!0&&t.preventDefault())},n=e=>{e.key===` `&&M?.setSpace(!1)};window.addEventListener(`keydown`,t),window.addEventListener(`keyup`,n),T(()=>{window.removeEventListener(`keydown`,t),window.removeEventListener(`keyup`,n)});let r=new URLSearchParams(location.search);(async()=>{await oe();let e=r.get(`project`);if(e){await F(e);let t=r.get(`file`);t&&I(t)}})()});let L=()=>j?.contentDocument??null;function se(){let e=L();if(!e||e.getElementById(`ptr-style`))return;let t=e.createElement(`style`);t.id=`ptr-style`,t.textContent=`[data-ptr-selected]{outline:2px solid #908030 !important;outline-offset:-2px;}
|
|
2
|
+
[data-ptr-hover]:not([data-ptr-selected]){outline:1px dashed rgba(144,128,48,.55) !important;outline-offset:-2px;}
|
|
3
|
+
[data-ptr-changed]{box-shadow:inset 0 0 0 2px #908030 !important;animation:ptr-pulse 1.4s ease-in-out 3;}
|
|
4
|
+
@keyframes ptr-pulse{0%,100%{box-shadow:inset 0 0 0 2px #908030}50%{box-shadow:inset 0 0 0 2px rgba(144,128,48,.35)}}
|
|
5
|
+
html{cursor:default;}
|
|
6
|
+
html,body{overflow:hidden;}`,e.head.appendChild(t)}function R(){let e=L();if(!e)return;for(let t of e.querySelectorAll(`[data-ptr-selected]`))t.removeAttribute(`data-ptr-selected`);let t=u();t&&e.querySelector(`[data-node-id="${$(t)}"]`)?.setAttribute(`data-ptr-selected`,``)}function z(e){return e.parentElement?.closest(`[data-node-id]`)??null}function ce(e){return e.querySelector(`:scope > [data-node-id]`)}function B(e){if(M?.consumeDragClick()===!0){e.preventDefault(),e.stopPropagation();return}let t=e.target?.closest(`[data-node-id]`);t&&(e.preventDefault(),e.stopPropagation(),q(e.altKey?z(t)??t:t))}function le(e,t){let n=L();if(!n)return;let r=u(),i=r===null?null:n.querySelector(`[data-node-id="${$(r)}"]`);if(i===null){let e=(n.elementFromPoint(t.x,t.y)?.closest(`[data-node-id]`))?.dataset.nodeId;e!==void 0&&J(e);return}let a=(e===1?z(i):ce(i))?.dataset.nodeId;a!==void 0&&J(a)}function ue(e){let t=L();if(t){for(let e of t.querySelectorAll(`[data-ptr-hover]`))e.removeAttribute(`data-ptr-hover`);(e.target?.closest(`[data-node-id]`))?.setAttribute(`data-ptr-hover`,``)}}async function fe(){let e=n(),t=o();if(e&&t)try{let n=await De(e,t);if(!n.ok||n.ids.length===0)return;let r=L();if(!r)return;for(let e of n.ids)r.querySelector(`[data-node-id="${$(e)}"]`)?.setAttribute(`data-ptr-changed`,``)}catch{}}function pe(){let e=L();return e?Array.from(e.querySelectorAll(`[data-board]`)).map(e=>{let t=e.dataset;return{id:t.nodeId??``,...t.boardName===void 0?{}:{name:t.boardName},x:Number(t.boardX??0),y:Number(t.boardY??0),w:Number(t.boardW??0),h:Number(t.boardH??0)}}):[]}function me(){let e=n(),t=o();return e&&t?`paintress:viewport:${e}/${t}`:null}function W(e){let t=me();t!==null&&(clearTimeout(ae),ae=setTimeout(()=>{try{localStorage.setItem(t,JSON.stringify(e))}catch{}},300))}function he(){let e=L();e&&(se(),M?.destroy(),M=Re({doc:e,onChange:e=>{A(e.z),W(e)},onLevelStep:le}),re(pe()),k(null),ve(),e.addEventListener(`click`,B,!0),e.addEventListener(`mousemove`,ue,!0),R(),fe())}function ve(){if(!M)return;let e=me(),t=e===null?null:localStorage.getItem(e),n=t===null?null:Fe(t);n===null?M.fitAll():M.set(n)}function ye(e){if(k(e),!M)return;if(e===null){M.fitAll();return}let t=D().find(t=>t.id===e);t&&M.focusBox({x:t.x,y:t.y,w:t.w,h:t.h})}function K(e){let t=[],n=e;for(;n;){let e=n.closest(`[data-node-id]`);if(!e)break;let r=e;t.unshift({id:r.dataset.nodeId??``,type:r.dataset.nodeType??`?`,name:r.dataset.nodeName}),n=e.parentElement}return t}async function q(e){let t=e.dataset.nodeId??``;if(t===``)return;let r=K(e);d(t),p(r),R();let i=n();if(i)try{await Te({project:i,nodeId:t,...e.dataset.nodeName===void 0?{}:{name:e.dataset.nodeName},...e.dataset.nodeType===void 0?{}:{type:e.dataset.nodeType},path:r.map(e=>e.name??e.type).join(` / `)}),l((await we(i)).marks),h(null)}catch(e){h(e instanceof Error?e.message:String(e))}}function J(e){d(e),R();let t=L(),n=t?.querySelector(`[data-node-id="${$(e)}"]`);if(!n||!t){p([]);return}p(K(n));let r=t.querySelector(`.ptr-canvas`);if(!r||!M){n.scrollIntoView({block:`center`});return}let i=n.getBoundingClientRect(),a=r.getBoundingClientRect(),o=M.get().z;M.centerOn({x:(i.left-a.left)/o,y:(i.top-a.top)/o,w:i.width/o,h:i.height/o})}async function Y(){let e=n();if(e)try{await Ee(e),l([]),d(null),p([]),R()}catch(e){h(e instanceof Error?e.message:String(e))}}x(w([n,o,v],()=>{let e=n(),t=o();ne(e&&t?`${Se(e,t)}&r=${v()}`:``)}));let X=null;return x(w([n,o,C],()=>{X?.close(),X=null;let e=n(),t=o();C()&&e&&t&&(X=new EventSource(Ce(e,t)),X.addEventListener(`change`,()=>S(e=>e+1)))})),T(()=>X?.close()),(()=>{var t=Ye(),r=t.firstChild,a=r.firstChild;a.firstChild.nextSibling;var s=a.nextSibling;s.firstChild;var l=s.nextSibling,d=l.firstChild,p=d.firstChild,h=d.nextSibling,_=r.nextSibling;return G(a,V(U,{get when(){return g().version},get children(){var e=ze();return e.firstChild,G(e,()=>g().version,null),e}}),null),G(s,V(U,{get when(){return e().length>0},get fallback(){return Xe()},get children(){var t=Be();return G(t,V(H,{get each(){return e()},children:e=>(()=>{var t=Ze(),r=t.firstChild,i=r.firstChild,a=i.nextSibling,o=a.firstChild;return r.$$click=()=>void F(e.name),G(i,()=>e.name),G(a,()=>e.fileCount,o),b(()=>r.classList.toggle(`active`,n()===e.name)),t})()})),t}}),null),G(r,V(U,{get when(){return n()},get children(){var t=Ve(),r=t.firstChild.firstChild.nextSibling;return r.firstChild,G(r,()=>e().find(e=>e.name===n())?.depth??`-`,null),G(t,V(U,{get when(){return i().length>0},get fallback(){return Qe()},get children(){var e=Be();return G(e,V(H,{get each(){return i()},children:e=>(()=>{var t=$e(),n=t.firstChild,r=n.firstChild;return n.$$click=()=>I(e),G(r,e),b(()=>n.classList.toggle(`active`,o()===e)),t})()})),e}}),null),t}}),l),G(r,V(U,{get when(){return c().length>0},get children(){var e=He(),t=e.firstChild,n=t.firstChild.nextSibling,r=t.nextSibling;return n.$$click=()=>void Y(),G(r,V(H,{get each(){return c()},children:e=>(()=>{var t=et(),n=t.firstChild,r=n.firstChild,i=r.firstChild;i.firstChild,i.nextSibling;var a=r.nextSibling;return n.$$click=()=>J(e.nodeId),G(i,()=>e.shortId,null),G(r,()=>e.name??e.nodeId,null),G(a,()=>e.path),b(()=>n.classList.toggle(`active`,u()===e.nodeId)),t})()})),e}}),l),p.addEventListener(`change`,e=>te(e.currentTarget.checked)),h.$$click=()=>void oe(),G(l,V(U,{get when(){return g().pid},get children(){var e=Ue();return e.firstChild,G(e,()=>g().pid,null),e}}),null),G(_,V(U,{get when(){return m()},get children(){var e=We();return G(e,m),e}}),null),G(_,V(U,{get when(){return de(()=>n()!==null)()&&o()!==null},get fallback(){return(()=>{var e=nt();return G(e,V(U,{get when(){return n()},get fallback(){return rt()},get children(){return tt()}})),e})()},get children(){return[(()=>{var e=Ke(),t=e.firstChild,r=t.nextSibling.firstChild,i=r.firstChild,a=r.nextSibling,s=a.nextSibling,c=s.nextSibling;return G(t,V(U,{get when(){return f().length===0},get fallback(){return V(H,{get each(){return f()},children:(e,t)=>[V(U,{get when(){return t()>0},get children(){return it()}}),(()=>{var t=at();return t.$$click=()=>J(e.id),G(t,()=>e.name??e.type),b(()=>t.classList.toggle(`active`,u()===e.id)),t})()]})},get children(){var e=Ge(),t=e.firstChild;return G(e,n,t),G(e,o,null),e}})),G(r,()=>Math.round(ie()*100),i),a.$$click=()=>M?.fitAll(),s.$$click=()=>M?.zoomToPercent(1),c.$$click=()=>S(e=>e+1),e})(),V(U,{get when(){return D().length>1},get children(){var e=qe(),t=e.firstChild;return t.$$click=()=>ye(null),G(e,V(H,{get each(){return D()},children:e=>(()=>{var t=ot(),n=t.firstChild,r=n.firstChild;return t.$$click=()=>ye(e.id),G(t,()=>e.name??`#${e.id}`,n),G(n,()=>Math.round(e.w),r),G(n,()=>Math.round(e.h),null),b(()=>t.classList.toggle(`active`,O()===e.id)),t})()}),null),b(()=>t.classList.toggle(`active`,O()===null)),e}}),(()=>{var e=Je();return e.addEventListener(`load`,he),_e(e=>{j=e},e),b(()=>ge(e,`src`,E())),e})()]}}),null),b(()=>p.checked=C()),t})()}he([`click`]);var ct=document.getElementById(`root`);if(!ct)throw Error(`缺少 #root 容器`);me(()=>V(st,{}),ct);
|
package/ui/dist/index.html
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<title>paintress</title>
|
|
7
|
-
<script type="module" crossorigin src="/assets/index-
|
|
7
|
+
<script type="module" crossorigin src="/assets/index-WQnLS4sD.js"></script>
|
|
8
8
|
<link rel="stylesheet" crossorigin href="/assets/index-lyiZ9W-B.css">
|
|
9
9
|
</head>
|
|
10
10
|
<body>
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),t.credentials=e.crossOrigin===`use-credentials`?`include`:e.crossOrigin===`anonymous`?`omit`:`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var e={context:void 0,registry:void 0,effects:void 0,done:!1,getContextId(){return t(this.context.count)},getNextContextId(){return t(this.context.count++)}};function t(t){let n=String(t),r=n.length-1;return e.context.id+(r?String.fromCharCode(96+r):``)+n}function n(t){e.context=t}var r=(e,t)=>e===t,i=Symbol(`solid-track`),a={equals:r},o=null,s=M,c=1,l=2,u={owned:null,cleanups:null,context:null,owner:null},d=null,f=null,p=null,m=null,h=null,g=0;function _(e,t){let n=p,r=d,i=e.length===0,a=t===void 0?r:t,o=i?u:{owned:null,cleanups:null,context:a?a.context:null,owner:a},s=i?e:()=>e(v(o));d=o,p=null;try{return j(s,!0)}finally{p=n,d=r}}function v(e){return()=>C(()=>F(e))}function y(e,t){t=t?Object.assign({},a,t):a;let n={value:e,observers:null,observerSlots:null,comparator:t.equals||void 0};return[ie.bind(n),e=>(typeof e==`function`&&(e=f&&f.running&&f.sources.has(n)?e(n.tValue):e(n.value)),D(n,e))]}function b(e,t,n){O(k(e,t,!1,c))}function x(e,t,n){s=se;let r=k(e,t,!1,c),i=E&&re(E);i&&(r.suspense=i),n&&n.render||(r.user=!0),h?h.push(r):O(r)}function S(e,t,n){n=n?Object.assign({},a,n):a;let r=k(e,t,!0,0);return r.observers=null,r.observerSlots=null,r.comparator=n.equals||void 0,O(r),ie.bind(r)}function C(e){if(p===null)return e();let t=p;p=null;try{return e()}finally{p=t}}function w(e,t,n){let r=Array.isArray(e),i,a=n&&n.defer;return n=>{let o;if(r){o=Array(e.length);for(let t=0;t<e.length;t++)o[t]=e[t]()}else o=e();if(a)return a=!1,n;let s=C(()=>t(o,i,n));return i=o,s}}function ee(e){x(()=>C(e))}function T(e){return d===null||(d.cleanups===null?d.cleanups=[e]:d.cleanups.push(e)),e}var[te,ne]=y(!1);function re(e){let t;return d&&d.context&&(t=d.context[e.id])!==void 0?t:e.defaultValue}var E;function ie(){let e=f&&f.running;if(this.sources&&(e?this.tState:this.state)){if((e?this.tState:this.state)===c)O(this);else{let e=m;m=null,j(()=>N(this),!1),m=e}}if(p){let e=this.observers;if(!e||e[e.length-1]!==p){let t=e?e.length:0;p.sources?(p.sources.push(this),p.sourceSlots.push(t)):(p.sources=[this],p.sourceSlots=[t]),e?(e.push(p),this.observerSlots.push(p.sources.length-1)):(this.observers=[p],this.observerSlots=[p.sources.length-1])}}return e&&f.sources.has(this)?this.tValue:this.value}function D(e,t,n){let r=f&&f.running&&f.sources.has(e)?e.tValue:e.value;if(!e.comparator||!e.comparator(r,t)){if(f){let r=f.running;(r||!n&&f.sources.has(e))&&(f.sources.add(e),e.tValue=t),r||(e.value=t)}else e.value=t;e.observers&&e.observers.length&&j(()=>{for(let t=0;t<e.observers.length;t+=1){let n=e.observers[t],r=f&&f.running;r&&f.disposed.has(n)||((r?!n.tState:!n.state)&&(n.pure?m.push(n):h.push(n),n.observers&&P(n)),r?n.tState=c:n.state=c)}if(m.length>1e6)throw m=[],Error()},!1)}return t}function O(e){if(!e.fn)return;F(e);let t=g;ae(e,f&&f.running&&f.sources.has(e)?e.tValue:e.value,t),f&&!f.running&&f.sources.has(e)&&queueMicrotask(()=>{j(()=>{f&&(f.running=!0),p=d=e,ae(e,e.tValue,t),p=d=null},!1)})}function ae(e,t,n){let r,i=d,a=p;p=d=e;try{r=e.fn(t)}catch(t){return e.pure&&(f&&f.running?(e.tState=c,e.tOwned&&e.tOwned.forEach(F),e.tOwned=void 0):(e.state=c,e.owned&&e.owned.forEach(F),e.owned=null)),e.updatedAt=n+1,R(t)}finally{p=a,d=i}(!e.updatedAt||e.updatedAt<=n)&&(e.updatedAt!=null&&`observers`in e?D(e,r,!0):f&&f.running&&e.pure?(f.sources.has(e)||(e.value=r),f.sources.add(e),e.tValue=r):e.value=r,e.updatedAt=n)}function k(e,t,n,r=c,i){let a={fn:e,state:r,updatedAt:null,owned:null,sources:null,sourceSlots:null,cleanups:null,value:t,owner:d,context:d?d.context:null,pure:n};return f&&f.running&&(a.state=0,a.tState=r),d===null||d!==u&&(f&&f.running&&d.pure?d.tOwned?d.tOwned.push(a):d.tOwned=[a]:d.owned?d.owned.push(a):d.owned=[a]),a}function A(e){let t=f&&f.running;if((t?e.tState:e.state)===0)return;if((t?e.tState:e.state)===l)return N(e);if(e.suspense&&C(e.suspense.inFallback))return e.suspense.effects.push(e);let n=[e];for(;(e=e.owner)&&(!e.updatedAt||e.updatedAt<g);){if(t&&f.disposed.has(e))return;(t?e.tState:e.state)&&n.push(e)}for(let r=n.length-1;r>=0;r--){if(e=n[r],t){let t=e,i=n[r+1];for(;(t=t.owner)&&t!==i;)if(f.disposed.has(t))return}if((t?e.tState:e.state)===c)O(e);else if((t?e.tState:e.state)===l){let t=m;m=null,j(()=>N(e,n[0]),!1),m=t}}}function j(e,t){if(m)return e();let n=!1;t||(m=[]),h?n=!0:h=[],g++;try{let t=e();return oe(n),t}catch(e){n||(h=null),m=null,R(e)}}function oe(e){if(m&&=(M(m),null),e)return;let t;if(f){if(!f.promises.size&&!f.queue.size){let e=f.sources,n=f.disposed;h.push.apply(h,f.effects),t=f.resolve;for(let e of h)`tState`in e&&(e.state=e.tState),delete e.tState;f=null,j(()=>{for(let e of n)F(e);for(let t of e){if(t.value=t.tValue,t.owned)for(let e=0,n=t.owned.length;e<n;e++)F(t.owned[e]);t.tOwned&&(t.owned=t.tOwned),delete t.tValue,delete t.tOwned,t.tState=0}ne(!1)},!1)}else if(f.running){f.running=!1,f.effects.push.apply(f.effects,h),h=null,ne(!0);return}}let n=h;h=null,n.length&&j(()=>s(n),!1),t&&t()}function M(e){for(let t=0;t<e.length;t++)A(e[t])}function se(t){let r,i=0;for(r=0;r<t.length;r++){let e=t[r];e.user?t[i++]=e:A(e)}if(e.context){if(e.count){e.effects||=[],e.effects.push(...t.slice(0,i));return}n()}for(e.effects&&(e.done||!e.count)&&(t=[...e.effects,...t],i+=e.effects.length,delete e.effects),r=0;r<i;r++)A(t[r])}function N(e,t){let n=f&&f.running;n?e.tState=0:e.state=0;for(let r=0;r<e.sources.length;r+=1){let i=e.sources[r];if(i.sources){let e=n?i.tState:i.state;e===c?i!==t&&(!i.updatedAt||i.updatedAt<g)&&A(i):e===l&&N(i,t)}}}function P(e){let t=f&&f.running;for(let n=0;n<e.observers.length;n+=1){let r=e.observers[n];(t?!r.tState:!r.state)&&(t?r.tState=l:r.state=l,r.pure?m.push(r):h.push(r),r.observers&&P(r))}}function F(e){let t;if(e.sources)for(;e.sources.length;){let t=e.sources.pop(),n=e.sourceSlots.pop(),r=t.observers;if(r&&r.length){let e=r.pop(),i=t.observerSlots.pop();n<r.length&&(e.sourceSlots[i]=n,r[n]=e,t.observerSlots[n]=i)}}if(e.tOwned){for(t=e.tOwned.length-1;t>=0;t--)F(e.tOwned[t]);delete e.tOwned}if(f&&f.running&&e.pure)I(e,!0);else if(e.owned){for(t=e.owned.length-1;t>=0;t--)F(e.owned[t]);e.owned=null}if(e.cleanups){for(t=e.cleanups.length-1;t>=0;t--)e.cleanups[t]();e.cleanups=null}f&&f.running?e.tState=0:e.state=0}function I(e,t){if(t||(e.tState=0,f.disposed.add(e)),e.owned)for(let t=0;t<e.owned.length;t++)I(e.owned[t])}function ce(e){return e instanceof Error?e:Error(typeof e==`string`?e:`Unknown error`,{cause:e})}function L(e,t,n){try{for(let n of t)n(e)}catch(e){R(e,n&&n.owner||null)}}function R(e,t=d){let n=o&&t&&t.context&&t.context[o],r=ce(e);if(!n)throw r;h?h.push({fn(){L(r,n,t)},state:c}):L(r,n,t)}var le=Symbol(`fallback`);function z(e){for(let t=0;t<e.length;t++)e[t]()}function ue(e,t,n={}){let r=[],a=[],o=[],s=0,c=t.length>1?[]:null;return T(()=>z(o)),()=>{let l=e()||[],u=l.length,d,f;return l[i],C(()=>{let e,t,i,m,h,g,v,y,b;if(u===0)s!==0&&(z(o),o=[],r=[],a=[],s=0,c&&=[]),n.fallback&&(r=[le],a[0]=_(e=>(o[0]=e,n.fallback())),s=1);else if(s===0){for(a=Array(u),f=0;f<u;f++)r[f]=l[f],a[f]=_(p);s=u}else{for(i=Array(u),m=Array(u),c&&(h=Array(u)),g=0,v=Math.min(s,u);g<v&&r[g]===l[g];g++);for(v=s-1,y=u-1;v>=g&&y>=g&&r[v]===l[y];v--,y--)i[y]=a[v],m[y]=o[v],c&&(h[y]=c[v]);for(e=new Map,t=Array(y+1),f=y;f>=g;f--)b=l[f],d=e.get(b),t[f]=d===void 0?-1:d,e.set(b,f);for(d=g;d<=v;d++)b=r[d],f=e.get(b),f!==void 0&&f!==-1?(i[f]=a[d],m[f]=o[d],c&&(h[f]=c[d]),f=t[f],e.set(b,f)):o[d]();for(f=g;f<u;f++)f in i?(a[f]=i[f],o[f]=m[f],c&&(c[f]=h[f],c[f](f))):a[f]=_(p);a=a.slice(0,s=u),r=l.slice(0)}return a});function p(e){if(o[f]=e,c){let[e,n]=y(f);return c[f]=n,t(l[f],e)}return t(l[f])}}}function B(e,t){return C(()=>e(t||{}))}var de=e=>`Stale read from <${e}>.`;function V(e){let t=`fallback`in e&&{fallback:()=>e.fallback};return S(ue(()=>e.each,e.children,t||void 0))}function H(e){let t=e.keyed,n=S(()=>e.when,void 0,void 0),r=t?n:S(n,void 0,{equals:(e,t)=>!e==!t});return S(()=>{let i=r();if(i){let a=e.children;return typeof a==`function`&&a.length>0?C(()=>a(t?i:()=>{if(!C(r))throw de(`Show`);return n()})):a}return e.fallback},void 0,void 0)}var fe=e=>S(()=>e());function pe(e,t,n){let r=n.length,i=t.length,a=r,o=0,s=0,c=t[i-1].nextSibling,l=null;for(;o<i||s<a;)if(t[o]===n[s])o++,s++;else{for(;t[i-1]===n[a-1];)i--,a--;if(i===o){let t=a<r?s?n[s-1].nextSibling:n[a-s]:c;for(;s<a;)e.insertBefore(n[s++],t)}else if(a===s)for(;o<i;)l&&l.has(t[o])||t[o].remove(),o++;else if(t[o]===n[a-1]&&n[s]===t[i-1]){let r=t[--i].nextSibling;e.insertBefore(n[s++],t[o++].nextSibling),e.insertBefore(n[--a],r),t[i]=n[a]}else{if(!l){l=new Map;let e=s;for(;e<a;)l.set(n[e],e++)}let r=l.get(t[o]);if(r!=null){if(s<r&&r<a){let c=o,u=1,d;for(;++c<i&&c<a&&(d=l.get(t[c]))!=null&&d===r+u;)u++;if(u>r-s){let i=t[o];for(;s<r;)e.insertBefore(n[s++],i)}else e.replaceChild(n[s++],t[o++])}else o++}else t[o++].remove()}}}var me=`_$DX_DELEGATE`;function U(e,t,n,r={}){let i;return _(r=>{i=r,t===document?e():G(t,e(),!n&&t.firstChild?null:void 0,n)},r.owner),()=>{i(),t.textContent=``}}function W(e,t,n,r){let i,a=()=>{let t=r?document.createElementNS(`http://www.w3.org/1998/Math/MathML`,`template`):document.createElement(`template`);return t.innerHTML=e,n?t.content.firstChild.firstChild:r?t.firstChild:t.content.firstChild},o=t?()=>C(()=>document.importNode(i||=a(),!0)):()=>(i||=a()).cloneNode(!0);return o.cloneNode=o,o}function he(e,t=window.document){let n=t[me]||(t[me]=new Set);for(let r=0,i=e.length;r<i;r++){let i=e[r];n.has(i)||(n.add(i),t.addEventListener(i,ve))}}function ge(e,t,n){K(e)||(n==null?e.removeAttribute(t):e.setAttribute(t,n))}function _e(e,t,n){return C(()=>e(t,n))}function G(e,t,n,r){if(n!==void 0&&!r&&(r=[]),typeof t!=`function`)return q(e,t,r,n);b(r=>q(e,t(),r,n),r)}function K(t){return!!e.context&&!e.done&&(!t||t.isConnected)}function ve(t){if(e.registry&&e.events&&e.events.find(([e,n])=>n===t))return;let n=t.target,r=`$$${t.type}`,i=t.target,a=t.currentTarget,o=e=>Object.defineProperty(t,"target",{configurable:!0,value:e}),s=()=>{let e=n[r];if(e&&!n.disabled){let i=n[`${r}Data`];if(i===void 0?e.call(n,t):e.call(n,i,t),t.cancelBubble)return}return n.host&&typeof n.host!=`string`&&!n.host._$host&&n.contains(t.target)&&o(n.host),!0},c=()=>{for(;s()&&(n=n._$host||n.parentNode||n.host););};Object.defineProperty(t,"currentTarget",{configurable:!0,get(){return n||document}}),e.registry&&!e.done&&(e.done=_$HY.done=!0);try{if(t.composedPath){let e=t.composedPath();o(e[0]);for(let t=0;t<e.length-2&&(n=e[t],s());t++){if(n._$host){n=n._$host,c();break}if(n.parentNode===a)break}}else c();o(i)}finally{t=n=null}}function q(e,t,n,r,i){let a=K(e);if(a){!n&&(n=[...e.childNodes]);let t=[];for(let e=0;e<n.length;e++){let r=n[e];r.nodeType===8&&r.data.slice(0,2)===`!$`?r.remove():t.push(r)}n=t}for(;typeof n==`function`;)n=n();if(t===n)return n;let o=typeof t,s=r!==void 0;if(e=s&&n[0]&&n[0].parentNode||e,o===`string`||o===`number`){if(a||o===`number`&&(t=t.toString(),t===n))return n;if(s){let i=n[0];i&&i.nodeType===3?i.data!==t&&(i.data=t):i=document.createTextNode(t),n=X(e,n,r,i)}else n=n!==``&&typeof n==`string`?e.firstChild.data=t:e.textContent=t}else if(t==null||o===`boolean`){if(a)return n;n=X(e,n,r)}else if(o===`function`)return b(()=>{let i=t();for(;typeof i==`function`;)i=i();n=q(e,i,n,r)}),()=>n;else if(Array.isArray(t)){let o=[],c=n&&Array.isArray(n);if(J(o,t,n,i))return b(()=>n=q(e,o,n,r,!0)),()=>n;if(a){if(!o.length)return n;if(r===void 0)return n=[...e.childNodes];let t=o[0];if(t.parentNode!==e)return n;let i=[t];for(;(t=t.nextSibling)!==r;)i.push(t);return n=i}if(o.length===0){if(n=X(e,n,r),s)return n}else c?n.length===0?Y(e,o,r):pe(e,n,o):(n&&X(e),Y(e,o));n=o}else if(t.nodeType){if(a&&t.parentNode)return n=s?[t]:t;if(Array.isArray(n)){if(s)return n=X(e,n,r,t);X(e,n,null,t)}else n==null||n===``||!e.firstChild?e.appendChild(t):e.replaceChild(t,e.firstChild);n=t}return n}function J(e,t,n,r){let i=!1;for(let a=0,o=t.length;a<o;a++){let o=t[a],s=n&&n[e.length],c;if(o!=null&&o!==!0&&o!==!1){if((c=typeof o)==`object`&&o.nodeType)e.push(o);else if(Array.isArray(o))i=J(e,o,s)||i;else if(c===`function`){if(r){for(;typeof o==`function`;)o=o();i=J(e,Array.isArray(o)?o:[o],Array.isArray(s)?s:[s])||i}else e.push(o),i=!0}else{let t=String(o);s&&s.nodeType===3&&s.data===t?e.push(s):e.push(document.createTextNode(t))}}}return i}function Y(e,t,n=null){for(let r=0,i=t.length;r<i;r++)e.insertBefore(t[r],n)}function X(e,t,n,r){if(n===void 0)return e.textContent=``;let i=r||document.createTextNode(``);if(t.length){let r=!1;for(let a=t.length-1;a>=0;a--){let o=t[a];if(i!==o){let t=o.parentNode===e;!r&&!a?t?e.replaceChild(i,o):e.insertBefore(i,n):t&&o.remove()}else r=!0}}else e.insertBefore(i,n);return[i]}async function Z(e){let t=await fetch(e,{headers:{accept:`application/json`}});if(!t.ok){let e=await t.text().catch(()=>``);throw Error(`HTTP ${t.status}${e?`: ${e.slice(0,200)}`:``}`)}return await t.json()}function ye(){return Z(`/api/projects`)}function be(e){return Z(`/api/projects/${encodeURIComponent(e)}/files`)}function xe(e,t){return`/render/${encodeURIComponent(e)}/${t.split(`/`).map(encodeURIComponent).join(`/`)}?embed=1`}function Se(e,t){return`/events?project=${encodeURIComponent(e)}&path=${encodeURIComponent(t)}`}function Ce(e){return Z(`/api/marks?project=${encodeURIComponent(e)}`)}async function we(e){let t=await fetch(`/api/marks`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify(e)});if(!t.ok)throw Error(`HTTP ${t.status}`);let n=await t.json();if(!n.ok)throw Error(n.error??`添加标记失败`);return n.mark}async function Te(e){let t=await fetch(`/api/marks?project=${encodeURIComponent(e)}`,{method:`DELETE`});if(!t.ok)throw Error(`HTTP ${t.status}`);return(await t.json()).cleared}function Ee(e,t){return Z(`/api/changes?project=${encodeURIComponent(e)}&path=${encodeURIComponent(t)}`)}var De=.1,Oe=.02;function Q(e,t=De){return Math.min(4,Math.max(t,e))}function ke(e,t,n,r,i=De){let a=Q(e.z*t,i);if(a===e.z)return e;let o=a/e.z;return{z:a,tx:n-(n-e.tx)*o,ty:r-(r-e.ty)*o}}function Ae(e,t,n,r=De){return ke(e,Q(t,r)/e.z,n.width/2,n.height/2,r)}function je(e,t,n=24){let r=Math.max(1,e.w),i=Math.max(1,e.h),a=Math.max(1,t.width-n*2),o=Math.max(1,t.height-n*2),s=Q(Math.min(a/r,o/i),Oe);return{z:s,tx:(t.width-r*s)/2-e.x*s,ty:(t.height-i*s)/2-e.y*s}}function Me(e,t,n){return{z:e.z,tx:e.tx+t,ty:e.ty+n}}function Ne(e){return`translate(${e.tx}px, ${e.ty}px) scale(${e.z})`}function Pe(e){if(e===null||e===``)return null;let t;try{t=JSON.parse(e)}catch{return null}if(typeof t!=`object`||!t)return null;let{z:n,tx:r,ty:i}=t;return typeof n!=`number`||typeof r!=`number`||typeof i!=`number`||!Number.isFinite(n)||!Number.isFinite(r)||!Number.isFinite(i)||n<=0?null:{z:Q(n,Oe),tx:r,ty:i}}var Fe=3,Ie=.0015;function Le({doc:e,onChange:t,onLevelStep:n}){let r=e.querySelector(`.ptr-canvas`);if(r===null)return null;let i=r;i.style.transformOrigin=`0 0`;let a={z:1,tx:0,ty:0},o=!1,s=!1,c=!1,l=null,u=()=>({width:e.documentElement.clientWidth||1,height:e.documentElement.clientHeight||1});function d(){i.style.transform=Ne(a),t?.(a)}function f(e){a=e,d()}function p(){i.style.transition=``}function m(e){i.style.transition=`transform 180ms ease-out`,f(e),setTimeout(p,220)}function h(t){e.documentElement.style.cursor=t}function g(e){if(e.preventDefault(),e.altKey&&n!==void 0){n(e.deltaY>0?-1:1,{x:e.clientX,y:e.clientY});return}p();let t=1;e.deltaMode===1?t=16:e.deltaMode===2&&(t=u().height),f(ke(a,Math.exp(-e.deltaY*t*Ie),e.clientX,e.clientY))}function _(t){return t.button===1?!0:t.button===0?o?!0:t.target===i||t.target===e.body||t.target===e.documentElement:!1}function v(e){_(e)&&(e.preventDefault(),l={lastX:e.clientX,lastY:e.clientY,startX:e.clientX,startY:e.clientY},s=!1)}function y(t){if(!l)return;if(!s){if(Math.hypot(t.clientX-l.startX,t.clientY-l.startY)<Fe)return;s=!0,p(),e.body.style.userSelect=`none`,h(`grabbing`)}let n=t.clientX-l.lastX,r=t.clientY-l.lastY;l.lastX=t.clientX,l.lastY=t.clientY,f(Me(a,n,r))}function b(){l&&(l=null,s&&(s=!1,c=!0,e.body.style.userSelect=``,h(o?`grab`:``)))}function x(e){o!==e&&(o=e,s||h(e?`grab`:``))}function S(e){if(e.key===` `&&!e.metaKey&&!e.ctrlKey&&!e.altKey){let t=e.target,n=t?.tagName??``;if(n===`INPUT`||n===`TEXTAREA`||t?.isContentEditable===!0)return;x(!0),e.preventDefault()}else ee(e)&&e.preventDefault()}function C(e){e.key===` `&&x(!1)}function w(){x(!1),b()}function ee(e){return(e.ctrlKey||e.metaKey)&&(e.key===`0`||e.key===`)`||e.code===`Digit0`||e.code===`Numpad0`)?(f(Ae(a,1,u())),!0):e.shiftKey&&!e.ctrlKey&&!e.metaKey&&(e.key===`!`||e.code===`Digit1`)?(T(),!0):!1}function T(){f(je({x:0,y:0,w:i.offsetWidth,h:i.offsetHeight},u()))}function te(e){let t=u();m({z:a.z,tx:t.width/2-(e.x+e.w/2)*a.z,ty:t.height/2-(e.y+e.h/2)*a.z})}return e.addEventListener(`wheel`,g,{passive:!1}),e.addEventListener(`mousedown`,v,!0),e.addEventListener(`mousemove`,y,!0),e.addEventListener(`mouseup`,b,!0),e.addEventListener(`keydown`,S),e.addEventListener(`keyup`,C),e.defaultView?.addEventListener(`blur`,w),{get:()=>a,set:f,fitAll:T,centerOn:te,focusBox:e=>m(je(e,u())),zoomToPercent:e=>f(Ae(a,e,u())),consumeDragClick:()=>{let e=c;return c=!1,e},handleKey:ee,setSpace:x,destroy:()=>{e.removeEventListener(`wheel`,g),e.removeEventListener(`mousedown`,v,!0),e.removeEventListener(`mousemove`,y,!0),e.removeEventListener(`mouseup`,b,!0),e.removeEventListener(`keydown`,S),e.removeEventListener(`keyup`,C),e.defaultView?.removeEventListener(`blur`,w)}}}var Re=W(`<span class=badge>v`),ze=W(`<ul class=list>`),Be=W(`<section class="section files"><h2>设计稿 <span class=hint>depth `),Ve=W(`<section class="section marks"><h2>标记<button class="ghost tiny">清空</button></h2><ul class=list>`),He=W(`<span class=hint>pid `),Ue=W(`<div class=error>`),We=W(`<code>/`),Ge=W(`<div class=toolbar><div class=crumbs></div><div class=tools><span class="hint zoom">%</span><button class="ghost tiny"title=适应窗口(Shift+1)>适应</button><button class="ghost tiny"title=100%(Ctrl/Cmd+0)>1:1</button><button class=ghost>重新渲染`),Ke=W(`<div class=boardbar><button class=board>全部`),qe=W(`<iframe class=preview title="design preview"sandbox="allow-same-origin allow-scripts">`),Je=W(`<div class=app><aside class=sidebar><header class=sidebar-head><img class=brand-mark src=/logo.svg alt><h1>paintress</h1></header><section class=section><h2>项目</h2></section><footer class=sidebar-foot><label class=toggle><input type=checkbox>实时刷新</label><button class=ghost>刷新列表</button></footer></aside><main class=stage>`),Ye=W(`<p class=empty>还没有注册项目<br><code>paintress watch <name> <dir>`),Xe=W(`<li><button class=item><span class=item-name></span><span class=item-meta> 个设计稿`),Ze=W(`<p class=empty>没有 .ptr / .pen 文件`),Qe=W(`<li><button class=item><span class=item-name>`),$e=W(`<li><button class=item><span class=item-name><b class=mark-no>#</b> </span><span class=item-meta>`),et=W(`<p>从左侧选择一个设计稿`),tt=W(`<div class=placeholder>`),nt=W(`<p>从左侧选择项目`),rt=W(`<span class=sep>/`),it=W(`<button class=crumb>`),at=W(`<button class=board><span class=board-size>×`);function $(e){return typeof CSS<`u`&&typeof CSS.escape==`function`?CSS.escape(e):e.replace(/["\\]/g,`\\$&`)}function ot(){let[e,t]=y([]),[n,r]=y(null),[i,a]=y([]),[o,s]=y(null),[c,l]=y([]),[u,d]=y(null),[f,p]=y([]),[m,h]=y(null),[g,_]=y({}),[v,S]=y(0),[C,te]=y(!0),[ne,re]=y(``),[E,ie]=y([]),[D,O]=y(null),[ae,k]=y(1),A,j=null,oe;function M(){let e=new URLSearchParams,t=n(),r=o();t&&e.set(`project`,t),r&&e.set(`file`,r);let i=e.toString();history.replaceState(null,``,i?`?${i}`:location.pathname)}async function se(){try{let e=await ye();t(e.projects),_({pid:e.pid,version:e.version}),h(null)}catch(e){h(e instanceof Error?e.message:String(e))}}async function N(e){try{l((await Ce(e)).marks)}catch{l([])}}async function P(e){r(e),s(null),d(null),p([]);try{let t=await be(e);a(t.files),h(null)}catch(e){a([]),h(e instanceof Error?e.message:String(e))}N(e),M()}function F(e){s(e),d(null),p([]),M()}ee(()=>{let e=e=>{let t=e.target;return t?.tagName===`INPUT`||t?.tagName===`TEXTAREA`||t?.isContentEditable===!0},t=t=>{e(t)||(t.key===` `&&!t.ctrlKey&&!t.metaKey&&!t.altKey?(j?.setSpace(!0),t.preventDefault()):j?.handleKey(t)===!0&&t.preventDefault())},n=e=>{e.key===` `&&j?.setSpace(!1)};window.addEventListener(`keydown`,t),window.addEventListener(`keyup`,n),T(()=>{window.removeEventListener(`keydown`,t),window.removeEventListener(`keyup`,n)});let r=new URLSearchParams(location.search);(async()=>{await se();let e=r.get(`project`);if(e){await P(e);let t=r.get(`file`);t&&F(t)}})()});let I=()=>A?.contentDocument??null;function ce(){let e=I();if(!e||e.getElementById(`ptr-style`))return;let t=e.createElement(`style`);t.id=`ptr-style`,t.textContent=`[data-ptr-selected]{outline:2px solid #908030 !important;outline-offset:-2px;}
|
|
2
|
-
[data-ptr-hover]:not([data-ptr-selected]){outline:1px dashed rgba(144,128,48,.55) !important;outline-offset:-2px;}
|
|
3
|
-
[data-ptr-changed]{box-shadow:inset 0 0 0 2px #908030 !important;animation:ptr-pulse 1.4s ease-in-out 3;}
|
|
4
|
-
@keyframes ptr-pulse{0%,100%{box-shadow:inset 0 0 0 2px #908030}50%{box-shadow:inset 0 0 0 2px rgba(144,128,48,.35)}}
|
|
5
|
-
html{cursor:default;}
|
|
6
|
-
html,body{overflow:hidden;}`,e.head.appendChild(t)}function L(){let e=I();if(!e)return;for(let t of e.querySelectorAll(`[data-ptr-selected]`))t.removeAttribute(`data-ptr-selected`);let t=u();t&&e.querySelector(`[data-node-id="${$(t)}"]`)?.setAttribute(`data-ptr-selected`,``)}function R(e){return e.parentElement?.closest(`[data-node-id]`)??null}function le(e){return e.querySelector(`:scope > [data-node-id]`)}function z(e){if(j?.consumeDragClick()===!0){e.preventDefault(),e.stopPropagation();return}let t=e.target?.closest(`[data-node-id]`);t&&(e.preventDefault(),e.stopPropagation(),J(e.altKey?R(t)??t:t))}function ue(e,t){let n=I();if(!n)return;let r=u(),i=r===null?null:n.querySelector(`[data-node-id="${$(r)}"]`);if(i===null){let e=(n.elementFromPoint(t.x,t.y)?.closest(`[data-node-id]`))?.dataset.nodeId;e!==void 0&&Y(e);return}let a=(e===1?R(i):le(i))?.dataset.nodeId;a!==void 0&&Y(a)}function de(e){let t=I();if(t){for(let e of t.querySelectorAll(`[data-ptr-hover]`))e.removeAttribute(`data-ptr-hover`);(e.target?.closest(`[data-node-id]`))?.setAttribute(`data-ptr-hover`,``)}}async function pe(){let e=n(),t=o();if(e&&t)try{let n=await Ee(e,t);if(!n.ok||n.ids.length===0)return;let r=I();if(!r)return;for(let e of n.ids)r.querySelector(`[data-node-id="${$(e)}"]`)?.setAttribute(`data-ptr-changed`,``)}catch{}}function me(){let e=I();return e?Array.from(e.querySelectorAll(`[data-board]`)).map(e=>{let t=e.dataset;return{id:t.nodeId??``,...t.boardName===void 0?{}:{name:t.boardName},x:Number(t.boardX??0),y:Number(t.boardY??0),w:Number(t.boardW??0),h:Number(t.boardH??0)}}):[]}function U(){let e=n(),t=o();return e&&t?`paintress:viewport:${e}/${t}`:null}function W(e){let t=U();t!==null&&(clearTimeout(oe),oe=setTimeout(()=>{try{localStorage.setItem(t,JSON.stringify(e))}catch{}},300))}function he(){let e=I();e&&(ce(),j?.destroy(),j=Le({doc:e,onChange:e=>{k(e.z),W(e)},onLevelStep:ue}),ie(me()),O(null),K(),e.addEventListener(`click`,z,!0),e.addEventListener(`mousemove`,de,!0),L(),pe())}function K(){if(!j)return;let e=U(),t=e===null?null:localStorage.getItem(e),n=t===null?null:Pe(t);n===null?j.fitAll():j.set(n)}function ve(e){if(O(e),!j)return;if(e===null){j.fitAll();return}let t=E().find(t=>t.id===e);t&&j.focusBox({x:t.x,y:t.y,w:t.w,h:t.h})}function q(e){let t=[],n=e;for(;n;){let e=n.closest(`[data-node-id]`);if(!e)break;let r=e;t.unshift({id:r.dataset.nodeId??``,type:r.dataset.nodeType??`?`,name:r.dataset.nodeName}),n=e.parentElement}return t}async function J(e){let t=e.dataset.nodeId??``;if(t===``)return;let r=q(e);d(t),p(r),L();let i=n();if(i)try{await we({project:i,nodeId:t,...e.dataset.nodeName===void 0?{}:{name:e.dataset.nodeName},...e.dataset.nodeType===void 0?{}:{type:e.dataset.nodeType},path:r.map(e=>e.name??e.type).join(` / `)}),l((await Ce(i)).marks),h(null)}catch(e){h(e instanceof Error?e.message:String(e))}}function Y(e){d(e),L();let t=I(),n=t?.querySelector(`[data-node-id="${$(e)}"]`);if(!n||!t){p([]);return}p(q(n));let r=t.querySelector(`.ptr-canvas`);if(!r||!j){n.scrollIntoView({block:`center`});return}let i=n.getBoundingClientRect(),a=r.getBoundingClientRect(),o=j.get().z;j.centerOn({x:(i.left-a.left)/o,y:(i.top-a.top)/o,w:i.width/o,h:i.height/o})}async function X(){let e=n();if(e)try{await Te(e),l([]),d(null),p([]),L()}catch(e){h(e instanceof Error?e.message:String(e))}}x(w([n,o,v],()=>{let e=n(),t=o();re(e&&t?`${xe(e,t)}&r=${v()}`:``)}));let Z=null;return x(w([n,o,C],()=>{Z?.close(),Z=null;let e=n(),t=o();C()&&e&&t&&(Z=new EventSource(Se(e,t)),Z.addEventListener(`change`,()=>S(e=>e+1)))})),T(()=>Z?.close()),(()=>{var t=Je(),r=t.firstChild,a=r.firstChild;a.firstChild.nextSibling;var s=a.nextSibling;s.firstChild;var l=s.nextSibling,d=l.firstChild,p=d.firstChild,h=d.nextSibling,_=r.nextSibling;return G(a,B(H,{get when(){return g().version},get children(){var e=Re();return e.firstChild,G(e,()=>g().version,null),e}}),null),G(s,B(H,{get when(){return e().length>0},get fallback(){return Ye()},get children(){var t=ze();return G(t,B(V,{get each(){return e()},children:e=>(()=>{var t=Xe(),r=t.firstChild,i=r.firstChild,a=i.nextSibling,o=a.firstChild;return r.$$click=()=>void P(e.name),G(i,()=>e.name),G(a,()=>e.fileCount,o),b(()=>r.classList.toggle(`active`,n()===e.name)),t})()})),t}}),null),G(r,B(H,{get when(){return n()},get children(){var t=Be(),r=t.firstChild.firstChild.nextSibling;return r.firstChild,G(r,()=>e().find(e=>e.name===n())?.depth??`-`,null),G(t,B(H,{get when(){return i().length>0},get fallback(){return Ze()},get children(){var e=ze();return G(e,B(V,{get each(){return i()},children:e=>(()=>{var t=Qe(),n=t.firstChild,r=n.firstChild;return n.$$click=()=>F(e),G(r,e),b(()=>n.classList.toggle(`active`,o()===e)),t})()})),e}}),null),t}}),l),G(r,B(H,{get when(){return c().length>0},get children(){var e=Ve(),t=e.firstChild,n=t.firstChild.nextSibling,r=t.nextSibling;return n.$$click=()=>void X(),G(r,B(V,{get each(){return c()},children:e=>(()=>{var t=$e(),n=t.firstChild,r=n.firstChild,i=r.firstChild;i.firstChild,i.nextSibling;var a=r.nextSibling;return n.$$click=()=>Y(e.nodeId),G(i,()=>e.shortId,null),G(r,()=>e.name??e.nodeId,null),G(a,()=>e.path),b(()=>n.classList.toggle(`active`,u()===e.nodeId)),t})()})),e}}),l),p.addEventListener(`change`,e=>te(e.currentTarget.checked)),h.$$click=()=>void se(),G(l,B(H,{get when(){return g().pid},get children(){var e=He();return e.firstChild,G(e,()=>g().pid,null),e}}),null),G(_,B(H,{get when(){return m()},get children(){var e=Ue();return G(e,m),e}}),null),G(_,B(H,{get when(){return fe(()=>n()!==null)()&&o()!==null},get fallback(){return(()=>{var e=tt();return G(e,B(H,{get when(){return n()},get fallback(){return nt()},get children(){return et()}})),e})()},get children(){return[(()=>{var e=Ge(),t=e.firstChild,r=t.nextSibling.firstChild,i=r.firstChild,a=r.nextSibling,s=a.nextSibling,c=s.nextSibling;return G(t,B(H,{get when(){return f().length===0},get fallback(){return B(V,{get each(){return f()},children:(e,t)=>[B(H,{get when(){return t()>0},get children(){return rt()}}),(()=>{var t=it();return t.$$click=()=>Y(e.id),G(t,()=>e.name??e.type),b(()=>t.classList.toggle(`active`,u()===e.id)),t})()]})},get children(){var e=We(),t=e.firstChild;return G(e,n,t),G(e,o,null),e}})),G(r,()=>Math.round(ae()*100),i),a.$$click=()=>j?.fitAll(),s.$$click=()=>j?.zoomToPercent(1),c.$$click=()=>S(e=>e+1),e})(),B(H,{get when(){return E().length>1},get children(){var e=Ke(),t=e.firstChild;return t.$$click=()=>ve(null),G(e,B(V,{get each(){return E()},children:e=>(()=>{var t=at(),n=t.firstChild,r=n.firstChild;return t.$$click=()=>ve(e.id),G(t,()=>e.name??`#${e.id}`,n),G(n,()=>Math.round(e.w),r),G(n,()=>Math.round(e.h),null),b(()=>t.classList.toggle(`active`,D()===e.id)),t})()}),null),b(()=>t.classList.toggle(`active`,D()===null)),e}}),(()=>{var e=qe();return e.addEventListener(`load`,he),_e(e=>{A=e},e),b(()=>ge(e,`src`,ne())),e})()]}}),null),b(()=>p.checked=C()),t})()}he([`click`]);var st=document.getElementById(`root`);if(!st)throw Error(`缺少 #root 容器`);U(()=>B(ot,{}),st);
|