zdashboard 2.9.0 → 2.10.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/dist/cli.js +64 -47
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -5,45 +5,11 @@ import path9 from "path";
|
|
|
5
5
|
import fs9 from "fs";
|
|
6
6
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
7
7
|
import { access, readdir } from "fs/promises";
|
|
8
|
-
import { parseArgs as utilParseArgs } from "util";
|
|
9
|
-
|
|
10
|
-
// src/server/detect.ts
|
|
11
|
-
import fs from "fs";
|
|
12
|
-
import path from "path";
|
|
13
|
-
import { execFile } from "child_process";
|
|
14
|
-
var JUST_PROBE_TIMEOUT_MS = 5e3;
|
|
15
|
-
var JUST_FALLBACK_TIMEOUT_MS = 3e3;
|
|
16
|
-
function justAvailable(cwd) {
|
|
17
|
-
const probe = (args, timeout) => new Promise((resolve) => {
|
|
18
|
-
const child = execFile("just", args, { cwd, timeout }, (err) => resolve(!err));
|
|
19
|
-
if (child.killed) resolve(false);
|
|
20
|
-
});
|
|
21
|
-
return probe(["--list", "--unsupported"], JUST_PROBE_TIMEOUT_MS).then((ok) => ok ? true : probe(["--version"], JUST_FALLBACK_TIMEOUT_MS));
|
|
22
|
-
}
|
|
23
|
-
async function detect(root) {
|
|
24
|
-
const hasOpenspec = fs.existsSync(path.join(root, "openspec"));
|
|
25
|
-
const hasDocs = fs.existsSync(path.join(root, "docs"));
|
|
26
|
-
const hasJust = await justAvailable(root);
|
|
27
|
-
return { hasOpenspec, hasDocs, hasJust };
|
|
28
|
-
}
|
|
29
|
-
async function detectLiveShape(root) {
|
|
30
|
-
return detect(root);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// src/cli.ts
|
|
34
|
-
import { Context } from "cordis";
|
|
35
|
-
|
|
36
|
-
// src/core/server.ts
|
|
37
|
-
import http from "http";
|
|
38
|
-
import fs3 from "fs";
|
|
39
|
-
import path3 from "path";
|
|
40
|
-
import crypto from "crypto";
|
|
41
|
-
import { fileURLToPath } from "url";
|
|
42
8
|
|
|
43
9
|
// package.json
|
|
44
10
|
var package_default = {
|
|
45
11
|
name: "zdashboard",
|
|
46
|
-
version: "2.
|
|
12
|
+
version: "2.10.0",
|
|
47
13
|
description: "ZCode skill dashboard platform \u2014 pluggable viewers for zdesign/zview/zreview/zgoal",
|
|
48
14
|
type: "module",
|
|
49
15
|
bin: {
|
|
@@ -134,12 +100,47 @@ var package_default = {
|
|
|
134
100
|
}
|
|
135
101
|
};
|
|
136
102
|
|
|
103
|
+
// src/cli.ts
|
|
104
|
+
import { parseArgs as utilParseArgs } from "util";
|
|
105
|
+
|
|
106
|
+
// src/server/detect.ts
|
|
107
|
+
import fs from "fs";
|
|
108
|
+
import path from "path";
|
|
109
|
+
import { execFile } from "child_process";
|
|
110
|
+
var JUST_PROBE_TIMEOUT_MS = 5e3;
|
|
111
|
+
var JUST_FALLBACK_TIMEOUT_MS = 3e3;
|
|
112
|
+
function justAvailable(cwd) {
|
|
113
|
+
const probe = (args, timeout) => new Promise((resolve) => {
|
|
114
|
+
const child = execFile("just", args, { cwd, timeout }, (err) => resolve(!err));
|
|
115
|
+
if (child.killed) resolve(false);
|
|
116
|
+
});
|
|
117
|
+
return probe(["--list", "--unsupported"], JUST_PROBE_TIMEOUT_MS).then((ok) => ok ? true : probe(["--version"], JUST_FALLBACK_TIMEOUT_MS));
|
|
118
|
+
}
|
|
119
|
+
async function detect(root) {
|
|
120
|
+
const hasOpenspec = fs.existsSync(path.join(root, "openspec"));
|
|
121
|
+
const hasDocs = fs.existsSync(path.join(root, "docs"));
|
|
122
|
+
const hasJust = await justAvailable(root);
|
|
123
|
+
return { hasOpenspec, hasDocs, hasJust };
|
|
124
|
+
}
|
|
125
|
+
async function detectLiveShape(root) {
|
|
126
|
+
return detect(root);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// src/cli.ts
|
|
130
|
+
import { Context } from "cordis";
|
|
131
|
+
|
|
137
132
|
// src/core/server.ts
|
|
133
|
+
import http from "http";
|
|
134
|
+
import fs3 from "fs";
|
|
135
|
+
import path3 from "path";
|
|
136
|
+
import crypto from "crypto";
|
|
137
|
+
import { fileURLToPath } from "url";
|
|
138
138
|
import { Service } from "cordis";
|
|
139
139
|
|
|
140
140
|
// src/core/instance.ts
|
|
141
141
|
import fs2 from "fs";
|
|
142
142
|
import path2 from "path";
|
|
143
|
+
var CURRENT_VERSION = package_default.version;
|
|
143
144
|
var RECORD_FILE = ".zdev/dashboard.json";
|
|
144
145
|
var VERIFY_TIMEOUT_MS = 1500;
|
|
145
146
|
var STOP_POLL_MS = 2e3;
|
|
@@ -169,7 +170,8 @@ function writeRecord(root, port) {
|
|
|
169
170
|
pid: process.pid,
|
|
170
171
|
port,
|
|
171
172
|
root,
|
|
172
|
-
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
173
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
174
|
+
version: CURRENT_VERSION
|
|
173
175
|
};
|
|
174
176
|
if (old?.plugins && typeof old.plugins === "object") {
|
|
175
177
|
rec.plugins = old.plugins;
|
|
@@ -269,20 +271,27 @@ async function fetchWithTimeout(url) {
|
|
|
269
271
|
async function verifyRoot(port, root) {
|
|
270
272
|
try {
|
|
271
273
|
const res = await fetchWithTimeout(`http://127.0.0.1:${port}/__config`);
|
|
272
|
-
if (res.status !== 200) return false;
|
|
274
|
+
if (res.status !== 200) return { reusable: false };
|
|
273
275
|
const body = await res.json();
|
|
274
|
-
if (typeof body.root !== "string") return false;
|
|
275
|
-
return
|
|
276
|
+
if (typeof body.root !== "string") return { reusable: false };
|
|
277
|
+
return {
|
|
278
|
+
reusable: body.root === root,
|
|
279
|
+
version: typeof body.version === "string" ? body.version : void 0
|
|
280
|
+
};
|
|
276
281
|
} catch {
|
|
277
|
-
return false;
|
|
282
|
+
return { reusable: false };
|
|
278
283
|
}
|
|
279
284
|
}
|
|
280
|
-
async function findReusable(root) {
|
|
285
|
+
async function findReusable(root, currentVersion) {
|
|
281
286
|
const rec = readRecord(root);
|
|
282
287
|
if (!rec) return null;
|
|
283
288
|
if (!isAlive(rec.pid)) return null;
|
|
284
|
-
|
|
285
|
-
return
|
|
289
|
+
const v = await verifyRoot(rec.port, root);
|
|
290
|
+
if (!v.reusable) return null;
|
|
291
|
+
if (v.version && v.version !== currentVersion) {
|
|
292
|
+
return { status: "stale-version", record: rec, liveVersion: v.version };
|
|
293
|
+
}
|
|
294
|
+
return { status: "reuse", record: rec };
|
|
286
295
|
}
|
|
287
296
|
async function stopInstance(record) {
|
|
288
297
|
try {
|
|
@@ -1645,17 +1654,25 @@ async function loadExternal(ctx, dir, root) {
|
|
|
1645
1654
|
async function main() {
|
|
1646
1655
|
const args = parseArgs();
|
|
1647
1656
|
const root = path9.resolve(args.dir);
|
|
1648
|
-
const
|
|
1649
|
-
|
|
1657
|
+
const found = await findReusable(root, package_default.version);
|
|
1658
|
+
const existing = found?.record ?? null;
|
|
1659
|
+
const autoUpgrade = found?.status === "stale-version";
|
|
1660
|
+
if (existing && !args.restart && !autoUpgrade) {
|
|
1650
1661
|
const u = `http://localhost:${existing.port}` + (args.page ? `#${args.page}` : "");
|
|
1651
1662
|
if (args.open) openUrl(u);
|
|
1652
1663
|
console.log(`[zdashboard] \u5DF2\u590D\u7528\u5B9E\u4F8B ${u}\uFF08--restart \u53EF\u5F3A\u5236\u91CD\u5F00\uFF09`);
|
|
1653
1664
|
await new Promise((resolve) => process.stdout.write("", () => resolve()));
|
|
1654
1665
|
process.exit(0);
|
|
1655
1666
|
}
|
|
1656
|
-
const oldRecord = existing && args.restart ? existing : null;
|
|
1667
|
+
const oldRecord = existing && (args.restart || autoUpgrade) ? existing : null;
|
|
1657
1668
|
if (oldRecord) {
|
|
1658
|
-
|
|
1669
|
+
if (autoUpgrade) {
|
|
1670
|
+
console.log(
|
|
1671
|
+
`[zdashboard] \u68C0\u6D4B\u5230\u65E7\u7248\u672C\u5B9E\u4F8B v${found.liveVersion ?? "unknown"}\uFF0C\u81EA\u52A8\u5347\u7EA7\u5230 v${package_default.version}\uFF08\u505C\u6B62\u65E7\u5B9E\u4F8B pid=${oldRecord.pid}\uFF09`
|
|
1672
|
+
);
|
|
1673
|
+
} else {
|
|
1674
|
+
console.log(`[zdashboard] --restart\uFF1A\u505C\u6B62\u65E7\u5B9E\u4F8B pid=${oldRecord.pid}`);
|
|
1675
|
+
}
|
|
1659
1676
|
await stopInstance(oldRecord);
|
|
1660
1677
|
}
|
|
1661
1678
|
const appDir = path9.resolve(__dirname2, "web");
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli.ts","../src/server/detect.ts","../src/core/server.ts","../package.json","../src/core/instance.ts","../src/core/open-url.ts","../src/core/reload.ts","../src/server/spec-scan.ts","../src/server/walk.ts","../src/core/tree.ts","../src/core/worktrees.ts","../src/core/manifest.ts","../src/core/read-body.ts","../src/server/just-runner.ts","../src/sdk/server.ts","../src/plugins/builtin.ts","../src/plugins/just/manifest.ts","../src/plugins/just/index.ts","../src/plugins/design/index.ts","../src/server/design-assets.ts","../src/plugins/design/manifest.ts","../src/plugins/view/manifest.ts","../src/plugins/view/index.ts","../src/plugins/stats/index.ts","../src/plugins/stats/manifest.ts"],"sourcesContent":["import path from 'node:path';\nimport fs from 'node:fs';\nimport { fileURLToPath } from 'node:url';\nimport { access, readdir } from 'node:fs/promises';\nimport { exec } from 'node:child_process';\nimport { parseArgs as utilParseArgs } from 'node:util';\nimport { detect } from './server/detect.js';\nimport type { DetectResult } from './server/detect.js';\nimport { Context, Service } from 'cordis';\nimport { ServerService, PLUGIN_STATIC_PREFIX } from './core/server.js';\nimport { ReloadService } from './core/reload.js';\nimport { apply as treeApply } from './core/tree.js';\nimport { apply as worktreesApply } from './core/worktrees.js';\nimport { DashboardService } from './core/manifest.js';\nimport {\n findReusable,\n stopInstance,\n writeRecord,\n clearRecord,\n stripDeadPluginConfig,\n} from './core/instance.js';\nimport { openUrl } from './core/open-url.js';\nimport { apply as justApply } from './plugins/just/index.js';\nimport { apply as designApply } from './plugins/design/index.js';\nimport { apply as viewApply } from './plugins/view/index.js';\nimport { apply as statsApply } from './plugins/stats/index.js';\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\nconst DEFAULT_PORT = 4190;\n\nfunction parseArgs() {\n const args = process.argv.slice(2);\n const { values } = utilParseArgs({\n options: {\n dir: { type: 'string' },\n port: { type: 'string' },\n open: { type: 'boolean', default: false },\n page: { type: 'string' },\n restart: { type: 'boolean', default: false },\n plugins: { type: 'string' },\n },\n args,\n strict: false,\n allowPositionals: false,\n });\n return {\n dir: typeof values.dir === 'string' ? values.dir : process.cwd(),\n port: typeof values.port === 'string' ? Number(values.port) : DEFAULT_PORT,\n portExplicit: args.some(a => a === '--port' || a.startsWith('--port=')),\n open: !!values.open,\n page: typeof values.page === 'string' ? values.page : null,\n restart: !!values.restart,\n plugins: typeof values.plugins === 'string' ? values.plugins : null,\n };\n}\n\nasync function pathExists(p: string): Promise<boolean> {\n try { await access(p); return true; } catch { return false; }\n}\n\nasync function loadExternal(ctx: Context, dir: string, root: string) {\n if (!dir) return;\n let tsxLoaded = false;\n try {\n const { register } = await import('tsx/esm/api');\n register();\n tsxLoaded = true;\n } catch {\n // tsx not available\n }\n\n try {\n const entries = await pathExists(dir) ? await readdir(dir, { withFileTypes: true }) : [];\n for (const ent of entries) {\n if (!ent.isDirectory()) continue;\n const candidates = tsxLoaded ? ['index.ts', 'index.js', 'index.mjs'] : ['index.js', 'index.mjs'];\n for (const name of candidates) {\n const p = path.join(dir, ent.name, name);\n if (await pathExists(p)) {\n try {\n const mod = await import(p);\n const plugin = mod.default ?? mod;\n if (plugin?.apply) {\n try {\n await ctx.plugin(plugin, { root });\n } catch (e) {\n console.error(`[zdashboard] failed to apply plugin ${ent.name}:`, e);\n break;\n }\n // 自动接线约定:mode === 目录名时补 external 标记与 viewerUrl\n const m = ctx.dashboard.get(ent.name);\n if (m && m.mode === ent.name) {\n const patch: Record<string, unknown> = { external: true };\n const webDir = path.join(dir, ent.name, 'web');\n if (await pathExists(path.join(webDir, 'index.html'))) {\n ctx.server.static(`${PLUGIN_STATIC_PREFIX}${ent.name}/`, webDir);\n if (!m.viewerUrl) patch.viewerUrl = `${PLUGIN_STATIC_PREFIX}${ent.name}/`;\n }\n ctx.dashboard.register({ ...m, ...patch });\n }\n }\n } catch (e) {\n console.error(`[zdashboard] failed to load plugin ${ent.name}:`, e);\n }\n break;\n }\n }\n }\n } catch {\n // ignore\n }\n}\n\nasync function main() {\n const args = parseArgs();\n const root = path.resolve(args.dir);\n\n // --- instance reuse (before creating Context) ---\n const existing = await findReusable(root);\n if (existing && !args.restart) {\n const u = `http://localhost:${existing.port}` + (args.page ? `#${args.page}` : '');\n if (args.open) openUrl(u);\n console.log(`[zdashboard] 已复用实例 ${u}(--restart 可强制重开)`);\n // 管道场景下 stdout 是异步写,显式等 flush 再 exit,避免日志被截断\n await new Promise<void>((resolve) => process.stdout.write('', () => resolve()));\n process.exit(0);\n }\n // 记录旧端口(--restart 时用于端口继承;stopInstance 会清 record)\n const oldRecord = existing && args.restart ? existing : null;\n if (oldRecord) {\n console.log(`[zdashboard] --restart:停止旧实例 pid=${oldRecord.pid}`);\n await stopInstance(oldRecord);\n }\n\n const appDir = path.resolve(__dirname, 'web');\n\n // built-in plugins:统一数组注册(未来迁移为 definePlugin 产出后无需改动此处)\n const BUILTIN_PLUGINS = [statsApply, justApply, designApply, viewApply];\n\n // 约定化扫描:启动一次性剥离 dashboard.json 里内置插件的死配置键(未声明 config 即清,external/未知保留)\n if (stripDeadPluginConfig(root, BUILTIN_PLUGINS.map((p) => p.manifest))) {\n console.log('[zdashboard] 已清理 dashboard.json 中内置插件的过时配置键');\n }\n\n // P2: restart 且有旧记录时,起始端口用 record.port(用户显式 --port 则尊重)\n const startPort = oldRecord && !args.portExplicit ? oldRecord.port : args.port;\n\n // P0: 数据目录检测(.zdev/ 存在则优先)\n const zdevDir = path.join(root, '.zdev');\n const dataDir = fs.existsSync(zdevDir) ? '.zdev/' : '';\n\n const det = await detect(root);\n\n const ctx = new Context();\n\n // core services\n ctx.plugin(ServerService, {\n root,\n appDir,\n port: startPort,\n open: args.open,\n detect: det,\n page: args.page,\n dataDir: dataDir || undefined,\n onListen: (port: number) => writeRecord(root, port),\n });\n ctx.plugin(ReloadService, { root });\n ctx.plugin(treeApply, { root });\n ctx.plugin(worktreesApply, { root });\n ctx.plugin(DashboardService);\n\n for (const apply of BUILTIN_PLUGINS) {\n try {\n ctx.plugin(apply, { root });\n } catch (e) {\n console.error('[zdashboard] builtin plugin failed:', e);\n }\n }\n\n // external plugins\n if (args.plugins) {\n await loadExternal(ctx, path.resolve(args.plugins), root);\n }\n\n // graceful shutdown: clear .zdev record on SIGTERM / SIGINT\n const shutdown = () => {\n try { clearRecord(root); } catch {}\n process.exit(0);\n };\n process.on('SIGTERM', shutdown);\n process.on('SIGINT', shutdown);\n\n return ctx;\n}\n\nawait main().catch((e) => {\n console.error(e);\n process.exit(1);\n});\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport { execFile } from 'node:child_process';\n\nexport interface DetectResult {\n hasOpenspec: boolean;\n hasDocs: boolean;\n hasJust: boolean;\n}\n\n/** --list 主探测超时(与迁移前一致) */\nconst JUST_PROBE_TIMEOUT_MS = 5000;\n/** --version 兜底探测超时(快失败:二进制存在性检查无需长等) */\nconst JUST_FALLBACK_TIMEOUT_MS = 3000;\n\nfunction justAvailable(cwd: string): Promise<boolean> {\n /** 探测一次:进程正常退出即视为可用 */\n const probe = (args: string[], timeout: number) => new Promise<boolean>((resolve) => {\n const child = execFile('just', args, { cwd, timeout }, (err) => resolve(!err));\n if (child.killed) resolve(false);\n });\n // 旧版以 --list --unsupported 判定;新版 just 移除该旗标会报错(hasJust 恒 false),\n // 回退 --version 探测二进制本身可用\n return probe(['--list', '--unsupported'], JUST_PROBE_TIMEOUT_MS)\n .then((ok) => (ok ? true : probe(['--version'], JUST_FALLBACK_TIMEOUT_MS)));\n}\n\nexport async function detect(root: string): Promise<DetectResult> {\n const hasOpenspec = fs.existsSync(path.join(root, 'openspec'));\n const hasDocs = fs.existsSync(path.join(root, 'docs'));\n const hasJust = await justAvailable(root);\n return { hasOpenspec, hasDocs, hasJust };\n}\n\n/** /__detect 的响应形状:与 DetectResult 同形(bugs 期兼容字段已随清理 change 摘除) */\nexport type DetectResponse = DetectResult;\n\n/** 现场探测(每次请求重新跑),供 /__detect 独立路由使用 */\nexport async function detectLiveShape(root: string): Promise<DetectResponse> {\n return detect(root);\n}\n","import http from 'node:http';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport crypto from 'node:crypto';\nimport { fileURLToPath } from 'node:url';\nimport pkg from '../../package.json' with { type: 'json' };\nimport type { Context } from 'cordis';\nimport type { DetectResult, DetectResponse } from '../server/detect.js';\nimport { detectLiveShape } from '../server/detect.js';\nimport type { PluginManifest, ConfigField } from '../core/manifest.js';\nimport { Service } from 'cordis';\nimport { clearRecord, readPluginsConfig, writePluginsConfig } from './instance.js';\nimport { openUrl } from './open-url.js';\nimport { readBody } from './read-body.js';\nimport { execFile } from 'node:child_process';\n\nconst VERSION = pkg.version;\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\nexport interface ServerOptions {\n root: string;\n appDir: string;\n port: number;\n open: boolean;\n page: string | null;\n detect: DetectResult;\n dataDir?: string;\n onListen?: (port: number) => void;\n}\n\ndeclare module 'cordis' {\n interface Context {\n server: ServerService;\n }\n}\n\n/** 扩展名 → Content-Type 表(SDK 插件路由等复用,勿在他处复制) */\nexport const MIME: Record<string, string> = {\n '.html': 'text/html; charset=utf-8', '.htm': 'text/html; charset=utf-8',\n '.css': 'text/css; charset=utf-8', '.js': 'application/javascript; charset=utf-8',\n '.mjs': 'application/javascript; charset=utf-8', '.json': 'application/json; charset=utf-8',\n '.svg': 'image/svg+xml', '.png': 'image/png', '.ico': 'image/x-icon',\n '.jpg': 'image/jpeg', '.jpeg': 'image/jpeg', '.gif': 'image/gif', '.webp': 'image/webp',\n '.avif': 'image/avif',\n '.md': 'text/markdown; charset=utf-8', '.txt': 'text/plain; charset=utf-8',\n '.sql': 'text/plain; charset=utf-8', '.csv': 'text/plain; charset=utf-8',\n '.tsv': 'text/plain; charset=utf-8', '.yaml': 'text/yaml; charset=utf-8',\n '.yml': 'text/yaml; charset=utf-8', '.xml': 'application/xml; charset=utf-8',\n '.py': 'text/plain; charset=utf-8', '.ts': 'text/plain; charset=utf-8',\n '.java': 'text/plain; charset=utf-8', '.go': 'text/plain; charset=utf-8',\n '.rs': 'text/plain; charset=utf-8', '.rb': 'text/plain; charset=utf-8',\n '.php': 'text/plain; charset=utf-8', '.c': 'text/plain; charset=utf-8',\n '.cpp': 'text/plain; charset=utf-8', '.h': 'text/plain; charset=utf-8',\n '.cs': 'text/plain; charset=utf-8', '.swift': 'text/plain; charset=utf-8',\n '.kt': 'text/plain; charset=utf-8', '.scala': 'text/plain; charset=utf-8',\n '.sh': 'text/plain; charset=utf-8', '.bash': 'text/plain; charset=utf-8',\n '.zsh': 'text/plain; charset=utf-8', '.fish': 'text/plain; charset=utf-8',\n '.env': 'text/plain; charset=utf-8', '.gitignore': 'text/plain; charset=utf-8',\n '.dockerfile': 'text/plain; charset=utf-8',\n '.mp4': 'video/mp4', '.webm': 'video/webm', '.mov': 'video/quicktime',\n '.m4a': 'audio/mp4', '.aac': 'audio/aac',\n '.woff': 'font/woff', '.woff2': 'font/woff2', '.ttf': 'font/woff',\n '.map': 'application/json; charset=utf-8',\n};\n\n// 静态 HTML 注入脚本:仅保留 _self 链接补丁(文件预览页内跳转留在当前窗口)。\n// 旧 EventSource('/__reload') 注入已随沙箱收紧移除——sandbox=allow-scripts 下 iframe\n// 为不透明源,/__reload 属跨域请求,只会制造 console error 且其处理器本已为空。\nconst INJECT = `<script>(function(){document.addEventListener('click',function(e){var t=e.target;if(t&&t.closest){var a=t.closest('a[target]');if(a&&a.target!=='_self'){a.target='_self';}}},true);})();</script>`;\n\nexport const PLUGIN_STATIC_PREFIX = '/__plugin/';\n\n/** json 响应助手:统一 Content-Type/缓存头与序列化,消灭 writeHead 样板 */\nexport function json(res: http.ServerResponse, data: unknown, status = 200): void {\n res.writeHead(status, { 'Content-Type': 'application/json; charset=utf-8', 'Cache-Control': 'no-cache' });\n res.end(JSON.stringify(data));\n}\n\n/** x-stop-token 鉴权助手:通过返回 true;未通过时已写 403 响应并返回 false */\nexport function guarded(req: http.IncomingMessage, res: http.ServerResponse, token: string): boolean {\n if (req.headers['x-stop-token'] !== token) {\n res.writeHead(403);\n res.end('forbidden');\n return false;\n }\n return true;\n}\n\nexport class ServerService extends Service {\n stopToken: string;\n private root: string;\n private appDir: string;\n private open: boolean;\n private page: string | null;\n private det: DetectResult;\n private dataDir?: string;\n private routes = new Map<string, (req: http.IncomingMessage, res: http.ServerResponse) => void>();\n private sses = new Map<string, (res: http.ServerResponse) => (() => void) | void>();\n private prefixStatic = new Map<string, string>();\n private server?: http.Server;\n private onListen?: (port: number) => void;\n\n constructor(ctx: Context, config: ServerOptions) {\n super(ctx, 'server');\n this.stopToken = crypto.randomBytes(12).toString('hex');\n this.root = config.root;\n this.appDir = config.appDir;\n this.open = config.open;\n this.page = config.page;\n this.det = config.detect;\n this.dataDir = config.dataDir;\n this.onListen = config.onListen;\n ctx.effect(() => () => this.dispose());\n\n this.refreshGitInfo();\n this.route('/__config', (_req, res) => {\n json(res, { stopToken: this.stopToken, version: VERSION, root: this.root, ...this.gitInfo });\n });\n\n // 独立探测接口(轻量,替代 HomeGrid 借道 /__files 全量树)\n this.route('/__detect', async (_req, res) => {\n const shape: DetectResponse = await detectLiveShape(this.root);\n json(res, shape);\n });\n\n // 应用级静态文件(index.html 引用但不在 /assets/ 下),避免落到项目目录 404\n this.route('/favicon.svg', (req, res) => {\n this.serveFile(path.join(this.appDir, 'favicon.svg'), req, res, false);\n });\n\n this.route('/__file-content', async (req, res) => {\n const url = new URL(req.url || '/', 'http://localhost');\n const rawPath = url.pathname.replace(/^\\/__file-content\\/?/, '');\n if (!rawPath || rawPath === '/') {\n res.writeHead(400);\n res.end('missing path');\n return;\n }\n const filePath = path.join(this.root, decodeURIComponent(rawPath));\n if (!filePath.startsWith(this.root + path.sep) && filePath !== this.root) {\n res.writeHead(403);\n res.end('Forbidden');\n return;\n }\n fs.stat(filePath, (err) => {\n if (err) { res.writeHead(404); return res.end('Not found'); }\n const ext = path.extname(filePath).toLowerCase();\n const ct = MIME[ext] ?? 'application/octet-stream';\n res.writeHead(200, { 'Content-Type': ct, 'Cache-Control': 'no-cache' });\n fs.createReadStream(filePath).pipe(res);\n });\n });\n\n this.route('/__stop', async (req, res) => {\n if (!guarded(req, res, this.stopToken)) return;\n json(res, { ok: true });\n this.stop();\n });\n\n this.start(config.port);\n }\n\n route(path: string, handler: (req: http.IncomingMessage, res: http.ServerResponse) => void) {\n this.routes.set(path, handler);\n this.ctx.effect(() => () => this.routes.delete(path));\n }\n\n sse(path: string, onConnect: (res: http.ServerResponse) => (() => void) | void) {\n this.sses.set(path, onConnect);\n this.ctx.effect(() => () => this.sses.delete(path));\n }\n\n static(prefix: string, dir: string) {\n this.prefixStatic.set(prefix, dir);\n this.ctx.effect(() => () => this.prefixStatic.delete(prefix));\n }\n\n private pluginsConfig: Record<string, Record<string, unknown>> = {};\n\n getPluginConfig(mode: string): Record<string, unknown> {\n return this.pluginsConfig[mode] ?? {};\n }\n\n refreshPluginsConfig() {\n this.pluginsConfig = readPluginsConfig(this.root);\n }\n\n savePluginConfig(merged: Record<string, Record<string, unknown>>) {\n this.pluginsConfig = merged;\n writePluginsConfig(this.root, merged);\n }\n\n private serveFile(filePath: string, req: http.IncomingMessage, res: http.ServerResponse, injectHtml: boolean) {\n fs.stat(filePath, (err, stat) => {\n if (err) { res.writeHead(404); return res.end('Not found'); }\n const ext = path.extname(filePath).toLowerCase();\n const ct = MIME[ext] ?? 'application/octet-stream';\n\n // ---- HTTP Range support ----\n const rangeHeader = (req.headers['range'] as string | undefined);\n let range: { start: number; end: number } | null = null;\n if (rangeHeader) {\n const m = rangeHeader.match(/^bytes=(\\d+)-(\\d*)$/);\n if (m) {\n const start = Number(m[1]);\n const end = m[2] !== '' ? Number(m[2]) : stat.size - 1;\n if (!Number.isNaN(start) && !Number.isNaN(end) && start <= end && start < stat.size) {\n range = { start, end: Math.min(end, stat.size - 1) };\n }\n // malformed range → fall through to 200 full response\n }\n // unparseable range header → fall through to 200 full response\n }\n\n if (range) {\n const { start, end } = range;\n const chunkSize = end - start + 1;\n res.writeHead(206, {\n 'Content-Type': ct,\n 'Content-Length': String(chunkSize),\n 'Content-Range': `bytes ${start}-${end}/${stat.size}`,\n 'Accept-Ranges': 'bytes',\n 'Cache-Control': 'no-cache',\n });\n // stat 成功后文件仍可能在 open 前被删/换(高频增删的工作区),流错误无人接会崩进程\n const stream = fs.createReadStream(filePath, { start, end });\n stream.on('error', () => { try { res.destroy(); } catch { /* 已断 */ } });\n stream.pipe(res);\n return;\n }\n\n // Full response\n fs.readFile(filePath, (err, data) => {\n if (err) { res.writeHead(404); return res.end('Not found'); }\n let body: string | Buffer = data;\n if (injectHtml && ext === '.html') {\n const s = data.toString('utf8');\n body = Buffer.from(s.indexOf('</body>') >= 0 ? s.replace('</body>', INJECT + '</body>') : s + INJECT);\n }\n res.writeHead(200, { 'Content-Type': ct, 'Accept-Ranges': 'bytes', 'Cache-Control': 'no-cache' });\n res.end(body);\n });\n });\n }\n\n private servePrefix(url: string, req: http.IncomingMessage, res: http.ServerResponse): boolean {\n for (const [prefix, dir] of this.prefixStatic) {\n if (url.indexOf(prefix) === 0) {\n let rel = this.safeDecode(url.slice(prefix.length));\n if (!rel || rel === '/' || !path.extname(rel)) rel = path.join(rel || '', 'index.html');\n const fp = path.join(dir, rel);\n if (fp.indexOf(dir + path.sep) !== 0) { res.writeHead(403); res.end('Forbidden'); return false; }\n this.serveFile(fp, req, res, true);\n return true;\n }\n }\n return false;\n }\n\n private safeDecode(raw: string): string {\n try { return decodeURIComponent(raw); } catch { return raw; }\n }\n\n private handler = (req: http.IncomingMessage, res: http.ServerResponse) => {\n try {\n const rawUrl = req.url || '/';\n const url = rawUrl.split('?')[0];\n\n const rh = this.routes.get(url);\n if (rh) { rh(req, res); return; }\n for (const [rp, rh2] of this.routes) {\n if (url.startsWith(rp + '/')) { rh2(req, res); return; }\n }\n const sh = this.sses.get(url);\n if (sh) {\n res.writeHead(200, { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', Connection: 'keep-alive' });\n res.write(': connected\\n\\n');\n const cleanup = sh(res);\n req.on('close', () => { cleanup?.(); });\n return;\n }\n\n if (this.servePrefix(url, req, res)) return;\n\n if (url === '/' || url.indexOf('/__app/') === 0 || url.indexOf('/assets/') === 0) {\n let fp = this.appDir;\n if (url !== '/') fp = path.join(this.appDir, this.safeDecode(url));\n if (url.indexOf('/__app/') === 0) fp = path.join(this.appDir, url.slice(7));\n if (fp !== this.appDir && fp.indexOf(this.appDir + path.sep) !== 0) { res.writeHead(403); return res.end('Forbidden'); }\n if (url === '/') fp = path.join(this.appDir, 'index.html');\n return this.serveFile(fp, req, res, false);\n }\n\n const fp = path.join(this.root, this.safeDecode(url));\n if (fp !== this.root && fp.indexOf(this.root + path.sep) !== 0) { res.writeHead(403); return res.end('Forbidden'); }\n return this.serveFile(fp, req, res, true);\n } catch (e) {\n try { res.writeHead(400); res.end('bad request'); } catch {}\n console.error('[zdashboard] handler error', e);\n }\n };\n\n start(port: number) {\n this.server = http.createServer(this.handler);\n // 浏览器复用空闲 keep-alive 连接时若已被服务端关闭,请求会石沉大海(点击无响应)。\n // 拉长 keep-alive 使其远大于浏览器侧空闲窗口\n this.server.keepAliveTimeout = 65_000;\n this.server.headersTimeout = 66_000;\n this.server.on('error', (err: NodeJS.ErrnoException) => {\n if (err.code === 'EADDRINUSE') {\n console.log(`[zdashboard] port ${port} busy, trying ${port + 1}`);\n this.start(port + 1);\n } else throw err;\n });\n this.server.listen(port, '127.0.0.1', () => {\n // port=0(测试/随机端口)时上报实际绑定端口\n const addr = this.server?.address();\n const bound = typeof addr === 'object' && addr ? addr.port : port;\n const u = `http://localhost:${bound}`;\n const target = this.page ? `${u}#${this.page}` : u;\n console.log(`[zdashboard] v${VERSION} dashboard -> ${u}`);\n console.log(`[zdashboard] project -> ${this.root}`);\n console.log(`[zdashboard] detect -> openspec:${this.det.hasOpenspec} docs:${this.det.hasDocs} just:${this.det.hasJust}`);\n if (this.dataDir) console.log(`[zdashboard] data -> ${this.dataDir}`);\n if (this.open) openUrl(target);\n this.onListen?.(bound);\n });\n }\n\n /** 项目 git 信息(分支/脏文件数),启动探测一次,文件变更时刷新 */\n private gitInfo: { branch?: string; dirty?: number } = {};\n\n refreshGitInfo() {\n const run = (args: string[]) => new Promise<string>((resolve) => {\n execFile('git', args, { cwd: this.root, timeout: 3000 }, (err, stdout) => resolve(err ? '' : stdout));\n });\n void (async () => {\n const [branch, status] = await Promise.all([\n run(['rev-parse', '--abbrev-ref', 'HEAD']),\n run(['status', '--porcelain']),\n ]);\n const b = branch.trim();\n this.gitInfo = b ? { branch: b, dirty: status ? status.split('\\n').filter(Boolean).length : 0 } : {};\n })();\n }\n\n stop() {\n if (this.server) { try { this.server.close(); } catch {} }\n try { clearRecord(this.root); } catch {}\n setTimeout(() => {\n try { this.ctx.root.fiber.dispose(); } catch {}\n process.exit(0);\n }, 50);\n }\n\n dispose() {\n if (this.server) { try { this.server.close(); } catch {} }\n try { clearRecord(this.root); } catch {}\n }\n}\n","{\n \"name\": \"zdashboard\",\n \"version\": \"2.9.0\",\n \"description\": \"ZCode skill dashboard platform — pluggable viewers for zdesign/zview/zreview/zgoal\",\n \"type\": \"module\",\n \"bin\": {\n \"zdashboard\": \"./dist/cli.js\"\n },\n \"files\": [\n \"dist\"\n ],\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"scripts\": {\n \"dev\": \"vite\",\n \"build\": \"tsup && vite build\",\n \"build:web\": \"vite build\",\n \"build:node\": \"tsup\",\n \"start\": \"node dist/cli.js\",\n \"test\": \"vitest run\",\n \"typecheck\": \"tsc --noEmit\",\n \"test:coverage\": \"vitest run --coverage\",\n \"preview\": \"vite preview\"\n },\n \"dependencies\": {\n \"@fontsource/vt323\": \"^5.3.0\",\n \"@phosphor-icons/react\": \"^2.1.10\",\n \"@radix-ui/react-dropdown-menu\": \"^2.1.24\",\n \"@radix-ui/react-scroll-area\": \"^1.2.0\",\n \"@radix-ui/react-separator\": \"^1.1.0\",\n \"@radix-ui/react-slot\": \"^1.1.0\",\n \"@radix-ui/react-tooltip\": \"^1.1.2\",\n \"@uidotdev/usehooks\": \"^2.4.0\",\n \"ansi-to-react\": \"^6.1.6\",\n \"class-variance-authority\": \"^0.7.0\",\n \"clsx\": \"^2.1.1\",\n \"cordis\": \"4.0.0-rc.8\",\n \"cosmokit\": \"^1.8.1\",\n \"date-fns\": \"^3.6.0\",\n \"filesize\": \"^11.0.0\",\n \"highlight.js\": \"^11.11.1\",\n \"iconv-lite\": \"0.7.3\",\n \"katex\": \"^0.16.11\",\n \"ky\": \"^1.7.0\",\n \"lodash-es\": \"^4.17.21\",\n \"lucide-react\": \"^0.460.0\",\n \"pixelarticons\": \"^2.4.1\",\n \"react\": \"^18.3.1\",\n \"react-dom\": \"^18.3.1\",\n \"react-error-boundary\": \"^5.0.0\",\n \"react-markdown\": \"^9.0.1\",\n \"rehype-autolink-headings\": \"^7.1.0\",\n \"rehype-highlight\": \"^7.0.1\",\n \"rehype-katex\": \"^7.0.1\",\n \"rehype-raw\": \"^7.0.0\",\n \"rehype-slug\": \"^6.0.0\",\n \"remark-frontmatter\": \"^5.0.0\",\n \"remark-gfm\": \"^4.0.0\",\n \"remark-math\": \"^6.0.0\",\n \"sonner\": \"^1.5.0\",\n \"tailwind-merge\": \"^2.5.4\",\n \"tsx\": \"^4.7.0\",\n \"use-debounce\": \"^10.0.0\",\n \"yaml\": \"^2.9.0\"\n },\n \"devDependencies\": {\n \"@tailwindcss/typography\": \"^0.5.20\",\n \"@testing-library/jest-dom\": \"^7.0.1\",\n \"@testing-library/react\": \"^16.3.2\",\n \"@types/lodash-es\": \"^4.17.12\",\n \"@types/node\": \"^22.9.0\",\n \"@types/react\": \"^18.3.12\",\n \"@types/react-dom\": \"^18.3.1\",\n \"@vitejs/plugin-react\": \"^4.7.0\",\n \"@vitest/coverage-v8\": \"1.6.0\",\n \"autoprefixer\": \"^10.4.20\",\n \"jsdom\": \"^30.0.1\",\n \"postcss\": \"^8.4.49\",\n \"tailwindcss\": \"^3.4.14\",\n \"tailwindcss-animate\": \"^1.0.7\",\n \"tsup\": \"^8.3.5\",\n \"typescript\": \"^5.6.3\",\n \"vite\": \"^5.4.10\",\n \"vitest\": \"^1.6.0\"\n },\n \"pnpm\": {\n \"onlyBuiltDependencies\": [\n \"esbuild\"\n ]\n }\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\n\nexport interface InstanceRecord {\n pid: number;\n port: number;\n root: string;\n startedAt: string;\n plugins?: Record<string, Record<string, unknown>>;\n}\n\nexport const RECORD_FILE = '.zdev/dashboard.json';\nexport const VERIFY_TIMEOUT_MS = 1500;\nexport const STOP_POLL_MS = 2000;\nexport const STOP_POLL_INTERVAL_MS = 100;\nexport const STOP_FINAL_WAIT_MS = 100;\n\nfunction recordPath(root: string): string {\n return path.join(root, RECORD_FILE);\n}\n\nexport function readRecord(root: string): InstanceRecord | null {\n try {\n const fp = recordPath(root);\n const raw = fs.readFileSync(fp, 'utf-8');\n const rec = JSON.parse(raw) as Partial<InstanceRecord>;\n if (\n typeof rec.pid === 'number' &&\n typeof rec.port === 'number' &&\n typeof rec.root === 'string' &&\n typeof rec.startedAt === 'string'\n ) {\n return rec as InstanceRecord;\n }\n return null;\n } catch {\n return null;\n }\n}\n\nexport function writeRecord(root: string, port: number): void {\n const fp = recordPath(root);\n fs.mkdirSync(path.dirname(fp), { recursive: true });\n // 读改写:onListen 每次启动都会调 writeRecord,需沿用旧记录的 plugins 段,\n // 只更新运行字段(pid/port/root/startedAt),否则插件配置跨重启清零。\n const old = readRecord(root); // 记录缺失/损坏 → null,兜底最小记录\n const rec: InstanceRecord = {\n pid: process.pid,\n port,\n root,\n startedAt: new Date().toISOString(),\n };\n if (old?.plugins && typeof old.plugins === 'object') {\n rec.plugins = old.plugins;\n }\n // tmp+rename 原子写(对齐 writePluginsConfig),避免半写状态被读到\n const tmp = fp + '.tmp';\n fs.writeFileSync(tmp, JSON.stringify(rec, null, 2) + '\\n');\n fs.renameSync(tmp, fp);\n}\n\nexport function readPluginsConfig(root: string): Record<string, Record<string, unknown>> {\n try {\n const rec = readRecord(root);\n if (rec?.plugins && typeof rec.plugins === 'object') {\n return rec.plugins as Record<string, Record<string, unknown>>;\n }\n } catch { /* ignore */ }\n return {};\n}\n\nexport function writePluginsConfig(root: string, plugins: Record<string, Record<string, unknown>>): void {\n const fp = recordPath(root);\n let rec: InstanceRecord;\n try {\n const raw = fs.readFileSync(fp, 'utf-8');\n rec = JSON.parse(raw) as InstanceRecord;\n } catch {\n rec = { pid: process.pid, port: 0, root, startedAt: new Date().toISOString() };\n }\n rec.plugins = plugins;\n const tmp = fp + '.tmp';\n fs.writeFileSync(tmp, JSON.stringify(rec, null, 2) + '\\n');\n fs.renameSync(tmp, fp);\n}\n\n/** 死键剥离判定所需的最小 manifest 投影(PluginManifest 结构兼容) */\nexport interface ConfigSchemaInfo {\n mode: string;\n external?: boolean;\n /** manifest.config 声明:缺省或空对象表示该内置插件无配置面 */\n config?: Record<string, unknown>;\n}\n\n/**\n * 启动一次性:剥离 dashboard.json 里内置插件的死配置键(通用规则,收敛自 view/design 约定化扫描)。\n * - 内置(非 external)未声明 config → 整段死键,清除;\n * - 内置已声明 config → 仅保留声明键(键级收敛);\n * - external 插件键保留;存储中无 manifest 声明的键(未知/未加载插件)保守保留。\n * 无变更/无记录时不写盘。返回是否发生了剥离。记录缺失/损坏跳过清理,不阻塞启动。\n */\nexport function stripDeadPluginConfig(root: string, manifests: readonly ConfigSchemaInfo[]): boolean {\n try {\n const rec = readRecord(root);\n if (!rec?.plugins || typeof rec.plugins !== 'object') return false;\n const byMode = new Map(manifests.map((m) => [m.mode, m]));\n const stored = rec.plugins as Record<string, unknown>;\n const plugins: Record<string, unknown> = { ...stored };\n let changed = false;\n for (const mode of Object.keys(plugins)) {\n const m = byMode.get(mode);\n // 无声明(未注册,可能是外部插件或已卸载)→ 保守不清;external → 保留\n if (!m || m.external) continue;\n const section = plugins[mode];\n if (section === null || typeof section !== 'object') continue;\n const keys = Object.keys(section as Record<string, unknown>);\n if (!m.config || Object.keys(m.config).length === 0) {\n // 内置且未声明 config → 整段死键\n if (keys.length > 0) {\n delete plugins[mode];\n changed = true;\n }\n continue;\n }\n // 键级收敛:仅保留 manifest.config 声明的键\n const kept: Record<string, unknown> = {};\n for (const key of Object.keys(m.config)) {\n if (key in (section as Record<string, unknown>)) kept[key] = (section as Record<string, unknown>)[key];\n }\n if (Object.keys(kept).length !== keys.length) {\n if (Object.keys(kept).length === 0) delete plugins[mode];\n else plugins[mode] = kept;\n changed = true;\n }\n }\n if (!changed) return false;\n writePluginsConfig(root, plugins as Record<string, Record<string, unknown>>); // tmp+rename 原子写\n return true;\n } catch {\n return false; // 记录缺失/损坏:跳过清理,不阻塞启动\n }\n}\n\nexport function clearRecord(root: string): void {\n try {\n // 属主校验:记录若已指向别的实例(并发双启落败者),不得误删胜者记录\n const rec = readRecord(root);\n if (rec && rec.pid !== process.pid) return;\n fs.unlinkSync(recordPath(root));\n } catch {\n // best-effort\n }\n}\n\nexport function isAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch (e) {\n if ((e as NodeJS.ErrnoException).code === 'ESRCH') return false;\n // EPERM or other → process exists, we just can't signal it\n return true;\n }\n}\n\nasync function fetchWithTimeout(url: string): Promise<Response> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), VERIFY_TIMEOUT_MS);\n try {\n return await fetch(url, { signal: controller.signal });\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport async function verifyRoot(port: number, root: string): Promise<boolean> {\n try {\n const res = await fetchWithTimeout(`http://127.0.0.1:${port}/__config`);\n if (res.status !== 200) return false;\n const body = await res.json();\n if (typeof body.root !== 'string') return false;\n return body.root === root;\n } catch {\n return false;\n }\n}\n\nexport async function findReusable(root: string): Promise<InstanceRecord | null> {\n const rec = readRecord(root);\n if (!rec) return null;\n if (!isAlive(rec.pid)) return null;\n if (!(await verifyRoot(rec.port, root))) return null;\n return rec;\n}\n\nexport async function stopInstance(record: InstanceRecord): Promise<void> {\n try {\n process.kill(record.pid, 'SIGTERM');\n } catch {\n return;\n }\n\n const deadline = Date.now() + STOP_POLL_MS;\n while (Date.now() < deadline) {\n if (!isAlive(record.pid)) return;\n await new Promise((r) => setTimeout(r, STOP_POLL_INTERVAL_MS));\n }\n\n // still alive → SIGKILL\n try {\n process.kill(record.pid, 'SIGKILL');\n } catch {\n // ignore\n }\n await new Promise((r) => setTimeout(r, STOP_FINAL_WAIT_MS));\n}\n","import { exec, execFile } from 'node:child_process';\n\n/** 跨平台打开浏览器(macOS open / Windows start / Linux xdg-open) */\nexport function openUrl(url: string): void {\n const cmd =\n process.platform === 'darwin' ? 'open' :\n process.platform === 'win32' ? 'start' :\n 'xdg-open';\n // win32 `start` 是 shell 内建命令,只能走 shell;其他平台直接用 execFile\n if (process.platform === 'win32') {\n exec(`start \"\" \"${url}\"`);\n } else {\n execFile(cmd, [url]);\n }\n}\n","import fs from 'node:fs';\nimport http from 'node:http';\nimport { Service } from 'cordis';\nimport type { Context } from 'cordis';\n\ndeclare module 'cordis' {\n interface Context {\n reload: ReloadService;\n }\n}\n\nconst WATCH_DEBOUNCE_MS = 300;\n\n/** 忽略目录(recursive watch 相对路径前缀)与编辑器/系统/日志噪音文件 */\nconst IGNORED_DIR_RE = /^(?:\\.git|node_modules|dist|\\.pnpm)(?:[/\\\\]|$)/;\nconst IGNORED_FILE_RE = /\\.(?:swp|tmp|log)$|~$|^\\.DS_Store$|^Thumbs\\.db$/i;\n\n/** filename 是否应被 watcher 忽略;null(平台未提供文件名)放行,行为不变 */\nexport function isIgnoredPath(filename: string | null): boolean {\n if (!filename) return false;\n return IGNORED_DIR_RE.test(filename) || IGNORED_FILE_RE.test(filename);\n}\n\nexport class ReloadService extends Service {\n static inject = ['server'];\n private clients = new Set<http.ServerResponse>();\n private watcher?: fs.FSWatcher;\n private timer?: NodeJS.Timeout;\n\n constructor(ctx: Context, config: { root: string }) {\n super(ctx, 'reload');\n this.ctx.effect(() => () => this.dispose());\n\n this.ctx.server.sse('/__reload', (res) => {\n this.clients.add(res);\n return () => this.clients.delete(res);\n });\n\n try {\n this.watcher = fs.watch(config.root, { recursive: true }, (eventType, filename) => {\n if (isIgnoredPath(filename)) return;\n if (this.timer) clearTimeout(this.timer);\n this.timer = setTimeout(() => {\n this.ctx.server.refreshGitInfo();\n this.broadcast('reload');\n this.broadcast('files');\n this.timer = undefined;\n }, WATCH_DEBOUNCE_MS);\n });\n } catch {\n // watch unavailable - static only\n }\n }\n\n broadcast(ev: string, data: unknown = '') {\n const payload = `event: ${ev}\\ndata: ${JSON.stringify(data == null ? '' : data)}\\n\\n`;\n for (const c of this.clients) {\n try { c.write(payload); } catch {}\n }\n }\n\n /** 插件专用频道:plugin:<mode>:<event>,客户端 usePluginData subscribe 消费 */\n broadcastPlugin(mode: string, event: string, data: unknown = '') {\n this.broadcast(`plugin:${mode}:${event}`, data);\n }\n\n dispose() {\n if (this.watcher) { try { this.watcher.close(); } catch {} }\n if (this.timer) { clearTimeout(this.timer); }\n for (const c of this.clients) { try { c.end(); } catch {} }\n this.clients.clear();\n }\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport { walkDir } from './walk.js';\n\nexport type NodeKind = 'file' | 'dir' | 'log';\nexport interface TreeNode {\n name: string;\n kind: NodeKind;\n path?: string;\n defaultCollapsed?: boolean;\n children?: TreeNode[];\n}\n\nfunction buildTree(paths: string[], defaultExpandDepth = 2): TreeNode[] {\n const root: TreeNode[] = [];\n const map = new Map<string, TreeNode>();\n\n for (const p of paths) {\n const parts = p.split('/');\n let current = '';\n let parent = root;\n\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i];\n current = current ? `${current}/${part}` : part;\n const isLast = i === parts.length - 1;\n const depth = i;\n\n if (!map.has(current)) {\n const isDir = !isLast;\n const collapsed = isDir && typeof defaultExpandDepth === 'number' && depth > defaultExpandDepth;\n const node: TreeNode = {\n name: part,\n kind: isLast ? 'file' : 'dir',\n ...(collapsed ? { defaultCollapsed: true } : {}),\n ...(isLast ? { path: p } : { children: [] }),\n };\n map.set(current, node);\n parent.push(node);\n }\n\n if (!isLast) {\n parent = map.get(current)!.children!;\n }\n }\n }\n\n const sortNodes = (nodes: TreeNode[]) => {\n nodes.sort((a, b) => (a.kind === b.kind ? a.name.localeCompare(b.name) : a.kind === 'dir' ? -1 : 1));\n for (const n of nodes) {\n if (n.children) sortNodes(n.children);\n }\n };\n\n sortNodes(root);\n return root;\n}\n\nexport interface ScanTreeOptions {\n defaultExpandDepth?: number;\n /** 允许点前缀的 scanDirs(如 .zdev/apply):声明后才扫描,且 walk 放行其内点前缀子目录;未声明的点前缀目录整组跳过 */\n dotDirs?: string[];\n}\n\nfunction prefixPaths(nodes: TreeNode[], prefix: string): TreeNode[] {\n return nodes.map((n) => {\n if (n.kind === 'file' && n.path) {\n return { ...n, path: `${prefix}/${n.path}` };\n }\n if (n.children) {\n return { ...n, children: prefixPaths(n.children, prefix) };\n }\n return n;\n });\n}\n\n/** 方案模式树形扫描:按 scanDirs 白名单扫描 */\nexport function scanTree(root: string, scanDirs: string[], opts?: ScanTreeOptions): TreeNode[] {\n const tree: TreeNode[] = [];\n const defaultExpandDepth = typeof opts?.defaultExpandDepth === 'number' ? opts.defaultExpandDepth : 2;\n const dotDeclared = new Set(Array.isArray(opts?.dotDirs) ? opts.dotDirs : []);\n const dirs = Array.isArray(scanDirs) ? scanDirs.filter((d) => typeof d === 'string' && d) : [];\n for (const dir of dirs) {\n // 点前缀目录须显式列入 dotDirs 才可扫(最小例外);未声明整组跳过\n if (dir.startsWith('.') && !dotDeclared.has(dir)) continue;\n const dirPath = path.join(root, dir);\n if (!fs.existsSync(dirPath)) continue;\n const paths: string[] = [];\n walkDir(dirPath, { maxDepth: 4, allowDotDirs: dotDeclared.has(dir), onFile: (_, rel) => paths.push(rel) });\n const prefix = dir;\n const children = prefixPaths(buildTree(paths, defaultExpandDepth), prefix);\n if (children.length) {\n tree.push({ name: `${dir} (${children.length})`, kind: 'dir', children });\n }\n }\n return tree;\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\n\nexport interface WalkOptions {\n skip?: Set<string>;\n maxDepth?: number;\n /** true 时点前缀「目录」不跳过(供显式列入 dotDirs 的扫描目录使用);点前缀「文件」仍恒跳过 */\n allowDotDirs?: boolean;\n onFile?: (abs: string, rel: string) => void;\n onDir?: (abs: string, rel: string) => void;\n}\n\nexport function walkDir(root: string, opts: WalkOptions = {}): void {\n const { skip = new Set(), maxDepth, allowDotDirs = false, onFile, onDir } = opts;\n\n function walk(dir: string, rel: string, depth: number) {\n if (typeof maxDepth === 'number' && depth > maxDepth) return;\n let ents: fs.Dirent[];\n try { ents = fs.readdirSync(dir, { withFileTypes: true }); } catch { return; }\n for (const ent of ents) {\n // 点前缀最小例外:仅目录可经 allowDotDirs 放行,文件一律跳过\n if (ent.name.startsWith('.') && !(allowDotDirs && ent.isDirectory())) continue;\n if (skip.has(ent.name)) continue;\n const abs = path.join(dir, ent.name);\n const r = rel ? `${rel}/${ent.name}` : ent.name;\n if (ent.isDirectory()) {\n onDir?.(abs, r);\n walk(abs, r, depth + 1);\n } else if (onFile) {\n onFile(abs, r);\n }\n }\n }\n\n walk(root, '', 0);\n}\n","import type { Context } from 'cordis';\nimport { scanTree } from '../server/spec-scan.js';\n\n/** 生态约定:项目根/worktree 根下的固定扫描目录,非用户可配;.zdev/apply 为点前缀目录,经 dotDirs 显式放行 */\nconst CONVENTION_SCAN_DIRS = ['openspec', 'docs', '.zdev/apply'] as const;\n/** 点前缀扫描目录子集:scanTree 须声明才可扫(walkDir 点前缀最小例外) */\nconst CONVENTION_DOT_DIRS = CONVENTION_SCAN_DIRS.filter((d) => d.startsWith('.'));\n\nexport const apply = {\n inject: ['server'] as const,\n apply(ctx: Context, config: { root: string }) {\n const server = ctx.server;\n if (server?.route) {\n // /__files 仅返回目录树;探测位已由独立轻量接口 /__detect 承担,不再搭车\n server.route('/__files', async (req, res) => {\n try {\n const url = new URL(req.url || '/', 'http://localhost');\n const wt = url.searchParams.get('wt');\n const scanRoot = wt ? decodeURIComponent(wt) : config.root;\n const tree = scanTree(scanRoot, [...CONVENTION_SCAN_DIRS], { dotDirs: [...CONVENTION_DOT_DIRS] });\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8', 'Cache-Control': 'no-cache' });\n res.end(JSON.stringify({ tree }));\n } catch {\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8', 'Cache-Control': 'no-cache' });\n res.end(JSON.stringify({ tree: [] }));\n }\n });\n }\n },\n};\n","import { execFile } from 'node:child_process';\nimport type { Context } from 'cordis';\n\nexport interface WorktreeInfo {\n path: string;\n name: string;\n branch: string;\n head: string;\n dirty: boolean;\n}\n\nconst GIT_TIMEOUT_MS = 5_000;\nconst ZWORKTREE_SEGMENT = '.zworktree/';\n\nfunction runGit(args: string[], cwd: string): Promise<string> {\n return new Promise((resolve) => {\n execFile('git', args, { cwd, timeout: GIT_TIMEOUT_MS }, (err, stdout) => {\n if (err) return resolve('');\n resolve(stdout);\n });\n });\n}\n\nexport async function listWorktrees(root: string): Promise<WorktreeInfo[]> {\n const raw = await runGit(['worktree', 'list', '--porcelain'], root);\n if (!raw) return [];\n\n const entries: WorktreeInfo[] = [];\n const lines = raw.split('\\n');\n let current: Partial<WorktreeInfo> = {};\n\n for (const line of lines) {\n const m = line.match(/^(worktree|HEAD|branch|detached)\\s+(.+)$/);\n if (!m) continue;\n const [, key, val] = m;\n if (key === 'worktree') {\n if (current.path && current.path.includes(ZWORKTREE_SEGMENT)) {\n entries.push({\n path: current.path,\n name: current.path.split(ZWORKTREE_SEGMENT).pop() ?? '',\n branch: current.branch ?? '',\n head: current.head ?? '',\n dirty: false,\n });\n }\n current = { path: val, head: '', branch: '' };\n } else if (key === 'HEAD') {\n current.head = val;\n } else if (key === 'branch') {\n current.branch = val.replace(/^refs\\/heads\\//, '');\n }\n }\n\n // flush last entry\n if (current.path && current.path.includes(ZWORKTREE_SEGMENT)) {\n entries.push({\n path: current.path,\n name: current.path.split(ZWORKTREE_SEGMENT).pop() ?? '',\n branch: current.branch ?? '',\n head: current.head ?? '',\n dirty: false,\n });\n }\n\n // dirty detection: git status --porcelain 非空即 dirty(失败默认 false)\n await Promise.all(\n entries.map(async (entry) => {\n try {\n const statusOut = await runGit(['status', '--porcelain'], entry.path);\n entry.dirty = statusOut.trim().length > 0;\n } catch {\n entry.dirty = false;\n }\n })\n );\n\n return entries;\n}\n\nexport const apply = {\n inject: ['server'] as const,\n apply(ctx: Context, config: { root: string }) {\n const server = ctx.server;\n if (!server?.route) return;\n\n server.route('/__worktrees', async (_req, res) => {\n try {\n const entries = await listWorktrees(config.root);\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8', 'Cache-Control': 'no-cache' });\n res.end(JSON.stringify(entries));\n } catch {\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8', 'Cache-Control': 'no-cache' });\n res.end(JSON.stringify([]));\n }\n });\n },\n};\n","import { Service } from 'cordis';\nimport type { Context } from 'cordis';\nimport { readBody } from './read-body.js';\n\ndeclare module 'cordis' {\n interface Context {\n dashboard: DashboardService;\n }\n}\n\nexport interface PluginManifest {\n mode: string;\n label: string;\n icon: string;\n description?: string;\n viewerUrl?: string; // 同源 URL,前端 iframe 渲染\n external?: boolean;\n order?: number; // 排序权重(小在前);缺省按字母序\n config?: Record<string, ConfigField>;\n}\n\nexport interface ConfigField {\n type: 'string' | 'text' | 'number' | 'boolean' | 'string[]' | 'select' | 'multiselect';\n label: string;\n default?: unknown;\n placeholder?: string;\n options?: { value: string; label: string }[];\n min?: number;\n max?: number;\n}\n\nexport class DashboardService extends Service {\n static inject = ['server', 'reload'];\n private plugins = new Map<string, PluginManifest>();\n private reloadRef: any;\n\n constructor(ctx: Context) {\n super(ctx, 'dashboard');\n this.ctx.effect(() => () => this.plugins.clear());\n this.reloadRef = ctx.reload;\n\n this.ctx.server.route('/__plugins', (_req, res) => {\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8', 'Cache-Control': 'no-cache' });\n res.end(JSON.stringify({ plugins: Array.from(this.plugins.values()) }));\n });\n\n this.ctx.server.route('/__plugins/config', async (req, res) => {\n const out: Record<string, Record<string, unknown>> = {};\n if (req.method === 'GET') {\n for (const m of this.plugins.values()) {\n const stored = this.ctx.server.getPluginConfig(m.mode);\n const schema = m.config ?? {};\n const merged: Record<string, unknown> = {};\n for (const [key, field] of Object.entries(schema)) {\n merged[key] = key in stored ? stored[key] : (field as ConfigField).default ?? '';\n }\n if (Object.keys(merged).length) out[m.mode] = merged;\n }\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8', 'Cache-Control': 'no-cache' });\n res.end(JSON.stringify(out));\n return;\n }\n if (req.method === 'POST') {\n if (req.headers['x-stop-token'] !== this.ctx.server.stopToken) {\n res.writeHead(403);\n res.end('forbidden');\n return;\n }\n try {\n const body = JSON.parse(await readBody(req));\n const merged: Record<string, Record<string, unknown>> = {};\n for (const mode of Object.keys(body)) {\n merged[mode] = body[mode] ?? {};\n }\n this.ctx.server.savePluginConfig(merged);\n for (const mode of Object.keys(body)) {\n try { this.reloadRef.broadcast('config', { plugin: mode }); } catch { /* ignore */ }\n }\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end('{\"ok\":true}');\n } catch (e) {\n console.error('[config] POST error', e);\n res.writeHead(400);\n res.end('{\"error\":\"bad request\"}');\n }\n return;\n }\n res.writeHead(405);\n res.end('{\"error\":\"method not allowed\"}');\n });\n }\n\n register(manifest: PluginManifest) {\n this.plugins.set(manifest.mode, manifest);\n this.ctx.effect(() => () => this.plugins.delete(manifest.mode));\n }\n\n list() {\n return Array.from(this.plugins.values());\n }\n\n get(mode: string): PluginManifest | undefined {\n return this.plugins.get(mode);\n }\n\n getConfig(mode: string): Record<string, unknown> {\n return this.ctx.server.getPluginConfig(mode);\n }\n}\n","import http from 'node:http';\n\n/**\n * Read the full body of an IncomingMessage.\n * Listens for 'error' to prevent a hanging promise when the client aborts mid-stream.\n */\nexport async function readBody(req: http.IncomingMessage): Promise<string> {\n return new Promise((resolve) => {\n let data = '';\n req.on('data', (chunk: string | Buffer) => { data += chunk; });\n req.on('end', () => resolve(data));\n req.on('error', () => resolve('')); // client abort → settle with empty string\n });\n}\n","import { spawn, execFile, type ChildProcess } from 'node:child_process';\nimport iconv from 'iconv-lite';\n\nexport interface Recipe { name: string; description: string; }\nexport type TaskStatus = 'running' | 'exited';\nexport interface TaskInfo { recipe: string; state: TaskStatus; code: number | null; startedAt: number; signal?: string }\n\nexport type JustEvent =\n | { type: 'log'; recipe: string; text: string }\n | { type: 'clear'; recipe: string }\n | { type: 'state'; recipe: string; state: TaskStatus; code: number | null; startedAt?: number; signal?: string };\n\ninterface Task {\n recipe: string;\n child: ChildProcess | null;\n state: TaskStatus;\n code: number | null;\n signal?: string;\n startedAt: number;\n buffer: string[];\n pending: Buffer; // 字节级行缓冲:块缓冲输出会在行中间断开,攒到 \\n(0x0A)才切行——多字节字符不会跨行界,解码只发生在完整行上\n}\n\nconst MAX_BUFFER = 1000;\n\nconst utf8Strict = new TextDecoder('utf-8', { fatal: true });\n\n/**\n * 逐行解码:先 UTF-8 严格解码,失败回退 GBK(Windows 码页输出)。\n * 行界按 0x0A 字节切分是安全的:UTF-8 续字节 ≥ 0x80、GBK 尾字节 0x40–0xFE,均不含 0x0A。\n */\nfunction decodeLine(buf: Buffer): string {\n try {\n return utf8Strict.decode(buf);\n } catch {\n return iconv.decode(buf, 'gbk');\n }\n}\n\n/** 多任务并发 runner:每个 recipe 独立进程/日志/状态,同名 start 即重启,互不影响 */\nexport class JustRunner {\n private cwd: string;\n private tasks = new Map<string, Task>();\n private clients = new Set<(ev: JustEvent) => void>();\n private recipesCache: Recipe[] | null = null;\n\n constructor(cwd: string) { this.cwd = cwd; }\n\n recipes(): Promise<Recipe[]> {\n if (this.recipesCache) return Promise.resolve(this.recipesCache);\n return new Promise((resolve) => {\n execFile('just', ['--list', '--unsorted'], { cwd: this.cwd, maxBuffer: 1 << 20, timeout: 8000 }, (err, stdout) => {\n if (err) { resolve([]); return; }\n const out: Recipe[] = [];\n const seen = new Set<string>();\n for (const line of stdout.split(/\\r?\\n/).slice(1)) { // 跳过 \"Available recipes:\"\n const trimmed = line.trim();\n if (!trimmed) continue;\n const hashIdx = trimmed.indexOf('#');\n const sig = (hashIdx >= 0 ? trimmed.slice(0, hashIdx) : trimmed).trim();\n if (!sig) continue;\n const name = sig.split(/\\s+/)[0]; // \"hello msg=...\" -> \"hello\"\n if (seen.has(name)) continue;\n seen.add(name);\n out.push({ name, description: hashIdx >= 0 ? trimmed.slice(hashIdx + 1).trim() : '' });\n }\n this.recipesCache = out;\n resolve(out);\n });\n });\n }\n\n subscribe(fn: (ev: JustEvent) => void): () => void {\n this.clients.add(fn);\n // 连上即重放:全部任务的日志与状态\n for (const t of this.tasks.values()) {\n for (const text of t.buffer) fn({ type: 'log', recipe: t.recipe, text });\n fn({ type: 'state', recipe: t.recipe, state: t.state, code: t.code, startedAt: t.startedAt });\n }\n return () => this.clients.delete(fn);\n }\n\n private emit(ev: JustEvent) { for (const fn of this.clients) fn(ev); }\n\n list(): TaskInfo[] {\n return Array.from(this.tasks.values(), (t) => ({ recipe: t.recipe, state: t.state, code: t.code, startedAt: t.startedAt }));\n }\n\n /** 启动 recipe:同名先停旧进程(重启语义),不影响其他任务;调用方须先用 recipes() 校验名字 */\n start(recipe: string) {\n this.killOne(recipe);\n const task: Task = { recipe, child: null, state: 'running', code: null, startedAt: Date.now(), buffer: [], pending: Buffer.alloc(0) };\n this.tasks.set(recipe, task);\n this.emit({ type: 'clear', recipe }); // 广播清屏:同步清掉该任务上一轮残留日志\n this.emit({ type: 'state', recipe, state: 'running', code: null, startedAt: task.startedAt });\n const child = spawn('just', [recipe], {\n cwd: this.cwd,\n shell: true,\n env: {\n ...process.env,\n FORCE_COLOR: '1', // node 生态(chalk 等)\n // maven 检测非 tty 会关颜色;经 MAVEN_OPTS 强制开(保留用户已有值)\n MAVEN_OPTS: `${process.env.MAVEN_OPTS ?? ''} -Dstyle.color=always`.trim(),\n CI: '',\n },\n });\n task.child = child;\n // 身份守卫:同名重启后旧进程的迟到输出/退出不得污染新任务(闭包 task 是旧对象时静默丢弃)\n const isStale = () => this.tasks.get(recipe) !== task;\n const push = (d: Buffer) => {\n if (isStale()) return;\n task.pending = Buffer.concat([task.pending, d]);\n let idx: number;\n while ((idx = task.pending.indexOf(0x0a)) >= 0) { // 字节级切行:行界 0x0A 不会落在多字节字符内部\n const line = task.pending.subarray(0, idx + 1);\n task.pending = task.pending.subarray(idx + 1);\n this.pushLine(task, decodeLine(line));\n }\n // 无 \\n 的尾巴留在字节缓冲,等下个 chunk(块缓冲输出会在行中断开,不能当独立行;半个多字节字符也在此安全等待)\n };\n child.stdout?.on('data', push);\n child.stderr?.on('data', push);\n child.on('error', (err) => { this.pushLine(task, `[zdashboard] spawn error: ${err.message}\\n`); });\n child.on('exit', (code, signal) => {\n if (task.pending.length > 0 && !isStale()) { this.pushLine(task, decodeLine(task.pending) + '\\n'); } // flush 末尾无换行的残留(空 Buffer 为 truthy,须按 length 判)\n task.pending = Buffer.alloc(0);\n task.child = null;\n task.state = 'exited';\n task.code = code ?? 0;\n task.signal = signal ?? undefined; // 用户主动 stop 时 code=null+SIGTERM,与成功退出区分\n if (isStale()) return; // 迟到的旧进程退出,不打扰新任务状态\n this.emit({ type: 'state', recipe, state: 'exited', code: task.code, startedAt: task.startedAt, signal: task.signal });\n });\n }\n\n private pushLine(task: Task, line: string) {\n task.buffer.push(line);\n if (task.buffer.length > MAX_BUFFER) task.buffer.shift();\n this.emit({ type: 'log', recipe: task.recipe, text: line });\n }\n\n /** 停单个任务;不传 recipe 停全部 */\n stop(recipe?: string) {\n if (recipe === undefined) { for (const t of this.tasks.values()) this.killOne(t.recipe); }\n else this.killOne(recipe);\n }\n\n restart(recipe: string) {\n if (this.tasks.has(recipe)) this.start(recipe);\n }\n\n /** 清空某任务的日志缓冲并广播(真源清除,重连重放不会复活) */\n clear(recipe: string) {\n const task = this.tasks.get(recipe);\n if (!task) return;\n task.buffer = [];\n task.pending = Buffer.alloc(0);\n this.emit({ type: 'clear', recipe });\n }\n\n private killOne(recipe: string) {\n const task = this.tasks.get(recipe);\n const child = task?.child;\n if (child?.pid) {\n try {\n if (process.platform === 'win32') spawn('taskkill', ['/PID', String(child.pid), '/T', '/F']);\n else child.kill('SIGTERM');\n } catch { /* 已退出 */ }\n }\n if (task) { task.child = null; }\n }\n}\n","/**\n * 插件 SDK(server 侧):definePlugin 是插件接入宿主的唯一姿势。\n *\n * 内部自动完成 dashboard.register(manifest) 与 effect 清理注册,\n * 插件作者只面对 PluginContext 的七个通道;四种 cordis 手写姿势由此消亡。\n */\nimport type http from 'node:http';\nimport { json, guarded } from '../core/server.js';\nimport type { Context } from 'cordis';\nimport type { PluginManifest } from '../core/manifest.js';\n\n/** handler 返回非 undefined 值时由 SDK 包装为 json 响应;自行写响应则返回 undefined */\nexport type RouteHandler = (\n req: http.IncomingMessage,\n res: http.ServerResponse,\n) => unknown | Promise<unknown>;\n\nexport type SseHandler = (res: http.ServerResponse) => (() => void) | void;\n\nexport interface PluginContext {\n /** manifest.mode 的只读镜像 */\n readonly mode: string;\n /** manifest.config 默认值合并 .zdev/dashboard.json 存储值(存储优先) */\n config<T extends Record<string, unknown> = Record<string, unknown>>(): T;\n /** 注册路由;handler 返回值自动 json 包装(200 + application/json) */\n route(path: string, handler: RouteHandler): void;\n /** 校验 x-stop-token 后执行 route 语义;缺/错 token 直接 403 */\n guardedRoute(path: string, handler: RouteHandler): void;\n sse(path: string, handler: SseHandler): void;\n static(prefix: string, dir: string): void;\n /** 广播到 SSE 频道 plugin:<mode>:<event>,客户端 usePluginData subscribe 消费 */\n broadcast(event: string, data?: unknown): void;\n onDispose(fn: () => void): void;\n}\n\ninterface CordisPluginApply {\n inject?: readonly string[];\n apply(ctx: Context, config: unknown): unknown;\n}\n\n/**\n * 定义内置/外部插件的 server 侧入口。\n * @param def.manifest 与 client defineWebPlugin 共享的同一份常量(SSOT)\n * @param def.setup 在 server/dashboard 服务就绪的上下文中执行\n */\nexport function definePlugin(def: {\n manifest: PluginManifest;\n setup(ctx: PluginContext): void;\n}): CordisPluginApply & { inject: readonly string[] } {\n const { manifest, setup } = def;\n\n return {\n inject: ['server', 'dashboard', 'reload'] as const,\n apply(this: void, ctx: Context) {\n const disposers: Array<() => void> = [];\n ctx.effect(() => () => {\n for (const fn of disposers.splice(0)) {\n try { fn(); } catch (e) {\n console.error(`[zdashboard] plugin ${manifest.mode} dispose error:`, e);\n }\n }\n });\n\n ctx.dashboard.register(manifest);\n\n /** json 包装语义与错误兜底;guardedRoute 不经此重注册路径 */\n const respondWith = (handler: RouteHandler) => async (req: http.IncomingMessage, res: http.ServerResponse) => {\n if (res.headersSent) return;\n try {\n const data = await handler(req, res);\n if (data !== undefined && !res.writableEnded) json(res, data);\n } catch (e) {\n console.error(`[zdashboard] plugin ${manifest.mode} route error:`, e);\n if (!res.headersSent) json(res, { error: 'internal' }, 500);\n }\n };\n\n const pctx: PluginContext = {\n mode: manifest.mode,\n config<T extends Record<string, unknown> = Record<string, unknown>>(): T {\n const schema = manifest.config ?? {};\n const stored = ctx.server.getPluginConfig(manifest.mode) ?? {};\n const defaults = Object.fromEntries(\n Object.entries(schema).map(([key, field]) => [key, field.default]),\n );\n return { ...defaults, ...stored } as T;\n },\n route(path: string, handler: RouteHandler): void {\n ctx.server.route(path, respondWith(handler));\n },\n guardedRoute(path: string, handler: RouteHandler): void {\n const token = () => ctx.server.stopToken;\n ctx.server.route(path, (req, res) => {\n if (!guarded(req, res, token())) return;\n void respondWith(handler)(req, res);\n });\n },\n sse(path: string, handler: SseHandler): void {\n ctx.server.sse(path, handler);\n },\n static(prefix: string, dir: string): void {\n ctx.server.static(prefix, dir);\n },\n broadcast(event: string, data?: unknown): void {\n ctx.reload?.broadcast(`plugin:${manifest.mode}:${event}`, data ?? '');\n },\n onDispose(fn: () => void): void {\n disposers.push(fn);\n },\n };\n\n setup(pctx);\n },\n };\n}\n","/**\n * 内置插件 root 注入壳(插件侧适配,不动 SDK 公共契约):\n *\n * SDK definePlugin 的 apply(ctx) 不向 setup 转发 cordis 插件 config,\n * 而六个内置插件都需要 cli 注入的 { root }。此壳在插件层捕获 config.root\n * 再调用 SDK 产出的 apply,setup 以第二参拿到 root。\n * 若 SDK 未来转发 config,此文件可整体删除。\n */\nimport type { Context } from 'cordis';\nimport { definePlugin, type PluginContext } from '../sdk/server.js';\nimport type { PluginManifest } from '../core/manifest.js';\n\nexport function defineBuiltin(def: {\n manifest: PluginManifest;\n setup(ctx: PluginContext, root: string): void;\n}) {\n let currentRoot = '';\n const inner = definePlugin({\n manifest: def.manifest,\n setup(pctx) { def.setup(pctx, currentRoot); },\n });\n\n return {\n inject: inner.inject,\n manifest: def.manifest, // cli 启动期死键剥离按 manifest 判定(config 声明/external)\n apply(ctx: Context, config: { root?: string }) {\n currentRoot = config?.root ?? '';\n inner.apply(ctx, config);\n },\n };\n}\n","/** just 插件单源:server definePlugin 与 web defineWebPlugin 共享 */\nimport type { PluginManifest } from '../../core/manifest.js';\nimport type { ParamSchema } from '../../sdk/shared.js';\n\nexport const manifest: PluginManifest = {\n mode: 'just',\n label: 'Just Runner',\n icon: '📜',\n description: 'Just 任务日志与执行',\n order: 50,\n};\n\n/** recipe:选中 recipe;task:活跃任务 id(与 recipe 同名空间) */\nexport const params: ParamSchema = [\n { name: 'recipe', label: 'Recipe', type: 'string', description: '选中的 recipe 名' },\n { name: 'task', label: '任务', type: 'string', description: '活跃任务 id' },\n];\n","/**\n * just server 侧:definePlugin 接入(manifest 单源)。\n *\n * JustRunner 并发核实结论(T5):src/server/just-runner.ts 已是多任务并发 runner ——\n * tasks Map 每 recipe 独立子进程/日志缓冲/状态,事件载荷自带 recipe(=taskId),\n * 无需 runner 池改造。plugin:just:log 等频道广播按事件原样携带 taskId。\n *\n * start/restart/stop/clear 走 guardedRoute(x-stop-token);\n * /__just/tasks 为任务列表提供只读路由。\n */\nimport type http from 'node:http';\nimport { JustRunner } from '../../server/just-runner.js';\nimport { readBody } from '../../core/read-body.js';\nimport { defineBuiltin } from '../builtin.js';\nimport { manifest } from './manifest.js';\nimport type { RouteHandler } from '../../sdk/server.js';\n\nexport const apply = defineBuiltin({\n manifest,\n setup(ctx, root) {\n const runner = new JustRunner(root);\n ctx.onDispose(() => runner.stop());\n\n ctx.route('/__just/recipes', async () => {\n try {\n return await runner.recipes();\n } catch {\n return [];\n }\n });\n\n ctx.route('/__just/tasks', async () => runner.list());\n\n ctx.sse('/__just/logs', (res) => {\n const unsub = runner.subscribe((ev) => {\n // 插件频道镜像:type 即事件名(log/clear/state),载荷携带 taskId(recipe)\n try { ctx.broadcast(ev.type, ev); } catch { /* reload 未就绪 */ }\n res.write(`data: ${JSON.stringify(ev)}\\n\\n`);\n });\n return unsub;\n });\n\n /** start/restart 须带合法 recipe(同名 start 即重启);stop 可带单个 recipe 或省略(停全部);clear 清日志 */\n const handleAction = async (req: http.IncomingMessage, res: http.ServerResponse, act: 'start' | 'stop' | 'restart' | 'clear') => {\n const body = await readBody(req);\n let recipe: string | undefined;\n try { recipe = JSON.parse(body || '{}').recipe; } catch { /* ignore */ }\n if (act === 'clear') {\n if (recipe) runner.clear(recipe);\n return { ok: true };\n }\n if (act !== 'stop') {\n if (!recipe) {\n res.writeHead(400, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end('{\"error\":\"no recipe\"}');\n return undefined;\n }\n const recipes = await runner.recipes();\n if (!recipes.some((r) => r.name === recipe)) {\n res.writeHead(403, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end('{\"error\":\"unknown recipe\"}');\n return undefined;\n }\n runner.start(recipe);\n } else {\n runner.stop(recipe || undefined);\n }\n return runner.list();\n };\n\n const routeAction = (name: 'start' | 'stop' | 'restart' | 'clear') => {\n ctx.guardedRoute(`/__just/${name}`, ((req, res) => handleAction(req, res, name)) satisfies RouteHandler);\n };\n routeAction('start');\n routeAction('stop');\n routeAction('restart');\n routeAction('clear');\n },\n});\n","/**\n * design server 侧:definePlugin 接入(约定化扫描)。\n * 恒扫 <root>/.zdev/design(zdesign 等 skill 统一产出目录,walkDir 跳过点目录扫根看不见);\n * 目录缺失 → emptyScan() 九组空数组。/__design/assets 响应形状(ScanResult)保持不变。\n * 另供只读代理 /__design/asset?path=<rel-to-.zdev/design>,viewers 由此加载资产(直取根路径必 404)。\n */\nimport path from 'node:path';\nimport fs from 'node:fs';\nimport { MIME } from '../../core/server.js';\nimport { scanAssets, type ScanResult, type AssetType } from '../../server/design-assets.js';\nimport { defineBuiltin } from '../builtin.js';\nimport { manifest } from './manifest.js';\n\nconst ASSET_KEYS: AssetType[] = ['page', 'component', 'icon', 'token', 'md', 'video', 'audio', 'pdf', 'font'];\n\nfunction emptyScan(): ScanResult {\n const out = {} as ScanResult;\n for (const k of ASSET_KEYS) out[k] = [];\n return out;\n}\n\nexport const apply = defineBuiltin({\n manifest,\n setup(ctx, root) {\n ctx.route('/__design/assets', async () => {\n const designRoot = path.join(root, '.zdev', 'design');\n return fs.existsSync(designRoot) ? scanAssets(designRoot) : emptyScan();\n });\n\n // 只读资产代理:三重防御钉死任意读(字符拒绝 → join 归一化 → 前缀校验),先例 /__file-content\n ctx.route('/__design/asset', async (req, res) => {\n const rel = new URL(req.url || '/', 'http://localhost').searchParams.get('path') ?? '';\n if (!rel || rel.includes('..') || rel.includes('\\\\') || path.isAbsolute(rel)) {\n res.writeHead(400);\n res.end('bad path');\n return;\n }\n const designRoot = path.join(root, '.zdev', 'design');\n const filePath = path.join(designRoot, rel);\n if (!filePath.startsWith(designRoot + path.sep)) {\n res.writeHead(400);\n res.end('bad path');\n return;\n }\n fs.stat(filePath, (err) => {\n if (err) { res.writeHead(404); return res.end('Not found'); }\n const ct = MIME[path.extname(filePath).toLowerCase()] ?? 'application/octet-stream';\n res.writeHead(200, { 'Content-Type': ct, 'Cache-Control': 'no-cache' });\n // stat 通过后文件仍可能被删,流错误无人接会崩进程(与 core/server serveFile 同款兜底)\n const stream = fs.createReadStream(filePath);\n stream.on('error', () => { try { res.destroy(); } catch { /* 已断 */ } });\n stream.pipe(res);\n });\n });\n },\n});\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport { walkDir } from './walk.js';\n\nexport type AssetType = 'page' | 'component' | 'icon' | 'token' | 'md' | 'video' | 'audio' | 'pdf' | 'font';\n\nconst PAGE_EXTS = ['.html', '.htm'];\nconst ICON_EXTS = ['.svg', '.png', '.ico', '.jpg', '.jpeg', '.gif', '.webp'];\nconst VIDEO_EXTS = ['.mp4', '.webm', '.mov', '.ogg', '.ogv'];\nconst AUDIO_EXTS = ['.mp3', '.wav', '.flac', '.aac', '.m4a'];\nconst CODE_EXTS = ['.js', '.mjs', '.cjs', '.mts', '.cts', '.ts', '.tsx', '.jsx', '.css', '.json', '.txt', '.xml', '.yml', '.yaml', '.sh', '.md'];\nconst FONT_EXTS = ['.woff', '.woff2', '.ttf', '.otf'];\nconst TOKEN_RE = /token|theme|design|color|palette|typograph/i;\n\nexport function categorize(rel: string, ext: string): AssetType | null {\n if (rel.indexOf('components/') === 0) return 'component';\n if (VIDEO_EXTS.includes(ext)) return 'video';\n if (AUDIO_EXTS.includes(ext)) return 'audio';\n if (ext === '.pdf') return 'pdf';\n if (ext === '.md') return 'md';\n if (FONT_EXTS.includes(ext)) return 'font';\n if (ICON_EXTS.includes(ext)) return 'icon';\n if (PAGE_EXTS.includes(ext)) return 'page';\n if (CODE_EXTS.includes(ext)) {\n if (TOKEN_RE.test(rel) && (ext === '.css' || ext === '.json')) return 'token';\n return null;\n }\n return null;\n}\n\nexport interface AssetFile { path: string; name: string; ext: string; type: AssetType; }\nexport type ScanResult = Record<AssetType, AssetFile[]>;\n\nexport function scanAssets(root: string, subDir = ''): ScanResult {\n const out: ScanResult = {} as ScanResult;\n const keys: AssetType[] = ['page','component','icon','token','md','video','audio','pdf','font'];\n for (const k of keys) out[k] = [];\n const SKIP = new Set(['node_modules', '.git', 'dist', 'build', 'coverage', '.next', '.cache']);\n const scanRoot = subDir ? path.join(root, subDir) : root;\n walkDir(scanRoot, { skip: SKIP, onFile: (abs, rel) => {\n const ext = path.extname(abs).toLowerCase();\n const t = categorize(rel, ext);\n if (t) out[t].push({ path: rel, name: path.basename(abs), ext, type: t });\n }});\n return out;\n}\n","/** design 插件单源:server definePlugin 与 web defineWebPlugin 共享 */\nimport type { PluginManifest } from '../../core/manifest.js';\nimport type { ParamSchema } from '../../sdk/shared.js';\n\nexport const manifest: PluginManifest = {\n mode: 'design',\n label: '设计资产',\n icon: '🎨',\n description: '设计资产分类浏览 · zdesign',\n order: 30,\n};\n\n/** type:资产类型;asset:选中资产路径;folder:资产路径过滤展示 */\nexport const params: ParamSchema = [\n { name: 'type', label: '资产类型', type: 'string', description: 'page/component/icon/token/md/video/audio/pdf/font' },\n { name: 'asset', label: '选中资产', type: 'string', description: '资产相对路径' },\n { name: 'folder', label: '当前文件夹', type: 'string', description: '限定展示的资产路径前缀' },\n];\n","/** view 插件单源:server definePlugin 与 web defineWebPlugin 共享 */\nimport type { PluginManifest } from '../../core/manifest.js';\nimport type { ParamSchema } from '../../sdk/shared.js';\n\nexport const manifest: PluginManifest = {\n mode: 'view',\n label: '项目浏览',\n icon: '👁️',\n description: 'openspec / docs / 文档预览',\n order: 20,\n};\n\n/** wt:worktree 绝对路径;file:文件相对路径;filter:树过滤词 */\nexport const params: ParamSchema = [\n { name: 'wt', label: 'Worktree 路径', type: 'string', description: 'worktree 绝对路径' },\n { name: 'file', label: '文件路径', type: 'string', description: '预览文件相对路径' },\n { name: 'filter', label: '过滤词', type: 'string', description: '文件树过滤词' },\n];\n","/**\n * view server 侧:definePlugin 接入(manifest 单源)。\n * 文件树路由 /__files 由 core/tree.ts 宿主服务提供(约定目录 ['openspec','docs'],非配置),此处仅注册 manifest。\n */\nimport { defineBuiltin } from '../builtin.js';\nimport { manifest } from './manifest.js';\n\nexport const apply = defineBuiltin({\n manifest,\n setup() { /* 路由由 core/tree.ts 承载 */ },\n});\n","/**\n * stats server 侧:definePlugin 接入(manifest 单源)。\n * /__stats/data 响应形状与迁移前保持一致。\n */\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { execFile } from 'node:child_process';\nimport { walkDir } from '../../server/walk.js';\nimport { listWorktrees } from '../../core/worktrees.js';\nimport { defineBuiltin } from '../builtin.js';\nimport { manifest } from './manifest.js';\n\ninterface Stats {\n root: string;\n files: number;\n dirs: number;\n totalSize: number;\n byExt: { ext: string; count: number }[];\n markdown: number;\n openspec: { active: number; archived: number };\n hasJust: boolean;\n worktrees: number;\n branch?: string;\n dirty?: number;\n}\n\nconst SKIP_DIRS = new Set(['node_modules', '.git', 'dist', 'build', '.next', '.cache']);\n\nfunction execFilePromise(file: string, args: string[], opts: { cwd: string }): Promise<string> {\n return new Promise((resolve) => {\n execFile(file, args, opts, (err, stdout) => resolve(err ? '' : stdout));\n });\n}\n\nfunction scan(root: string): Stats {\n const stats: Stats = {\n root: path.basename(root),\n files: 0,\n dirs: 0,\n totalSize: 0,\n byExt: [],\n markdown: 0,\n openspec: { active: 0, archived: 0 },\n hasJust: fs.existsSync(path.join(root, 'justfile')),\n worktrees: 0,\n };\n const extMap = new Map<string, number>();\n\n const walk = (dir: string) => {\n walkDir(dir, { skip: SKIP_DIRS, onDir: () => { stats.dirs++; }, onFile: (abs) => {\n stats.files++;\n try { stats.totalSize += fs.statSync(abs).size; } catch {}\n const ext = path.extname(abs).toLowerCase() || '(无扩展名)';\n extMap.set(ext, (extMap.get(ext) ?? 0) + 1);\n if (ext === '.md' || ext === '.markdown') stats.markdown++;\n }});\n };\n walk(root);\n\n const changesDir = path.join(root, 'openspec', 'changes');\n if (fs.existsSync(changesDir)) {\n for (const ent of fs.readdirSync(changesDir, { withFileTypes: true })) {\n if (!ent.isDirectory() || ent.name.startsWith('.')) continue;\n if (ent.name === 'archive') {\n try {\n stats.openspec.archived = fs.readdirSync(path.join(changesDir, 'archive'), { withFileTypes: true })\n .filter(e => e.isDirectory() && !e.name.startsWith('.')).length;\n } catch { /* ignore */ }\n } else stats.openspec.active++;\n }\n }\n\n stats.byExt = Array.from(extMap.entries())\n .map(([ext, count]) => ({ ext, count }))\n .sort((a, b) => b.count - a.count)\n .slice(0, 10);\n return stats;\n}\n\nexport const apply = defineBuiltin({\n manifest,\n setup(ctx, root) {\n ctx.route('/__stats/data', async () => {\n const stats = scan(root);\n try {\n const wts = await listWorktrees(root);\n stats.worktrees = wts.length;\n } catch {\n stats.worktrees = 0;\n }\n try {\n const branchOut = await execFilePromise('git', ['rev-parse', '--abbrev-ref', 'HEAD'], { cwd: root });\n stats.branch = branchOut.trim() || undefined;\n } catch { /* ignore */ }\n try {\n const statusOut = await execFilePromise('git', ['status', '--porcelain'], { cwd: root });\n stats.dirty = statusOut.trim() ? statusOut.trim().split('\\n').length : 0;\n } catch { /* ignore */ }\n return stats;\n });\n },\n});\n","/** stats 插件单源:server definePlugin 与 web defineWebPlugin 共享 */\nimport type { PluginManifest } from '../../core/manifest.js';\nimport type { ParamSchema } from '../../sdk/shared.js';\n\nexport const manifest: PluginManifest = {\n mode: 'stats',\n label: '项目统计',\n icon: '📊',\n description: '项目文件统计 · 扫描生成',\n order: 10,\n};\n\n/** card:钻取来源(worktree/dirty),view 侧读取后高亮 */\nexport const params: ParamSchema = [\n { name: 'card', label: '钻取来源', type: 'string', description: '钻取来源(worktree/dirty),view 侧读取后高亮' },\n];\n"],"mappings":";;;AAAA,OAAOA,WAAU;AACjB,OAAOC,SAAQ;AACf,SAAS,iBAAAC,sBAAqB;AAC9B,SAAS,QAAQ,eAAe;AAEhC,SAAS,aAAa,qBAAqB;;;ACL3C,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,SAAS,gBAAgB;AASzB,IAAM,wBAAwB;AAE9B,IAAM,2BAA2B;AAEjC,SAAS,cAAc,KAA+B;AAEpD,QAAM,QAAQ,CAAC,MAAgB,YAAoB,IAAI,QAAiB,CAAC,YAAY;AACnF,UAAM,QAAQ,SAAS,QAAQ,MAAM,EAAE,KAAK,QAAQ,GAAG,CAAC,QAAQ,QAAQ,CAAC,GAAG,CAAC;AAC7E,QAAI,MAAM,OAAQ,SAAQ,KAAK;AAAA,EACjC,CAAC;AAGD,SAAO,MAAM,CAAC,UAAU,eAAe,GAAG,qBAAqB,EAC5D,KAAK,CAAC,OAAQ,KAAK,OAAO,MAAM,CAAC,WAAW,GAAG,wBAAwB,CAAE;AAC9E;AAEA,eAAsB,OAAO,MAAqC;AAChE,QAAM,cAAc,GAAG,WAAW,KAAK,KAAK,MAAM,UAAU,CAAC;AAC7D,QAAM,UAAU,GAAG,WAAW,KAAK,KAAK,MAAM,MAAM,CAAC;AACrD,QAAM,UAAU,MAAM,cAAc,IAAI;AACxC,SAAO,EAAE,aAAa,SAAS,QAAQ;AACzC;AAMA,eAAsB,gBAAgB,MAAuC;AAC3E,SAAO,OAAO,IAAI;AACpB;;;ADhCA,SAAS,eAAwB;;;AERjC,OAAO,UAAU;AACjB,OAAOC,SAAQ;AACf,OAAOC,WAAU;AACjB,OAAO,YAAY;AACnB,SAAS,qBAAqB;;;ACJ9B;AAAA,EACE,MAAQ;AAAA,EACR,SAAW;AAAA,EACX,aAAe;AAAA,EACf,MAAQ;AAAA,EACR,KAAO;AAAA,IACL,YAAc;AAAA,EAChB;AAAA,EACA,OAAS;AAAA,IACP;AAAA,EACF;AAAA,EACA,eAAiB;AAAA,IACf,QAAU;AAAA,EACZ;AAAA,EACA,SAAW;AAAA,IACT,KAAO;AAAA,IACP,OAAS;AAAA,IACT,aAAa;AAAA,IACb,cAAc;AAAA,IACd,OAAS;AAAA,IACT,MAAQ;AAAA,IACR,WAAa;AAAA,IACb,iBAAiB;AAAA,IACjB,SAAW;AAAA,EACb;AAAA,EACA,cAAgB;AAAA,IACd,qBAAqB;AAAA,IACrB,yBAAyB;AAAA,IACzB,iCAAiC;AAAA,IACjC,+BAA+B;AAAA,IAC/B,6BAA6B;AAAA,IAC7B,wBAAwB;AAAA,IACxB,2BAA2B;AAAA,IAC3B,sBAAsB;AAAA,IACtB,iBAAiB;AAAA,IACjB,4BAA4B;AAAA,IAC5B,MAAQ;AAAA,IACR,QAAU;AAAA,IACV,UAAY;AAAA,IACZ,YAAY;AAAA,IACZ,UAAY;AAAA,IACZ,gBAAgB;AAAA,IAChB,cAAc;AAAA,IACd,OAAS;AAAA,IACT,IAAM;AAAA,IACN,aAAa;AAAA,IACb,gBAAgB;AAAA,IAChB,eAAiB;AAAA,IACjB,OAAS;AAAA,IACT,aAAa;AAAA,IACb,wBAAwB;AAAA,IACxB,kBAAkB;AAAA,IAClB,4BAA4B;AAAA,IAC5B,oBAAoB;AAAA,IACpB,gBAAgB;AAAA,IAChB,cAAc;AAAA,IACd,eAAe;AAAA,IACf,sBAAsB;AAAA,IACtB,cAAc;AAAA,IACd,eAAe;AAAA,IACf,QAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,KAAO;AAAA,IACP,gBAAgB;AAAA,IAChB,MAAQ;AAAA,EACV;AAAA,EACA,iBAAmB;AAAA,IACjB,2BAA2B;AAAA,IAC3B,6BAA6B;AAAA,IAC7B,0BAA0B;AAAA,IAC1B,oBAAoB;AAAA,IACpB,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,oBAAoB;AAAA,IACpB,wBAAwB;AAAA,IACxB,uBAAuB;AAAA,IACvB,cAAgB;AAAA,IAChB,OAAS;AAAA,IACT,SAAW;AAAA,IACX,aAAe;AAAA,IACf,uBAAuB;AAAA,IACvB,MAAQ;AAAA,IACR,YAAc;AAAA,IACd,MAAQ;AAAA,IACR,QAAU;AAAA,EACZ;AAAA,EACA,MAAQ;AAAA,IACN,uBAAyB;AAAA,MACvB;AAAA,IACF;AAAA,EACF;AACF;;;ADjFA,SAAS,eAAe;;;AEVxB,OAAOC,SAAQ;AACf,OAAOC,WAAU;AAUV,IAAM,cAAc;AACpB,IAAM,oBAAoB;AAC1B,IAAM,eAAe;AACrB,IAAM,wBAAwB;AAC9B,IAAM,qBAAqB;AAElC,SAAS,WAAW,MAAsB;AACxC,SAAOA,MAAK,KAAK,MAAM,WAAW;AACpC;AAEO,SAAS,WAAW,MAAqC;AAC9D,MAAI;AACF,UAAM,KAAK,WAAW,IAAI;AAC1B,UAAM,MAAMD,IAAG,aAAa,IAAI,OAAO;AACvC,UAAM,MAAM,KAAK,MAAM,GAAG;AAC1B,QACE,OAAO,IAAI,QAAQ,YACnB,OAAO,IAAI,SAAS,YACpB,OAAO,IAAI,SAAS,YACpB,OAAO,IAAI,cAAc,UACzB;AACA,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,YAAY,MAAc,MAAoB;AAC5D,QAAM,KAAK,WAAW,IAAI;AAC1B,EAAAA,IAAG,UAAUC,MAAK,QAAQ,EAAE,GAAG,EAAE,WAAW,KAAK,CAAC;AAGlD,QAAM,MAAM,WAAW,IAAI;AAC3B,QAAM,MAAsB;AAAA,IAC1B,KAAK,QAAQ;AAAA,IACb;AAAA,IACA;AAAA,IACA,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,EACpC;AACA,MAAI,KAAK,WAAW,OAAO,IAAI,YAAY,UAAU;AACnD,QAAI,UAAU,IAAI;AAAA,EACpB;AAEA,QAAM,MAAM,KAAK;AACjB,EAAAD,IAAG,cAAc,KAAK,KAAK,UAAU,KAAK,MAAM,CAAC,IAAI,IAAI;AACzD,EAAAA,IAAG,WAAW,KAAK,EAAE;AACvB;AAEO,SAAS,kBAAkB,MAAuD;AACvF,MAAI;AACF,UAAM,MAAM,WAAW,IAAI;AAC3B,QAAI,KAAK,WAAW,OAAO,IAAI,YAAY,UAAU;AACnD,aAAO,IAAI;AAAA,IACb;AAAA,EACF,QAAQ;AAAA,EAAe;AACvB,SAAO,CAAC;AACV;AAEO,SAAS,mBAAmB,MAAc,SAAwD;AACvG,QAAM,KAAK,WAAW,IAAI;AAC1B,MAAI;AACJ,MAAI;AACF,UAAM,MAAMA,IAAG,aAAa,IAAI,OAAO;AACvC,UAAM,KAAK,MAAM,GAAG;AAAA,EACtB,QAAQ;AACN,UAAM,EAAE,KAAK,QAAQ,KAAK,MAAM,GAAG,MAAM,YAAW,oBAAI,KAAK,GAAE,YAAY,EAAE;AAAA,EAC/E;AACA,MAAI,UAAU;AACd,QAAM,MAAM,KAAK;AACjB,EAAAA,IAAG,cAAc,KAAK,KAAK,UAAU,KAAK,MAAM,CAAC,IAAI,IAAI;AACzD,EAAAA,IAAG,WAAW,KAAK,EAAE;AACvB;AAiBO,SAAS,sBAAsB,MAAc,WAAiD;AACnG,MAAI;AACF,UAAM,MAAM,WAAW,IAAI;AAC3B,QAAI,CAAC,KAAK,WAAW,OAAO,IAAI,YAAY,SAAU,QAAO;AAC7D,UAAM,SAAS,IAAI,IAAI,UAAU,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;AACxD,UAAM,SAAS,IAAI;AACnB,UAAM,UAAmC,EAAE,GAAG,OAAO;AACrD,QAAI,UAAU;AACd,eAAW,QAAQ,OAAO,KAAK,OAAO,GAAG;AACvC,YAAM,IAAI,OAAO,IAAI,IAAI;AAEzB,UAAI,CAAC,KAAK,EAAE,SAAU;AACtB,YAAM,UAAU,QAAQ,IAAI;AAC5B,UAAI,YAAY,QAAQ,OAAO,YAAY,SAAU;AACrD,YAAM,OAAO,OAAO,KAAK,OAAkC;AAC3D,UAAI,CAAC,EAAE,UAAU,OAAO,KAAK,EAAE,MAAM,EAAE,WAAW,GAAG;AAEnD,YAAI,KAAK,SAAS,GAAG;AACnB,iBAAO,QAAQ,IAAI;AACnB,oBAAU;AAAA,QACZ;AACA;AAAA,MACF;AAEA,YAAM,OAAgC,CAAC;AACvC,iBAAW,OAAO,OAAO,KAAK,EAAE,MAAM,GAAG;AACvC,YAAI,OAAQ,QAAqC,MAAK,GAAG,IAAK,QAAoC,GAAG;AAAA,MACvG;AACA,UAAI,OAAO,KAAK,IAAI,EAAE,WAAW,KAAK,QAAQ;AAC5C,YAAI,OAAO,KAAK,IAAI,EAAE,WAAW,EAAG,QAAO,QAAQ,IAAI;AAAA,YAClD,SAAQ,IAAI,IAAI;AACrB,kBAAU;AAAA,MACZ;AAAA,IACF;AACA,QAAI,CAAC,QAAS,QAAO;AACrB,uBAAmB,MAAM,OAAkD;AAC3E,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,YAAY,MAAoB;AAC9C,MAAI;AAEF,UAAM,MAAM,WAAW,IAAI;AAC3B,QAAI,OAAO,IAAI,QAAQ,QAAQ,IAAK;AACpC,IAAAA,IAAG,WAAW,WAAW,IAAI,CAAC;AAAA,EAChC,QAAQ;AAAA,EAER;AACF;AAEO,SAAS,QAAQ,KAAsB;AAC5C,MAAI;AACF,YAAQ,KAAK,KAAK,CAAC;AACnB,WAAO;AAAA,EACT,SAAS,GAAG;AACV,QAAK,EAA4B,SAAS,QAAS,QAAO;AAE1D,WAAO;AAAA,EACT;AACF;AAEA,eAAe,iBAAiB,KAAgC;AAC9D,QAAM,aAAa,IAAI,gBAAgB;AACvC,QAAM,QAAQ,WAAW,MAAM,WAAW,MAAM,GAAG,iBAAiB;AACpE,MAAI;AACF,WAAO,MAAM,MAAM,KAAK,EAAE,QAAQ,WAAW,OAAO,CAAC;AAAA,EACvD,UAAE;AACA,iBAAa,KAAK;AAAA,EACpB;AACF;AAEA,eAAsB,WAAW,MAAc,MAAgC;AAC7E,MAAI;AACF,UAAM,MAAM,MAAM,iBAAiB,oBAAoB,IAAI,WAAW;AACtE,QAAI,IAAI,WAAW,IAAK,QAAO;AAC/B,UAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,QAAI,OAAO,KAAK,SAAS,SAAU,QAAO;AAC1C,WAAO,KAAK,SAAS;AAAA,EACvB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,aAAa,MAA8C;AAC/E,QAAM,MAAM,WAAW,IAAI;AAC3B,MAAI,CAAC,IAAK,QAAO;AACjB,MAAI,CAAC,QAAQ,IAAI,GAAG,EAAG,QAAO;AAC9B,MAAI,CAAE,MAAM,WAAW,IAAI,MAAM,IAAI,EAAI,QAAO;AAChD,SAAO;AACT;AAEA,eAAsB,aAAa,QAAuC;AACxE,MAAI;AACF,YAAQ,KAAK,OAAO,KAAK,SAAS;AAAA,EACpC,QAAQ;AACN;AAAA,EACF;AAEA,QAAM,WAAW,KAAK,IAAI,IAAI;AAC9B,SAAO,KAAK,IAAI,IAAI,UAAU;AAC5B,QAAI,CAAC,QAAQ,OAAO,GAAG,EAAG;AAC1B,UAAM,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,qBAAqB,CAAC;AAAA,EAC/D;AAGA,MAAI;AACF,YAAQ,KAAK,OAAO,KAAK,SAAS;AAAA,EACpC,QAAQ;AAAA,EAER;AACA,QAAM,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,kBAAkB,CAAC;AAC5D;;;ACvNA,SAAS,MAAM,YAAAE,iBAAgB;AAGxB,SAAS,QAAQ,KAAmB;AACzC,QAAM,MACJ,QAAQ,aAAa,WAAW,SAChC,QAAQ,aAAa,UAAU,UAC/B;AAEF,MAAI,QAAQ,aAAa,SAAS;AAChC,SAAK,aAAa,GAAG,GAAG;AAAA,EAC1B,OAAO;AACL,IAAAA,UAAS,KAAK,CAAC,GAAG,CAAC;AAAA,EACrB;AACF;;;AHAA,SAAS,YAAAC,iBAAgB;AAEzB,IAAM,UAAU,gBAAI;AACpB,IAAM,YAAYC,MAAK,QAAQ,cAAc,YAAY,GAAG,CAAC;AAoBtD,IAAM,OAA+B;AAAA,EAC1C,SAAS;AAAA,EAA4B,QAAQ;AAAA,EAC7C,QAAQ;AAAA,EAA2B,OAAO;AAAA,EAC1C,QAAQ;AAAA,EAAyC,SAAS;AAAA,EAC1D,QAAQ;AAAA,EAAiB,QAAQ;AAAA,EAAa,QAAQ;AAAA,EACtD,QAAQ;AAAA,EAAc,SAAS;AAAA,EAAc,QAAQ;AAAA,EAAa,SAAS;AAAA,EAC3E,SAAS;AAAA,EACT,OAAO;AAAA,EAAgC,QAAQ;AAAA,EAC/C,QAAQ;AAAA,EAA6B,QAAQ;AAAA,EAC7C,QAAQ;AAAA,EAA6B,SAAS;AAAA,EAC9C,QAAQ;AAAA,EAA4B,QAAQ;AAAA,EAC5C,OAAO;AAAA,EAA6B,OAAO;AAAA,EAC3C,SAAS;AAAA,EAA6B,OAAO;AAAA,EAC7C,OAAO;AAAA,EAA6B,OAAO;AAAA,EAC3C,QAAQ;AAAA,EAA6B,MAAM;AAAA,EAC3C,QAAQ;AAAA,EAA6B,MAAM;AAAA,EAC3C,OAAO;AAAA,EAA6B,UAAU;AAAA,EAC9C,OAAO;AAAA,EAA6B,UAAU;AAAA,EAC9C,OAAO;AAAA,EAA6B,SAAS;AAAA,EAC7C,QAAQ;AAAA,EAA6B,SAAS;AAAA,EAC9C,QAAQ;AAAA,EAA6B,cAAc;AAAA,EACnD,eAAe;AAAA,EACf,QAAQ;AAAA,EAAa,SAAS;AAAA,EAAc,QAAQ;AAAA,EACpD,QAAQ;AAAA,EAAa,QAAQ;AAAA,EAC7B,SAAS;AAAA,EAAa,UAAU;AAAA,EAAc,QAAQ;AAAA,EACtD,QAAQ;AACV;AAKA,IAAM,SAAS;AAER,IAAM,uBAAuB;AAG7B,SAAS,KAAK,KAA0B,MAAe,SAAS,KAAW;AAChF,MAAI,UAAU,QAAQ,EAAE,gBAAgB,mCAAmC,iBAAiB,WAAW,CAAC;AACxG,MAAI,IAAI,KAAK,UAAU,IAAI,CAAC;AAC9B;AAGO,SAAS,QAAQ,KAA2B,KAA0B,OAAwB;AACnG,MAAI,IAAI,QAAQ,cAAc,MAAM,OAAO;AACzC,QAAI,UAAU,GAAG;AACjB,QAAI,IAAI,WAAW;AACnB,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEO,IAAM,gBAAN,cAA4B,QAAQ;AAAA,EACzC;AAAA,EACQ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,SAAS,oBAAI,IAA2E;AAAA,EACxF,OAAO,oBAAI,IAA+D;AAAA,EAC1E,eAAe,oBAAI,IAAoB;AAAA,EACvC;AAAA,EACA;AAAA,EAER,YAAY,KAAc,QAAuB;AAC/C,UAAM,KAAK,QAAQ;AACnB,SAAK,YAAY,OAAO,YAAY,EAAE,EAAE,SAAS,KAAK;AACtD,SAAK,OAAO,OAAO;AACnB,SAAK,SAAS,OAAO;AACrB,SAAK,OAAO,OAAO;AACnB,SAAK,OAAO,OAAO;AACnB,SAAK,MAAM,OAAO;AAClB,SAAK,UAAU,OAAO;AACtB,SAAK,WAAW,OAAO;AACvB,QAAI,OAAO,MAAM,MAAM,KAAK,QAAQ,CAAC;AAErC,SAAK,eAAe;AACpB,SAAK,MAAM,aAAa,CAAC,MAAM,QAAQ;AACrC,WAAK,KAAK,EAAE,WAAW,KAAK,WAAW,SAAS,SAAS,MAAM,KAAK,MAAM,GAAG,KAAK,QAAQ,CAAC;AAAA,IAC7F,CAAC;AAGD,SAAK,MAAM,aAAa,OAAO,MAAM,QAAQ;AAC3C,YAAM,QAAwB,MAAM,gBAAgB,KAAK,IAAI;AAC7D,WAAK,KAAK,KAAK;AAAA,IACjB,CAAC;AAGD,SAAK,MAAM,gBAAgB,CAAC,KAAK,QAAQ;AACvC,WAAK,UAAUA,MAAK,KAAK,KAAK,QAAQ,aAAa,GAAG,KAAK,KAAK,KAAK;AAAA,IACvE,CAAC;AAED,SAAK,MAAM,mBAAmB,OAAO,KAAK,QAAQ;AAChD,YAAM,MAAM,IAAI,IAAI,IAAI,OAAO,KAAK,kBAAkB;AACtD,YAAM,UAAU,IAAI,SAAS,QAAQ,wBAAwB,EAAE;AAC/D,UAAI,CAAC,WAAW,YAAY,KAAK;AAC/B,YAAI,UAAU,GAAG;AACjB,YAAI,IAAI,cAAc;AACtB;AAAA,MACF;AACA,YAAM,WAAWA,MAAK,KAAK,KAAK,MAAM,mBAAmB,OAAO,CAAC;AACjE,UAAI,CAAC,SAAS,WAAW,KAAK,OAAOA,MAAK,GAAG,KAAK,aAAa,KAAK,MAAM;AACxE,YAAI,UAAU,GAAG;AACjB,YAAI,IAAI,WAAW;AACnB;AAAA,MACF;AACA,MAAAC,IAAG,KAAK,UAAU,CAAC,QAAQ;AACzB,YAAI,KAAK;AAAE,cAAI,UAAU,GAAG;AAAG,iBAAO,IAAI,IAAI,WAAW;AAAA,QAAG;AAC5D,cAAM,MAAMD,MAAK,QAAQ,QAAQ,EAAE,YAAY;AAC/C,cAAM,KAAK,KAAK,GAAG,KAAK;AACxB,YAAI,UAAU,KAAK,EAAE,gBAAgB,IAAI,iBAAiB,WAAW,CAAC;AACtE,QAAAC,IAAG,iBAAiB,QAAQ,EAAE,KAAK,GAAG;AAAA,MACxC,CAAC;AAAA,IACH,CAAC;AAED,SAAK,MAAM,WAAW,OAAO,KAAK,QAAQ;AACxC,UAAI,CAAC,QAAQ,KAAK,KAAK,KAAK,SAAS,EAAG;AACxC,WAAK,KAAK,EAAE,IAAI,KAAK,CAAC;AACtB,WAAK,KAAK;AAAA,IACZ,CAAC;AAED,SAAK,MAAM,OAAO,IAAI;AAAA,EACxB;AAAA,EAEA,MAAMD,QAAc,SAAwE;AAC1F,SAAK,OAAO,IAAIA,QAAM,OAAO;AAC7B,SAAK,IAAI,OAAO,MAAM,MAAM,KAAK,OAAO,OAAOA,MAAI,CAAC;AAAA,EACtD;AAAA,EAEA,IAAIA,QAAc,WAA8D;AAC9E,SAAK,KAAK,IAAIA,QAAM,SAAS;AAC7B,SAAK,IAAI,OAAO,MAAM,MAAM,KAAK,KAAK,OAAOA,MAAI,CAAC;AAAA,EACpD;AAAA,EAEA,OAAO,QAAgB,KAAa;AAClC,SAAK,aAAa,IAAI,QAAQ,GAAG;AACjC,SAAK,IAAI,OAAO,MAAM,MAAM,KAAK,aAAa,OAAO,MAAM,CAAC;AAAA,EAC9D;AAAA,EAEQ,gBAAyD,CAAC;AAAA,EAElE,gBAAgB,MAAuC;AACrD,WAAO,KAAK,cAAc,IAAI,KAAK,CAAC;AAAA,EACtC;AAAA,EAEA,uBAAuB;AACrB,SAAK,gBAAgB,kBAAkB,KAAK,IAAI;AAAA,EAClD;AAAA,EAEA,iBAAiB,QAAiD;AAChE,SAAK,gBAAgB;AACrB,uBAAmB,KAAK,MAAM,MAAM;AAAA,EACtC;AAAA,EAEQ,UAAU,UAAkB,KAA2B,KAA0B,YAAqB;AAC5G,IAAAC,IAAG,KAAK,UAAU,CAAC,KAAK,SAAS;AAC/B,UAAI,KAAK;AAAE,YAAI,UAAU,GAAG;AAAG,eAAO,IAAI,IAAI,WAAW;AAAA,MAAG;AAC5D,YAAM,MAAMD,MAAK,QAAQ,QAAQ,EAAE,YAAY;AAC/C,YAAM,KAAK,KAAK,GAAG,KAAK;AAGxB,YAAM,cAAe,IAAI,QAAQ,OAAO;AACxC,UAAI,QAA+C;AACnD,UAAI,aAAa;AACf,cAAM,IAAI,YAAY,MAAM,qBAAqB;AACjD,YAAI,GAAG;AACL,gBAAM,QAAQ,OAAO,EAAE,CAAC,CAAC;AACzB,gBAAM,MAAQ,EAAE,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC,CAAC,IAAI,KAAK,OAAO;AACvD,cAAI,CAAC,OAAO,MAAM,KAAK,KAAK,CAAC,OAAO,MAAM,GAAG,KAAK,SAAS,OAAO,QAAQ,KAAK,MAAM;AACnF,oBAAQ,EAAE,OAAO,KAAK,KAAK,IAAI,KAAK,KAAK,OAAO,CAAC,EAAE;AAAA,UACrD;AAAA,QAEF;AAAA,MAEF;AAEA,UAAI,OAAO;AACT,cAAM,EAAE,OAAO,IAAI,IAAI;AACvB,cAAM,YAAY,MAAM,QAAQ;AAChC,YAAI,UAAU,KAAK;AAAA,UACjB,gBAAgB;AAAA,UAChB,kBAAkB,OAAO,SAAS;AAAA,UAClC,iBAAiB,SAAS,KAAK,IAAI,GAAG,IAAI,KAAK,IAAI;AAAA,UACnD,iBAAiB;AAAA,UACjB,iBAAiB;AAAA,QACnB,CAAC;AAED,cAAM,SAASC,IAAG,iBAAiB,UAAU,EAAE,OAAO,IAAI,CAAC;AAC3D,eAAO,GAAG,SAAS,MAAM;AAAE,cAAI;AAAE,gBAAI,QAAQ;AAAA,UAAG,QAAQ;AAAA,UAAW;AAAA,QAAE,CAAC;AACtE,eAAO,KAAK,GAAG;AACf;AAAA,MACF;AAGA,MAAAA,IAAG,SAAS,UAAU,CAACC,MAAK,SAAS;AACnC,YAAIA,MAAK;AAAE,cAAI,UAAU,GAAG;AAAG,iBAAO,IAAI,IAAI,WAAW;AAAA,QAAG;AAC5D,YAAI,OAAwB;AAC5B,YAAI,cAAc,QAAQ,SAAS;AACjC,gBAAM,IAAI,KAAK,SAAS,MAAM;AAC9B,iBAAO,OAAO,KAAK,EAAE,QAAQ,SAAS,KAAK,IAAI,EAAE,QAAQ,WAAW,SAAS,SAAS,IAAI,IAAI,MAAM;AAAA,QACtG;AACA,YAAI,UAAU,KAAK,EAAE,gBAAgB,IAAI,iBAAiB,SAAS,iBAAiB,WAAW,CAAC;AAChG,YAAI,IAAI,IAAI;AAAA,MACd,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA,EAEQ,YAAY,KAAa,KAA2B,KAAmC;AAC7F,eAAW,CAAC,QAAQ,GAAG,KAAK,KAAK,cAAc;AAC7C,UAAI,IAAI,QAAQ,MAAM,MAAM,GAAG;AAC7B,YAAI,MAAM,KAAK,WAAW,IAAI,MAAM,OAAO,MAAM,CAAC;AAClD,YAAI,CAAC,OAAO,QAAQ,OAAO,CAACF,MAAK,QAAQ,GAAG,EAAG,OAAMA,MAAK,KAAK,OAAO,IAAI,YAAY;AACtF,cAAM,KAAKA,MAAK,KAAK,KAAK,GAAG;AAC7B,YAAI,GAAG,QAAQ,MAAMA,MAAK,GAAG,MAAM,GAAG;AAAE,cAAI,UAAU,GAAG;AAAG,cAAI,IAAI,WAAW;AAAG,iBAAO;AAAA,QAAO;AAChG,aAAK,UAAU,IAAI,KAAK,KAAK,IAAI;AACjC,eAAO;AAAA,MACT;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,WAAW,KAAqB;AACtC,QAAI;AAAE,aAAO,mBAAmB,GAAG;AAAA,IAAG,QAAQ;AAAE,aAAO;AAAA,IAAK;AAAA,EAC9D;AAAA,EAEQ,UAAU,CAAC,KAA2B,QAA6B;AACzE,QAAI;AACF,YAAM,SAAS,IAAI,OAAO;AAC1B,YAAM,MAAM,OAAO,MAAM,GAAG,EAAE,CAAC;AAEjC,YAAM,KAAK,KAAK,OAAO,IAAI,GAAG;AAC9B,UAAI,IAAI;AAAE,WAAG,KAAK,GAAG;AAAG;AAAA,MAAQ;AAChC,iBAAW,CAAC,IAAI,GAAG,KAAK,KAAK,QAAQ;AACnC,YAAI,IAAI,WAAW,KAAK,GAAG,GAAG;AAAE,cAAI,KAAK,GAAG;AAAG;AAAA,QAAQ;AAAA,MACzD;AACA,YAAM,KAAK,KAAK,KAAK,IAAI,GAAG;AAC1B,UAAI,IAAI;AACN,YAAI,UAAU,KAAK,EAAE,gBAAgB,qBAAqB,iBAAiB,YAAY,YAAY,aAAa,CAAC;AACjH,YAAI,MAAM,iBAAiB;AAC3B,cAAM,UAAU,GAAG,GAAG;AACtB,YAAI,GAAG,SAAS,MAAM;AAAE,oBAAU;AAAA,QAAG,CAAC;AACtC;AAAA,MACF;AAEA,UAAI,KAAK,YAAY,KAAK,KAAK,GAAG,EAAG;AAErC,UAAI,QAAQ,OAAO,IAAI,QAAQ,SAAS,MAAM,KAAK,IAAI,QAAQ,UAAU,MAAM,GAAG;AAChF,YAAIG,MAAK,KAAK;AACd,YAAI,QAAQ,IAAK,CAAAA,MAAKH,MAAK,KAAK,KAAK,QAAQ,KAAK,WAAW,GAAG,CAAC;AACjE,YAAI,IAAI,QAAQ,SAAS,MAAM,EAAG,CAAAG,MAAKH,MAAK,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,CAAC;AAC1E,YAAIG,QAAO,KAAK,UAAUA,IAAG,QAAQ,KAAK,SAASH,MAAK,GAAG,MAAM,GAAG;AAAE,cAAI,UAAU,GAAG;AAAG,iBAAO,IAAI,IAAI,WAAW;AAAA,QAAG;AACvH,YAAI,QAAQ,IAAK,CAAAG,MAAKH,MAAK,KAAK,KAAK,QAAQ,YAAY;AACzD,eAAO,KAAK,UAAUG,KAAI,KAAK,KAAK,KAAK;AAAA,MAC3C;AAEA,YAAM,KAAKH,MAAK,KAAK,KAAK,MAAM,KAAK,WAAW,GAAG,CAAC;AACpD,UAAI,OAAO,KAAK,QAAQ,GAAG,QAAQ,KAAK,OAAOA,MAAK,GAAG,MAAM,GAAG;AAAE,YAAI,UAAU,GAAG;AAAG,eAAO,IAAI,IAAI,WAAW;AAAA,MAAG;AACnH,aAAO,KAAK,UAAU,IAAI,KAAK,KAAK,IAAI;AAAA,IAC1C,SAAS,GAAG;AACV,UAAI;AAAE,YAAI,UAAU,GAAG;AAAG,YAAI,IAAI,aAAa;AAAA,MAAG,QAAQ;AAAA,MAAC;AAC3D,cAAQ,MAAM,8BAA8B,CAAC;AAAA,IAC/C;AAAA,EACF;AAAA,EAEA,MAAM,MAAc;AAClB,SAAK,SAAS,KAAK,aAAa,KAAK,OAAO;AAG5C,SAAK,OAAO,mBAAmB;AAC/B,SAAK,OAAO,iBAAiB;AAC7B,SAAK,OAAO,GAAG,SAAS,CAAC,QAA+B;AACtD,UAAI,IAAI,SAAS,cAAc;AAC7B,gBAAQ,IAAI,qBAAqB,IAAI,iBAAiB,OAAO,CAAC,EAAE;AAChE,aAAK,MAAM,OAAO,CAAC;AAAA,MACrB,MAAO,OAAM;AAAA,IACf,CAAC;AACD,SAAK,OAAO,OAAO,MAAM,aAAa,MAAM;AAE1C,YAAM,OAAO,KAAK,QAAQ,QAAQ;AAClC,YAAM,QAAQ,OAAO,SAAS,YAAY,OAAO,KAAK,OAAO;AAC7D,YAAM,IAAI,oBAAoB,KAAK;AACnC,YAAM,SAAS,KAAK,OAAO,GAAG,CAAC,IAAI,KAAK,IAAI,KAAK;AACjD,cAAQ,IAAI,iBAAiB,OAAO,iBAAiB,CAAC,EAAE;AACxD,cAAQ,IAAI,6BAA6B,KAAK,IAAI,EAAE;AACpD,cAAQ,IAAI,sCAAsC,KAAK,IAAI,WAAW,SAAS,KAAK,IAAI,OAAO,SAAS,KAAK,IAAI,OAAO,EAAE;AAC1H,UAAI,KAAK,QAAS,SAAQ,IAAI,6BAA6B,KAAK,OAAO,EAAE;AACzE,UAAI,KAAK,KAAM,SAAQ,MAAM;AAC7B,WAAK,WAAW,KAAK;AAAA,IACvB,CAAC;AAAA,EACH;AAAA;AAAA,EAGQ,UAA+C,CAAC;AAAA,EAExD,iBAAiB;AACf,UAAM,MAAM,CAAC,SAAmB,IAAI,QAAgB,CAAC,YAAY;AAC/D,MAAAD,UAAS,OAAO,MAAM,EAAE,KAAK,KAAK,MAAM,SAAS,IAAK,GAAG,CAAC,KAAK,WAAW,QAAQ,MAAM,KAAK,MAAM,CAAC;AAAA,IACtG,CAAC;AACD,UAAM,YAAY;AAChB,YAAM,CAAC,QAAQ,MAAM,IAAI,MAAM,QAAQ,IAAI;AAAA,QACzC,IAAI,CAAC,aAAa,gBAAgB,MAAM,CAAC;AAAA,QACzC,IAAI,CAAC,UAAU,aAAa,CAAC;AAAA,MAC/B,CAAC;AACD,YAAM,IAAI,OAAO,KAAK;AACtB,WAAK,UAAU,IAAI,EAAE,QAAQ,GAAG,OAAO,SAAS,OAAO,MAAM,IAAI,EAAE,OAAO,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC;AAAA,IACrG,GAAG;AAAA,EACL;AAAA,EAEA,OAAO;AACL,QAAI,KAAK,QAAQ;AAAE,UAAI;AAAE,aAAK,OAAO,MAAM;AAAA,MAAG,QAAQ;AAAA,MAAC;AAAA,IAAE;AACzD,QAAI;AAAE,kBAAY,KAAK,IAAI;AAAA,IAAG,QAAQ;AAAA,IAAC;AACvC,eAAW,MAAM;AACf,UAAI;AAAE,aAAK,IAAI,KAAK,MAAM,QAAQ;AAAA,MAAG,QAAQ;AAAA,MAAC;AAC9C,cAAQ,KAAK,CAAC;AAAA,IAChB,GAAG,EAAE;AAAA,EACP;AAAA,EAEA,UAAU;AACR,QAAI,KAAK,QAAQ;AAAE,UAAI;AAAE,aAAK,OAAO,MAAM;AAAA,MAAG,QAAQ;AAAA,MAAC;AAAA,IAAE;AACzD,QAAI;AAAE,kBAAY,KAAK,IAAI;AAAA,IAAG,QAAQ;AAAA,IAAC;AAAA,EACzC;AACF;;;AIvWA,OAAOK,SAAQ;AAEf,SAAS,WAAAC,gBAAe;AASxB,IAAM,oBAAoB;AAG1B,IAAM,iBAAiB;AACvB,IAAM,kBAAkB;AAGjB,SAAS,cAAc,UAAkC;AAC9D,MAAI,CAAC,SAAU,QAAO;AACtB,SAAO,eAAe,KAAK,QAAQ,KAAK,gBAAgB,KAAK,QAAQ;AACvE;AAEO,IAAM,gBAAN,cAA4BA,SAAQ;AAAA,EACzC,OAAO,SAAS,CAAC,QAAQ;AAAA,EACjB,UAAU,oBAAI,IAAyB;AAAA,EACvC;AAAA,EACA;AAAA,EAER,YAAY,KAAc,QAA0B;AAClD,UAAM,KAAK,QAAQ;AACnB,SAAK,IAAI,OAAO,MAAM,MAAM,KAAK,QAAQ,CAAC;AAE1C,SAAK,IAAI,OAAO,IAAI,aAAa,CAAC,QAAQ;AACxC,WAAK,QAAQ,IAAI,GAAG;AACpB,aAAO,MAAM,KAAK,QAAQ,OAAO,GAAG;AAAA,IACtC,CAAC;AAED,QAAI;AACF,WAAK,UAAUD,IAAG,MAAM,OAAO,MAAM,EAAE,WAAW,KAAK,GAAG,CAAC,WAAW,aAAa;AACjF,YAAI,cAAc,QAAQ,EAAG;AAC7B,YAAI,KAAK,MAAO,cAAa,KAAK,KAAK;AACvC,aAAK,QAAQ,WAAW,MAAM;AAC5B,eAAK,IAAI,OAAO,eAAe;AAC/B,eAAK,UAAU,QAAQ;AACvB,eAAK,UAAU,OAAO;AACtB,eAAK,QAAQ;AAAA,QACf,GAAG,iBAAiB;AAAA,MACtB,CAAC;AAAA,IACH,QAAQ;AAAA,IAER;AAAA,EACF;AAAA,EAEA,UAAU,IAAY,OAAgB,IAAI;AACxC,UAAM,UAAU,UAAU,EAAE;AAAA,QAAW,KAAK,UAAU,QAAQ,OAAO,KAAK,IAAI,CAAC;AAAA;AAAA;AAC/E,eAAW,KAAK,KAAK,SAAS;AAC5B,UAAI;AAAE,UAAE,MAAM,OAAO;AAAA,MAAG,QAAQ;AAAA,MAAC;AAAA,IACnC;AAAA,EACF;AAAA;AAAA,EAGA,gBAAgB,MAAc,OAAe,OAAgB,IAAI;AAC/D,SAAK,UAAU,UAAU,IAAI,IAAI,KAAK,IAAI,IAAI;AAAA,EAChD;AAAA,EAEA,UAAU;AACR,QAAI,KAAK,SAAS;AAAE,UAAI;AAAE,aAAK,QAAQ,MAAM;AAAA,MAAG,QAAQ;AAAA,MAAC;AAAA,IAAE;AAC3D,QAAI,KAAK,OAAO;AAAE,mBAAa,KAAK,KAAK;AAAA,IAAG;AAC5C,eAAW,KAAK,KAAK,SAAS;AAAE,UAAI;AAAE,UAAE,IAAI;AAAA,MAAG,QAAQ;AAAA,MAAC;AAAA,IAAE;AAC1D,SAAK,QAAQ,MAAM;AAAA,EACrB;AACF;;;ACxEA,OAAOE,SAAQ;AACf,OAAOC,WAAU;;;ACDjB,OAAOC,SAAQ;AACf,OAAOC,WAAU;AAWV,SAAS,QAAQ,MAAc,OAAoB,CAAC,GAAS;AAClE,QAAM,EAAE,OAAO,oBAAI,IAAI,GAAG,UAAU,eAAe,OAAO,QAAQ,MAAM,IAAI;AAE5E,WAAS,KAAK,KAAa,KAAa,OAAe;AACrD,QAAI,OAAO,aAAa,YAAY,QAAQ,SAAU;AACtD,QAAI;AACJ,QAAI;AAAE,aAAOD,IAAG,YAAY,KAAK,EAAE,eAAe,KAAK,CAAC;AAAA,IAAG,QAAQ;AAAE;AAAA,IAAQ;AAC7E,eAAW,OAAO,MAAM;AAEtB,UAAI,IAAI,KAAK,WAAW,GAAG,KAAK,EAAE,gBAAgB,IAAI,YAAY,GAAI;AACtE,UAAI,KAAK,IAAI,IAAI,IAAI,EAAG;AACxB,YAAM,MAAMC,MAAK,KAAK,KAAK,IAAI,IAAI;AACnC,YAAM,IAAI,MAAM,GAAG,GAAG,IAAI,IAAI,IAAI,KAAK,IAAI;AAC3C,UAAI,IAAI,YAAY,GAAG;AACrB,gBAAQ,KAAK,CAAC;AACd,aAAK,KAAK,GAAG,QAAQ,CAAC;AAAA,MACxB,WAAW,QAAQ;AACjB,eAAO,KAAK,CAAC;AAAA,MACf;AAAA,IACF;AAAA,EACF;AAEA,OAAK,MAAM,IAAI,CAAC;AAClB;;;ADtBA,SAAS,UAAU,OAAiB,qBAAqB,GAAe;AACtE,QAAM,OAAmB,CAAC;AAC1B,QAAM,MAAM,oBAAI,IAAsB;AAEtC,aAAW,KAAK,OAAO;AACrB,UAAM,QAAQ,EAAE,MAAM,GAAG;AACzB,QAAI,UAAU;AACd,QAAI,SAAS;AAEb,aAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,YAAM,OAAO,MAAM,CAAC;AACpB,gBAAU,UAAU,GAAG,OAAO,IAAI,IAAI,KAAK;AAC3C,YAAM,SAAS,MAAM,MAAM,SAAS;AACpC,YAAM,QAAQ;AAEd,UAAI,CAAC,IAAI,IAAI,OAAO,GAAG;AACrB,cAAM,QAAQ,CAAC;AACf,cAAM,YAAY,SAAS,OAAO,uBAAuB,YAAY,QAAQ;AAC7E,cAAM,OAAiB;AAAA,UACrB,MAAM;AAAA,UACN,MAAM,SAAS,SAAS;AAAA,UACxB,GAAI,YAAY,EAAE,kBAAkB,KAAK,IAAI,CAAC;AAAA,UAC9C,GAAI,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,CAAC,EAAE;AAAA,QAC5C;AACA,YAAI,IAAI,SAAS,IAAI;AACrB,eAAO,KAAK,IAAI;AAAA,MAClB;AAEA,UAAI,CAAC,QAAQ;AACX,iBAAS,IAAI,IAAI,OAAO,EAAG;AAAA,MAC7B;AAAA,IACF;AAAA,EACF;AAEA,QAAM,YAAY,CAAC,UAAsB;AACvC,UAAM,KAAK,CAAC,GAAG,MAAO,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,cAAc,EAAE,IAAI,IAAI,EAAE,SAAS,QAAQ,KAAK,CAAE;AACnG,eAAW,KAAK,OAAO;AACrB,UAAI,EAAE,SAAU,WAAU,EAAE,QAAQ;AAAA,IACtC;AAAA,EACF;AAEA,YAAU,IAAI;AACd,SAAO;AACT;AAQA,SAAS,YAAY,OAAmB,QAA4B;AAClE,SAAO,MAAM,IAAI,CAAC,MAAM;AACtB,QAAI,EAAE,SAAS,UAAU,EAAE,MAAM;AAC/B,aAAO,EAAE,GAAG,GAAG,MAAM,GAAG,MAAM,IAAI,EAAE,IAAI,GAAG;AAAA,IAC7C;AACA,QAAI,EAAE,UAAU;AACd,aAAO,EAAE,GAAG,GAAG,UAAU,YAAY,EAAE,UAAU,MAAM,EAAE;AAAA,IAC3D;AACA,WAAO;AAAA,EACT,CAAC;AACH;AAGO,SAAS,SAAS,MAAc,UAAoB,MAAoC;AAC7F,QAAM,OAAmB,CAAC;AAC1B,QAAM,qBAAqB,OAAO,MAAM,uBAAuB,WAAW,KAAK,qBAAqB;AACpG,QAAM,cAAc,IAAI,IAAI,MAAM,QAAQ,MAAM,OAAO,IAAI,KAAK,UAAU,CAAC,CAAC;AAC5E,QAAM,OAAO,MAAM,QAAQ,QAAQ,IAAI,SAAS,OAAO,CAAC,MAAM,OAAO,MAAM,YAAY,CAAC,IAAI,CAAC;AAC7F,aAAW,OAAO,MAAM;AAEtB,QAAI,IAAI,WAAW,GAAG,KAAK,CAAC,YAAY,IAAI,GAAG,EAAG;AAClD,UAAM,UAAUC,MAAK,KAAK,MAAM,GAAG;AACnC,QAAI,CAACC,IAAG,WAAW,OAAO,EAAG;AAC7B,UAAM,QAAkB,CAAC;AACzB,YAAQ,SAAS,EAAE,UAAU,GAAG,cAAc,YAAY,IAAI,GAAG,GAAG,QAAQ,CAAC,GAAG,QAAQ,MAAM,KAAK,GAAG,EAAE,CAAC;AACzG,UAAM,SAAS;AACf,UAAM,WAAW,YAAY,UAAU,OAAO,kBAAkB,GAAG,MAAM;AACzE,QAAI,SAAS,QAAQ;AACnB,WAAK,KAAK,EAAE,MAAM,GAAG,GAAG,KAAK,SAAS,MAAM,KAAK,MAAM,OAAO,SAAS,CAAC;AAAA,IAC1E;AAAA,EACF;AACA,SAAO;AACT;;;AE5FA,IAAM,uBAAuB,CAAC,YAAY,QAAQ,aAAa;AAE/D,IAAM,sBAAsB,qBAAqB,OAAO,CAAC,MAAM,EAAE,WAAW,GAAG,CAAC;AAEzE,IAAM,QAAQ;AAAA,EACnB,QAAQ,CAAC,QAAQ;AAAA,EACjB,MAAM,KAAc,QAA0B;AAC5C,UAAM,SAAS,IAAI;AACnB,QAAI,QAAQ,OAAO;AAEjB,aAAO,MAAM,YAAY,OAAO,KAAK,QAAQ;AAC3C,YAAI;AACF,gBAAM,MAAM,IAAI,IAAI,IAAI,OAAO,KAAK,kBAAkB;AACtD,gBAAM,KAAK,IAAI,aAAa,IAAI,IAAI;AACpC,gBAAM,WAAW,KAAK,mBAAmB,EAAE,IAAI,OAAO;AACtD,gBAAM,OAAO,SAAS,UAAU,CAAC,GAAG,oBAAoB,GAAG,EAAE,SAAS,CAAC,GAAG,mBAAmB,EAAE,CAAC;AAChG,cAAI,UAAU,KAAK,EAAE,gBAAgB,mCAAmC,iBAAiB,WAAW,CAAC;AACrG,cAAI,IAAI,KAAK,UAAU,EAAE,KAAK,CAAC,CAAC;AAAA,QAClC,QAAQ;AACN,cAAI,UAAU,KAAK,EAAE,gBAAgB,mCAAmC,iBAAiB,WAAW,CAAC;AACrG,cAAI,IAAI,KAAK,UAAU,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;AAAA,QACtC;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AACF;;;AC7BA,SAAS,YAAAC,iBAAgB;AAWzB,IAAM,iBAAiB;AACvB,IAAM,oBAAoB;AAE1B,SAAS,OAAO,MAAgB,KAA8B;AAC5D,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,IAAAA,UAAS,OAAO,MAAM,EAAE,KAAK,SAAS,eAAe,GAAG,CAAC,KAAK,WAAW;AACvE,UAAI,IAAK,QAAO,QAAQ,EAAE;AAC1B,cAAQ,MAAM;AAAA,IAChB,CAAC;AAAA,EACH,CAAC;AACH;AAEA,eAAsB,cAAc,MAAuC;AACzE,QAAM,MAAM,MAAM,OAAO,CAAC,YAAY,QAAQ,aAAa,GAAG,IAAI;AAClE,MAAI,CAAC,IAAK,QAAO,CAAC;AAElB,QAAM,UAA0B,CAAC;AACjC,QAAM,QAAQ,IAAI,MAAM,IAAI;AAC5B,MAAI,UAAiC,CAAC;AAEtC,aAAW,QAAQ,OAAO;AACxB,UAAM,IAAI,KAAK,MAAM,0CAA0C;AAC/D,QAAI,CAAC,EAAG;AACR,UAAM,CAAC,EAAE,KAAK,GAAG,IAAI;AACrB,QAAI,QAAQ,YAAY;AACtB,UAAI,QAAQ,QAAQ,QAAQ,KAAK,SAAS,iBAAiB,GAAG;AAC5D,gBAAQ,KAAK;AAAA,UACX,MAAM,QAAQ;AAAA,UACd,MAAM,QAAQ,KAAK,MAAM,iBAAiB,EAAE,IAAI,KAAK;AAAA,UACrD,QAAQ,QAAQ,UAAU;AAAA,UAC1B,MAAM,QAAQ,QAAQ;AAAA,UACtB,OAAO;AAAA,QACT,CAAC;AAAA,MACH;AACA,gBAAU,EAAE,MAAM,KAAK,MAAM,IAAI,QAAQ,GAAG;AAAA,IAC9C,WAAW,QAAQ,QAAQ;AACzB,cAAQ,OAAO;AAAA,IACjB,WAAW,QAAQ,UAAU;AAC3B,cAAQ,SAAS,IAAI,QAAQ,kBAAkB,EAAE;AAAA,IACnD;AAAA,EACF;AAGA,MAAI,QAAQ,QAAQ,QAAQ,KAAK,SAAS,iBAAiB,GAAG;AAC5D,YAAQ,KAAK;AAAA,MACX,MAAM,QAAQ;AAAA,MACd,MAAM,QAAQ,KAAK,MAAM,iBAAiB,EAAE,IAAI,KAAK;AAAA,MACrD,QAAQ,QAAQ,UAAU;AAAA,MAC1B,MAAM,QAAQ,QAAQ;AAAA,MACtB,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AAGA,QAAM,QAAQ;AAAA,IACZ,QAAQ,IAAI,OAAO,UAAU;AAC3B,UAAI;AACF,cAAM,YAAY,MAAM,OAAO,CAAC,UAAU,aAAa,GAAG,MAAM,IAAI;AACpE,cAAM,QAAQ,UAAU,KAAK,EAAE,SAAS;AAAA,MAC1C,QAAQ;AACN,cAAM,QAAQ;AAAA,MAChB;AAAA,IACF,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAEO,IAAMC,SAAQ;AAAA,EACnB,QAAQ,CAAC,QAAQ;AAAA,EACjB,MAAM,KAAc,QAA0B;AAC5C,UAAM,SAAS,IAAI;AACnB,QAAI,CAAC,QAAQ,MAAO;AAEpB,WAAO,MAAM,gBAAgB,OAAO,MAAM,QAAQ;AAChD,UAAI;AACF,cAAM,UAAU,MAAM,cAAc,OAAO,IAAI;AAC/C,YAAI,UAAU,KAAK,EAAE,gBAAgB,mCAAmC,iBAAiB,WAAW,CAAC;AACrG,YAAI,IAAI,KAAK,UAAU,OAAO,CAAC;AAAA,MACjC,QAAQ;AACN,YAAI,UAAU,KAAK,EAAE,gBAAgB,mCAAmC,iBAAiB,WAAW,CAAC;AACrG,YAAI,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC;AAAA,MAC5B;AAAA,IACF,CAAC;AAAA,EACH;AACF;;;AChGA,SAAS,WAAAC,gBAAe;;;ACMxB,eAAsB,SAAS,KAA4C;AACzE,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,QAAI,OAAO;AACX,QAAI,GAAG,QAAQ,CAAC,UAA2B;AAAE,cAAQ;AAAA,IAAO,CAAC;AAC7D,QAAI,GAAG,OAAO,MAAM,QAAQ,IAAI,CAAC;AACjC,QAAI,GAAG,SAAS,MAAM,QAAQ,EAAE,CAAC;AAAA,EACnC,CAAC;AACH;;;ADkBO,IAAM,mBAAN,cAA+BC,SAAQ;AAAA,EAC5C,OAAO,SAAS,CAAC,UAAU,QAAQ;AAAA,EAC3B,UAAU,oBAAI,IAA4B;AAAA,EAC1C;AAAA,EAER,YAAY,KAAc;AACxB,UAAM,KAAK,WAAW;AACtB,SAAK,IAAI,OAAO,MAAM,MAAM,KAAK,QAAQ,MAAM,CAAC;AAChD,SAAK,YAAY,IAAI;AAErB,SAAK,IAAI,OAAO,MAAM,cAAc,CAAC,MAAM,QAAQ;AACjD,UAAI,UAAU,KAAK,EAAE,gBAAgB,mCAAmC,iBAAiB,WAAW,CAAC;AACrG,UAAI,IAAI,KAAK,UAAU,EAAE,SAAS,MAAM,KAAK,KAAK,QAAQ,OAAO,CAAC,EAAE,CAAC,CAAC;AAAA,IACxE,CAAC;AAED,SAAK,IAAI,OAAO,MAAM,qBAAqB,OAAO,KAAK,QAAQ;AAC7D,YAAM,MAA+C,CAAC;AACtD,UAAI,IAAI,WAAW,OAAO;AACxB,mBAAW,KAAK,KAAK,QAAQ,OAAO,GAAG;AACrC,gBAAM,SAAS,KAAK,IAAI,OAAO,gBAAgB,EAAE,IAAI;AACrD,gBAAM,SAAS,EAAE,UAAU,CAAC;AAC5B,gBAAM,SAAkC,CAAC;AACzC,qBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AACjD,mBAAO,GAAG,IAAI,OAAO,SAAS,OAAO,GAAG,IAAK,MAAsB,WAAW;AAAA,UAChF;AACA,cAAI,OAAO,KAAK,MAAM,EAAE,OAAQ,KAAI,EAAE,IAAI,IAAI;AAAA,QAChD;AACA,YAAI,UAAU,KAAK,EAAE,gBAAgB,mCAAmC,iBAAiB,WAAW,CAAC;AACrG,YAAI,IAAI,KAAK,UAAU,GAAG,CAAC;AAC3B;AAAA,MACF;AACA,UAAI,IAAI,WAAW,QAAQ;AACzB,YAAI,IAAI,QAAQ,cAAc,MAAM,KAAK,IAAI,OAAO,WAAW;AAC7D,cAAI,UAAU,GAAG;AACjB,cAAI,IAAI,WAAW;AACnB;AAAA,QACF;AACA,YAAI;AACF,gBAAM,OAAO,KAAK,MAAM,MAAM,SAAS,GAAG,CAAC;AAC3C,gBAAM,SAAkD,CAAC;AACzD,qBAAW,QAAQ,OAAO,KAAK,IAAI,GAAG;AACpC,mBAAO,IAAI,IAAI,KAAK,IAAI,KAAK,CAAC;AAAA,UAChC;AACA,eAAK,IAAI,OAAO,iBAAiB,MAAM;AACvC,qBAAW,QAAQ,OAAO,KAAK,IAAI,GAAG;AACpC,gBAAI;AAAE,mBAAK,UAAU,UAAU,UAAU,EAAE,QAAQ,KAAK,CAAC;AAAA,YAAG,QAAQ;AAAA,YAAe;AAAA,UACrF;AACA,cAAI,UAAU,KAAK,EAAE,gBAAgB,kCAAkC,CAAC;AACxE,cAAI,IAAI,aAAa;AAAA,QACvB,SAAS,GAAG;AACV,kBAAQ,MAAM,uBAAuB,CAAC;AACtC,cAAI,UAAU,GAAG;AACjB,cAAI,IAAI,yBAAyB;AAAA,QACnC;AACA;AAAA,MACF;AACA,UAAI,UAAU,GAAG;AACjB,UAAI,IAAI,gCAAgC;AAAA,IAC1C,CAAC;AAAA,EACH;AAAA,EAEA,SAASC,WAA0B;AACjC,SAAK,QAAQ,IAAIA,UAAS,MAAMA,SAAQ;AACxC,SAAK,IAAI,OAAO,MAAM,MAAM,KAAK,QAAQ,OAAOA,UAAS,IAAI,CAAC;AAAA,EAChE;AAAA,EAEA,OAAO;AACL,WAAO,MAAM,KAAK,KAAK,QAAQ,OAAO,CAAC;AAAA,EACzC;AAAA,EAEA,IAAI,MAA0C;AAC5C,WAAO,KAAK,QAAQ,IAAI,IAAI;AAAA,EAC9B;AAAA,EAEA,UAAU,MAAuC;AAC/C,WAAO,KAAK,IAAI,OAAO,gBAAgB,IAAI;AAAA,EAC7C;AACF;;;AE5GA,SAAS,OAAO,YAAAC,iBAAmC;AACnD,OAAO,WAAW;AAsBlB,IAAM,aAAa;AAEnB,IAAM,aAAa,IAAI,YAAY,SAAS,EAAE,OAAO,KAAK,CAAC;AAM3D,SAAS,WAAW,KAAqB;AACvC,MAAI;AACF,WAAO,WAAW,OAAO,GAAG;AAAA,EAC9B,QAAQ;AACN,WAAO,MAAM,OAAO,KAAK,KAAK;AAAA,EAChC;AACF;AAGO,IAAM,aAAN,MAAiB;AAAA,EACd;AAAA,EACA,QAAQ,oBAAI,IAAkB;AAAA,EAC9B,UAAU,oBAAI,IAA6B;AAAA,EAC3C,eAAgC;AAAA,EAExC,YAAY,KAAa;AAAE,SAAK,MAAM;AAAA,EAAK;AAAA,EAE3C,UAA6B;AAC3B,QAAI,KAAK,aAAc,QAAO,QAAQ,QAAQ,KAAK,YAAY;AAC/D,WAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,MAAAA,UAAS,QAAQ,CAAC,UAAU,YAAY,GAAG,EAAE,KAAK,KAAK,KAAK,WAAW,KAAK,IAAI,SAAS,IAAK,GAAG,CAAC,KAAK,WAAW;AAChH,YAAI,KAAK;AAAE,kBAAQ,CAAC,CAAC;AAAG;AAAA,QAAQ;AAChC,cAAM,MAAgB,CAAC;AACvB,cAAM,OAAO,oBAAI,IAAY;AAC7B,mBAAW,QAAQ,OAAO,MAAM,OAAO,EAAE,MAAM,CAAC,GAAG;AACjD,gBAAM,UAAU,KAAK,KAAK;AAC1B,cAAI,CAAC,QAAS;AACd,gBAAM,UAAU,QAAQ,QAAQ,GAAG;AACnC,gBAAM,OAAO,WAAW,IAAI,QAAQ,MAAM,GAAG,OAAO,IAAI,SAAS,KAAK;AACtE,cAAI,CAAC,IAAK;AACV,gBAAM,OAAO,IAAI,MAAM,KAAK,EAAE,CAAC;AAC/B,cAAI,KAAK,IAAI,IAAI,EAAG;AACpB,eAAK,IAAI,IAAI;AACb,cAAI,KAAK,EAAE,MAAM,aAAa,WAAW,IAAI,QAAQ,MAAM,UAAU,CAAC,EAAE,KAAK,IAAI,GAAG,CAAC;AAAA,QACvF;AACA,aAAK,eAAe;AACpB,gBAAQ,GAAG;AAAA,MACb,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA,EAEA,UAAU,IAAyC;AACjD,SAAK,QAAQ,IAAI,EAAE;AAEnB,eAAW,KAAK,KAAK,MAAM,OAAO,GAAG;AACnC,iBAAW,QAAQ,EAAE,OAAQ,IAAG,EAAE,MAAM,OAAO,QAAQ,EAAE,QAAQ,KAAK,CAAC;AACvE,SAAG,EAAE,MAAM,SAAS,QAAQ,EAAE,QAAQ,OAAO,EAAE,OAAO,MAAM,EAAE,MAAM,WAAW,EAAE,UAAU,CAAC;AAAA,IAC9F;AACA,WAAO,MAAM,KAAK,QAAQ,OAAO,EAAE;AAAA,EACrC;AAAA,EAEQ,KAAK,IAAe;AAAE,eAAW,MAAM,KAAK,QAAS,IAAG,EAAE;AAAA,EAAG;AAAA,EAErE,OAAmB;AACjB,WAAO,MAAM,KAAK,KAAK,MAAM,OAAO,GAAG,CAAC,OAAO,EAAE,QAAQ,EAAE,QAAQ,OAAO,EAAE,OAAO,MAAM,EAAE,MAAM,WAAW,EAAE,UAAU,EAAE;AAAA,EAC5H;AAAA;AAAA,EAGA,MAAM,QAAgB;AACpB,SAAK,QAAQ,MAAM;AACnB,UAAM,OAAa,EAAE,QAAQ,OAAO,MAAM,OAAO,WAAW,MAAM,MAAM,WAAW,KAAK,IAAI,GAAG,QAAQ,CAAC,GAAG,SAAS,OAAO,MAAM,CAAC,EAAE;AACpI,SAAK,MAAM,IAAI,QAAQ,IAAI;AAC3B,SAAK,KAAK,EAAE,MAAM,SAAS,OAAO,CAAC;AACnC,SAAK,KAAK,EAAE,MAAM,SAAS,QAAQ,OAAO,WAAW,MAAM,MAAM,WAAW,KAAK,UAAU,CAAC;AAC5F,UAAM,QAAQ,MAAM,QAAQ,CAAC,MAAM,GAAG;AAAA,MACpC,KAAK,KAAK;AAAA,MACV,OAAO;AAAA,MACP,KAAK;AAAA,QACH,GAAG,QAAQ;AAAA,QACX,aAAa;AAAA;AAAA;AAAA,QAEb,YAAY,GAAG,QAAQ,IAAI,cAAc,EAAE,wBAAwB,KAAK;AAAA,QACxE,IAAI;AAAA,MACN;AAAA,IACF,CAAC;AACD,SAAK,QAAQ;AAEb,UAAM,UAAU,MAAM,KAAK,MAAM,IAAI,MAAM,MAAM;AACjD,UAAM,OAAO,CAAC,MAAc;AAC1B,UAAI,QAAQ,EAAG;AACf,WAAK,UAAU,OAAO,OAAO,CAAC,KAAK,SAAS,CAAC,CAAC;AAC9C,UAAI;AACJ,cAAQ,MAAM,KAAK,QAAQ,QAAQ,EAAI,MAAM,GAAG;AAC9C,cAAM,OAAO,KAAK,QAAQ,SAAS,GAAG,MAAM,CAAC;AAC7C,aAAK,UAAU,KAAK,QAAQ,SAAS,MAAM,CAAC;AAC5C,aAAK,SAAS,MAAM,WAAW,IAAI,CAAC;AAAA,MACtC;AAAA,IAEF;AACA,UAAM,QAAQ,GAAG,QAAQ,IAAI;AAC7B,UAAM,QAAQ,GAAG,QAAQ,IAAI;AAC7B,UAAM,GAAG,SAAS,CAAC,QAAQ;AAAE,WAAK,SAAS,MAAM,6BAA6B,IAAI,OAAO;AAAA,CAAI;AAAA,IAAG,CAAC;AACjG,UAAM,GAAG,QAAQ,CAAC,MAAM,WAAW;AACjC,UAAI,KAAK,QAAQ,SAAS,KAAK,CAAC,QAAQ,GAAG;AAAE,aAAK,SAAS,MAAM,WAAW,KAAK,OAAO,IAAI,IAAI;AAAA,MAAG;AACnG,WAAK,UAAU,OAAO,MAAM,CAAC;AAC7B,WAAK,QAAQ;AACb,WAAK,QAAQ;AACb,WAAK,OAAO,QAAQ;AACpB,WAAK,SAAS,UAAU;AACxB,UAAI,QAAQ,EAAG;AACf,WAAK,KAAK,EAAE,MAAM,SAAS,QAAQ,OAAO,UAAU,MAAM,KAAK,MAAM,WAAW,KAAK,WAAW,QAAQ,KAAK,OAAO,CAAC;AAAA,IACvH,CAAC;AAAA,EACH;AAAA,EAEQ,SAAS,MAAY,MAAc;AACzC,SAAK,OAAO,KAAK,IAAI;AACrB,QAAI,KAAK,OAAO,SAAS,WAAY,MAAK,OAAO,MAAM;AACvD,SAAK,KAAK,EAAE,MAAM,OAAO,QAAQ,KAAK,QAAQ,MAAM,KAAK,CAAC;AAAA,EAC5D;AAAA;AAAA,EAGA,KAAK,QAAiB;AACpB,QAAI,WAAW,QAAW;AAAE,iBAAW,KAAK,KAAK,MAAM,OAAO,EAAG,MAAK,QAAQ,EAAE,MAAM;AAAA,IAAG,MACpF,MAAK,QAAQ,MAAM;AAAA,EAC1B;AAAA,EAEA,QAAQ,QAAgB;AACtB,QAAI,KAAK,MAAM,IAAI,MAAM,EAAG,MAAK,MAAM,MAAM;AAAA,EAC/C;AAAA;AAAA,EAGA,MAAM,QAAgB;AACpB,UAAM,OAAO,KAAK,MAAM,IAAI,MAAM;AAClC,QAAI,CAAC,KAAM;AACX,SAAK,SAAS,CAAC;AACf,SAAK,UAAU,OAAO,MAAM,CAAC;AAC7B,SAAK,KAAK,EAAE,MAAM,SAAS,OAAO,CAAC;AAAA,EACrC;AAAA,EAEQ,QAAQ,QAAgB;AAC9B,UAAM,OAAO,KAAK,MAAM,IAAI,MAAM;AAClC,UAAM,QAAQ,MAAM;AACpB,QAAI,OAAO,KAAK;AACd,UAAI;AACF,YAAI,QAAQ,aAAa,QAAS,OAAM,YAAY,CAAC,QAAQ,OAAO,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC;AAAA,YACtF,OAAM,KAAK,SAAS;AAAA,MAC3B,QAAQ;AAAA,MAAY;AAAA,IACtB;AACA,QAAI,MAAM;AAAE,WAAK,QAAQ;AAAA,IAAM;AAAA,EACjC;AACF;;;AC9HO,SAAS,aAAa,KAGyB;AACpD,QAAM,EAAE,UAAAC,WAAU,MAAM,IAAI;AAE5B,SAAO;AAAA,IACL,QAAQ,CAAC,UAAU,aAAa,QAAQ;AAAA,IACxC,MAAkB,KAAc;AAC9B,YAAM,YAA+B,CAAC;AACtC,UAAI,OAAO,MAAM,MAAM;AACrB,mBAAW,MAAM,UAAU,OAAO,CAAC,GAAG;AACpC,cAAI;AAAE,eAAG;AAAA,UAAG,SAAS,GAAG;AACtB,oBAAQ,MAAM,uBAAuBA,UAAS,IAAI,mBAAmB,CAAC;AAAA,UACxE;AAAA,QACF;AAAA,MACF,CAAC;AAED,UAAI,UAAU,SAASA,SAAQ;AAG/B,YAAM,cAAc,CAAC,YAA0B,OAAO,KAA2B,QAA6B;AAC5G,YAAI,IAAI,YAAa;AACrB,YAAI;AACF,gBAAM,OAAO,MAAM,QAAQ,KAAK,GAAG;AACnC,cAAI,SAAS,UAAa,CAAC,IAAI,cAAe,MAAK,KAAK,IAAI;AAAA,QAC9D,SAAS,GAAG;AACV,kBAAQ,MAAM,uBAAuBA,UAAS,IAAI,iBAAiB,CAAC;AACpE,cAAI,CAAC,IAAI,YAAa,MAAK,KAAK,EAAE,OAAO,WAAW,GAAG,GAAG;AAAA,QAC5D;AAAA,MACF;AAEA,YAAM,OAAsB;AAAA,QAC1B,MAAMA,UAAS;AAAA,QACf,SAAyE;AACvE,gBAAM,SAASA,UAAS,UAAU,CAAC;AACnC,gBAAM,SAAS,IAAI,OAAO,gBAAgBA,UAAS,IAAI,KAAK,CAAC;AAC7D,gBAAM,WAAW,OAAO;AAAA,YACtB,OAAO,QAAQ,MAAM,EAAE,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM,CAAC,KAAK,MAAM,OAAO,CAAC;AAAA,UACnE;AACA,iBAAO,EAAE,GAAG,UAAU,GAAG,OAAO;AAAA,QAClC;AAAA,QACA,MAAMC,QAAc,SAA6B;AAC/C,cAAI,OAAO,MAAMA,QAAM,YAAY,OAAO,CAAC;AAAA,QAC7C;AAAA,QACA,aAAaA,QAAc,SAA6B;AACtD,gBAAM,QAAQ,MAAM,IAAI,OAAO;AAC/B,cAAI,OAAO,MAAMA,QAAM,CAAC,KAAK,QAAQ;AACnC,gBAAI,CAAC,QAAQ,KAAK,KAAK,MAAM,CAAC,EAAG;AACjC,iBAAK,YAAY,OAAO,EAAE,KAAK,GAAG;AAAA,UACpC,CAAC;AAAA,QACH;AAAA,QACA,IAAIA,QAAc,SAA2B;AAC3C,cAAI,OAAO,IAAIA,QAAM,OAAO;AAAA,QAC9B;AAAA,QACA,OAAO,QAAgB,KAAmB;AACxC,cAAI,OAAO,OAAO,QAAQ,GAAG;AAAA,QAC/B;AAAA,QACA,UAAU,OAAe,MAAsB;AAC7C,cAAI,QAAQ,UAAU,UAAUD,UAAS,IAAI,IAAI,KAAK,IAAI,QAAQ,EAAE;AAAA,QACtE;AAAA,QACA,UAAU,IAAsB;AAC9B,oBAAU,KAAK,EAAE;AAAA,QACnB;AAAA,MACF;AAEA,YAAM,IAAI;AAAA,IACZ;AAAA,EACF;AACF;;;ACtGO,SAAS,cAAc,KAG3B;AACD,MAAI,cAAc;AAClB,QAAM,QAAQ,aAAa;AAAA,IACzB,UAAU,IAAI;AAAA,IACd,MAAM,MAAM;AAAE,UAAI,MAAM,MAAM,WAAW;AAAA,IAAG;AAAA,EAC9C,CAAC;AAED,SAAO;AAAA,IACL,QAAQ,MAAM;AAAA,IACd,UAAU,IAAI;AAAA;AAAA,IACd,MAAM,KAAc,QAA2B;AAC7C,oBAAc,QAAQ,QAAQ;AAC9B,YAAM,MAAM,KAAK,MAAM;AAAA,IACzB;AAAA,EACF;AACF;;;AC1BO,IAAM,WAA2B;AAAA,EACtC,MAAM;AAAA,EACN,OAAO;AAAA,EACP,MAAM;AAAA,EACN,aAAa;AAAA,EACb,OAAO;AACT;;;ACOO,IAAME,SAAQ,cAAc;AAAA,EACjC;AAAA,EACA,MAAM,KAAK,MAAM;AACf,UAAM,SAAS,IAAI,WAAW,IAAI;AAClC,QAAI,UAAU,MAAM,OAAO,KAAK,CAAC;AAEjC,QAAI,MAAM,mBAAmB,YAAY;AACvC,UAAI;AACF,eAAO,MAAM,OAAO,QAAQ;AAAA,MAC9B,QAAQ;AACN,eAAO,CAAC;AAAA,MACV;AAAA,IACF,CAAC;AAED,QAAI,MAAM,iBAAiB,YAAY,OAAO,KAAK,CAAC;AAEpD,QAAI,IAAI,gBAAgB,CAAC,QAAQ;AAC/B,YAAM,QAAQ,OAAO,UAAU,CAAC,OAAO;AAErC,YAAI;AAAE,cAAI,UAAU,GAAG,MAAM,EAAE;AAAA,QAAG,QAAQ;AAAA,QAAmB;AAC7D,YAAI,MAAM,SAAS,KAAK,UAAU,EAAE,CAAC;AAAA;AAAA,CAAM;AAAA,MAC7C,CAAC;AACD,aAAO;AAAA,IACT,CAAC;AAGD,UAAM,eAAe,OAAO,KAA2B,KAA0B,QAAgD;AAC/H,YAAM,OAAO,MAAM,SAAS,GAAG;AAC/B,UAAI;AACJ,UAAI;AAAE,iBAAS,KAAK,MAAM,QAAQ,IAAI,EAAE;AAAA,MAAQ,QAAQ;AAAA,MAAe;AACvE,UAAI,QAAQ,SAAS;AACnB,YAAI,OAAQ,QAAO,MAAM,MAAM;AAC/B,eAAO,EAAE,IAAI,KAAK;AAAA,MACpB;AACA,UAAI,QAAQ,QAAQ;AAClB,YAAI,CAAC,QAAQ;AACX,cAAI,UAAU,KAAK,EAAE,gBAAgB,kCAAkC,CAAC;AACxE,cAAI,IAAI,uBAAuB;AAC/B,iBAAO;AAAA,QACT;AACA,cAAM,UAAU,MAAM,OAAO,QAAQ;AACrC,YAAI,CAAC,QAAQ,KAAK,CAAC,MAAM,EAAE,SAAS,MAAM,GAAG;AAC3C,cAAI,UAAU,KAAK,EAAE,gBAAgB,kCAAkC,CAAC;AACxE,cAAI,IAAI,4BAA4B;AACpC,iBAAO;AAAA,QACT;AACA,eAAO,MAAM,MAAM;AAAA,MACrB,OAAO;AACL,eAAO,KAAK,UAAU,MAAS;AAAA,MACjC;AACA,aAAO,OAAO,KAAK;AAAA,IACrB;AAEA,UAAM,cAAc,CAAC,SAAiD;AACpE,UAAI,aAAa,WAAW,IAAI,KAAK,CAAC,KAAK,QAAQ,aAAa,KAAK,KAAK,IAAI,EAAyB;AAAA,IACzG;AACA,gBAAY,OAAO;AACnB,gBAAY,MAAM;AAClB,gBAAY,SAAS;AACrB,gBAAY,OAAO;AAAA,EACrB;AACF,CAAC;;;ACxED,OAAOC,WAAU;AACjB,OAAOC,SAAQ;;;ACNf,OAAOC,WAAU;AAKjB,IAAM,YAAY,CAAC,SAAS,MAAM;AAClC,IAAM,YAAY,CAAC,QAAQ,QAAQ,QAAQ,QAAQ,SAAS,QAAQ,OAAO;AAC3E,IAAM,aAAa,CAAC,QAAQ,SAAS,QAAQ,QAAQ,MAAM;AAC3D,IAAM,aAAa,CAAC,QAAQ,QAAQ,SAAS,QAAQ,MAAM;AAC3D,IAAM,YAAY,CAAC,OAAO,QAAQ,QAAQ,QAAQ,QAAQ,OAAO,QAAQ,QAAQ,QAAQ,SAAS,QAAQ,QAAQ,QAAQ,SAAS,OAAO,KAAK;AAC/I,IAAM,YAAY,CAAC,SAAS,UAAU,QAAQ,MAAM;AACpD,IAAM,WAAW;AAEV,SAAS,WAAW,KAAa,KAA+B;AACrE,MAAI,IAAI,QAAQ,aAAa,MAAM,EAAG,QAAO;AAC7C,MAAI,WAAW,SAAS,GAAG,EAAG,QAAO;AACrC,MAAI,WAAW,SAAS,GAAG,EAAG,QAAO;AACrC,MAAI,QAAQ,OAAQ,QAAO;AAC3B,MAAI,QAAQ,MAAO,QAAO;AAC1B,MAAI,UAAU,SAAS,GAAG,EAAG,QAAO;AACpC,MAAI,UAAU,SAAS,GAAG,EAAG,QAAO;AACpC,MAAI,UAAU,SAAS,GAAG,EAAG,QAAO;AACpC,MAAI,UAAU,SAAS,GAAG,GAAG;AAC3B,QAAI,SAAS,KAAK,GAAG,MAAM,QAAQ,UAAU,QAAQ,SAAU,QAAO;AACtE,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAKO,SAAS,WAAW,MAAc,SAAS,IAAgB;AAChE,QAAM,MAAkB,CAAC;AACzB,QAAM,OAAoB,CAAC,QAAO,aAAY,QAAO,SAAQ,MAAK,SAAQ,SAAQ,OAAM,MAAM;AAC9F,aAAW,KAAK,KAAM,KAAI,CAAC,IAAI,CAAC;AAChC,QAAM,OAAO,oBAAI,IAAI,CAAC,gBAAgB,QAAQ,QAAQ,SAAS,YAAY,SAAS,QAAQ,CAAC;AAC7F,QAAM,WAAW,SAASC,MAAK,KAAK,MAAM,MAAM,IAAI;AACpD,UAAQ,UAAU,EAAE,MAAM,MAAM,QAAQ,CAAC,KAAK,QAAQ;AACpD,UAAM,MAAMA,MAAK,QAAQ,GAAG,EAAE,YAAY;AAC1C,UAAM,IAAI,WAAW,KAAK,GAAG;AAC7B,QAAI,EAAG,KAAI,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,MAAMA,MAAK,SAAS,GAAG,GAAG,KAAK,MAAM,EAAE,CAAC;AAAA,EAC1E,EAAC,CAAC;AACF,SAAO;AACT;;;ACzCO,IAAMC,YAA2B;AAAA,EACtC,MAAM;AAAA,EACN,OAAO;AAAA,EACP,MAAM;AAAA,EACN,aAAa;AAAA,EACb,OAAO;AACT;;;AFGA,IAAM,aAA0B,CAAC,QAAQ,aAAa,QAAQ,SAAS,MAAM,SAAS,SAAS,OAAO,MAAM;AAE5G,SAAS,YAAwB;AAC/B,QAAM,MAAM,CAAC;AACb,aAAW,KAAK,WAAY,KAAI,CAAC,IAAI,CAAC;AACtC,SAAO;AACT;AAEO,IAAMC,SAAQ,cAAc;AAAA,EACjC,UAAAC;AAAA,EACA,MAAM,KAAK,MAAM;AACf,QAAI,MAAM,oBAAoB,YAAY;AACxC,YAAM,aAAaC,MAAK,KAAK,MAAM,SAAS,QAAQ;AACpD,aAAOC,IAAG,WAAW,UAAU,IAAI,WAAW,UAAU,IAAI,UAAU;AAAA,IACxE,CAAC;AAGD,QAAI,MAAM,mBAAmB,OAAO,KAAK,QAAQ;AAC/C,YAAM,MAAM,IAAI,IAAI,IAAI,OAAO,KAAK,kBAAkB,EAAE,aAAa,IAAI,MAAM,KAAK;AACpF,UAAI,CAAC,OAAO,IAAI,SAAS,IAAI,KAAK,IAAI,SAAS,IAAI,KAAKD,MAAK,WAAW,GAAG,GAAG;AAC5E,YAAI,UAAU,GAAG;AACjB,YAAI,IAAI,UAAU;AAClB;AAAA,MACF;AACA,YAAM,aAAaA,MAAK,KAAK,MAAM,SAAS,QAAQ;AACpD,YAAM,WAAWA,MAAK,KAAK,YAAY,GAAG;AAC1C,UAAI,CAAC,SAAS,WAAW,aAAaA,MAAK,GAAG,GAAG;AAC/C,YAAI,UAAU,GAAG;AACjB,YAAI,IAAI,UAAU;AAClB;AAAA,MACF;AACA,MAAAC,IAAG,KAAK,UAAU,CAAC,QAAQ;AACzB,YAAI,KAAK;AAAE,cAAI,UAAU,GAAG;AAAG,iBAAO,IAAI,IAAI,WAAW;AAAA,QAAG;AAC5D,cAAM,KAAK,KAAKD,MAAK,QAAQ,QAAQ,EAAE,YAAY,CAAC,KAAK;AACzD,YAAI,UAAU,KAAK,EAAE,gBAAgB,IAAI,iBAAiB,WAAW,CAAC;AAEtE,cAAM,SAASC,IAAG,iBAAiB,QAAQ;AAC3C,eAAO,GAAG,SAAS,MAAM;AAAE,cAAI;AAAE,gBAAI,QAAQ;AAAA,UAAG,QAAQ;AAAA,UAAW;AAAA,QAAE,CAAC;AACtE,eAAO,KAAK,GAAG;AAAA,MACjB,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AACF,CAAC;;;AGnDM,IAAMC,YAA2B;AAAA,EACtC,MAAM;AAAA,EACN,OAAO;AAAA,EACP,MAAM;AAAA,EACN,aAAa;AAAA,EACb,OAAO;AACT;;;ACHO,IAAMC,SAAQ,cAAc;AAAA,EACjC,UAAAC;AAAA,EACA,QAAQ;AAAA,EAA4B;AACtC,CAAC;;;ACND,OAAOC,SAAQ;AACf,OAAOC,WAAU;AACjB,SAAS,YAAAC,iBAAgB;;;ACFlB,IAAMC,YAA2B;AAAA,EACtC,MAAM;AAAA,EACN,OAAO;AAAA,EACP,MAAM;AAAA,EACN,aAAa;AAAA,EACb,OAAO;AACT;;;ADgBA,IAAM,YAAY,oBAAI,IAAI,CAAC,gBAAgB,QAAQ,QAAQ,SAAS,SAAS,QAAQ,CAAC;AAEtF,SAAS,gBAAgB,MAAc,MAAgB,MAAwC;AAC7F,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,IAAAC,UAAS,MAAM,MAAM,MAAM,CAAC,KAAK,WAAW,QAAQ,MAAM,KAAK,MAAM,CAAC;AAAA,EACxE,CAAC;AACH;AAEA,SAAS,KAAK,MAAqB;AACjC,QAAM,QAAe;AAAA,IACnB,MAAMC,MAAK,SAAS,IAAI;AAAA,IACxB,OAAO;AAAA,IACP,MAAM;AAAA,IACN,WAAW;AAAA,IACX,OAAO,CAAC;AAAA,IACR,UAAU;AAAA,IACV,UAAU,EAAE,QAAQ,GAAG,UAAU,EAAE;AAAA,IACnC,SAASC,IAAG,WAAWD,MAAK,KAAK,MAAM,UAAU,CAAC;AAAA,IAClD,WAAW;AAAA,EACb;AACA,QAAM,SAAS,oBAAI,IAAoB;AAEvC,QAAM,OAAO,CAAC,QAAgB;AAC5B,YAAQ,KAAK,EAAE,MAAM,WAAW,OAAO,MAAM;AAAE,YAAM;AAAA,IAAQ,GAAG,QAAQ,CAAC,QAAQ;AAC/E,YAAM;AACN,UAAI;AAAE,cAAM,aAAaC,IAAG,SAAS,GAAG,EAAE;AAAA,MAAM,QAAQ;AAAA,MAAC;AACzD,YAAM,MAAMD,MAAK,QAAQ,GAAG,EAAE,YAAY,KAAK;AAC/C,aAAO,IAAI,MAAM,OAAO,IAAI,GAAG,KAAK,KAAK,CAAC;AAC1C,UAAI,QAAQ,SAAS,QAAQ,YAAa,OAAM;AAAA,IAClD,EAAC,CAAC;AAAA,EACJ;AACA,OAAK,IAAI;AAET,QAAM,aAAaA,MAAK,KAAK,MAAM,YAAY,SAAS;AACxD,MAAIC,IAAG,WAAW,UAAU,GAAG;AAC7B,eAAW,OAAOA,IAAG,YAAY,YAAY,EAAE,eAAe,KAAK,CAAC,GAAG;AACrE,UAAI,CAAC,IAAI,YAAY,KAAK,IAAI,KAAK,WAAW,GAAG,EAAG;AACpD,UAAI,IAAI,SAAS,WAAW;AAC1B,YAAI;AACF,gBAAM,SAAS,WAAWA,IAAG,YAAYD,MAAK,KAAK,YAAY,SAAS,GAAG,EAAE,eAAe,KAAK,CAAC,EAC/F,OAAO,OAAK,EAAE,YAAY,KAAK,CAAC,EAAE,KAAK,WAAW,GAAG,CAAC,EAAE;AAAA,QAC7D,QAAQ;AAAA,QAAe;AAAA,MACzB,MAAO,OAAM,SAAS;AAAA,IACxB;AAAA,EACF;AAEA,QAAM,QAAQ,MAAM,KAAK,OAAO,QAAQ,CAAC,EACtC,IAAI,CAAC,CAAC,KAAK,KAAK,OAAO,EAAE,KAAK,MAAM,EAAE,EACtC,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK,EAChC,MAAM,GAAG,EAAE;AACd,SAAO;AACT;AAEO,IAAME,SAAQ,cAAc;AAAA,EACjC,UAAAC;AAAA,EACA,MAAM,KAAK,MAAM;AACf,QAAI,MAAM,iBAAiB,YAAY;AACrC,YAAM,QAAQ,KAAK,IAAI;AACvB,UAAI;AACF,cAAM,MAAM,MAAM,cAAc,IAAI;AACpC,cAAM,YAAY,IAAI;AAAA,MACxB,QAAQ;AACN,cAAM,YAAY;AAAA,MACpB;AACA,UAAI;AACF,cAAM,YAAY,MAAM,gBAAgB,OAAO,CAAC,aAAa,gBAAgB,MAAM,GAAG,EAAE,KAAK,KAAK,CAAC;AACnG,cAAM,SAAS,UAAU,KAAK,KAAK;AAAA,MACrC,QAAQ;AAAA,MAAe;AACvB,UAAI;AACF,cAAM,YAAY,MAAM,gBAAgB,OAAO,CAAC,UAAU,aAAa,GAAG,EAAE,KAAK,KAAK,CAAC;AACvF,cAAM,QAAQ,UAAU,KAAK,IAAI,UAAU,KAAK,EAAE,MAAM,IAAI,EAAE,SAAS;AAAA,MACzE,QAAQ;AAAA,MAAe;AACvB,aAAO;AAAA,IACT,CAAC;AAAA,EACH;AACF,CAAC;;;AvB1ED,IAAMC,aAAYC,MAAK,QAAQC,eAAc,YAAY,GAAG,CAAC;AAE7D,IAAM,eAAe;AAErB,SAAS,YAAY;AACnB,QAAM,OAAO,QAAQ,KAAK,MAAM,CAAC;AACjC,QAAM,EAAE,OAAO,IAAI,cAAc;AAAA,IAC/B,SAAS;AAAA,MACP,KAAK,EAAE,MAAM,SAAS;AAAA,MACtB,MAAM,EAAE,MAAM,SAAS;AAAA,MACvB,MAAM,EAAE,MAAM,WAAW,SAAS,MAAM;AAAA,MACxC,MAAM,EAAE,MAAM,SAAS;AAAA,MACvB,SAAS,EAAE,MAAM,WAAW,SAAS,MAAM;AAAA,MAC3C,SAAS,EAAE,MAAM,SAAS;AAAA,IAC5B;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,IACR,kBAAkB;AAAA,EACpB,CAAC;AACD,SAAO;AAAA,IACL,KAAK,OAAO,OAAO,QAAQ,WAAW,OAAO,MAAM,QAAQ,IAAI;AAAA,IAC/D,MAAM,OAAO,OAAO,SAAS,WAAW,OAAO,OAAO,IAAI,IAAI;AAAA,IAC9D,cAAc,KAAK,KAAK,OAAK,MAAM,YAAY,EAAE,WAAW,SAAS,CAAC;AAAA,IACtE,MAAM,CAAC,CAAC,OAAO;AAAA,IACf,MAAM,OAAO,OAAO,SAAS,WAAW,OAAO,OAAO;AAAA,IACtD,SAAS,CAAC,CAAC,OAAO;AAAA,IAClB,SAAS,OAAO,OAAO,YAAY,WAAW,OAAO,UAAU;AAAA,EACjE;AACF;AAEA,eAAe,WAAW,GAA6B;AACrD,MAAI;AAAE,UAAM,OAAO,CAAC;AAAG,WAAO;AAAA,EAAM,QAAQ;AAAE,WAAO;AAAA,EAAO;AAC9D;AAEA,eAAe,aAAa,KAAc,KAAa,MAAc;AACnE,MAAI,CAAC,IAAK;AACV,MAAI,YAAY;AAChB,MAAI;AACF,UAAM,EAAE,SAAS,IAAI,MAAM,OAAO,aAAa;AAC/C,aAAS;AACT,gBAAY;AAAA,EACd,QAAQ;AAAA,EAER;AAEA,MAAI;AACF,UAAM,UAAU,MAAM,WAAW,GAAG,IAAI,MAAM,QAAQ,KAAK,EAAE,eAAe,KAAK,CAAC,IAAI,CAAC;AACvF,eAAW,OAAO,SAAS;AACzB,UAAI,CAAC,IAAI,YAAY,EAAG;AACxB,YAAM,aAAa,YAAY,CAAC,YAAY,YAAY,WAAW,IAAI,CAAC,YAAY,WAAW;AAC/F,iBAAW,QAAQ,YAAY;AAC7B,cAAM,IAAID,MAAK,KAAK,KAAK,IAAI,MAAM,IAAI;AACvC,YAAI,MAAM,WAAW,CAAC,GAAG;AACvB,cAAI;AACF,kBAAM,MAAM,MAAM,OAAO;AACzB,kBAAM,SAAS,IAAI,WAAW;AAC9B,gBAAI,QAAQ,OAAO;AACjB,kBAAI;AACF,sBAAM,IAAI,OAAO,QAAQ,EAAE,KAAK,CAAC;AAAA,cACnC,SAAS,GAAG;AACV,wBAAQ,MAAM,uCAAuC,IAAI,IAAI,KAAK,CAAC;AACnE;AAAA,cACF;AAEA,oBAAM,IAAI,IAAI,UAAU,IAAI,IAAI,IAAI;AACpC,kBAAI,KAAK,EAAE,SAAS,IAAI,MAAM;AAC5B,sBAAM,QAAiC,EAAE,UAAU,KAAK;AACxD,sBAAM,SAASA,MAAK,KAAK,KAAK,IAAI,MAAM,KAAK;AAC7C,oBAAI,MAAM,WAAWA,MAAK,KAAK,QAAQ,YAAY,CAAC,GAAG;AACrD,sBAAI,OAAO,OAAO,GAAG,oBAAoB,GAAG,IAAI,IAAI,KAAK,MAAM;AAC/D,sBAAI,CAAC,EAAE,UAAW,OAAM,YAAY,GAAG,oBAAoB,GAAG,IAAI,IAAI;AAAA,gBACxE;AACA,oBAAI,UAAU,SAAS,EAAE,GAAG,GAAG,GAAG,MAAM,CAAC;AAAA,cAC3C;AAAA,YACF;AAAA,UACF,SAAS,GAAG;AACV,oBAAQ,MAAM,sCAAsC,IAAI,IAAI,KAAK,CAAC;AAAA,UACpE;AACA;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF,QAAQ;AAAA,EAER;AACF;AAEA,eAAe,OAAO;AACpB,QAAM,OAAO,UAAU;AACvB,QAAM,OAAOA,MAAK,QAAQ,KAAK,GAAG;AAGlC,QAAM,WAAW,MAAM,aAAa,IAAI;AACxC,MAAI,YAAY,CAAC,KAAK,SAAS;AAC7B,UAAM,IAAI,oBAAoB,SAAS,IAAI,MAAM,KAAK,OAAO,IAAI,KAAK,IAAI,KAAK;AAC/E,QAAI,KAAK,KAAM,SAAQ,CAAC;AACxB,YAAQ,IAAI,+CAAsB,CAAC,sDAAmB;AAEtD,UAAM,IAAI,QAAc,CAAC,YAAY,QAAQ,OAAO,MAAM,IAAI,MAAM,QAAQ,CAAC,CAAC;AAC9E,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,YAAY,YAAY,KAAK,UAAU,WAAW;AACxD,MAAI,WAAW;AACb,YAAQ,IAAI,kEAAoC,UAAU,GAAG,EAAE;AAC/D,UAAM,aAAa,SAAS;AAAA,EAC9B;AAEA,QAAM,SAASA,MAAK,QAAQD,YAAW,KAAK;AAG5C,QAAM,kBAAkB,CAACG,QAAYA,QAAWA,QAAaA,MAAS;AAGtE,MAAI,sBAAsB,MAAM,gBAAgB,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,GAAG;AACvE,YAAQ,IAAI,mHAA6C;AAAA,EAC3D;AAGA,QAAM,YAAY,aAAa,CAAC,KAAK,eAAe,UAAU,OAAO,KAAK;AAG1E,QAAM,UAAUF,MAAK,KAAK,MAAM,OAAO;AACvC,QAAM,UAAUG,IAAG,WAAW,OAAO,IAAI,WAAW;AAEpD,QAAM,MAAM,MAAM,OAAO,IAAI;AAE7B,QAAM,MAAM,IAAI,QAAQ;AAGxB,MAAI,OAAO,eAAe;AAAA,IACxB;AAAA,IACA;AAAA,IACA,MAAM;AAAA,IACN,MAAM,KAAK;AAAA,IACX,QAAQ;AAAA,IACR,MAAM,KAAK;AAAA,IACX,SAAS,WAAW;AAAA,IACpB,UAAU,CAAC,SAAiB,YAAY,MAAM,IAAI;AAAA,EACpD,CAAC;AACD,MAAI,OAAO,eAAe,EAAE,KAAK,CAAC;AAClC,MAAI,OAAO,OAAW,EAAE,KAAK,CAAC;AAC9B,MAAI,OAAOD,QAAgB,EAAE,KAAK,CAAC;AACnC,MAAI,OAAO,gBAAgB;AAE3B,aAAWA,UAAS,iBAAiB;AACnC,QAAI;AACF,UAAI,OAAOA,QAAO,EAAE,KAAK,CAAC;AAAA,IAC5B,SAAS,GAAG;AACV,cAAQ,MAAM,uCAAuC,CAAC;AAAA,IACxD;AAAA,EACF;AAGA,MAAI,KAAK,SAAS;AAChB,UAAM,aAAa,KAAKF,MAAK,QAAQ,KAAK,OAAO,GAAG,IAAI;AAAA,EAC1D;AAGA,QAAM,WAAW,MAAM;AACrB,QAAI;AAAE,kBAAY,IAAI;AAAA,IAAG,QAAQ;AAAA,IAAC;AAClC,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,UAAQ,GAAG,WAAW,QAAQ;AAC9B,UAAQ,GAAG,UAAU,QAAQ;AAE7B,SAAO;AACT;AAEA,MAAM,KAAK,EAAE,MAAM,CAAC,MAAM;AACxB,UAAQ,MAAM,CAAC;AACf,UAAQ,KAAK,CAAC;AAChB,CAAC;","names":["path","fs","fileURLToPath","fs","path","fs","path","execFile","execFile","path","fs","err","fp","fs","Service","fs","path","fs","path","path","fs","execFile","apply","Service","Service","manifest","execFile","manifest","path","apply","path","fs","path","path","manifest","apply","manifest","path","fs","manifest","apply","manifest","fs","path","execFile","manifest","execFile","path","fs","apply","manifest","__dirname","path","fileURLToPath","apply","fs"]}
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../package.json","../src/server/detect.ts","../src/core/server.ts","../src/core/instance.ts","../src/core/open-url.ts","../src/core/reload.ts","../src/server/spec-scan.ts","../src/server/walk.ts","../src/core/tree.ts","../src/core/worktrees.ts","../src/core/manifest.ts","../src/core/read-body.ts","../src/server/just-runner.ts","../src/sdk/server.ts","../src/plugins/builtin.ts","../src/plugins/just/manifest.ts","../src/plugins/just/index.ts","../src/plugins/design/index.ts","../src/server/design-assets.ts","../src/plugins/design/manifest.ts","../src/plugins/view/manifest.ts","../src/plugins/view/index.ts","../src/plugins/stats/index.ts","../src/plugins/stats/manifest.ts"],"sourcesContent":["import path from 'node:path';\nimport fs from 'node:fs';\nimport { fileURLToPath } from 'node:url';\nimport { access, readdir } from 'node:fs/promises';\nimport { exec } from 'node:child_process';\nimport pkg from '../package.json' with { type: 'json' };\nimport { parseArgs as utilParseArgs } from 'node:util';\nimport { detect } from './server/detect.js';\nimport type { DetectResult } from './server/detect.js';\nimport { Context, Service } from 'cordis';\nimport { ServerService, PLUGIN_STATIC_PREFIX } from './core/server.js';\nimport { ReloadService } from './core/reload.js';\nimport { apply as treeApply } from './core/tree.js';\nimport { apply as worktreesApply } from './core/worktrees.js';\nimport { DashboardService } from './core/manifest.js';\nimport {\n findReusable,\n stopInstance,\n writeRecord,\n clearRecord,\n stripDeadPluginConfig,\n} from './core/instance.js';\nimport { openUrl } from './core/open-url.js';\nimport { apply as justApply } from './plugins/just/index.js';\nimport { apply as designApply } from './plugins/design/index.js';\nimport { apply as viewApply } from './plugins/view/index.js';\nimport { apply as statsApply } from './plugins/stats/index.js';\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\nconst DEFAULT_PORT = 4190;\n\nfunction parseArgs() {\n const args = process.argv.slice(2);\n const { values } = utilParseArgs({\n options: {\n dir: { type: 'string' },\n port: { type: 'string' },\n open: { type: 'boolean', default: false },\n page: { type: 'string' },\n restart: { type: 'boolean', default: false },\n plugins: { type: 'string' },\n },\n args,\n strict: false,\n allowPositionals: false,\n });\n return {\n dir: typeof values.dir === 'string' ? values.dir : process.cwd(),\n port: typeof values.port === 'string' ? Number(values.port) : DEFAULT_PORT,\n portExplicit: args.some(a => a === '--port' || a.startsWith('--port=')),\n open: !!values.open,\n page: typeof values.page === 'string' ? values.page : null,\n restart: !!values.restart,\n plugins: typeof values.plugins === 'string' ? values.plugins : null,\n };\n}\n\nasync function pathExists(p: string): Promise<boolean> {\n try { await access(p); return true; } catch { return false; }\n}\n\nasync function loadExternal(ctx: Context, dir: string, root: string) {\n if (!dir) return;\n let tsxLoaded = false;\n try {\n const { register } = await import('tsx/esm/api');\n register();\n tsxLoaded = true;\n } catch {\n // tsx not available\n }\n\n try {\n const entries = await pathExists(dir) ? await readdir(dir, { withFileTypes: true }) : [];\n for (const ent of entries) {\n if (!ent.isDirectory()) continue;\n const candidates = tsxLoaded ? ['index.ts', 'index.js', 'index.mjs'] : ['index.js', 'index.mjs'];\n for (const name of candidates) {\n const p = path.join(dir, ent.name, name);\n if (await pathExists(p)) {\n try {\n const mod = await import(p);\n const plugin = mod.default ?? mod;\n if (plugin?.apply) {\n try {\n await ctx.plugin(plugin, { root });\n } catch (e) {\n console.error(`[zdashboard] failed to apply plugin ${ent.name}:`, e);\n break;\n }\n // 自动接线约定:mode === 目录名时补 external 标记与 viewerUrl\n const m = ctx.dashboard.get(ent.name);\n if (m && m.mode === ent.name) {\n const patch: Record<string, unknown> = { external: true };\n const webDir = path.join(dir, ent.name, 'web');\n if (await pathExists(path.join(webDir, 'index.html'))) {\n ctx.server.static(`${PLUGIN_STATIC_PREFIX}${ent.name}/`, webDir);\n if (!m.viewerUrl) patch.viewerUrl = `${PLUGIN_STATIC_PREFIX}${ent.name}/`;\n }\n ctx.dashboard.register({ ...m, ...patch });\n }\n }\n } catch (e) {\n console.error(`[zdashboard] failed to load plugin ${ent.name}:`, e);\n }\n break;\n }\n }\n }\n } catch {\n // ignore\n }\n}\n\nasync function main() {\n const args = parseArgs();\n const root = path.resolve(args.dir);\n\n // --- instance reuse (before creating Context) ---\n // 版本比对:活实例版本落后当前 CLI → 自动停旧接管(零操作升级);--restart 仍为强制重开\n const found = await findReusable(root, pkg.version);\n const existing = found?.record ?? null;\n const autoUpgrade = found?.status === 'stale-version';\n if (existing && !args.restart && !autoUpgrade) {\n const u = `http://localhost:${existing.port}` + (args.page ? `#${args.page}` : '');\n if (args.open) openUrl(u);\n console.log(`[zdashboard] 已复用实例 ${u}(--restart 可强制重开)`);\n // 管道场景下 stdout 是异步写,显式等 flush 再 exit,避免日志被截断\n await new Promise<void>((resolve) => process.stdout.write('', () => resolve()));\n process.exit(0);\n }\n // 记录旧端口(--restart/自动升级时用于端口继承;stopInstance 会清 record)\n const oldRecord = existing && (args.restart || autoUpgrade) ? existing : null;\n if (oldRecord) {\n if (autoUpgrade) {\n console.log(\n `[zdashboard] 检测到旧版本实例 v${found!.liveVersion ?? 'unknown'},自动升级到 v${pkg.version}(停止旧实例 pid=${oldRecord.pid})`,\n );\n } else {\n console.log(`[zdashboard] --restart:停止旧实例 pid=${oldRecord.pid}`);\n }\n await stopInstance(oldRecord);\n }\n\n const appDir = path.resolve(__dirname, 'web');\n\n // built-in plugins:统一数组注册(未来迁移为 definePlugin 产出后无需改动此处)\n const BUILTIN_PLUGINS = [statsApply, justApply, designApply, viewApply];\n\n // 约定化扫描:启动一次性剥离 dashboard.json 里内置插件的死配置键(未声明 config 即清,external/未知保留)\n if (stripDeadPluginConfig(root, BUILTIN_PLUGINS.map((p) => p.manifest))) {\n console.log('[zdashboard] 已清理 dashboard.json 中内置插件的过时配置键');\n }\n\n // P2: restart 且有旧记录时,起始端口用 record.port(用户显式 --port 则尊重)\n const startPort = oldRecord && !args.portExplicit ? oldRecord.port : args.port;\n\n // P0: 数据目录检测(.zdev/ 存在则优先)\n const zdevDir = path.join(root, '.zdev');\n const dataDir = fs.existsSync(zdevDir) ? '.zdev/' : '';\n\n const det = await detect(root);\n\n const ctx = new Context();\n\n // core services\n ctx.plugin(ServerService, {\n root,\n appDir,\n port: startPort,\n open: args.open,\n detect: det,\n page: args.page,\n dataDir: dataDir || undefined,\n onListen: (port: number) => writeRecord(root, port),\n });\n ctx.plugin(ReloadService, { root });\n ctx.plugin(treeApply, { root });\n ctx.plugin(worktreesApply, { root });\n ctx.plugin(DashboardService);\n\n for (const apply of BUILTIN_PLUGINS) {\n try {\n ctx.plugin(apply, { root });\n } catch (e) {\n console.error('[zdashboard] builtin plugin failed:', e);\n }\n }\n\n // external plugins\n if (args.plugins) {\n await loadExternal(ctx, path.resolve(args.plugins), root);\n }\n\n // graceful shutdown: clear .zdev record on SIGTERM / SIGINT\n const shutdown = () => {\n try { clearRecord(root); } catch {}\n process.exit(0);\n };\n process.on('SIGTERM', shutdown);\n process.on('SIGINT', shutdown);\n\n return ctx;\n}\n\nawait main().catch((e) => {\n console.error(e);\n process.exit(1);\n});\n","{\n \"name\": \"zdashboard\",\n \"version\": \"2.10.0\",\n \"description\": \"ZCode skill dashboard platform — pluggable viewers for zdesign/zview/zreview/zgoal\",\n \"type\": \"module\",\n \"bin\": {\n \"zdashboard\": \"./dist/cli.js\"\n },\n \"files\": [\n \"dist\"\n ],\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"scripts\": {\n \"dev\": \"vite\",\n \"build\": \"tsup && vite build\",\n \"build:web\": \"vite build\",\n \"build:node\": \"tsup\",\n \"start\": \"node dist/cli.js\",\n \"test\": \"vitest run\",\n \"typecheck\": \"tsc --noEmit\",\n \"test:coverage\": \"vitest run --coverage\",\n \"preview\": \"vite preview\"\n },\n \"dependencies\": {\n \"@fontsource/vt323\": \"^5.3.0\",\n \"@phosphor-icons/react\": \"^2.1.10\",\n \"@radix-ui/react-dropdown-menu\": \"^2.1.24\",\n \"@radix-ui/react-scroll-area\": \"^1.2.0\",\n \"@radix-ui/react-separator\": \"^1.1.0\",\n \"@radix-ui/react-slot\": \"^1.1.0\",\n \"@radix-ui/react-tooltip\": \"^1.1.2\",\n \"@uidotdev/usehooks\": \"^2.4.0\",\n \"ansi-to-react\": \"^6.1.6\",\n \"class-variance-authority\": \"^0.7.0\",\n \"clsx\": \"^2.1.1\",\n \"cordis\": \"4.0.0-rc.8\",\n \"cosmokit\": \"^1.8.1\",\n \"date-fns\": \"^3.6.0\",\n \"filesize\": \"^11.0.0\",\n \"highlight.js\": \"^11.11.1\",\n \"iconv-lite\": \"0.7.3\",\n \"katex\": \"^0.16.11\",\n \"ky\": \"^1.7.0\",\n \"lodash-es\": \"^4.17.21\",\n \"lucide-react\": \"^0.460.0\",\n \"pixelarticons\": \"^2.4.1\",\n \"react\": \"^18.3.1\",\n \"react-dom\": \"^18.3.1\",\n \"react-error-boundary\": \"^5.0.0\",\n \"react-markdown\": \"^9.0.1\",\n \"rehype-autolink-headings\": \"^7.1.0\",\n \"rehype-highlight\": \"^7.0.1\",\n \"rehype-katex\": \"^7.0.1\",\n \"rehype-raw\": \"^7.0.0\",\n \"rehype-slug\": \"^6.0.0\",\n \"remark-frontmatter\": \"^5.0.0\",\n \"remark-gfm\": \"^4.0.0\",\n \"remark-math\": \"^6.0.0\",\n \"sonner\": \"^1.5.0\",\n \"tailwind-merge\": \"^2.5.4\",\n \"tsx\": \"^4.7.0\",\n \"use-debounce\": \"^10.0.0\",\n \"yaml\": \"^2.9.0\"\n },\n \"devDependencies\": {\n \"@tailwindcss/typography\": \"^0.5.20\",\n \"@testing-library/jest-dom\": \"^7.0.1\",\n \"@testing-library/react\": \"^16.3.2\",\n \"@types/lodash-es\": \"^4.17.12\",\n \"@types/node\": \"^22.9.0\",\n \"@types/react\": \"^18.3.12\",\n \"@types/react-dom\": \"^18.3.1\",\n \"@vitejs/plugin-react\": \"^4.7.0\",\n \"@vitest/coverage-v8\": \"1.6.0\",\n \"autoprefixer\": \"^10.4.20\",\n \"jsdom\": \"^30.0.1\",\n \"postcss\": \"^8.4.49\",\n \"tailwindcss\": \"^3.4.14\",\n \"tailwindcss-animate\": \"^1.0.7\",\n \"tsup\": \"^8.3.5\",\n \"typescript\": \"^5.6.3\",\n \"vite\": \"^5.4.10\",\n \"vitest\": \"^1.6.0\"\n },\n \"pnpm\": {\n \"onlyBuiltDependencies\": [\n \"esbuild\"\n ]\n }\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport { execFile } from 'node:child_process';\n\nexport interface DetectResult {\n hasOpenspec: boolean;\n hasDocs: boolean;\n hasJust: boolean;\n}\n\n/** --list 主探测超时(与迁移前一致) */\nconst JUST_PROBE_TIMEOUT_MS = 5000;\n/** --version 兜底探测超时(快失败:二进制存在性检查无需长等) */\nconst JUST_FALLBACK_TIMEOUT_MS = 3000;\n\nfunction justAvailable(cwd: string): Promise<boolean> {\n /** 探测一次:进程正常退出即视为可用 */\n const probe = (args: string[], timeout: number) => new Promise<boolean>((resolve) => {\n const child = execFile('just', args, { cwd, timeout }, (err) => resolve(!err));\n if (child.killed) resolve(false);\n });\n // 旧版以 --list --unsupported 判定;新版 just 移除该旗标会报错(hasJust 恒 false),\n // 回退 --version 探测二进制本身可用\n return probe(['--list', '--unsupported'], JUST_PROBE_TIMEOUT_MS)\n .then((ok) => (ok ? true : probe(['--version'], JUST_FALLBACK_TIMEOUT_MS)));\n}\n\nexport async function detect(root: string): Promise<DetectResult> {\n const hasOpenspec = fs.existsSync(path.join(root, 'openspec'));\n const hasDocs = fs.existsSync(path.join(root, 'docs'));\n const hasJust = await justAvailable(root);\n return { hasOpenspec, hasDocs, hasJust };\n}\n\n/** /__detect 的响应形状:与 DetectResult 同形(bugs 期兼容字段已随清理 change 摘除) */\nexport type DetectResponse = DetectResult;\n\n/** 现场探测(每次请求重新跑),供 /__detect 独立路由使用 */\nexport async function detectLiveShape(root: string): Promise<DetectResponse> {\n return detect(root);\n}\n","import http from 'node:http';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport crypto from 'node:crypto';\nimport { fileURLToPath } from 'node:url';\nimport pkg from '../../package.json' with { type: 'json' };\nimport type { Context } from 'cordis';\nimport type { DetectResult, DetectResponse } from '../server/detect.js';\nimport { detectLiveShape } from '../server/detect.js';\nimport type { PluginManifest, ConfigField } from '../core/manifest.js';\nimport { Service } from 'cordis';\nimport { clearRecord, readPluginsConfig, writePluginsConfig } from './instance.js';\nimport { openUrl } from './open-url.js';\nimport { readBody } from './read-body.js';\nimport { execFile } from 'node:child_process';\n\nconst VERSION = pkg.version;\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\nexport interface ServerOptions {\n root: string;\n appDir: string;\n port: number;\n open: boolean;\n page: string | null;\n detect: DetectResult;\n dataDir?: string;\n onListen?: (port: number) => void;\n}\n\ndeclare module 'cordis' {\n interface Context {\n server: ServerService;\n }\n}\n\n/** 扩展名 → Content-Type 表(SDK 插件路由等复用,勿在他处复制) */\nexport const MIME: Record<string, string> = {\n '.html': 'text/html; charset=utf-8', '.htm': 'text/html; charset=utf-8',\n '.css': 'text/css; charset=utf-8', '.js': 'application/javascript; charset=utf-8',\n '.mjs': 'application/javascript; charset=utf-8', '.json': 'application/json; charset=utf-8',\n '.svg': 'image/svg+xml', '.png': 'image/png', '.ico': 'image/x-icon',\n '.jpg': 'image/jpeg', '.jpeg': 'image/jpeg', '.gif': 'image/gif', '.webp': 'image/webp',\n '.avif': 'image/avif',\n '.md': 'text/markdown; charset=utf-8', '.txt': 'text/plain; charset=utf-8',\n '.sql': 'text/plain; charset=utf-8', '.csv': 'text/plain; charset=utf-8',\n '.tsv': 'text/plain; charset=utf-8', '.yaml': 'text/yaml; charset=utf-8',\n '.yml': 'text/yaml; charset=utf-8', '.xml': 'application/xml; charset=utf-8',\n '.py': 'text/plain; charset=utf-8', '.ts': 'text/plain; charset=utf-8',\n '.java': 'text/plain; charset=utf-8', '.go': 'text/plain; charset=utf-8',\n '.rs': 'text/plain; charset=utf-8', '.rb': 'text/plain; charset=utf-8',\n '.php': 'text/plain; charset=utf-8', '.c': 'text/plain; charset=utf-8',\n '.cpp': 'text/plain; charset=utf-8', '.h': 'text/plain; charset=utf-8',\n '.cs': 'text/plain; charset=utf-8', '.swift': 'text/plain; charset=utf-8',\n '.kt': 'text/plain; charset=utf-8', '.scala': 'text/plain; charset=utf-8',\n '.sh': 'text/plain; charset=utf-8', '.bash': 'text/plain; charset=utf-8',\n '.zsh': 'text/plain; charset=utf-8', '.fish': 'text/plain; charset=utf-8',\n '.env': 'text/plain; charset=utf-8', '.gitignore': 'text/plain; charset=utf-8',\n '.dockerfile': 'text/plain; charset=utf-8',\n '.mp4': 'video/mp4', '.webm': 'video/webm', '.mov': 'video/quicktime',\n '.m4a': 'audio/mp4', '.aac': 'audio/aac',\n '.woff': 'font/woff', '.woff2': 'font/woff2', '.ttf': 'font/woff',\n '.map': 'application/json; charset=utf-8',\n};\n\n// 静态 HTML 注入脚本:仅保留 _self 链接补丁(文件预览页内跳转留在当前窗口)。\n// 旧 EventSource('/__reload') 注入已随沙箱收紧移除——sandbox=allow-scripts 下 iframe\n// 为不透明源,/__reload 属跨域请求,只会制造 console error 且其处理器本已为空。\nconst INJECT = `<script>(function(){document.addEventListener('click',function(e){var t=e.target;if(t&&t.closest){var a=t.closest('a[target]');if(a&&a.target!=='_self'){a.target='_self';}}},true);})();</script>`;\n\nexport const PLUGIN_STATIC_PREFIX = '/__plugin/';\n\n/** json 响应助手:统一 Content-Type/缓存头与序列化,消灭 writeHead 样板 */\nexport function json(res: http.ServerResponse, data: unknown, status = 200): void {\n res.writeHead(status, { 'Content-Type': 'application/json; charset=utf-8', 'Cache-Control': 'no-cache' });\n res.end(JSON.stringify(data));\n}\n\n/** x-stop-token 鉴权助手:通过返回 true;未通过时已写 403 响应并返回 false */\nexport function guarded(req: http.IncomingMessage, res: http.ServerResponse, token: string): boolean {\n if (req.headers['x-stop-token'] !== token) {\n res.writeHead(403);\n res.end('forbidden');\n return false;\n }\n return true;\n}\n\nexport class ServerService extends Service {\n stopToken: string;\n private root: string;\n private appDir: string;\n private open: boolean;\n private page: string | null;\n private det: DetectResult;\n private dataDir?: string;\n private routes = new Map<string, (req: http.IncomingMessage, res: http.ServerResponse) => void>();\n private sses = new Map<string, (res: http.ServerResponse) => (() => void) | void>();\n private prefixStatic = new Map<string, string>();\n private server?: http.Server;\n private onListen?: (port: number) => void;\n\n constructor(ctx: Context, config: ServerOptions) {\n super(ctx, 'server');\n this.stopToken = crypto.randomBytes(12).toString('hex');\n this.root = config.root;\n this.appDir = config.appDir;\n this.open = config.open;\n this.page = config.page;\n this.det = config.detect;\n this.dataDir = config.dataDir;\n this.onListen = config.onListen;\n ctx.effect(() => () => this.dispose());\n\n this.refreshGitInfo();\n this.route('/__config', (_req, res) => {\n json(res, { stopToken: this.stopToken, version: VERSION, root: this.root, ...this.gitInfo });\n });\n\n // 独立探测接口(轻量,替代 HomeGrid 借道 /__files 全量树)\n this.route('/__detect', async (_req, res) => {\n const shape: DetectResponse = await detectLiveShape(this.root);\n json(res, shape);\n });\n\n // 应用级静态文件(index.html 引用但不在 /assets/ 下),避免落到项目目录 404\n this.route('/favicon.svg', (req, res) => {\n this.serveFile(path.join(this.appDir, 'favicon.svg'), req, res, false);\n });\n\n this.route('/__file-content', async (req, res) => {\n const url = new URL(req.url || '/', 'http://localhost');\n const rawPath = url.pathname.replace(/^\\/__file-content\\/?/, '');\n if (!rawPath || rawPath === '/') {\n res.writeHead(400);\n res.end('missing path');\n return;\n }\n const filePath = path.join(this.root, decodeURIComponent(rawPath));\n if (!filePath.startsWith(this.root + path.sep) && filePath !== this.root) {\n res.writeHead(403);\n res.end('Forbidden');\n return;\n }\n fs.stat(filePath, (err) => {\n if (err) { res.writeHead(404); return res.end('Not found'); }\n const ext = path.extname(filePath).toLowerCase();\n const ct = MIME[ext] ?? 'application/octet-stream';\n res.writeHead(200, { 'Content-Type': ct, 'Cache-Control': 'no-cache' });\n fs.createReadStream(filePath).pipe(res);\n });\n });\n\n this.route('/__stop', async (req, res) => {\n if (!guarded(req, res, this.stopToken)) return;\n json(res, { ok: true });\n this.stop();\n });\n\n this.start(config.port);\n }\n\n route(path: string, handler: (req: http.IncomingMessage, res: http.ServerResponse) => void) {\n this.routes.set(path, handler);\n this.ctx.effect(() => () => this.routes.delete(path));\n }\n\n sse(path: string, onConnect: (res: http.ServerResponse) => (() => void) | void) {\n this.sses.set(path, onConnect);\n this.ctx.effect(() => () => this.sses.delete(path));\n }\n\n static(prefix: string, dir: string) {\n this.prefixStatic.set(prefix, dir);\n this.ctx.effect(() => () => this.prefixStatic.delete(prefix));\n }\n\n private pluginsConfig: Record<string, Record<string, unknown>> = {};\n\n getPluginConfig(mode: string): Record<string, unknown> {\n return this.pluginsConfig[mode] ?? {};\n }\n\n refreshPluginsConfig() {\n this.pluginsConfig = readPluginsConfig(this.root);\n }\n\n savePluginConfig(merged: Record<string, Record<string, unknown>>) {\n this.pluginsConfig = merged;\n writePluginsConfig(this.root, merged);\n }\n\n private serveFile(filePath: string, req: http.IncomingMessage, res: http.ServerResponse, injectHtml: boolean) {\n fs.stat(filePath, (err, stat) => {\n if (err) { res.writeHead(404); return res.end('Not found'); }\n const ext = path.extname(filePath).toLowerCase();\n const ct = MIME[ext] ?? 'application/octet-stream';\n\n // ---- HTTP Range support ----\n const rangeHeader = (req.headers['range'] as string | undefined);\n let range: { start: number; end: number } | null = null;\n if (rangeHeader) {\n const m = rangeHeader.match(/^bytes=(\\d+)-(\\d*)$/);\n if (m) {\n const start = Number(m[1]);\n const end = m[2] !== '' ? Number(m[2]) : stat.size - 1;\n if (!Number.isNaN(start) && !Number.isNaN(end) && start <= end && start < stat.size) {\n range = { start, end: Math.min(end, stat.size - 1) };\n }\n // malformed range → fall through to 200 full response\n }\n // unparseable range header → fall through to 200 full response\n }\n\n if (range) {\n const { start, end } = range;\n const chunkSize = end - start + 1;\n res.writeHead(206, {\n 'Content-Type': ct,\n 'Content-Length': String(chunkSize),\n 'Content-Range': `bytes ${start}-${end}/${stat.size}`,\n 'Accept-Ranges': 'bytes',\n 'Cache-Control': 'no-cache',\n });\n // stat 成功后文件仍可能在 open 前被删/换(高频增删的工作区),流错误无人接会崩进程\n const stream = fs.createReadStream(filePath, { start, end });\n stream.on('error', () => { try { res.destroy(); } catch { /* 已断 */ } });\n stream.pipe(res);\n return;\n }\n\n // Full response\n fs.readFile(filePath, (err, data) => {\n if (err) { res.writeHead(404); return res.end('Not found'); }\n let body: string | Buffer = data;\n if (injectHtml && ext === '.html') {\n const s = data.toString('utf8');\n body = Buffer.from(s.indexOf('</body>') >= 0 ? s.replace('</body>', INJECT + '</body>') : s + INJECT);\n }\n res.writeHead(200, { 'Content-Type': ct, 'Accept-Ranges': 'bytes', 'Cache-Control': 'no-cache' });\n res.end(body);\n });\n });\n }\n\n private servePrefix(url: string, req: http.IncomingMessage, res: http.ServerResponse): boolean {\n for (const [prefix, dir] of this.prefixStatic) {\n if (url.indexOf(prefix) === 0) {\n let rel = this.safeDecode(url.slice(prefix.length));\n if (!rel || rel === '/' || !path.extname(rel)) rel = path.join(rel || '', 'index.html');\n const fp = path.join(dir, rel);\n if (fp.indexOf(dir + path.sep) !== 0) { res.writeHead(403); res.end('Forbidden'); return false; }\n this.serveFile(fp, req, res, true);\n return true;\n }\n }\n return false;\n }\n\n private safeDecode(raw: string): string {\n try { return decodeURIComponent(raw); } catch { return raw; }\n }\n\n private handler = (req: http.IncomingMessage, res: http.ServerResponse) => {\n try {\n const rawUrl = req.url || '/';\n const url = rawUrl.split('?')[0];\n\n const rh = this.routes.get(url);\n if (rh) { rh(req, res); return; }\n for (const [rp, rh2] of this.routes) {\n if (url.startsWith(rp + '/')) { rh2(req, res); return; }\n }\n const sh = this.sses.get(url);\n if (sh) {\n res.writeHead(200, { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', Connection: 'keep-alive' });\n res.write(': connected\\n\\n');\n const cleanup = sh(res);\n req.on('close', () => { cleanup?.(); });\n return;\n }\n\n if (this.servePrefix(url, req, res)) return;\n\n if (url === '/' || url.indexOf('/__app/') === 0 || url.indexOf('/assets/') === 0) {\n let fp = this.appDir;\n if (url !== '/') fp = path.join(this.appDir, this.safeDecode(url));\n if (url.indexOf('/__app/') === 0) fp = path.join(this.appDir, url.slice(7));\n if (fp !== this.appDir && fp.indexOf(this.appDir + path.sep) !== 0) { res.writeHead(403); return res.end('Forbidden'); }\n if (url === '/') fp = path.join(this.appDir, 'index.html');\n return this.serveFile(fp, req, res, false);\n }\n\n const fp = path.join(this.root, this.safeDecode(url));\n if (fp !== this.root && fp.indexOf(this.root + path.sep) !== 0) { res.writeHead(403); return res.end('Forbidden'); }\n return this.serveFile(fp, req, res, true);\n } catch (e) {\n try { res.writeHead(400); res.end('bad request'); } catch {}\n console.error('[zdashboard] handler error', e);\n }\n };\n\n start(port: number) {\n this.server = http.createServer(this.handler);\n // 浏览器复用空闲 keep-alive 连接时若已被服务端关闭,请求会石沉大海(点击无响应)。\n // 拉长 keep-alive 使其远大于浏览器侧空闲窗口\n this.server.keepAliveTimeout = 65_000;\n this.server.headersTimeout = 66_000;\n this.server.on('error', (err: NodeJS.ErrnoException) => {\n if (err.code === 'EADDRINUSE') {\n console.log(`[zdashboard] port ${port} busy, trying ${port + 1}`);\n this.start(port + 1);\n } else throw err;\n });\n this.server.listen(port, '127.0.0.1', () => {\n // port=0(测试/随机端口)时上报实际绑定端口\n const addr = this.server?.address();\n const bound = typeof addr === 'object' && addr ? addr.port : port;\n const u = `http://localhost:${bound}`;\n const target = this.page ? `${u}#${this.page}` : u;\n console.log(`[zdashboard] v${VERSION} dashboard -> ${u}`);\n console.log(`[zdashboard] project -> ${this.root}`);\n console.log(`[zdashboard] detect -> openspec:${this.det.hasOpenspec} docs:${this.det.hasDocs} just:${this.det.hasJust}`);\n if (this.dataDir) console.log(`[zdashboard] data -> ${this.dataDir}`);\n if (this.open) openUrl(target);\n this.onListen?.(bound);\n });\n }\n\n /** 项目 git 信息(分支/脏文件数),启动探测一次,文件变更时刷新 */\n private gitInfo: { branch?: string; dirty?: number } = {};\n\n refreshGitInfo() {\n const run = (args: string[]) => new Promise<string>((resolve) => {\n execFile('git', args, { cwd: this.root, timeout: 3000 }, (err, stdout) => resolve(err ? '' : stdout));\n });\n void (async () => {\n const [branch, status] = await Promise.all([\n run(['rev-parse', '--abbrev-ref', 'HEAD']),\n run(['status', '--porcelain']),\n ]);\n const b = branch.trim();\n this.gitInfo = b ? { branch: b, dirty: status ? status.split('\\n').filter(Boolean).length : 0 } : {};\n })();\n }\n\n stop() {\n if (this.server) { try { this.server.close(); } catch {} }\n try { clearRecord(this.root); } catch {}\n setTimeout(() => {\n try { this.ctx.root.fiber.dispose(); } catch {}\n process.exit(0);\n }, 50);\n }\n\n dispose() {\n if (this.server) { try { this.server.close(); } catch {} }\n try { clearRecord(this.root); } catch {}\n }\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport pkg from '../../package.json' with { type: 'json' };\n\nconst CURRENT_VERSION: string = pkg.version;\n\nexport interface InstanceRecord {\n pid: number;\n port: number;\n root: string;\n startedAt: string;\n /** 写入该记录的实例版本(信息用途;活实例版本以 /__config 实时值为准) */\n version?: string;\n plugins?: Record<string, Record<string, unknown>>;\n}\n\nexport const RECORD_FILE = '.zdev/dashboard.json';\nexport const VERIFY_TIMEOUT_MS = 1500;\nexport const STOP_POLL_MS = 2000;\nexport const STOP_POLL_INTERVAL_MS = 100;\nexport const STOP_FINAL_WAIT_MS = 100;\n\nfunction recordPath(root: string): string {\n return path.join(root, RECORD_FILE);\n}\n\nexport function readRecord(root: string): InstanceRecord | null {\n try {\n const fp = recordPath(root);\n const raw = fs.readFileSync(fp, 'utf-8');\n const rec = JSON.parse(raw) as Partial<InstanceRecord>;\n if (\n typeof rec.pid === 'number' &&\n typeof rec.port === 'number' &&\n typeof rec.root === 'string' &&\n typeof rec.startedAt === 'string'\n ) {\n return rec as InstanceRecord;\n }\n return null;\n } catch {\n return null;\n }\n}\n\nexport function writeRecord(root: string, port: number): void {\n const fp = recordPath(root);\n fs.mkdirSync(path.dirname(fp), { recursive: true });\n // 读改写:onListen 每次启动都会调 writeRecord,需沿用旧记录的 plugins 段,\n // 只更新运行字段(pid/port/root/startedAt),否则插件配置跨重启清零。\n const old = readRecord(root); // 记录缺失/损坏 → null,兜底最小记录\n const rec: InstanceRecord = {\n pid: process.pid,\n port,\n root,\n startedAt: new Date().toISOString(),\n version: CURRENT_VERSION,\n };\n if (old?.plugins && typeof old.plugins === 'object') {\n rec.plugins = old.plugins;\n }\n // tmp+rename 原子写(对齐 writePluginsConfig),避免半写状态被读到\n const tmp = fp + '.tmp';\n fs.writeFileSync(tmp, JSON.stringify(rec, null, 2) + '\\n');\n fs.renameSync(tmp, fp);\n}\n\nexport function readPluginsConfig(root: string): Record<string, Record<string, unknown>> {\n try {\n const rec = readRecord(root);\n if (rec?.plugins && typeof rec.plugins === 'object') {\n return rec.plugins as Record<string, Record<string, unknown>>;\n }\n } catch { /* ignore */ }\n return {};\n}\n\nexport function writePluginsConfig(root: string, plugins: Record<string, Record<string, unknown>>): void {\n const fp = recordPath(root);\n let rec: InstanceRecord;\n try {\n const raw = fs.readFileSync(fp, 'utf-8');\n rec = JSON.parse(raw) as InstanceRecord;\n } catch {\n rec = { pid: process.pid, port: 0, root, startedAt: new Date().toISOString() };\n }\n rec.plugins = plugins;\n const tmp = fp + '.tmp';\n fs.writeFileSync(tmp, JSON.stringify(rec, null, 2) + '\\n');\n fs.renameSync(tmp, fp);\n}\n\n/** 死键剥离判定所需的最小 manifest 投影(PluginManifest 结构兼容) */\nexport interface ConfigSchemaInfo {\n mode: string;\n external?: boolean;\n /** manifest.config 声明:缺省或空对象表示该内置插件无配置面 */\n config?: Record<string, unknown>;\n}\n\n/**\n * 启动一次性:剥离 dashboard.json 里内置插件的死配置键(通用规则,收敛自 view/design 约定化扫描)。\n * - 内置(非 external)未声明 config → 整段死键,清除;\n * - 内置已声明 config → 仅保留声明键(键级收敛);\n * - external 插件键保留;存储中无 manifest 声明的键(未知/未加载插件)保守保留。\n * 无变更/无记录时不写盘。返回是否发生了剥离。记录缺失/损坏跳过清理,不阻塞启动。\n */\nexport function stripDeadPluginConfig(root: string, manifests: readonly ConfigSchemaInfo[]): boolean {\n try {\n const rec = readRecord(root);\n if (!rec?.plugins || typeof rec.plugins !== 'object') return false;\n const byMode = new Map(manifests.map((m) => [m.mode, m]));\n const stored = rec.plugins as Record<string, unknown>;\n const plugins: Record<string, unknown> = { ...stored };\n let changed = false;\n for (const mode of Object.keys(plugins)) {\n const m = byMode.get(mode);\n // 无声明(未注册,可能是外部插件或已卸载)→ 保守不清;external → 保留\n if (!m || m.external) continue;\n const section = plugins[mode];\n if (section === null || typeof section !== 'object') continue;\n const keys = Object.keys(section as Record<string, unknown>);\n if (!m.config || Object.keys(m.config).length === 0) {\n // 内置且未声明 config → 整段死键\n if (keys.length > 0) {\n delete plugins[mode];\n changed = true;\n }\n continue;\n }\n // 键级收敛:仅保留 manifest.config 声明的键\n const kept: Record<string, unknown> = {};\n for (const key of Object.keys(m.config)) {\n if (key in (section as Record<string, unknown>)) kept[key] = (section as Record<string, unknown>)[key];\n }\n if (Object.keys(kept).length !== keys.length) {\n if (Object.keys(kept).length === 0) delete plugins[mode];\n else plugins[mode] = kept;\n changed = true;\n }\n }\n if (!changed) return false;\n writePluginsConfig(root, plugins as Record<string, Record<string, unknown>>); // tmp+rename 原子写\n return true;\n } catch {\n return false; // 记录缺失/损坏:跳过清理,不阻塞启动\n }\n}\n\nexport function clearRecord(root: string): void {\n try {\n // 属主校验:记录若已指向别的实例(并发双启落败者),不得误删胜者记录\n const rec = readRecord(root);\n if (rec && rec.pid !== process.pid) return;\n fs.unlinkSync(recordPath(root));\n } catch {\n // best-effort\n }\n}\n\nexport function isAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch (e) {\n if ((e as NodeJS.ErrnoException).code === 'ESRCH') return false;\n // EPERM or other → process exists, we just can't signal it\n return true;\n }\n}\n\nasync function fetchWithTimeout(url: string): Promise<Response> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), VERIFY_TIMEOUT_MS);\n try {\n return await fetch(url, { signal: controller.signal });\n } finally {\n clearTimeout(timer);\n }\n}\n\n/** 活实例核验结果:reusable = 存活且 root 匹配;version 为该实例实时版本(供旧版检测) */\nexport interface VerifyResult {\n reusable: boolean;\n version?: string;\n}\n\nexport async function verifyRoot(port: number, root: string): Promise<VerifyResult> {\n try {\n const res = await fetchWithTimeout(`http://127.0.0.1:${port}/__config`);\n if (res.status !== 200) return { reusable: false };\n const body = await res.json();\n if (typeof body.root !== 'string') return { reusable: false };\n return {\n reusable: body.root === root,\n version: typeof body.version === 'string' ? body.version : undefined,\n };\n } catch {\n return { reusable: false };\n }\n}\n\n/**\n * 可复用实例发现:\n * - reuse → 存活 + root 匹配 + 版本一致,直接复用;\n * - stale-version → 存活 + root 匹配但版本落后(调用方决定提示或自动升级接管);\n * - null → 无可复用实例(无记录/进程死亡/端口被无关进程占用)。\n */\nexport async function findReusable(\n root: string,\n currentVersion: string,\n): Promise<{ status: 'reuse'; record: InstanceRecord } | { status: 'stale-version'; record: InstanceRecord; liveVersion?: string } | null> {\n const rec = readRecord(root);\n if (!rec) return null;\n if (!isAlive(rec.pid)) return null;\n const v = await verifyRoot(rec.port, root);\n if (!v.reusable) return null;\n if (v.version && v.version !== currentVersion) {\n return { status: 'stale-version', record: rec, liveVersion: v.version };\n }\n return { status: 'reuse', record: rec };\n}\n\nexport async function stopInstance(record: InstanceRecord): Promise<void> {\n try {\n process.kill(record.pid, 'SIGTERM');\n } catch {\n return;\n }\n\n const deadline = Date.now() + STOP_POLL_MS;\n while (Date.now() < deadline) {\n if (!isAlive(record.pid)) return;\n await new Promise((r) => setTimeout(r, STOP_POLL_INTERVAL_MS));\n }\n\n // still alive → SIGKILL\n try {\n process.kill(record.pid, 'SIGKILL');\n } catch {\n // ignore\n }\n await new Promise((r) => setTimeout(r, STOP_FINAL_WAIT_MS));\n}\n","import { exec, execFile } from 'node:child_process';\n\n/** 跨平台打开浏览器(macOS open / Windows start / Linux xdg-open) */\nexport function openUrl(url: string): void {\n const cmd =\n process.platform === 'darwin' ? 'open' :\n process.platform === 'win32' ? 'start' :\n 'xdg-open';\n // win32 `start` 是 shell 内建命令,只能走 shell;其他平台直接用 execFile\n if (process.platform === 'win32') {\n exec(`start \"\" \"${url}\"`);\n } else {\n execFile(cmd, [url]);\n }\n}\n","import fs from 'node:fs';\nimport http from 'node:http';\nimport { Service } from 'cordis';\nimport type { Context } from 'cordis';\n\ndeclare module 'cordis' {\n interface Context {\n reload: ReloadService;\n }\n}\n\nconst WATCH_DEBOUNCE_MS = 300;\n\n/** 忽略目录(recursive watch 相对路径前缀)与编辑器/系统/日志噪音文件 */\nconst IGNORED_DIR_RE = /^(?:\\.git|node_modules|dist|\\.pnpm)(?:[/\\\\]|$)/;\nconst IGNORED_FILE_RE = /\\.(?:swp|tmp|log)$|~$|^\\.DS_Store$|^Thumbs\\.db$/i;\n\n/** filename 是否应被 watcher 忽略;null(平台未提供文件名)放行,行为不变 */\nexport function isIgnoredPath(filename: string | null): boolean {\n if (!filename) return false;\n return IGNORED_DIR_RE.test(filename) || IGNORED_FILE_RE.test(filename);\n}\n\nexport class ReloadService extends Service {\n static inject = ['server'];\n private clients = new Set<http.ServerResponse>();\n private watcher?: fs.FSWatcher;\n private timer?: NodeJS.Timeout;\n\n constructor(ctx: Context, config: { root: string }) {\n super(ctx, 'reload');\n this.ctx.effect(() => () => this.dispose());\n\n this.ctx.server.sse('/__reload', (res) => {\n this.clients.add(res);\n return () => this.clients.delete(res);\n });\n\n try {\n this.watcher = fs.watch(config.root, { recursive: true }, (eventType, filename) => {\n if (isIgnoredPath(filename)) return;\n if (this.timer) clearTimeout(this.timer);\n this.timer = setTimeout(() => {\n this.ctx.server.refreshGitInfo();\n this.broadcast('reload');\n this.broadcast('files');\n this.timer = undefined;\n }, WATCH_DEBOUNCE_MS);\n });\n } catch {\n // watch unavailable - static only\n }\n }\n\n broadcast(ev: string, data: unknown = '') {\n const payload = `event: ${ev}\\ndata: ${JSON.stringify(data == null ? '' : data)}\\n\\n`;\n for (const c of this.clients) {\n try { c.write(payload); } catch {}\n }\n }\n\n /** 插件专用频道:plugin:<mode>:<event>,客户端 usePluginData subscribe 消费 */\n broadcastPlugin(mode: string, event: string, data: unknown = '') {\n this.broadcast(`plugin:${mode}:${event}`, data);\n }\n\n dispose() {\n if (this.watcher) { try { this.watcher.close(); } catch {} }\n if (this.timer) { clearTimeout(this.timer); }\n for (const c of this.clients) { try { c.end(); } catch {} }\n this.clients.clear();\n }\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport { walkDir } from './walk.js';\n\nexport type NodeKind = 'file' | 'dir' | 'log';\nexport interface TreeNode {\n name: string;\n kind: NodeKind;\n path?: string;\n defaultCollapsed?: boolean;\n children?: TreeNode[];\n}\n\nfunction buildTree(paths: string[], defaultExpandDepth = 2): TreeNode[] {\n const root: TreeNode[] = [];\n const map = new Map<string, TreeNode>();\n\n for (const p of paths) {\n const parts = p.split('/');\n let current = '';\n let parent = root;\n\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i];\n current = current ? `${current}/${part}` : part;\n const isLast = i === parts.length - 1;\n const depth = i;\n\n if (!map.has(current)) {\n const isDir = !isLast;\n const collapsed = isDir && typeof defaultExpandDepth === 'number' && depth > defaultExpandDepth;\n const node: TreeNode = {\n name: part,\n kind: isLast ? 'file' : 'dir',\n ...(collapsed ? { defaultCollapsed: true } : {}),\n ...(isLast ? { path: p } : { children: [] }),\n };\n map.set(current, node);\n parent.push(node);\n }\n\n if (!isLast) {\n parent = map.get(current)!.children!;\n }\n }\n }\n\n const sortNodes = (nodes: TreeNode[]) => {\n nodes.sort((a, b) => (a.kind === b.kind ? a.name.localeCompare(b.name) : a.kind === 'dir' ? -1 : 1));\n for (const n of nodes) {\n if (n.children) sortNodes(n.children);\n }\n };\n\n sortNodes(root);\n return root;\n}\n\nexport interface ScanTreeOptions {\n defaultExpandDepth?: number;\n /** 允许点前缀的 scanDirs(如 .zdev/apply):声明后才扫描,且 walk 放行其内点前缀子目录;未声明的点前缀目录整组跳过 */\n dotDirs?: string[];\n}\n\nfunction prefixPaths(nodes: TreeNode[], prefix: string): TreeNode[] {\n return nodes.map((n) => {\n if (n.kind === 'file' && n.path) {\n return { ...n, path: `${prefix}/${n.path}` };\n }\n if (n.children) {\n return { ...n, children: prefixPaths(n.children, prefix) };\n }\n return n;\n });\n}\n\n/** 方案模式树形扫描:按 scanDirs 白名单扫描 */\nexport function scanTree(root: string, scanDirs: string[], opts?: ScanTreeOptions): TreeNode[] {\n const tree: TreeNode[] = [];\n const defaultExpandDepth = typeof opts?.defaultExpandDepth === 'number' ? opts.defaultExpandDepth : 2;\n const dotDeclared = new Set(Array.isArray(opts?.dotDirs) ? opts.dotDirs : []);\n const dirs = Array.isArray(scanDirs) ? scanDirs.filter((d) => typeof d === 'string' && d) : [];\n for (const dir of dirs) {\n // 点前缀目录须显式列入 dotDirs 才可扫(最小例外);未声明整组跳过\n if (dir.startsWith('.') && !dotDeclared.has(dir)) continue;\n const dirPath = path.join(root, dir);\n if (!fs.existsSync(dirPath)) continue;\n const paths: string[] = [];\n walkDir(dirPath, { maxDepth: 4, allowDotDirs: dotDeclared.has(dir), onFile: (_, rel) => paths.push(rel) });\n const prefix = dir;\n const children = prefixPaths(buildTree(paths, defaultExpandDepth), prefix);\n if (children.length) {\n tree.push({ name: `${dir} (${children.length})`, kind: 'dir', children });\n }\n }\n return tree;\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\n\nexport interface WalkOptions {\n skip?: Set<string>;\n maxDepth?: number;\n /** true 时点前缀「目录」不跳过(供显式列入 dotDirs 的扫描目录使用);点前缀「文件」仍恒跳过 */\n allowDotDirs?: boolean;\n onFile?: (abs: string, rel: string) => void;\n onDir?: (abs: string, rel: string) => void;\n}\n\nexport function walkDir(root: string, opts: WalkOptions = {}): void {\n const { skip = new Set(), maxDepth, allowDotDirs = false, onFile, onDir } = opts;\n\n function walk(dir: string, rel: string, depth: number) {\n if (typeof maxDepth === 'number' && depth > maxDepth) return;\n let ents: fs.Dirent[];\n try { ents = fs.readdirSync(dir, { withFileTypes: true }); } catch { return; }\n for (const ent of ents) {\n // 点前缀最小例外:仅目录可经 allowDotDirs 放行,文件一律跳过\n if (ent.name.startsWith('.') && !(allowDotDirs && ent.isDirectory())) continue;\n if (skip.has(ent.name)) continue;\n const abs = path.join(dir, ent.name);\n const r = rel ? `${rel}/${ent.name}` : ent.name;\n if (ent.isDirectory()) {\n onDir?.(abs, r);\n walk(abs, r, depth + 1);\n } else if (onFile) {\n onFile(abs, r);\n }\n }\n }\n\n walk(root, '', 0);\n}\n","import type { Context } from 'cordis';\nimport { scanTree } from '../server/spec-scan.js';\n\n/** 生态约定:项目根/worktree 根下的固定扫描目录,非用户可配;.zdev/apply 为点前缀目录,经 dotDirs 显式放行 */\nconst CONVENTION_SCAN_DIRS = ['openspec', 'docs', '.zdev/apply'] as const;\n/** 点前缀扫描目录子集:scanTree 须声明才可扫(walkDir 点前缀最小例外) */\nconst CONVENTION_DOT_DIRS = CONVENTION_SCAN_DIRS.filter((d) => d.startsWith('.'));\n\nexport const apply = {\n inject: ['server'] as const,\n apply(ctx: Context, config: { root: string }) {\n const server = ctx.server;\n if (server?.route) {\n // /__files 仅返回目录树;探测位已由独立轻量接口 /__detect 承担,不再搭车\n server.route('/__files', async (req, res) => {\n try {\n const url = new URL(req.url || '/', 'http://localhost');\n const wt = url.searchParams.get('wt');\n const scanRoot = wt ? decodeURIComponent(wt) : config.root;\n const tree = scanTree(scanRoot, [...CONVENTION_SCAN_DIRS], { dotDirs: [...CONVENTION_DOT_DIRS] });\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8', 'Cache-Control': 'no-cache' });\n res.end(JSON.stringify({ tree }));\n } catch {\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8', 'Cache-Control': 'no-cache' });\n res.end(JSON.stringify({ tree: [] }));\n }\n });\n }\n },\n};\n","import { execFile } from 'node:child_process';\nimport type { Context } from 'cordis';\n\nexport interface WorktreeInfo {\n path: string;\n name: string;\n branch: string;\n head: string;\n dirty: boolean;\n}\n\nconst GIT_TIMEOUT_MS = 5_000;\nconst ZWORKTREE_SEGMENT = '.zworktree/';\n\nfunction runGit(args: string[], cwd: string): Promise<string> {\n return new Promise((resolve) => {\n execFile('git', args, { cwd, timeout: GIT_TIMEOUT_MS }, (err, stdout) => {\n if (err) return resolve('');\n resolve(stdout);\n });\n });\n}\n\nexport async function listWorktrees(root: string): Promise<WorktreeInfo[]> {\n const raw = await runGit(['worktree', 'list', '--porcelain'], root);\n if (!raw) return [];\n\n const entries: WorktreeInfo[] = [];\n const lines = raw.split('\\n');\n let current: Partial<WorktreeInfo> = {};\n\n for (const line of lines) {\n const m = line.match(/^(worktree|HEAD|branch|detached)\\s+(.+)$/);\n if (!m) continue;\n const [, key, val] = m;\n if (key === 'worktree') {\n if (current.path && current.path.includes(ZWORKTREE_SEGMENT)) {\n entries.push({\n path: current.path,\n name: current.path.split(ZWORKTREE_SEGMENT).pop() ?? '',\n branch: current.branch ?? '',\n head: current.head ?? '',\n dirty: false,\n });\n }\n current = { path: val, head: '', branch: '' };\n } else if (key === 'HEAD') {\n current.head = val;\n } else if (key === 'branch') {\n current.branch = val.replace(/^refs\\/heads\\//, '');\n }\n }\n\n // flush last entry\n if (current.path && current.path.includes(ZWORKTREE_SEGMENT)) {\n entries.push({\n path: current.path,\n name: current.path.split(ZWORKTREE_SEGMENT).pop() ?? '',\n branch: current.branch ?? '',\n head: current.head ?? '',\n dirty: false,\n });\n }\n\n // dirty detection: git status --porcelain 非空即 dirty(失败默认 false)\n await Promise.all(\n entries.map(async (entry) => {\n try {\n const statusOut = await runGit(['status', '--porcelain'], entry.path);\n entry.dirty = statusOut.trim().length > 0;\n } catch {\n entry.dirty = false;\n }\n })\n );\n\n return entries;\n}\n\nexport const apply = {\n inject: ['server'] as const,\n apply(ctx: Context, config: { root: string }) {\n const server = ctx.server;\n if (!server?.route) return;\n\n server.route('/__worktrees', async (_req, res) => {\n try {\n const entries = await listWorktrees(config.root);\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8', 'Cache-Control': 'no-cache' });\n res.end(JSON.stringify(entries));\n } catch {\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8', 'Cache-Control': 'no-cache' });\n res.end(JSON.stringify([]));\n }\n });\n },\n};\n","import { Service } from 'cordis';\nimport type { Context } from 'cordis';\nimport { readBody } from './read-body.js';\n\ndeclare module 'cordis' {\n interface Context {\n dashboard: DashboardService;\n }\n}\n\nexport interface PluginManifest {\n mode: string;\n label: string;\n icon: string;\n description?: string;\n viewerUrl?: string; // 同源 URL,前端 iframe 渲染\n external?: boolean;\n order?: number; // 排序权重(小在前);缺省按字母序\n config?: Record<string, ConfigField>;\n}\n\nexport interface ConfigField {\n type: 'string' | 'text' | 'number' | 'boolean' | 'string[]' | 'select' | 'multiselect';\n label: string;\n default?: unknown;\n placeholder?: string;\n options?: { value: string; label: string }[];\n min?: number;\n max?: number;\n}\n\nexport class DashboardService extends Service {\n static inject = ['server', 'reload'];\n private plugins = new Map<string, PluginManifest>();\n private reloadRef: any;\n\n constructor(ctx: Context) {\n super(ctx, 'dashboard');\n this.ctx.effect(() => () => this.plugins.clear());\n this.reloadRef = ctx.reload;\n\n this.ctx.server.route('/__plugins', (_req, res) => {\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8', 'Cache-Control': 'no-cache' });\n res.end(JSON.stringify({ plugins: Array.from(this.plugins.values()) }));\n });\n\n this.ctx.server.route('/__plugins/config', async (req, res) => {\n const out: Record<string, Record<string, unknown>> = {};\n if (req.method === 'GET') {\n for (const m of this.plugins.values()) {\n const stored = this.ctx.server.getPluginConfig(m.mode);\n const schema = m.config ?? {};\n const merged: Record<string, unknown> = {};\n for (const [key, field] of Object.entries(schema)) {\n merged[key] = key in stored ? stored[key] : (field as ConfigField).default ?? '';\n }\n if (Object.keys(merged).length) out[m.mode] = merged;\n }\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8', 'Cache-Control': 'no-cache' });\n res.end(JSON.stringify(out));\n return;\n }\n if (req.method === 'POST') {\n if (req.headers['x-stop-token'] !== this.ctx.server.stopToken) {\n res.writeHead(403);\n res.end('forbidden');\n return;\n }\n try {\n const body = JSON.parse(await readBody(req));\n const merged: Record<string, Record<string, unknown>> = {};\n for (const mode of Object.keys(body)) {\n merged[mode] = body[mode] ?? {};\n }\n this.ctx.server.savePluginConfig(merged);\n for (const mode of Object.keys(body)) {\n try { this.reloadRef.broadcast('config', { plugin: mode }); } catch { /* ignore */ }\n }\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end('{\"ok\":true}');\n } catch (e) {\n console.error('[config] POST error', e);\n res.writeHead(400);\n res.end('{\"error\":\"bad request\"}');\n }\n return;\n }\n res.writeHead(405);\n res.end('{\"error\":\"method not allowed\"}');\n });\n }\n\n register(manifest: PluginManifest) {\n this.plugins.set(manifest.mode, manifest);\n this.ctx.effect(() => () => this.plugins.delete(manifest.mode));\n }\n\n list() {\n return Array.from(this.plugins.values());\n }\n\n get(mode: string): PluginManifest | undefined {\n return this.plugins.get(mode);\n }\n\n getConfig(mode: string): Record<string, unknown> {\n return this.ctx.server.getPluginConfig(mode);\n }\n}\n","import http from 'node:http';\n\n/**\n * Read the full body of an IncomingMessage.\n * Listens for 'error' to prevent a hanging promise when the client aborts mid-stream.\n */\nexport async function readBody(req: http.IncomingMessage): Promise<string> {\n return new Promise((resolve) => {\n let data = '';\n req.on('data', (chunk: string | Buffer) => { data += chunk; });\n req.on('end', () => resolve(data));\n req.on('error', () => resolve('')); // client abort → settle with empty string\n });\n}\n","import { spawn, execFile, type ChildProcess } from 'node:child_process';\nimport iconv from 'iconv-lite';\n\nexport interface Recipe { name: string; description: string; }\nexport type TaskStatus = 'running' | 'exited';\nexport interface TaskInfo { recipe: string; state: TaskStatus; code: number | null; startedAt: number; signal?: string }\n\nexport type JustEvent =\n | { type: 'log'; recipe: string; text: string }\n | { type: 'clear'; recipe: string }\n | { type: 'state'; recipe: string; state: TaskStatus; code: number | null; startedAt?: number; signal?: string };\n\ninterface Task {\n recipe: string;\n child: ChildProcess | null;\n state: TaskStatus;\n code: number | null;\n signal?: string;\n startedAt: number;\n buffer: string[];\n pending: Buffer; // 字节级行缓冲:块缓冲输出会在行中间断开,攒到 \\n(0x0A)才切行——多字节字符不会跨行界,解码只发生在完整行上\n}\n\nconst MAX_BUFFER = 1000;\n\nconst utf8Strict = new TextDecoder('utf-8', { fatal: true });\n\n/**\n * 逐行解码:先 UTF-8 严格解码,失败回退 GBK(Windows 码页输出)。\n * 行界按 0x0A 字节切分是安全的:UTF-8 续字节 ≥ 0x80、GBK 尾字节 0x40–0xFE,均不含 0x0A。\n */\nfunction decodeLine(buf: Buffer): string {\n try {\n return utf8Strict.decode(buf);\n } catch {\n return iconv.decode(buf, 'gbk');\n }\n}\n\n/** 多任务并发 runner:每个 recipe 独立进程/日志/状态,同名 start 即重启,互不影响 */\nexport class JustRunner {\n private cwd: string;\n private tasks = new Map<string, Task>();\n private clients = new Set<(ev: JustEvent) => void>();\n private recipesCache: Recipe[] | null = null;\n\n constructor(cwd: string) { this.cwd = cwd; }\n\n recipes(): Promise<Recipe[]> {\n if (this.recipesCache) return Promise.resolve(this.recipesCache);\n return new Promise((resolve) => {\n execFile('just', ['--list', '--unsorted'], { cwd: this.cwd, maxBuffer: 1 << 20, timeout: 8000 }, (err, stdout) => {\n if (err) { resolve([]); return; }\n const out: Recipe[] = [];\n const seen = new Set<string>();\n for (const line of stdout.split(/\\r?\\n/).slice(1)) { // 跳过 \"Available recipes:\"\n const trimmed = line.trim();\n if (!trimmed) continue;\n const hashIdx = trimmed.indexOf('#');\n const sig = (hashIdx >= 0 ? trimmed.slice(0, hashIdx) : trimmed).trim();\n if (!sig) continue;\n const name = sig.split(/\\s+/)[0]; // \"hello msg=...\" -> \"hello\"\n if (seen.has(name)) continue;\n seen.add(name);\n out.push({ name, description: hashIdx >= 0 ? trimmed.slice(hashIdx + 1).trim() : '' });\n }\n this.recipesCache = out;\n resolve(out);\n });\n });\n }\n\n subscribe(fn: (ev: JustEvent) => void): () => void {\n this.clients.add(fn);\n // 连上即重放:全部任务的日志与状态\n for (const t of this.tasks.values()) {\n for (const text of t.buffer) fn({ type: 'log', recipe: t.recipe, text });\n fn({ type: 'state', recipe: t.recipe, state: t.state, code: t.code, startedAt: t.startedAt });\n }\n return () => this.clients.delete(fn);\n }\n\n private emit(ev: JustEvent) { for (const fn of this.clients) fn(ev); }\n\n list(): TaskInfo[] {\n return Array.from(this.tasks.values(), (t) => ({ recipe: t.recipe, state: t.state, code: t.code, startedAt: t.startedAt }));\n }\n\n /** 启动 recipe:同名先停旧进程(重启语义),不影响其他任务;调用方须先用 recipes() 校验名字 */\n start(recipe: string) {\n this.killOne(recipe);\n const task: Task = { recipe, child: null, state: 'running', code: null, startedAt: Date.now(), buffer: [], pending: Buffer.alloc(0) };\n this.tasks.set(recipe, task);\n this.emit({ type: 'clear', recipe }); // 广播清屏:同步清掉该任务上一轮残留日志\n this.emit({ type: 'state', recipe, state: 'running', code: null, startedAt: task.startedAt });\n const child = spawn('just', [recipe], {\n cwd: this.cwd,\n shell: true,\n env: {\n ...process.env,\n FORCE_COLOR: '1', // node 生态(chalk 等)\n // maven 检测非 tty 会关颜色;经 MAVEN_OPTS 强制开(保留用户已有值)\n MAVEN_OPTS: `${process.env.MAVEN_OPTS ?? ''} -Dstyle.color=always`.trim(),\n CI: '',\n },\n });\n task.child = child;\n // 身份守卫:同名重启后旧进程的迟到输出/退出不得污染新任务(闭包 task 是旧对象时静默丢弃)\n const isStale = () => this.tasks.get(recipe) !== task;\n const push = (d: Buffer) => {\n if (isStale()) return;\n task.pending = Buffer.concat([task.pending, d]);\n let idx: number;\n while ((idx = task.pending.indexOf(0x0a)) >= 0) { // 字节级切行:行界 0x0A 不会落在多字节字符内部\n const line = task.pending.subarray(0, idx + 1);\n task.pending = task.pending.subarray(idx + 1);\n this.pushLine(task, decodeLine(line));\n }\n // 无 \\n 的尾巴留在字节缓冲,等下个 chunk(块缓冲输出会在行中断开,不能当独立行;半个多字节字符也在此安全等待)\n };\n child.stdout?.on('data', push);\n child.stderr?.on('data', push);\n child.on('error', (err) => { this.pushLine(task, `[zdashboard] spawn error: ${err.message}\\n`); });\n child.on('exit', (code, signal) => {\n if (task.pending.length > 0 && !isStale()) { this.pushLine(task, decodeLine(task.pending) + '\\n'); } // flush 末尾无换行的残留(空 Buffer 为 truthy,须按 length 判)\n task.pending = Buffer.alloc(0);\n task.child = null;\n task.state = 'exited';\n task.code = code ?? 0;\n task.signal = signal ?? undefined; // 用户主动 stop 时 code=null+SIGTERM,与成功退出区分\n if (isStale()) return; // 迟到的旧进程退出,不打扰新任务状态\n this.emit({ type: 'state', recipe, state: 'exited', code: task.code, startedAt: task.startedAt, signal: task.signal });\n });\n }\n\n private pushLine(task: Task, line: string) {\n task.buffer.push(line);\n if (task.buffer.length > MAX_BUFFER) task.buffer.shift();\n this.emit({ type: 'log', recipe: task.recipe, text: line });\n }\n\n /** 停单个任务;不传 recipe 停全部 */\n stop(recipe?: string) {\n if (recipe === undefined) { for (const t of this.tasks.values()) this.killOne(t.recipe); }\n else this.killOne(recipe);\n }\n\n restart(recipe: string) {\n if (this.tasks.has(recipe)) this.start(recipe);\n }\n\n /** 清空某任务的日志缓冲并广播(真源清除,重连重放不会复活) */\n clear(recipe: string) {\n const task = this.tasks.get(recipe);\n if (!task) return;\n task.buffer = [];\n task.pending = Buffer.alloc(0);\n this.emit({ type: 'clear', recipe });\n }\n\n private killOne(recipe: string) {\n const task = this.tasks.get(recipe);\n const child = task?.child;\n if (child?.pid) {\n try {\n if (process.platform === 'win32') spawn('taskkill', ['/PID', String(child.pid), '/T', '/F']);\n else child.kill('SIGTERM');\n } catch { /* 已退出 */ }\n }\n if (task) { task.child = null; }\n }\n}\n","/**\n * 插件 SDK(server 侧):definePlugin 是插件接入宿主的唯一姿势。\n *\n * 内部自动完成 dashboard.register(manifest) 与 effect 清理注册,\n * 插件作者只面对 PluginContext 的七个通道;四种 cordis 手写姿势由此消亡。\n */\nimport type http from 'node:http';\nimport { json, guarded } from '../core/server.js';\nimport type { Context } from 'cordis';\nimport type { PluginManifest } from '../core/manifest.js';\n\n/** handler 返回非 undefined 值时由 SDK 包装为 json 响应;自行写响应则返回 undefined */\nexport type RouteHandler = (\n req: http.IncomingMessage,\n res: http.ServerResponse,\n) => unknown | Promise<unknown>;\n\nexport type SseHandler = (res: http.ServerResponse) => (() => void) | void;\n\nexport interface PluginContext {\n /** manifest.mode 的只读镜像 */\n readonly mode: string;\n /** manifest.config 默认值合并 .zdev/dashboard.json 存储值(存储优先) */\n config<T extends Record<string, unknown> = Record<string, unknown>>(): T;\n /** 注册路由;handler 返回值自动 json 包装(200 + application/json) */\n route(path: string, handler: RouteHandler): void;\n /** 校验 x-stop-token 后执行 route 语义;缺/错 token 直接 403 */\n guardedRoute(path: string, handler: RouteHandler): void;\n sse(path: string, handler: SseHandler): void;\n static(prefix: string, dir: string): void;\n /** 广播到 SSE 频道 plugin:<mode>:<event>,客户端 usePluginData subscribe 消费 */\n broadcast(event: string, data?: unknown): void;\n onDispose(fn: () => void): void;\n}\n\ninterface CordisPluginApply {\n inject?: readonly string[];\n apply(ctx: Context, config: unknown): unknown;\n}\n\n/**\n * 定义内置/外部插件的 server 侧入口。\n * @param def.manifest 与 client defineWebPlugin 共享的同一份常量(SSOT)\n * @param def.setup 在 server/dashboard 服务就绪的上下文中执行\n */\nexport function definePlugin(def: {\n manifest: PluginManifest;\n setup(ctx: PluginContext): void;\n}): CordisPluginApply & { inject: readonly string[] } {\n const { manifest, setup } = def;\n\n return {\n inject: ['server', 'dashboard', 'reload'] as const,\n apply(this: void, ctx: Context) {\n const disposers: Array<() => void> = [];\n ctx.effect(() => () => {\n for (const fn of disposers.splice(0)) {\n try { fn(); } catch (e) {\n console.error(`[zdashboard] plugin ${manifest.mode} dispose error:`, e);\n }\n }\n });\n\n ctx.dashboard.register(manifest);\n\n /** json 包装语义与错误兜底;guardedRoute 不经此重注册路径 */\n const respondWith = (handler: RouteHandler) => async (req: http.IncomingMessage, res: http.ServerResponse) => {\n if (res.headersSent) return;\n try {\n const data = await handler(req, res);\n if (data !== undefined && !res.writableEnded) json(res, data);\n } catch (e) {\n console.error(`[zdashboard] plugin ${manifest.mode} route error:`, e);\n if (!res.headersSent) json(res, { error: 'internal' }, 500);\n }\n };\n\n const pctx: PluginContext = {\n mode: manifest.mode,\n config<T extends Record<string, unknown> = Record<string, unknown>>(): T {\n const schema = manifest.config ?? {};\n const stored = ctx.server.getPluginConfig(manifest.mode) ?? {};\n const defaults = Object.fromEntries(\n Object.entries(schema).map(([key, field]) => [key, field.default]),\n );\n return { ...defaults, ...stored } as T;\n },\n route(path: string, handler: RouteHandler): void {\n ctx.server.route(path, respondWith(handler));\n },\n guardedRoute(path: string, handler: RouteHandler): void {\n const token = () => ctx.server.stopToken;\n ctx.server.route(path, (req, res) => {\n if (!guarded(req, res, token())) return;\n void respondWith(handler)(req, res);\n });\n },\n sse(path: string, handler: SseHandler): void {\n ctx.server.sse(path, handler);\n },\n static(prefix: string, dir: string): void {\n ctx.server.static(prefix, dir);\n },\n broadcast(event: string, data?: unknown): void {\n ctx.reload?.broadcast(`plugin:${manifest.mode}:${event}`, data ?? '');\n },\n onDispose(fn: () => void): void {\n disposers.push(fn);\n },\n };\n\n setup(pctx);\n },\n };\n}\n","/**\n * 内置插件 root 注入壳(插件侧适配,不动 SDK 公共契约):\n *\n * SDK definePlugin 的 apply(ctx) 不向 setup 转发 cordis 插件 config,\n * 而六个内置插件都需要 cli 注入的 { root }。此壳在插件层捕获 config.root\n * 再调用 SDK 产出的 apply,setup 以第二参拿到 root。\n * 若 SDK 未来转发 config,此文件可整体删除。\n */\nimport type { Context } from 'cordis';\nimport { definePlugin, type PluginContext } from '../sdk/server.js';\nimport type { PluginManifest } from '../core/manifest.js';\n\nexport function defineBuiltin(def: {\n manifest: PluginManifest;\n setup(ctx: PluginContext, root: string): void;\n}) {\n let currentRoot = '';\n const inner = definePlugin({\n manifest: def.manifest,\n setup(pctx) { def.setup(pctx, currentRoot); },\n });\n\n return {\n inject: inner.inject,\n manifest: def.manifest, // cli 启动期死键剥离按 manifest 判定(config 声明/external)\n apply(ctx: Context, config: { root?: string }) {\n currentRoot = config?.root ?? '';\n inner.apply(ctx, config);\n },\n };\n}\n","/** just 插件单源:server definePlugin 与 web defineWebPlugin 共享 */\nimport type { PluginManifest } from '../../core/manifest.js';\nimport type { ParamSchema } from '../../sdk/shared.js';\n\nexport const manifest: PluginManifest = {\n mode: 'just',\n label: 'Just Runner',\n icon: '📜',\n description: 'Just 任务日志与执行',\n order: 50,\n};\n\n/** recipe:选中 recipe;task:活跃任务 id(与 recipe 同名空间) */\nexport const params: ParamSchema = [\n { name: 'recipe', label: 'Recipe', type: 'string', description: '选中的 recipe 名' },\n { name: 'task', label: '任务', type: 'string', description: '活跃任务 id' },\n];\n","/**\n * just server 侧:definePlugin 接入(manifest 单源)。\n *\n * JustRunner 并发核实结论(T5):src/server/just-runner.ts 已是多任务并发 runner ——\n * tasks Map 每 recipe 独立子进程/日志缓冲/状态,事件载荷自带 recipe(=taskId),\n * 无需 runner 池改造。plugin:just:log 等频道广播按事件原样携带 taskId。\n *\n * start/restart/stop/clear 走 guardedRoute(x-stop-token);\n * /__just/tasks 为任务列表提供只读路由。\n */\nimport type http from 'node:http';\nimport { JustRunner } from '../../server/just-runner.js';\nimport { readBody } from '../../core/read-body.js';\nimport { defineBuiltin } from '../builtin.js';\nimport { manifest } from './manifest.js';\nimport type { RouteHandler } from '../../sdk/server.js';\n\nexport const apply = defineBuiltin({\n manifest,\n setup(ctx, root) {\n const runner = new JustRunner(root);\n ctx.onDispose(() => runner.stop());\n\n ctx.route('/__just/recipes', async () => {\n try {\n return await runner.recipes();\n } catch {\n return [];\n }\n });\n\n ctx.route('/__just/tasks', async () => runner.list());\n\n ctx.sse('/__just/logs', (res) => {\n const unsub = runner.subscribe((ev) => {\n // 插件频道镜像:type 即事件名(log/clear/state),载荷携带 taskId(recipe)\n try { ctx.broadcast(ev.type, ev); } catch { /* reload 未就绪 */ }\n res.write(`data: ${JSON.stringify(ev)}\\n\\n`);\n });\n return unsub;\n });\n\n /** start/restart 须带合法 recipe(同名 start 即重启);stop 可带单个 recipe 或省略(停全部);clear 清日志 */\n const handleAction = async (req: http.IncomingMessage, res: http.ServerResponse, act: 'start' | 'stop' | 'restart' | 'clear') => {\n const body = await readBody(req);\n let recipe: string | undefined;\n try { recipe = JSON.parse(body || '{}').recipe; } catch { /* ignore */ }\n if (act === 'clear') {\n if (recipe) runner.clear(recipe);\n return { ok: true };\n }\n if (act !== 'stop') {\n if (!recipe) {\n res.writeHead(400, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end('{\"error\":\"no recipe\"}');\n return undefined;\n }\n const recipes = await runner.recipes();\n if (!recipes.some((r) => r.name === recipe)) {\n res.writeHead(403, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end('{\"error\":\"unknown recipe\"}');\n return undefined;\n }\n runner.start(recipe);\n } else {\n runner.stop(recipe || undefined);\n }\n return runner.list();\n };\n\n const routeAction = (name: 'start' | 'stop' | 'restart' | 'clear') => {\n ctx.guardedRoute(`/__just/${name}`, ((req, res) => handleAction(req, res, name)) satisfies RouteHandler);\n };\n routeAction('start');\n routeAction('stop');\n routeAction('restart');\n routeAction('clear');\n },\n});\n","/**\n * design server 侧:definePlugin 接入(约定化扫描)。\n * 恒扫 <root>/.zdev/design(zdesign 等 skill 统一产出目录,walkDir 跳过点目录扫根看不见);\n * 目录缺失 → emptyScan() 九组空数组。/__design/assets 响应形状(ScanResult)保持不变。\n * 另供只读代理 /__design/asset?path=<rel-to-.zdev/design>,viewers 由此加载资产(直取根路径必 404)。\n */\nimport path from 'node:path';\nimport fs from 'node:fs';\nimport { MIME } from '../../core/server.js';\nimport { scanAssets, type ScanResult, type AssetType } from '../../server/design-assets.js';\nimport { defineBuiltin } from '../builtin.js';\nimport { manifest } from './manifest.js';\n\nconst ASSET_KEYS: AssetType[] = ['page', 'component', 'icon', 'token', 'md', 'video', 'audio', 'pdf', 'font'];\n\nfunction emptyScan(): ScanResult {\n const out = {} as ScanResult;\n for (const k of ASSET_KEYS) out[k] = [];\n return out;\n}\n\nexport const apply = defineBuiltin({\n manifest,\n setup(ctx, root) {\n ctx.route('/__design/assets', async () => {\n const designRoot = path.join(root, '.zdev', 'design');\n return fs.existsSync(designRoot) ? scanAssets(designRoot) : emptyScan();\n });\n\n // 只读资产代理:三重防御钉死任意读(字符拒绝 → join 归一化 → 前缀校验),先例 /__file-content\n ctx.route('/__design/asset', async (req, res) => {\n const rel = new URL(req.url || '/', 'http://localhost').searchParams.get('path') ?? '';\n if (!rel || rel.includes('..') || rel.includes('\\\\') || path.isAbsolute(rel)) {\n res.writeHead(400);\n res.end('bad path');\n return;\n }\n const designRoot = path.join(root, '.zdev', 'design');\n const filePath = path.join(designRoot, rel);\n if (!filePath.startsWith(designRoot + path.sep)) {\n res.writeHead(400);\n res.end('bad path');\n return;\n }\n fs.stat(filePath, (err) => {\n if (err) { res.writeHead(404); return res.end('Not found'); }\n const ct = MIME[path.extname(filePath).toLowerCase()] ?? 'application/octet-stream';\n res.writeHead(200, { 'Content-Type': ct, 'Cache-Control': 'no-cache' });\n // stat 通过后文件仍可能被删,流错误无人接会崩进程(与 core/server serveFile 同款兜底)\n const stream = fs.createReadStream(filePath);\n stream.on('error', () => { try { res.destroy(); } catch { /* 已断 */ } });\n stream.pipe(res);\n });\n });\n },\n});\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport { walkDir } from './walk.js';\n\nexport type AssetType = 'page' | 'component' | 'icon' | 'token' | 'md' | 'video' | 'audio' | 'pdf' | 'font';\n\nconst PAGE_EXTS = ['.html', '.htm'];\nconst ICON_EXTS = ['.svg', '.png', '.ico', '.jpg', '.jpeg', '.gif', '.webp'];\nconst VIDEO_EXTS = ['.mp4', '.webm', '.mov', '.ogg', '.ogv'];\nconst AUDIO_EXTS = ['.mp3', '.wav', '.flac', '.aac', '.m4a'];\nconst CODE_EXTS = ['.js', '.mjs', '.cjs', '.mts', '.cts', '.ts', '.tsx', '.jsx', '.css', '.json', '.txt', '.xml', '.yml', '.yaml', '.sh', '.md'];\nconst FONT_EXTS = ['.woff', '.woff2', '.ttf', '.otf'];\nconst TOKEN_RE = /token|theme|design|color|palette|typograph/i;\n\nexport function categorize(rel: string, ext: string): AssetType | null {\n if (rel.indexOf('components/') === 0) return 'component';\n if (VIDEO_EXTS.includes(ext)) return 'video';\n if (AUDIO_EXTS.includes(ext)) return 'audio';\n if (ext === '.pdf') return 'pdf';\n if (ext === '.md') return 'md';\n if (FONT_EXTS.includes(ext)) return 'font';\n if (ICON_EXTS.includes(ext)) return 'icon';\n if (PAGE_EXTS.includes(ext)) return 'page';\n if (CODE_EXTS.includes(ext)) {\n if (TOKEN_RE.test(rel) && (ext === '.css' || ext === '.json')) return 'token';\n return null;\n }\n return null;\n}\n\nexport interface AssetFile { path: string; name: string; ext: string; type: AssetType; }\nexport type ScanResult = Record<AssetType, AssetFile[]>;\n\nexport function scanAssets(root: string, subDir = ''): ScanResult {\n const out: ScanResult = {} as ScanResult;\n const keys: AssetType[] = ['page','component','icon','token','md','video','audio','pdf','font'];\n for (const k of keys) out[k] = [];\n const SKIP = new Set(['node_modules', '.git', 'dist', 'build', 'coverage', '.next', '.cache']);\n const scanRoot = subDir ? path.join(root, subDir) : root;\n walkDir(scanRoot, { skip: SKIP, onFile: (abs, rel) => {\n const ext = path.extname(abs).toLowerCase();\n const t = categorize(rel, ext);\n if (t) out[t].push({ path: rel, name: path.basename(abs), ext, type: t });\n }});\n return out;\n}\n","/** design 插件单源:server definePlugin 与 web defineWebPlugin 共享 */\nimport type { PluginManifest } from '../../core/manifest.js';\nimport type { ParamSchema } from '../../sdk/shared.js';\n\nexport const manifest: PluginManifest = {\n mode: 'design',\n label: '设计资产',\n icon: '🎨',\n description: '设计资产分类浏览 · zdesign',\n order: 30,\n};\n\n/** type:资产类型;asset:选中资产路径;folder:资产路径过滤展示 */\nexport const params: ParamSchema = [\n { name: 'type', label: '资产类型', type: 'string', description: 'page/component/icon/token/md/video/audio/pdf/font' },\n { name: 'asset', label: '选中资产', type: 'string', description: '资产相对路径' },\n { name: 'folder', label: '当前文件夹', type: 'string', description: '限定展示的资产路径前缀' },\n];\n","/** view 插件单源:server definePlugin 与 web defineWebPlugin 共享 */\nimport type { PluginManifest } from '../../core/manifest.js';\nimport type { ParamSchema } from '../../sdk/shared.js';\n\nexport const manifest: PluginManifest = {\n mode: 'view',\n label: '项目浏览',\n icon: '👁️',\n description: 'openspec / docs / 文档预览',\n order: 20,\n};\n\n/** wt:worktree 绝对路径;file:文件相对路径;filter:树过滤词 */\nexport const params: ParamSchema = [\n { name: 'wt', label: 'Worktree 路径', type: 'string', description: 'worktree 绝对路径' },\n { name: 'file', label: '文件路径', type: 'string', description: '预览文件相对路径' },\n { name: 'filter', label: '过滤词', type: 'string', description: '文件树过滤词' },\n];\n","/**\n * view server 侧:definePlugin 接入(manifest 单源)。\n * 文件树路由 /__files 由 core/tree.ts 宿主服务提供(约定目录 ['openspec','docs'],非配置),此处仅注册 manifest。\n */\nimport { defineBuiltin } from '../builtin.js';\nimport { manifest } from './manifest.js';\n\nexport const apply = defineBuiltin({\n manifest,\n setup() { /* 路由由 core/tree.ts 承载 */ },\n});\n","/**\n * stats server 侧:definePlugin 接入(manifest 单源)。\n * /__stats/data 响应形状与迁移前保持一致。\n */\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { execFile } from 'node:child_process';\nimport { walkDir } from '../../server/walk.js';\nimport { listWorktrees } from '../../core/worktrees.js';\nimport { defineBuiltin } from '../builtin.js';\nimport { manifest } from './manifest.js';\n\ninterface Stats {\n root: string;\n files: number;\n dirs: number;\n totalSize: number;\n byExt: { ext: string; count: number }[];\n markdown: number;\n openspec: { active: number; archived: number };\n hasJust: boolean;\n worktrees: number;\n branch?: string;\n dirty?: number;\n}\n\nconst SKIP_DIRS = new Set(['node_modules', '.git', 'dist', 'build', '.next', '.cache']);\n\nfunction execFilePromise(file: string, args: string[], opts: { cwd: string }): Promise<string> {\n return new Promise((resolve) => {\n execFile(file, args, opts, (err, stdout) => resolve(err ? '' : stdout));\n });\n}\n\nfunction scan(root: string): Stats {\n const stats: Stats = {\n root: path.basename(root),\n files: 0,\n dirs: 0,\n totalSize: 0,\n byExt: [],\n markdown: 0,\n openspec: { active: 0, archived: 0 },\n hasJust: fs.existsSync(path.join(root, 'justfile')),\n worktrees: 0,\n };\n const extMap = new Map<string, number>();\n\n const walk = (dir: string) => {\n walkDir(dir, { skip: SKIP_DIRS, onDir: () => { stats.dirs++; }, onFile: (abs) => {\n stats.files++;\n try { stats.totalSize += fs.statSync(abs).size; } catch {}\n const ext = path.extname(abs).toLowerCase() || '(无扩展名)';\n extMap.set(ext, (extMap.get(ext) ?? 0) + 1);\n if (ext === '.md' || ext === '.markdown') stats.markdown++;\n }});\n };\n walk(root);\n\n const changesDir = path.join(root, 'openspec', 'changes');\n if (fs.existsSync(changesDir)) {\n for (const ent of fs.readdirSync(changesDir, { withFileTypes: true })) {\n if (!ent.isDirectory() || ent.name.startsWith('.')) continue;\n if (ent.name === 'archive') {\n try {\n stats.openspec.archived = fs.readdirSync(path.join(changesDir, 'archive'), { withFileTypes: true })\n .filter(e => e.isDirectory() && !e.name.startsWith('.')).length;\n } catch { /* ignore */ }\n } else stats.openspec.active++;\n }\n }\n\n stats.byExt = Array.from(extMap.entries())\n .map(([ext, count]) => ({ ext, count }))\n .sort((a, b) => b.count - a.count)\n .slice(0, 10);\n return stats;\n}\n\nexport const apply = defineBuiltin({\n manifest,\n setup(ctx, root) {\n ctx.route('/__stats/data', async () => {\n const stats = scan(root);\n try {\n const wts = await listWorktrees(root);\n stats.worktrees = wts.length;\n } catch {\n stats.worktrees = 0;\n }\n try {\n const branchOut = await execFilePromise('git', ['rev-parse', '--abbrev-ref', 'HEAD'], { cwd: root });\n stats.branch = branchOut.trim() || undefined;\n } catch { /* ignore */ }\n try {\n const statusOut = await execFilePromise('git', ['status', '--porcelain'], { cwd: root });\n stats.dirty = statusOut.trim() ? statusOut.trim().split('\\n').length : 0;\n } catch { /* ignore */ }\n return stats;\n });\n },\n});\n","/** stats 插件单源:server definePlugin 与 web defineWebPlugin 共享 */\nimport type { PluginManifest } from '../../core/manifest.js';\nimport type { ParamSchema } from '../../sdk/shared.js';\n\nexport const manifest: PluginManifest = {\n mode: 'stats',\n label: '项目统计',\n icon: '📊',\n description: '项目文件统计 · 扫描生成',\n order: 10,\n};\n\n/** card:钻取来源(worktree/dirty),view 侧读取后高亮 */\nexport const params: ParamSchema = [\n { name: 'card', label: '钻取来源', type: 'string', description: '钻取来源(worktree/dirty),view 侧读取后高亮' },\n];\n"],"mappings":"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","names":["path","fs","fileURLToPath","fs","path","fs","path","path","fs","execFile","execFile","path","fs","err","fp","fs","Service","fs","path","fs","path","path","fs","execFile","apply","Service","Service","manifest","execFile","manifest","path","apply","path","fs","path","path","manifest","apply","manifest","path","fs","manifest","apply","manifest","fs","path","execFile","manifest","execFile","path","fs","apply","manifest","__dirname","path","fileURLToPath","apply","fs"]}
|