contactsheet 0.1.8 → 0.1.9

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 CHANGED
@@ -1048,13 +1048,16 @@ var MIME = {
1048
1048
  function mimeOf(file) {
1049
1049
  return MIME[path4.extname(file)] ?? "application/octet-stream";
1050
1050
  }
1051
- function pkgVersion() {
1051
+ var VERSION = (() => {
1052
1052
  try {
1053
1053
  const pkg = JSON.parse(fs3.readFileSync(path4.join(pkgRoot, "package.json"), "utf8"));
1054
1054
  return pkg.version ?? "0.0.0";
1055
1055
  } catch {
1056
1056
  return "0.0.0";
1057
1057
  }
1058
+ })();
1059
+ function pkgVersion() {
1060
+ return VERSION;
1058
1061
  }
1059
1062
 
1060
1063
  // src/server/push.ts
@@ -1929,6 +1932,8 @@ async function up(flags) {
1929
1932
  closing = true;
1930
1933
  console.log(dim(`
1931
1934
  [contactsheet] \u6536\u5230 ${sig},\u6B63\u5728\u9000\u51FA\u2026`));
1935
+ const deadline = setTimeout(() => process.exit(0), 5e3);
1936
+ deadline.unref();
1932
1937
  if (watcher) await quiet(() => watcher.close());
1933
1938
  await quiet(() => server.close());
1934
1939
  await quiet(() => closeBrowser());
package/dist/cli.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/cli.ts", "../src/config.ts", "../src/inject/index.ts", "../src/inject/templates.ts", "../src/init/index.ts", "../src/term.ts", "../src/server/index.ts", "../src/mcp/index.ts", "../src/shot/index.ts", "../src/server/api.ts", "../src/server/assets.ts", "../src/server/push.ts", "../src/server/health.ts", "../src/server/sse.ts", "../src/server/store.ts", "../src/server/proxy-log.ts", "../src/watch/index.ts"],
4
- "sourcesContent": ["// contactsheet CLI:\u9ED8\u8BA4 up(\u6CE8\u5165 \u2192 \u76D1\u542C \u2192 \u8D77\u5916\u58F3),\u53E6\u6709 init / clean\n// http-proxy \u5185\u90E8\u7528 util._extend \u4F1A\u89E6\u53D1 DEP0060,\u7528\u6237\u5BF9\u4F9D\u8D56\u7684\u5F03\u7528\u8B66\u544A\u65E0\u80FD\u4E3A\u529B,\u53EA\u4F1A\u5F04\u810F\u8F93\u51FA\nprocess.noDeprecation = true\nimport { parseArgs } from \"node:util\"\nimport { loadConfig } from \"./config.js\"\nimport { ensureInjected, removeInjected } from \"./inject/index.js\"\nimport { runInit } from \"./init/index.js\"\nimport { broadcast, startServer } from \"./server/index.js\"\nimport { closeBrowser } from \"./shot/index.js\"\nimport { startWatcher } from \"./watch/index.js\"\nimport { bold, cyan, dim, link, ok, warn } from \"./term.js\"\nimport type { CsConfig } from \"./types.js\"\n\nconst HELP = `contactsheet \u2014\u2014 \u628A UI \u7684\u5404\u79CD\u72B6\u6001\u644A\u5728\u4E00\u9762\u53EF\u7F29\u653E\u7684\u5899\u4E0A\n\n contactsheet [up] \u9644\u7740\u5230\u5F53\u524D Next.js repo:\u6CE8\u5165\u753B\u677F\u8DEF\u7531 + \u8D77\u5916\u58F3(\u9ED8\u8BA4\u547D\u4EE4)\n contactsheet init \u521D\u59CB\u5316\u914D\u7F6E\u3001.mcp.json\u3001hook,\u5E76\u81EA\u52A8\u94FA\u4E00\u6279\u753B\u677F\n contactsheet clean \u79FB\u9664\u6CE8\u5165\u7684\u6587\u4EF6\n\n --port <n> \u5916\u58F3\u7AEF\u53E3(\u9ED8\u8BA4 5199)\n --target <url> next dev \u5730\u5740(\u9ED8\u8BA4 http://localhost:3000)\n --design-dir <dir> \u753B\u677F\u76EE\u5F55(\u9ED8\u8BA4 design)\n -h, --help \u663E\u793A\u672C\u5E2E\u52A9`\n\nmain().catch((err: unknown) => {\n console.error(`[contactsheet] ${err instanceof Error ? err.message : String(err)}`)\n process.exit(1)\n})\n\nasync function main(): Promise<void> {\n const { values, positionals } = parseArgs({\n args: process.argv.slice(2),\n options: {\n port: { type: \"string\" },\n target: { type: \"string\" },\n \"design-dir\": { type: \"string\" },\n help: { type: \"boolean\", short: \"h\" },\n },\n allowPositionals: true,\n })\n\n if (values.help) {\n console.log(HELP)\n return\n }\n\n const flags: Partial<CsConfig> = {}\n if (values.port !== undefined) {\n const port = Number(values.port)\n if (!Number.isInteger(port)) throw new Error(`--port \u4E0D\u662F\u6574\u6570:${values.port}`)\n flags.port = port\n }\n if (values.target !== undefined) flags.target = values.target\n if (values[\"design-dir\"] !== undefined) flags.designDir = values[\"design-dir\"]\n\n const cmd = positionals[0] ?? \"up\"\n if (cmd === \"up\") return up(flags)\n if (cmd === \"init\") return runInit(process.cwd(), flags)\n if (cmd === \"clean\") return removeInjected(loadConfig(process.cwd(), flags))\n\n console.error(`\u672A\u77E5\u547D\u4EE4:${cmd}\\n\\n${HELP}`)\n process.exit(1)\n}\n\nasync function up(flags: Partial<CsConfig>): Promise<void> {\n const cfg = loadConfig(process.cwd(), flags)\n\n // \u6CE8\u5165\u4E0E\u6587\u4EF6\u76D1\u542C\u5F52 Agent B;\u8FD9\u4E24\u6B65\u5931\u8D25\u53EA\u544A\u8B66,\u5916\u58F3\u7167\u5E38\u8D77(\u753B\u5E03\u672C\u8EAB\u4E0D\u4F9D\u8D56\u5B83\u4EEC)\n const injected = await tryStep(\"\u6CE8\u5165\u753B\u677F\u8DEF\u7531\", () => ensureInjected(cfg))\n if (injected !== null) console.log(ok(dim(\"\u753B\u677F\u8DEF\u7531\u5DF2\u6CE8\u5165\")))\n const watcher = await tryStep(\"\u542F\u52A8\u6587\u4EF6\u76D1\u542C\", () =>\n startWatcher(cfg, (entries) => broadcast({ type: \"registry\", entries }))\n )\n if (watcher) console.log(ok(dim(`\u76D1\u542C ${cfg.designDir}/**/*.artboard.{tsx,ts}`)))\n\n const server = await startServer(cfg)\n banner(cfg, server.port)\n\n let closing = false\n const shutdown = async (sig: string): Promise<void> => {\n if (closing) return\n closing = true\n console.log(dim(`\\n[contactsheet] \u6536\u5230 ${sig},\u6B63\u5728\u9000\u51FA\u2026`))\n if (watcher) await quiet(() => watcher.close())\n await quiet(() => server.close())\n await quiet(() => closeBrowser())\n process.exit(0)\n }\n process.on(\"SIGINT\", () => void shutdown(\"SIGINT\"))\n process.on(\"SIGTERM\", () => void shutdown(\"SIGTERM\"))\n}\n\n/** \u8DD1\u4E00\u6B65,\u5931\u8D25\u53EA\u544A\u8B66\u4E0D\u4E2D\u65AD(\u5BF9\u9762\u6A21\u5757\u53EF\u80FD\u8FD8\u662F stub) */\nasync function tryStep<T>(label: string, fn: () => Promise<T>): Promise<T | null> {\n try {\n return await fn()\n } catch (err) {\n console.warn(warn(`${label}\u5931\u8D25,\u5DF2\u8DF3\u8FC7:${err instanceof Error ? err.message : String(err)}`))\n return null\n }\n}\n\n/** \u9000\u51FA\u8DEF\u5F84\u4E0A\u7684\u8C03\u7528,\u51FA\u9519\u4E0D\u8FFD\u7A76 */\nasync function quiet(fn: () => Promise<unknown>): Promise<void> {\n try {\n await fn()\n } catch {\n // \u6B63\u5728\u9000\u51FA,\u5FFD\u7565\n }\n}\n\nfunction banner(cfg: CsConfig, port: number): void {\n console.log(`\n ${bold(cyan(\"\u25C6\"))} ${bold(\"contactsheet\")} ${link(`http://localhost:${port}/__cs`)}\n ${dim(\"\u4EE3\u7406\u76EE\u6807\")} ${cfg.target}\n ${dim(\"\u753B\u677F\u76EE\u5F55\")} ${cfg.designDir}/ ${dim(\"\u00B7\")} app \u76EE\u5F55 ${cfg.appDir}/\n ${dim(\"Ctrl-C \u9000\u51FA\")}\n`)\n}\n", "// \u914D\u7F6E\u52A0\u8F7D:<cwd>/contactsheet.config.json + CLI flags \u5408\u5E76,\u7F3A\u7701\u503C\u515C\u5E95\nimport fs from \"node:fs\"\nimport path from \"node:path\"\nimport type { CsConfig } from \"./types.js\"\n\nconst DEFAULT_TARGET = \"http://localhost:3000\"\nconst DEFAULT_PORT = 5199\nconst DEFAULT_DESIGN_DIR = \"design\"\n\nexport function loadConfig(cwd: string, flags: Partial<CsConfig>): CsConfig {\n const projectRoot = path.resolve(cwd)\n const file = path.join(projectRoot, \"contactsheet.config.json\")\n\n // \u914D\u7F6E\u6587\u4EF6\u53EF\u4EE5\u4E0D\u5B58\u5728;\u5B58\u5728\u4F46\u5185\u5BB9\u574F\u4E86\u8981\u663E\u5F0F\u62A5\u9519,\u522B\u9759\u9ED8\u9000\u56DE\u9ED8\u8BA4\u503C\n let fromFile: Partial<CsConfig> = {}\n if (fs.existsSync(file)) {\n try {\n fromFile = JSON.parse(fs.readFileSync(file, \"utf8\")) as Partial<CsConfig>\n } catch (err) {\n throw new Error(`contactsheet.config.json \u89E3\u6790\u5931\u8D25:${(err as Error).message}`)\n }\n }\n\n // \u4F18\u5148\u7EA7:CLI flags > \u914D\u7F6E\u6587\u4EF6 > \u9ED8\u8BA4\u503C\n const pick = <K extends keyof CsConfig>(key: K): CsConfig[K] | undefined => flags[key] ?? fromFile[key]\n\n const port = Number(pick(\"port\") ?? DEFAULT_PORT)\n if (!Number.isInteger(port) || port <= 0 || port > 65535) throw new Error(`\u7AEF\u53E3\u4E0D\u5408\u6CD5:${String(pick(\"port\"))}`)\n\n return {\n projectRoot,\n // \u672B\u5C3E\u659C\u6760\u53BB\u6389,\u540E\u9762\u4E00\u5F8B\u9760 `${target}/xxx` \u62FC\n target: String(pick(\"target\") ?? DEFAULT_TARGET).replace(/\\/+$/, \"\"),\n port,\n appDir: pick(\"appDir\") ?? detectAppDir(projectRoot),\n designDir: pick(\"designDir\") ?? DEFAULT_DESIGN_DIR,\n }\n}\n\n/** app \u76EE\u5F55\u63A2\u6D4B:\u5B58\u5728 src/app \u7528 src/app,\u5426\u5219 app */\nfunction detectAppDir(projectRoot: string): string {\n return fs.existsSync(path.join(projectRoot, \"src\", \"app\")) ? \"src/app\" : \"app\"\n}\n", "// ============================================================\n// [Agent B] \u6CE8\u5165 / \u5378\u8F7D Next \u4FA7\u6587\u4EF6 + \u751F\u6210\u753B\u677F registry\n// \u7B7E\u540D\u51BB\u7ED3,\u89C1 CONTRACTS.md\n// ============================================================\nimport { promises as fs } from \"node:fs\"\nimport path from \"node:path\"\nimport type { CsConfig, RegistryEntry } from \"../types.js\"\nimport {\n boundaryTemplate,\n pageTemplate,\n registryTemplate,\n routeTemplate,\n tokensTemplate,\n type RegistryItem,\n} from \"./templates.js\"\n\n/** \u6CE8\u5165\u8DEF\u7531\u7684\u6587\u4EF6\u5939\u540D:App Router \u91CC\u4E0B\u5212\u7EBF\u5F00\u5934\u662F private folder,\u5FC5\u987B\u5199\u6210 %5F \u8F6C\u4E49,URL \u5373 /__cs/... */\nconst CS_DIR = \"%5F%5Fcs\"\n\nconst GITIGNORE_BEGIN = \"# contactsheet begin\"\nconst GITIGNORE_END = \"# contactsheet end\"\n\n/** \u914D\u7F6E\u91CC\u7684\u76F8\u5BF9\u8DEF\u5F84\u7EDF\u4E00\u6210 posix\u3001\u65E0\u524D\u5BFC \"./\"\u3001\u65E0\u5C3E\u659C\u6760 */\nfunction normRel(p: string): string {\n return p.replace(/\\\\/g, \"/\").replace(/^\\.\\//, \"\").replace(/\\/+$/, \"\")\n}\n\n/** \u6CE8\u5165\u6839\u76EE\u5F55(repo \u76F8\u5BF9,posix) */\nfunction csDirRel(cfg: CsConfig): string {\n return normRel(cfg.appDir) + \"/\" + CS_DIR\n}\n\n/** \u4ECE\u67D0\u4E2A\u6CE8\u5165\u6587\u4EF6\u6240\u5728\u76EE\u5F55 import \u5230 <designDir>/__generated__/registry \u7684\u76F8\u5BF9\u8BF4\u660E\u7B26 */\nfunction registryImportFrom(fromDirRel: string, cfg: CsConfig): string {\n const target = normRel(cfg.designDir) + \"/__generated__/registry\"\n const rel = path.posix.relative(fromDirRel, target)\n return rel.startsWith(\".\") ? rel : \"./\" + rel\n}\n\nasync function readOr(file: string, fallback: string | null): Promise<string | null> {\n try {\n return await fs.readFile(file, \"utf8\")\n } catch {\n return fallback\n }\n}\n\n/** \u5185\u5BB9\u76F8\u540C\u5C31\u4E0D\u5199:\u907F\u514D\u52A8 mtime \u89E6\u53D1 Next \u65E0\u8C13\u91CD\u7F16\u8BD1 */\nasync function writeIfChanged(file: string, content: string): Promise<boolean> {\n if ((await readOr(file, null)) === content) return false\n await fs.mkdir(path.dirname(file), { recursive: true })\n await fs.writeFile(file, content, \"utf8\")\n return true\n}\n\n/** \u5B9A\u4F4D .gitignore \u91CC\u7684 contactsheet \u5757(\u542B\u9996\u5C3E\u6807\u8BB0) */\nfunction findBlock(text: string): { start: number; end: number } | null {\n const start = text.indexOf(GITIGNORE_BEGIN)\n if (start < 0) return null\n const at = text.indexOf(GITIGNORE_END, start)\n if (at < 0) return null\n return { start, end: at + GITIGNORE_END.length }\n}\n\nfunction gitignoreBlock(cfg: CsConfig): string {\n const design = normRel(cfg.designDir)\n return [GITIGNORE_BEGIN, csDirRel(cfg) + \"/\", design + \"/__generated__/\", design + \"/.canvas/\", GITIGNORE_END].join(\n \"\\n\"\n )\n}\n\n/** \u5E42\u7B49\u5199 .gitignore:\u6709\u65E7\u5757\u6574\u5757\u66FF\u6362(\u6A21\u677F\u5347\u7EA7),\u6CA1\u6709\u5C31\u8FFD\u52A0 */\nasync function updateGitignore(cfg: CsConfig): Promise<void> {\n const file = path.join(cfg.projectRoot, \".gitignore\")\n const old = (await readOr(file, \"\")) as string\n const block = gitignoreBlock(cfg)\n const found = findBlock(old)\n const next = found\n ? old.slice(0, found.start) + block + old.slice(found.end)\n : (old.trimEnd() ? old.trimEnd() + \"\\n\\n\" : \"\") + block + \"\\n\"\n await writeIfChanged(file, next)\n}\n\nasync function removeGitignoreBlock(cfg: CsConfig): Promise<void> {\n const file = path.join(cfg.projectRoot, \".gitignore\")\n const old = await readOr(file, null)\n if (old === null) return\n const found = findBlock(old)\n if (!found) return\n const left = (old.slice(0, found.start) + old.slice(found.end)).replace(/\\n{3,}/g, \"\\n\\n\").trimEnd()\n await writeIfChanged(file, left ? left + \"\\n\" : \"\")\n}\n\n/** \u5199/\u66F4\u65B0\u5168\u90E8\u6CE8\u5165\u6587\u4EF6 + gitignore */\nexport async function ensureInjected(cfg: CsConfig): Promise<void> {\n const root = cfg.projectRoot\n const designAbs = path.join(root, normRel(cfg.designDir))\n await fs.mkdir(designAbs, { recursive: true })\n await fs.mkdir(path.join(designAbs, \".canvas\"), { recursive: true })\n\n const abDirRel = csDirRel(cfg) + \"/ab/[id]\"\n await writeIfChanged(path.join(root, abDirRel, \"page.tsx\"), pageTemplate(registryImportFrom(abDirRel, cfg)))\n await writeIfChanged(path.join(root, abDirRel, \"boundary.tsx\"), boundaryTemplate())\n\n const routeDirRel = csDirRel(cfg) + \"/registry\"\n await writeIfChanged(path.join(root, routeDirRel, \"route.ts\"), routeTemplate(registryImportFrom(routeDirRel, cfg)))\n\n await writeIfChanged(path.join(root, csDirRel(cfg), \"tokens\", \"page.tsx\"), tokensTemplate())\n\n await updateGitignore(cfg)\n // \u5148\u4FDD\u8BC1 page/route \u7684 import \u76EE\u6807\u5B58\u5728,\u514D\u5F97 watcher \u9996\u6B21\u5237\u65B0\u524D\u6253\u5F00\u753B\u677F\u62A5\u89E3\u6790\u5931\u8D25\n await regenerateRegistry(cfg)\n}\n\n/** clean \u547D\u4EE4:\u5220\u6CE8\u5165\u76EE\u5F55\u4E0E\u751F\u6210\u7269,design \u4E0B\u7684\u7528\u6237\u753B\u677F\u4E0D\u52A8 */\nexport async function removeInjected(cfg: CsConfig): Promise<void> {\n await fs.rm(path.join(cfg.projectRoot, csDirRel(cfg)), { recursive: true, force: true })\n await fs.rm(path.join(cfg.projectRoot, normRel(cfg.designDir), \"__generated__\"), { recursive: true, force: true })\n await removeGitignoreBlock(cfg)\n}\n\n/** \u9012\u5F52\u626B designDir,\u8FD4\u56DE *.artboard.{tsx,ts} \u7684 posix \u76F8\u5BF9\u8DEF\u5F84 */\nasync function scanArtboards(designAbs: string, sub = \"\"): Promise<string[]> {\n let dirents\n try {\n dirents = await fs.readdir(path.join(designAbs, sub), { withFileTypes: true })\n } catch {\n return [] // design \u76EE\u5F55\u4E0D\u5B58\u5728\n }\n const out: string[] = []\n for (const d of dirents) {\n const rel = sub ? sub + \"/\" + d.name : d.name\n if (d.isDirectory()) {\n // \u5FFD\u7565\u751F\u6210\u7269\u3001\u753B\u5E03\u6570\u636E(.canvas)\u4E0E\u4EFB\u4F55\u9690\u85CF\u76EE\u5F55\n if (d.name === \"__generated__\" || d.name === \"node_modules\" || d.name.startsWith(\".\")) continue\n out.push(...(await scanArtboards(designAbs, rel)))\n } else if (/\\.artboard\\.tsx?$/.test(d.name)) {\n out.push(rel)\n }\n }\n return out\n}\n\n/** \u6B63\u5219\u63D0\u53D6 export const \u540D(v1 \u63A5\u53D7\u5176\u5C40\u9650,\u89C1 CONTRACTS) */\nfunction extractExports(source: string): string[] {\n const re = /^export\\s+const\\s+([\\p{L}\\w$]+)/gmu\n const names: string[] = []\n let m: RegExpExecArray | null\n while ((m = re.exec(source)) !== null) {\n if (!names.includes(m[1])) names.push(m[1])\n }\n return names\n}\n\n/** fileSlug:designDir \u4E0B\u76F8\u5BF9\u8DEF\u5F84\u53BB\u6389 .artboard.tsx?,\"/\" \u2192 \"__\" */\nfunction slugOf(rel: string): string {\n return rel.replace(/\\.artboard\\.tsx?$/, \"\").replace(/\\//g, \"__\")\n}\n\n/** \u626B\u63CF + \u91CD\u5199 <designDir>/__generated__/registry.tsx,\u8FD4\u56DE\u6761\u76EE(args/env \u7559 undefined,\u771F\u503C\u7531 Next \u4FA7 route \u7ED9) */\nexport async function regenerateRegistry(cfg: CsConfig): Promise<RegistryEntry[]> {\n const designRel = normRel(cfg.designDir)\n const designAbs = path.join(cfg.projectRoot, designRel)\n const rels = (await scanArtboards(designAbs)).sort()\n\n const items: RegistryItem[] = []\n const entries: RegistryEntry[] = []\n for (const rel of rels) {\n const source = await readOr(path.join(designAbs, rel), null)\n if (source === null) continue // \u626B\u63CF\u540E\u88AB\u5220,\u8DF3\u8FC7\n const names = extractExports(source)\n if (names.length === 0) continue // \u6CA1\u6709 export const \u7684\u6587\u4EF6\u4E0D\u8FDB registry\n const slug = slugOf(rel)\n const file = designRel + \"/\" + rel\n items.push({\n varName: \"m\" + items.length,\n // registry.tsx \u5728 <designDir>/__generated__/ \u4E0B,\u4E0A\u4E00\u7EA7\u5C31\u662F designDir\n importPath: \"../\" + rel.replace(/\\.tsx?$/, \"\"),\n slug,\n file,\n })\n for (const exportName of names) {\n // kind \u8FD9\u91CC\u4E00\u5F8B component,screen \u7531 Next \u4FA7 registry route \u6309\u6709\u6CA1\u6709 url \u5224\u771F\u503C\n entries.push({ id: slug + \"--\" + exportName, file, exportName, kind: \"component\" })\n }\n }\n\n await writeIfChanged(path.join(designAbs, \"__generated__\", \"registry.tsx\"), registryTemplate(items))\n return entries\n}\n", "// ============================================================\n// [Agent B] \u6CE8\u5165\u5230\u7528\u6237 Next \u9879\u76EE\u7684\u6587\u4EF6\u6A21\u677F\n// \u672C\u4ED3\u5E93 tsconfig \u4E0D\u7F16\u8BD1 JSX,\u6240\u4EE5\u5168\u90E8\u4EE5\u6A21\u677F\u5B57\u7B26\u4E32\u5F62\u5F0F\u5B58\u653E\u3002\n// \u4E00\u5F8B\u7528 String.raw:\u6A21\u677F\u91CC\u51FA\u73B0\u7684\u53CD\u659C\u6760(\u5982 \"\\\\u003c\")\u539F\u6837\u843D\u5230\u751F\u6210\u6587\u4EF6,\n// \u53EA\u6709 ${...} \u4F1A\u88AB\u66FF\u6362 \u2014\u2014 \u751F\u6210\u7684\u4EE3\u7801\u91CC\u4E0D\u8981\u51FA\u73B0\u53CD\u5F15\u53F7\u548C\u5176\u5B83 ${\u3002\n// ============================================================\n\n/** design/__generated__/registry \u91CC\u7684\u4E00\u6761 import \u63CF\u8FF0 */\nexport interface RegistryItem {\n /** \u6A21\u5757\u53D8\u91CF\u540D m0 / m1 \u2026 */\n varName: string\n /** \u76F8\u5BF9 __generated__ \u76EE\u5F55\u7684 import \u8BF4\u660E\u7B26,\u5982 \"../Button.artboard\" */\n importPath: string\n /** modules / files \u7684 key,\u5373 fileSlug */\n slug: string\n /** repo \u76F8\u5BF9\u8DEF\u5F84,\u5982 \"design/Button.artboard.tsx\" */\n file: string\n}\n\nconst HEADER = \"// \u7531 contactsheet \u81EA\u52A8\u751F\u6210 \u2014\u2014 \u8BF7\u52FF\u7F16\u8F91,\u4E0B\u6B21\u542F\u52A8\u4F1A\u88AB\u8986\u76D6\\n\"\n\n/** <appDir>/%5F%5Fcs/ab/[id]/page.tsx \u2014\u2014 \u753B\u677F\u8DEF\u7531(server component) */\nexport function pageTemplate(registryImport: string): string {\n return (\n HEADER +\n String.raw`import { Suspense } from \"react\"\nimport { notFound } from \"next/navigation\"\nimport { modules } from \"${registryImport}\"\nimport { CsErrorBoundary, CsErrorCard } from \"./boundary\"\n\n// \u7C7B\u578B\u4E00\u5F8B\u7528 any:\u4E0D\u4F9D\u8D56\u7528\u6237\u9879\u76EE\u7684 Next typegen(PageProps<\"...\"> \u8981\u6C42 .next/types \u5DF2\u751F\u6210)\n\n// Next 16 \u7684 params \u4E0D\u89E3\u7801\u767E\u5206\u53F7\u8F6C\u4E49(\u5B9E\u6D4B params.id = \"Button--%E9%BB%98%E8%AE%A4\"),\u8FD9\u91CC\u81EA\u5DF1\u89E3\nfunction decodeId(raw: string): string {\n try {\n return decodeURIComponent(raw)\n } catch {\n return raw // \u6587\u4EF6\u540D\u91CC\u771F\u5E26 % \u65F6 decode \u4F1A\u629B,\u9000\u56DE\u539F\u4E32\n }\n}\n\n// id = fileSlug + \"--\" + exportName;exportName \u4E0D\u542B \"-\",\u6240\u4EE5\u6309\u6700\u540E\u4E00\u4E2A \"--\" \u5207\nfunction lookupEntry(id: string): any {\n const i = id.lastIndexOf(\"--\")\n if (i <= 0) return null\n const mod: any = (modules as any)[id.slice(0, i)]\n if (!mod) return null\n return mod[id.slice(i + 2)] ?? null\n}\n\n// ?args= \u662F encodeURIComponent(JSON.stringify(args)),Next \u5DF2\u89E3\u7801\u4E00\u5C42,\u8FD9\u91CC\u53EA\u9700 JSON.parse\nfunction parseArgs(raw: any): any {\n if (typeof raw !== \"string\" || raw.length === 0) return {}\n try {\n const v = JSON.parse(raw)\n return v && typeof v === \"object\" ? v : {}\n } catch {\n return {}\n }\n}\n\n// \u9ED8\u8BA4\u65E0\u5E95\u8272(\u88F8\u653E\u753B\u5E03);\u5E95\u8272\u7531\u5916\u58F3\u6309\u6BCF\u677F\u5F00\u5173\u6CE8\u5165(\u5927\u90E8\u5206\u7EC4\u4EF6\u81EA\u5E26 surface,\u65E0\u5E95\u8272\u7684\u4E00\u952E\u5207\u6362)\n// \u4E0D\u7559\u5185\u8FB9\u8DDD:wrapper \u4E00\u65E6\u6709 padding,\u7EC4\u4EF6\u7684\u9AD8\u4EAE\u6846\u5C31\u6C38\u8FDC\u6BD4\u53EF\u89C1\u7684\u767D\u5E95\u5C0F\u4E00\u5708(\u5B9E\u6D4B 390 \u5BBD\u7684\u677F\n// \u56DB\u5468\u5404\u5DEE 16px),\u4E24\u8005\u5BF9\u4E0D\u9F50\u3002\u7559\u767D\u4EA4\u7ED9\u7EC4\u4EF6\u81EA\u5DF1,\u753B\u677F\u7684\u5E95\u5C31\u7B49\u4E8E\u7EC4\u4EF6\u7684\u76D2\u5B50\u3002\nconst wrap: any = {}\n// \u63D0\u793A\u4E0E\u9519\u8BEF\u5361\u4E0D\u662F\u88AB\u5BA1\u89C6\u7684\u7EC4\u4EF6,\u8D34\u8FB9\u53CD\u800C\u6324,\u5355\u72EC\u7559\u5185\u8FB9\u8DDD\nconst padded: any = { padding: 16 }\nconst hint: any = { font: \"13px/1.6 ui-monospace, SFMono-Regular, Menlo, monospace\", color: \"#666\" }\nconst loading: any = { font: \"12px/1.5 ui-monospace, SFMono-Regular, Menlo, monospace\", opacity: 0.5 }\n\nexport default async function Page(props: any) {\n if (process.env.NODE_ENV === \"production\") notFound() // \u751F\u4EA7\u6784\u5EFA\u91CC\u8FD9\u6761\u8DEF\u4E0D\u5B58\u5728\n const params: any = await props.params\n const searchParams: any = await props.searchParams\n const id: string = decodeId(String(params?.id ?? \"\"))\n const entry: any = lookupEntry(id)\n if (!entry) notFound()\n\n const kind: string = typeof entry.url === \"string\" ? \"screen\" : \"component\"\n const args: any = { ...(entry.args ?? {}), ...parseArgs(searchParams?.args) }\n // \u8F6C\u4E49 \"<\" \u9632\u6B62 args \u91CC\u7684\u5B57\u7B26\u4E32\u63D0\u524D\u95ED\u5408 script \u6807\u7B7E(JSON \u91CC < \u89E3\u6790\u56DE \"<\")\n const meta: string = JSON.stringify({ id, args, env: entry.env, kind }).replace(/</g, \"\\\\u003c\")\n const metaTag = <script type=\"application/json\" id=\"__cs_meta\" dangerouslySetInnerHTML={{ __html: meta }} />\n\n // \u9875\u9762\u753B\u677F\u7531\u5916\u58F3\u76F4\u63A5 iframe \u76EE\u6807 url,\u4E0D\u5728\u8FD9\u6761\u8DEF\u7531\u6E32\u67D3\n if (kind === \"screen\") {\n return (\n <div data-cs-artboard={id} style={padded}>\n {metaTag}\n <p style={hint}>\u9875\u9762\u753B\u677F:\u8BF7\u76F4\u63A5\u6253\u5F00 {entry.url}</p>\n </div>\n )\n }\n\n if (typeof entry.render !== \"function\") {\n return (\n <div data-cs-artboard={id} style={padded}>\n {metaTag}\n <CsErrorCard name={id} error=\"\u753B\u677F\u65E2\u6CA1\u6709 render(args) \u4E5F\u6CA1\u6709 url\" />\n </div>\n )\n }\n\n // render \u81EA\u5DF1\u540C\u6B65\u629B\u9519\u65F6 ErrorBoundary \u591F\u4E0D\u7740,\u8FD9\u91CC\u515C\u4E00\u5C42\n let node: any = null\n try {\n node = entry.render(args)\n } catch (err: any) {\n return (\n <div data-cs-artboard={id} style={padded}>\n {metaTag}\n <CsErrorCard name={id} error={String(err?.message ?? err)} />\n </div>\n )\n }\n\n // \u6CA1\u58F0\u660E env.width \u7684\u7EC4\u4EF6\u753B\u677F\u6536\u7F29\u5230\u5185\u5BB9\u5BBD(shrink-wrap),\u5916\u58F3\u6309\u5B83\u5B9A iframe \u5BBD \u2014\u2014 \"\u88F8\u653E\u5728\u753B\u5E03\u4E0A\"\n const wrapStyle: any = entry.env && entry.env.width ? wrap : { ...wrap, width: \"fit-content\" }\n\n return (\n <div data-cs-artboard={id} style={wrapStyle}>\n {metaTag}\n <CsErrorBoundary name={id}>\n <Suspense fallback={<div style={loading}>loading\u2026</div>}>{node}</Suspense>\n </CsErrorBoundary>\n </div>\n )\n}\n`\n )\n}\n\n/** <appDir>/%5F%5Fcs/ab/[id]/boundary.tsx \u2014\u2014 \u753B\u677F\u5D29\u6E83\u65F6\u663E\u793A\u7EA2\u8272\u865A\u7EBF\u9519\u8BEF\u5361 */\nexport function boundaryTemplate(): string {\n return (\n HEADER +\n String.raw`\"use client\"\nimport React from \"react\"\n\nconst cardStyle: any = {\n border: \"1px dashed #e5484d\",\n borderRadius: 6,\n background: \"#fff5f5\",\n color: \"#c62a2f\",\n padding: \"10px 12px\",\n font: \"12px/1.5 ui-monospace, SFMono-Regular, Menlo, monospace\",\n whiteSpace: \"pre-wrap\",\n wordBreak: \"break-word\",\n}\n\nexport function CsErrorCard(props: any) {\n return (\n <div style={cardStyle} data-cs-error=\"1\">\n <div style={{ fontWeight: 700, marginBottom: 4 }}>{props.name}</div>\n <div>{props.error}</div>\n </div>\n )\n}\n\nexport class CsErrorBoundary extends React.Component<any, any> {\n constructor(props: any) {\n super(props)\n this.state = { error: null }\n }\n static getDerivedStateFromError(error: any) {\n return { error: String(error?.message ?? error) }\n }\n render() {\n if (this.state.error) return <CsErrorCard name={this.props.name} error={this.state.error} />\n return this.props.children\n }\n}\n`\n )\n}\n\n/** <appDir>/%5F%5Fcs/registry/route.ts \u2014\u2014 GET \u8FD4\u56DE RegistryEntry[] */\nexport function routeTemplate(registryImport: string): string {\n return (\n HEADER +\n String.raw`import { modules, files } from \"${registryImport}\"\n\n// \u4E0D\u8981\u52A0 export const dynamic = \"force-dynamic\":\u5B83\u4E0E Next 16 \u7684 cacheComponents \u4E92\u65A5,\n// \u7528\u6237\u5F00\u4E86\u90A3\u4E2A\u914D\u7F6E\u4F1A\u8BA9 registry/ab/tokens \u4E09\u6761\u8DEF\u7531\u540C\u65F6 500,\u4E14\u62A5\u9519\u6307\u5411\u7528\u6237\u81EA\u5DF1\u7684 next.config\u3002\n// dev \u4E0B route handler \u672C\u6765\u5C31\u4E0D\u7F13\u5B58,production \u4E0B\u8FD9\u6761\u8DEF\u7531\u76F4\u63A5 404,\u52A0\u5B83\u6CA1\u6709\u6536\u76CA\u3002\n\n// GET /__cs/registry \u2192 RegistryEntry[];kind \u5728\u8FD9\u91CC\u5224\u771F\u503C:\u6709 url \u662F screen,\u6709 render \u662F component\nexport async function GET() {\n if (process.env.NODE_ENV === \"production\") return new Response(\"Not Found\", { status: 404 })\n\n const entries: any[] = []\n for (const slug of Object.keys(modules as any)) {\n const mod: any = (modules as any)[slug]\n if (!mod) continue\n for (const exportName of Object.keys(mod)) {\n const v: any = mod[exportName]\n if (!v || typeof v !== \"object\") continue\n // \u6CA1\u6709 render \u4E5F\u6CA1\u6709 url \u7684\u5BF9\u8C61\u7167\u6837\u8FDB\u6CE8\u518C\u8868(\u6309 component):\u5899\u4E0A\u51FA\u9519\u8BEF\u5361,\n // \u800C\u4E0D\u662F\u9759\u9ED8\u6D88\u5931 \u2014\u2014 \u7528\u6237\u628A render \u6572\u9519\u65F6\u5FC5\u987B\u6709\u53CD\u9988\n const kind = typeof v.url === \"string\" ? \"screen\" : \"component\"\n entries.push({\n id: slug + \"--\" + exportName,\n file: (files as any)[slug] ?? \"\",\n exportName,\n kind,\n args: v.args,\n env: v.env,\n url: v.url,\n })\n }\n }\n return Response.json(entries)\n}\n`\n )\n}\n\n/** <appDir>/%5F%5Fcs/tokens/page.tsx \u2014\u2014 \u8BBE\u8BA1\u53D8\u91CF\u603B\u89C8(client) */\nexport function tokensTemplate(): string {\n return (\n HEADER +\n String.raw`\"use client\"\nimport { useEffect, useState } from \"react\"\n\ntype Token = { name: string; value: string }\n\n// \u679A\u4E3E\u540C\u6E90\u6837\u5F0F\u8868\u91CC :root / :host / html \u4E0B\u7684\u81EA\u5B9A\u4E49\u5C5E\u6027\n// (Tailwind v4 \u7684 @theme \u7F16\u8BD1\u540E\u5C31\u662F @layer theme \u91CC\u7684 \":root, :host\",\u9760\u9012\u5F52 cssRules \u62FF\u5230)\nfunction collectTokens(): Token[] {\n const found = new Map<string, string>()\n const visit = (rules: any) => {\n if (!rules) return\n for (let i = 0; i < rules.length; i++) {\n const rule: any = rules[i]\n if (rule.cssRules) visit(rule.cssRules)\n const style: any = rule.style\n if (!style) continue\n const sel: string = typeof rule.selectorText === \"string\" ? rule.selectorText : \"\"\n if (sel && !/:root|:host|(^|,)\\s*html\\b/.test(sel)) continue\n for (let k = 0; k < style.length; k++) {\n const prop: string = style[k]\n if (prop && prop.slice(0, 2) === \"--\") found.set(prop, String(style.getPropertyValue(prop)).trim())\n }\n }\n }\n for (let i = 0; i < document.styleSheets.length; i++) {\n try {\n visit((document.styleSheets[i] as any).cssRules)\n } catch {\n // \u8DE8\u57DF\u6837\u5F0F\u8868\u8BFB\u4E0D\u5230 cssRules,\u8DF3\u8FC7\n }\n }\n return Array.from(found, ([name, value]) => ({ name, value })).sort((a, b) => a.name.localeCompare(b.name))\n}\n\n// \u503C\u672C\u8EAB\u5C31\u662F\u989C\u8272\u7684(shadcn \u7684 --primary / --background \u8FD9\u4E9B\u6CA1\u6709 --color- \u524D\u7F00)\u4E5F\u7ED9\u65B9\u5757\nfunction isColorValue(v: string): boolean {\n return /^(#|rgba?\\(|hsla?\\(|hwb\\(|lab\\(|lch\\(|oklab\\(|oklch\\(|color\\()/i.test(v)\n}\n\nconst mono = \"12px/1.5 ui-monospace, SFMono-Regular, Menlo, monospace\"\nconst page: any = { padding: 24, font: mono, color: \"#111\", background: \"#fff\", minHeight: \"100vh\" }\nconst h2: any = { font: \"600 13px/1.5 ui-monospace, SFMono-Regular, Menlo, monospace\", margin: \"24px 0 10px\", color: \"#555\" }\nconst grid: any = { display: \"grid\", gridTemplateColumns: \"repeat(auto-fill, minmax(190px, 1fr))\", gap: 12 }\nconst cell: any = { border: \"1px solid #eee\", borderRadius: 6, padding: 10, overflow: \"hidden\" }\nconst nameStyle: any = { fontWeight: 600, wordBreak: \"break-all\" }\nconst valueStyle: any = { color: \"#888\", wordBreak: \"break-all\" }\n\nfunction Cell(props: any) {\n return (\n <div style={cell}>\n {props.children}\n <div style={nameStyle}>{props.token.name}</div>\n <div style={valueStyle}>{props.token.value}</div>\n </div>\n )\n}\n\nfunction Group(props: any) {\n if (props.tokens.length === 0) return null\n return (\n <section>\n <h2 style={h2}>\n {props.title} \u00B7 {props.tokens.length}\n </h2>\n <div style={grid}>\n {props.tokens.map((t: Token) => (\n <Cell key={t.name} token={t}>\n {props.kind === \"color\" || isColorValue(t.value) ? (\n <div\n style={{\n height: 44,\n marginBottom: 8,\n borderRadius: 4,\n border: \"1px solid rgba(0,0,0,.1)\",\n background: \"var(\" + t.name + \")\",\n }}\n />\n ) : null}\n {props.kind === \"radius\" ? (\n <div\n style={{\n height: 44,\n marginBottom: 8,\n border: \"1px solid #ddd\",\n background: \"#f6f6f6\",\n borderRadius: \"var(\" + t.name + \")\",\n }}\n />\n ) : null}\n </Cell>\n ))}\n </div>\n </section>\n )\n}\n\nexport default function TokensPage() {\n const [tokens, setTokens] = useState<Token[]>([])\n useEffect(() => {\n setTokens(collectTokens())\n }, [])\n\n if (process.env.NODE_ENV === \"production\") return null // \u751F\u4EA7\u91CC\u8FD9\u9875\u4E0D\u51FA\u73B0\n\n const pick = (p: string) => tokens.filter((t) => t.name.indexOf(p) === 0)\n const known = [\"--color-\", \"--radius-\", \"--font-\", \"--spacing-\"]\n const rest = tokens.filter((t) => !known.some((p) => t.name.indexOf(p) === 0))\n\n return (\n <main style={page}>\n <div style={{ font: mono, color: \"#888\" }}>contactsheet \u00B7 design tokens \u00B7 \u5171 {tokens.length} \u4E2A\u81EA\u5B9A\u4E49\u5C5E\u6027</div>\n {tokens.length === 0 ? (\n <p style={{ color: \"#888\", marginTop: 16 }}>\u6CA1\u8BFB\u5230\u81EA\u5B9A\u4E49\u5C5E\u6027(\u6837\u5F0F\u8868\u53EF\u80FD\u8FD8\u6CA1\u52A0\u8F7D\u5B8C,\u6216\u90FD\u662F\u8DE8\u57DF\u7684)\u3002</p>\n ) : null}\n <Group title=\"\u989C\u8272 --color-*\" kind=\"color\" tokens={pick(\"--color-\")} />\n <Group title=\"\u5706\u89D2 --radius-*\" kind=\"radius\" tokens={pick(\"--radius-\")} />\n <Group title=\"\u5B57\u4F53 --font-*\" kind=\"text\" tokens={pick(\"--font-\")} />\n <Group title=\"\u95F4\u8DDD --spacing-*\" kind=\"text\" tokens={pick(\"--spacing-\")} />\n <Group title=\"\u5176\u5B83\" kind=\"text\" tokens={rest} />\n </main>\n )\n}\n`\n )\n}\n\n/** <designDir>/__generated__/registry.tsx \u2014\u2014 watcher \u751F\u6210\u7684\u753B\u677F\u7D22\u5F15 */\nexport function registryTemplate(items: RegistryItem[]): string {\n const imports = items.map((it) => 'import * as ' + it.varName + ' from \"' + it.importPath + '\"').join(\"\\n\")\n const mods = items.map((it) => ' \"' + it.slug + '\": ' + it.varName + \",\").join(\"\\n\")\n const fileMap = items.map((it) => ' \"' + it.slug + '\": \"' + it.file + '\",').join(\"\\n\")\n return (\n \"// \u7531 contactsheet \u81EA\u52A8\u751F\u6210 \u2014\u2014 \u8BF7\u52FF\u7F16\u8F91,\u753B\u677F\u6587\u4EF6\u589E\u5220\u6539\u540E\u4F1A\u88AB\u91CD\u5199\\n\" +\n (imports ? imports + \"\\n\\n\" : \"\") +\n \"export const modules: Record<string, Record<string, unknown>> = \" +\n (items.length ? \"{\\n\" + mods + \"\\n}\\n\" : \"{}\\n\") +\n \"\\n// fileSlug \u2192 repo \u76F8\u5BF9\u8DEF\u5F84,\u7ED9 /__cs/registry \u586B RegistryEntry.file\\n\" +\n \"export const files: Record<string, string> = \" +\n (items.length ? \"{\\n\" + fileMap + \"\\n}\\n\" : \"{}\\n\")\n )\n}\n", "// [Agent E] contactsheet init \u2014\u2014 \u628A contactsheet \u63A5\u5230\u4E00\u4E2A\u5DF2\u6709\u7684 Next.js \u9879\u76EE\u4E0A\n// \u94C1\u5F8B:\u6240\u6709 JSON \u90FD\u662F\u5408\u5E76\u5199\u5165,\u7528\u6237\u5DF2\u6709\u7684\u5185\u5BB9\u4E00\u4E2A\u5B57\u90FD\u4E0D\u80FD\u4E22;\u770B\u4E0D\u61C2\u7684\u6587\u4EF6\u5B81\u53EF\u4E2D\u6B62\u4E5F\u4E0D\u8986\u76D6\u3002\n// \u53EA\u7528 node \u5185\u5EFA\u3002\n\nimport { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from \"node:fs\"\nimport { dirname, join, relative, resolve } from \"node:path\"\nimport type { CsConfig } from \"../types.js\"\nimport { bold, cyan, dim, green, link, ok } from \"../term.js\"\n\nconst DEFAULT_TARGET = \"http://localhost:3000\"\nconst DEFAULT_PORT = 5199\nconst DEFAULT_DESIGN_DIR = \"design\"\n\n/** \u7528\u6237\u9879\u76EE\u91CC shadcn \u7EC4\u4EF6\u7684\u5E38\u89C1\u843D\u70B9,\u6309\u987A\u5E8F\u63A2\u6D4B */\nconst UI_DIR_CANDIDATES = [\"components/ui\", \"src/components/ui\"]\n\n// ============================================================\n// \u5165\u53E3\n// ============================================================\n\nexport async function runInit(cwd: string, flags: Partial<CsConfig>): Promise<void> {\n const root = resolve(cwd)\n\n // a. \u5FC5\u987B\u662F\u4E2A Next.js \u9879\u76EE\n assertNextProject(root)\n\n // b. \u63A2\u6D4B appDir + \u5199\u914D\u7F6E\n const appDir = detectAppDir(root)\n const cfg = writeConfigFile(root, appDir, flags)\n console.log(`${bold(cyan(\"\u25C6\"))} ${bold(\"contactsheet init\")} ${dim(\"\u2014\u2014\")} ${root}`)\n console.log(ok(`app \u76EE\u5F55:${cfg.appDir}`))\n console.log(ok(`\u914D\u7F6E:contactsheet.config.json(target ${cfg.target},port ${cfg.port},\u753B\u677F\u76EE\u5F55 ${cfg.designDir})`))\n\n // c. .gitignore \u7531\u6CE8\u5165\u5668(contactsheet \u8FD0\u884C\u65F6)\u8D1F\u8D23,init \u4E0D\u78B0\n\n // d. \u81EA\u52A8\u94FA\u753B\u677F\n seedArtboards(root, cfg.designDir)\n\n // e. .mcp.json\n writeMcpJson(root, cfg.port)\n\n // f. .claude/settings.json \u7684 UserPromptSubmit hook\n writeClaudeHook(root, cfg.port)\n\n // g. \u4E0B\u4E00\u6B65\n console.log(\"\")\n console.log(bold(\"\u4E0B\u4E00\u6B65:\"))\n console.log(` 1. \u7167\u5E38\u8D77\u4F60\u81EA\u5DF1\u7684 dev server(next dev),\u786E\u8BA4\u5B83\u5728 ${cyan(cfg.target)}`)\n console.log(` 2. \u53E6\u5F00\u4E00\u4E2A\u7EC8\u7AEF:${cyan(\"npx contactsheet\")}`)\n console.log(` 3. \u6253\u5F00 ${link(`http://localhost:${cfg.port}/__cs`)}`)\n console.log(\"\")\n console.log(dim(\"\u7AEF\u53E3\u90FD\u53EF\u4EE5\u6362:dev server \u4E0D\u5728 \") + cfg.target + dim(\" \u5C31 --target <url>,\"))\n console.log(dim(` ${cfg.port} \u88AB\u5360\u5C31 --port <n>(\u6216\u6539 contactsheet.config.json \u540E\u91CD\u8DD1 init,MCP/hook \u4F1A\u8DDF\u7740\u6362)\u3002`))\n console.log(dim(` ${cfg.port} \u88AB\u522B\u7684\u8FDB\u7A0B\u5360\u7740\u65F6,contactsheet \u4F1A\u81EA\u52A8\u987A\u5EF6\u5230\u4E0B\u4E00\u4E2A\u7A7A\u95F2\u7AEF\u53E3\u5E76\u63D0\u793A\u3002`))\n}\n\n// ============================================================\n// a. Next \u9879\u76EE\u6821\u9A8C\n// ============================================================\n\nfunction assertNextProject(root: string): void {\n const pkgPath = join(root, \"package.json\")\n if (!existsSync(pkgPath)) {\n throw new Error(\n `contactsheet init \u4E2D\u6B62:${root} \u4E0B\u6CA1\u6709 package.json\u3002\\n` +\n `contactsheet \u662F\u9644\u7740\u5728\u4F60\u81EA\u5DF1\u7684 Next.js \u9879\u76EE\u4E0A\u8DD1\u7684,\u8BF7\u5230\u9879\u76EE\u6839\u76EE\u5F55\u518D\u6267\u884C\u4E00\u6B21\u3002`,\n )\n }\n const pkg = readJsonObject(pkgPath) ?? {}\n const deps = { ...asRecord(pkg[\"dependencies\"]), ...asRecord(pkg[\"devDependencies\"]) }\n if (!(\"next\" in deps)) {\n throw new Error(\n `contactsheet init \u4E2D\u6B62:${pkgPath} \u7684 dependencies / devDependencies \u91CC\u6CA1\u6709 next\u3002\\n` +\n `contactsheet v1 \u53EA\u8BA4 Next.js App Router \u9879\u76EE \u2014\u2014 \u5B83\u9760\u5F80\u4F60\u7684 app \u76EE\u5F55\u6CE8\u5165\u4E00\u6761\u753B\u677F\u8DEF\u7531\u5E72\u6D3B,\\n` +\n `\u6E32\u67D3\u540E\u7AEF\u5C31\u662F\u4F60\u81EA\u5DF1\u7684 next dev,\u6CA1\u6709 Next \u5C31\u6CA1\u6709\u753B\u677F\u3002`,\n )\n }\n}\n\n// ============================================================\n// b. appDir \u63A2\u6D4B + \u914D\u7F6E\u6587\u4EF6\n// ============================================================\n\n/** src/app \u4F18\u5148\u4E8E app;\u90FD\u6CA1\u6709\u8BF4\u660E\u4E0D\u662F App Router \u9879\u76EE */\nfunction detectAppDir(root: string): string {\n for (const candidate of [\"src/app\", \"app\"]) {\n if (isDir(join(root, candidate))) return candidate\n }\n throw new Error(\n `contactsheet init \u4E2D\u6B62:${root} \u4E0B\u65E2\u6CA1\u6709 src/app/ \u4E5F\u6CA1\u6709 app/\u3002\\n` +\n `contactsheet v1 \u53EA\u652F\u6301 App Router(\u753B\u677F\u8DEF\u7531\u8981\u6CE8\u5165\u5230 app \u76EE\u5F55\u91CC)\u3002Pages Router \u9879\u76EE\u6682\u65F6\u7528\u4E0D\u4E86\u3002`,\n )\n}\n\n/** \u4ECE package.json \u7684 dev script \u91CC\u8BA4\u7AEF\u53E3(next dev -p 3100 / --port 3100 / PORT=3100),\n * \u8BA4\u51FA\u6765\u975E 3000 \u5C31\u5F53\u9ED8\u8BA4 target \u2014\u2014 \u7528\u6237\u8DD1\u7684\u672C\u6765\u5C31\u4E0D\u662F 3000 \u65F6,\u522B\u518D\u8BA9\u4ED6\u624B\u6539\u914D\u7F6E */\nfunction detectDevTarget(root: string): string | null {\n try {\n const pkg = JSON.parse(readFileSync(join(root, \"package.json\"), \"utf8\")) as {\n scripts?: Record<string, string>\n }\n const dev = pkg.scripts?.[\"dev\"] ?? \"\"\n const m = dev.match(/(?:-p|--port)[ =](\\d{2,5})/) ?? dev.match(/\\bPORT=(\\d{2,5})/)\n if (m && m[1] !== \"3000\") return `http://localhost:${m[1]}`\n } catch {\n /* \u8BFB\u4E0D\u5230\u5C31\u7528\u9ED8\u8BA4 */\n }\n return null\n}\n\nfunction writeConfigFile(root: string, appDir: string, flags: Partial<CsConfig>): CsConfig {\n const file = join(root, \"contactsheet.config.json\")\n const existing = readJsonObject(file) ?? {}\n\n // \u4F18\u5148\u7EA7:CLI flags > \u7528\u6237\u5DF2\u6709\u914D\u7F6E > \u63A2\u6D4B/\u9ED8\u8BA4\u503C\u3002\u7528\u6237\u624B\u6539\u8FC7\u7684\u503C\u4E0D\u4F1A\u88AB init \u62B9\u6389\u3002\n const resolved = {\n target: pickString(flags.target, existing[\"target\"], detectDevTarget(root) ?? DEFAULT_TARGET),\n port: pickNumber(flags.port, existing[\"port\"], DEFAULT_PORT),\n appDir: pickString(flags.appDir, existing[\"appDir\"], appDir),\n designDir: pickString(flags.designDir, existing[\"designDir\"], DEFAULT_DESIGN_DIR),\n }\n\n // \u5C55\u5F00 existing \u5728\u524D:\u7528\u6237\u52A0\u7684\u989D\u5916\u5B57\u6BB5\u539F\u6837\u4FDD\u7559,\u952E\u987A\u5E8F\u4E5F\u7A33\u5B9A(\u91CD\u590D\u8DD1 init \u5185\u5BB9\u4E0D\u53D8)\n writeJsonFile(file, { ...existing, ...resolved })\n\n return { projectRoot: root, ...resolved }\n}\n\n// ============================================================\n// d. \u81EA\u52A8\u94FA\u753B\u677F\n// ============================================================\n\nfunction seedArtboards(root: string, designDir: string): void {\n const uiDir = UI_DIR_CANDIDATES.map((p) => join(root, p)).find(isDir)\n if (!uiDir) {\n console.log(` \u753B\u677F:\u6CA1\u627E\u5230 components/ui/,\u8DF3\u8FC7\u81EA\u52A8\u94FA\u753B\u677F(\u624B\u5199 ${designDir}/*.artboard.tsx \u4E00\u6837\u7528)`)\n return\n }\n\n const files = readdirSync(uiDir)\n .filter((f) => f.endsWith(\".tsx\"))\n .sort()\n const targetDir = join(root, designDir)\n\n let created = 0\n let skipped = 0\n let unreadable = 0\n\n for (const base of files) {\n const componentFile = join(uiDir, base)\n const name = firstComponentExport(readFileSync(componentFile, \"utf8\"))\n if (!name) {\n unreadable++\n continue\n }\n const artboard = join(targetDir, `${name}.artboard.tsx`)\n if (existsSync(artboard)) {\n skipped++\n continue\n }\n mkdirSync(targetDir, { recursive: true })\n writeFileSync(artboard, artboardTemplate(name, importPathFor(root, designDir, componentFile)), \"utf8\")\n created++\n }\n\n console.log(ok(`\u753B\u677F:\u94FA\u4E86 ${green(String(created))} \u5757,\u8DF3\u8FC7 ${skipped} \u4E2A\u5DF2\u5B58\u5728`) + (unreadable ? `,${unreadable} \u4E2A\u6587\u4EF6\u6CA1\u8BA4\u51FA\u7EC4\u4EF6\u5BFC\u51FA` : \"\"))\n}\n\n/**\n * \u53D6\u6587\u4EF6\u91CC\u51FA\u73B0\u4F4D\u7F6E\u6700\u9760\u524D\u7684 PascalCase \u5BFC\u51FA\u3002\n * \u8BA4\u4E09\u79CD\u5199\u6CD5:export const X / export function X / export { X, Y }(\u542B\u8DE8\u884C\u4E0E as \u91CD\u547D\u540D)\u3002\n * v1 \u63A5\u53D7\u8FD9\u4E2A\u6B63\u5219\u7684\u5C40\u9650 \u2014\u2014 \u8BA4\u9519\u4E86\u5C31\u624B\u6539\u751F\u6210\u51FA\u6765\u7684\u753B\u677F\u6587\u4EF6\u3002\n */\nfunction firstComponentExport(source: string): string | null {\n const hits: Array<{ index: number; name: string }> = []\n\n const declRe = /^export\\s+(?:async\\s+)?(?:const|let|var|function|class)\\s+([A-Za-z_$][\\w$]*)/gm\n for (const m of source.matchAll(declRe)) {\n if (isPascal(m[1]!)) hits.push({ index: m.index ?? 0, name: m[1]! })\n }\n\n const listRe = /^export\\s*\\{([^}]*)\\}/gm\n for (const m of source.matchAll(listRe)) {\n for (const raw of m[1]!.split(\",\")) {\n const item = raw.trim()\n if (!item || item.startsWith(\"type \")) continue\n // `A as B` \u5BF9\u5916\u5BFC\u51FA\u7684\u662F B\n const parts = item.split(/\\s+as\\s+/)\n const name = parts[parts.length - 1]!.trim()\n if (isPascal(name)) {\n hits.push({ index: m.index ?? 0, name })\n break\n }\n }\n }\n\n if (hits.length === 0) return null\n hits.sort((a, b) => a.index - b.index)\n return hits[0]!.name\n}\n\nfunction isPascal(name: string): boolean {\n return /^[A-Z][A-Za-z0-9_$]*$/.test(name)\n}\n\n/** \u6709 @/* alias \u4E14\u7EC4\u4EF6\u786E\u5B9E\u5728 alias \u6307\u5411\u7684\u76EE\u5F55\u4E0B\u624D\u7528 alias,\u5426\u5219\u8001\u5B9E\u7528\u76F8\u5BF9\u8DEF\u5F84 */\nfunction importPathFor(root: string, designDir: string, componentFile: string): string {\n const aliasBase = readAliasBase(root)\n if (aliasBase && toPosix(componentFile).startsWith(toPosix(aliasBase) + \"/\")) {\n return \"@/\" + toPosix(relative(aliasBase, componentFile)).replace(/\\.tsx$/, \"\")\n }\n const rel = toPosix(relative(join(root, designDir), componentFile)).replace(/\\.tsx$/, \"\")\n return rel.startsWith(\".\") ? rel : \"./\" + rel\n}\n\n/** \u8BFB tsconfig.json \u7684 paths[\"@/*\"],\u8FD4\u56DE\u5B83\u6307\u5411\u7684\u7EDD\u5BF9\u76EE\u5F55;\u6CA1\u914D(\u6216 tsconfig \u89E3\u6790\u4E0D\u52A8)\u2192 null,\u8D70\u76F8\u5BF9\u8DEF\u5F84 */\nfunction readAliasBase(root: string): string | null {\n const file = join(root, \"tsconfig.json\")\n if (!existsSync(file)) return null\n let parsed: unknown\n try {\n parsed = JSON.parse(readFileSync(file, \"utf8\"))\n } catch {\n return null\n }\n const paths = asRecord(asRecord(asRecord(parsed)[\"compilerOptions\"])[\"paths\"])\n const entry = paths[\"@/*\"]\n const first = Array.isArray(entry) ? entry[0] : undefined\n if (typeof first !== \"string\") return null\n return resolve(root, first.replace(/\\/?\\*$/, \"\"))\n}\n\nfunction artboardTemplate(name: string, importPath: string): string {\n return (\n `// contactsheet \u81EA\u52A8\u751F\u6210\u7684\u753B\u677F\u9AA8\u67B6 \u2014\u2014 \u968F\u4FBF\u6539,init \u4E0D\u4F1A\u518D\u8986\u76D6\u5B83\\n` +\n `import { ${name} } from '${importPath}'\\n` +\n `\\n` +\n `export const \u9ED8\u8BA4 = {\\n` +\n ` render: () => <${name}>\u793A\u4F8B</${name}>,\\n` +\n `}\\n`\n )\n}\n\n// ============================================================\n// e. .mcp.json\n// ============================================================\n\nfunction writeMcpJson(root: string, port: number): void {\n const file = join(root, \".mcp.json\")\n const doc = readJsonObject(file) ?? {}\n const servers = asRecord(doc[\"mcpServers\"])\n const had = \"contactsheet\" in servers\n\n servers[\"contactsheet\"] = { type: \"http\", url: `http://localhost:${port}/__cs/mcp` }\n doc[\"mcpServers\"] = servers\n writeJsonFile(file, doc)\n\n const others = Object.keys(servers).filter((k) => k !== \"contactsheet\").length\n console.log(\n ` .mcp.json:${had ? \"\u66F4\u65B0\" : \"\u5199\u5165\"} mcpServers.contactsheet` + (others ? `(\u53E6\u5916 ${others} \u4E2A server \u539F\u6837\u4FDD\u7559)` : \"\"),\n )\n}\n\n// ============================================================\n// f. .claude/settings.json \u7684 UserPromptSubmit hook\n// ============================================================\n\nfunction writeClaudeHook(root: string, port: number): void {\n const file = join(root, \".claude\", \"settings.json\")\n const doc = readJsonObject(file) ?? {}\n const hooks = asRecord(doc[\"hooks\"])\n const list = Array.isArray(hooks[\"UserPromptSubmit\"]) ? (hooks[\"UserPromptSubmit\"] as unknown[]) : []\n\n // \u5E42\u7B49:\u5DF2\u7ECF\u6709\u4E00\u6761\u4F1A\u53BB\u6253 /__cs/api/context \u7684 command \u5C31\u4E0D\u518D\u52A0\n const existingCommands: string[] = []\n for (const group of list) {\n for (const h of Array.isArray(asRecord(group)[\"hooks\"]) ? (asRecord(group)[\"hooks\"] as unknown[]) : []) {\n const cmd = asRecord(h)[\"command\"]\n if (typeof cmd === \"string\") existingCommands.push(cmd)\n }\n }\n const already = existingCommands.filter((c) => c.includes(\"/__cs/api/context\"))\n if (already.length > 0) {\n console.log(` .claude/settings.json:context hook \u5DF2\u5B58\u5728,\u4E0D\u91CD\u590D\u6DFB\u52A0`)\n if (!already.some((c) => c.includes(`localhost:${port}/`))) {\n console.log(` \u6CE8\u610F:\u5DF2\u6709\u7684 hook \u6253\u7684\u4E0D\u662F :${port},\u7AEF\u53E3\u6362\u8FC7\u7684\u8BDD\u8BF7\u624B\u6539\u8FD9\u6761 command`)\n }\n return\n }\n\n const command = `curl -s --noproxy '*' --max-time 1 http://localhost:${port}/__cs/api/context || true`\n list.push({ hooks: [{ type: \"command\", command }] })\n hooks[\"UserPromptSubmit\"] = list\n doc[\"hooks\"] = hooks\n writeJsonFile(file, doc)\n console.log(` .claude/settings.json:\u52A0\u4E86 UserPromptSubmit hook(\u81EA\u52A8\u628A\u6279\u6CE8\u548C\u9009\u4E2D\u5143\u7D20\u5E26\u7ED9 Claude)`)\n}\n\n// ============================================================\n// \u5C0F\u5DE5\u5177\n// ============================================================\n\nfunction isDir(p: string): boolean {\n try {\n return statSync(p).isDirectory()\n } catch {\n return false\n }\n}\n\nfunction toPosix(p: string): string {\n return p.split(\"\\\\\").join(\"/\")\n}\n\nfunction asRecord(v: unknown): Record<string, unknown> {\n return v !== null && typeof v === \"object\" && !Array.isArray(v) ? (v as Record<string, unknown>) : {}\n}\n\nfunction pickString(...candidates: unknown[]): string {\n for (const c of candidates) if (typeof c === \"string\" && c !== \"\") return c\n return \"\"\n}\n\nfunction pickNumber(...candidates: unknown[]): number {\n for (const c of candidates) if (typeof c === \"number\" && Number.isFinite(c)) return c\n return 0\n}\n\n/** \u8BFB JSON \u5BF9\u8C61;\u6587\u4EF6\u4E0D\u5B58\u5728 \u2192 null;\u5185\u5BB9\u4E0D\u662F\u5408\u6CD5 JSON \u5BF9\u8C61 \u2192 \u4E2D\u6B62(\u7EDD\u4E0D\u8986\u76D6) */\nfunction readJsonObject(file: string): Record<string, unknown> | null {\n if (!existsSync(file)) return null\n const raw = readFileSync(file, \"utf8\")\n if (raw.trim() === \"\") return {}\n let parsed: unknown\n try {\n parsed = JSON.parse(raw)\n } catch (err) {\n throw new Error(\n `contactsheet init \u4E2D\u6B62:${file} \u4E0D\u662F\u5408\u6CD5\u7684 JSON(${(err as Error).message})\u3002\\n` +\n `init \u53EA\u4F1A\u5F80\u91CC\u5408\u5E76\u3001\u4E0D\u4F1A\u91CD\u5199,\u6240\u4EE5\u770B\u4E0D\u61C2\u7684\u6587\u4EF6\u4E00\u5F8B\u4E0D\u52A8 \u2014\u2014 \u8BF7\u5148\u4FEE\u597D\u5B83\u518D\u8DD1\u4E00\u6B21\u3002`,\n )\n }\n if (parsed === null || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n throw new Error(`contactsheet init \u4E2D\u6B62:${file} \u7684\u9876\u5C42\u4E0D\u662F\u4E00\u4E2A JSON \u5BF9\u8C61,init \u4E0D\u52A8\u5B83\u3002`)\n }\n return parsed as Record<string, unknown>\n}\n\nfunction writeJsonFile(file: string, value: unknown): void {\n mkdirSync(dirname(file), { recursive: true })\n writeFileSync(file, JSON.stringify(value, null, 2) + \"\\n\", \"utf8\")\n}\n", "// \u7EC8\u7AEF\u8F93\u51FA\u7684\u8272\u5F69\u4E0E\u7B26\u53F7:\u96F6\u4F9D\u8D56 ANSI\u3002\n// \u7EA6\u5B9A:\u2713 \u7EFF = \u5B8C\u6210;\u26A0 \u9EC4 = \u8981\u6CE8\u610F\u4F46\u4E0D\u81F4\u547D;\u2716 \u7EA2 = \u5931\u8D25;\u25CF \u9752 = \u5730\u5740/\u5165\u53E3;\u6697\u6DE1 = \u6B21\u8981\u4FE1\u606F\u3002\n// \u5C0A\u91CD NO_COLOR(https://no-color.org)\u4E0E\u975E TTY(\u7BA1\u9053/\u91CD\u5B9A\u5411\u65F6\u8F93\u51FA\u7EAF\u6587\u672C,\u65E5\u5FD7\u4E0D\u5E26\u8F6C\u4E49\u7801)\u3002\n\nconst on = process.stdout.isTTY === true && !process.env.NO_COLOR && process.env.TERM !== \"dumb\"\n\nconst wrap = (open: number, close: number) => (s: string) =>\n on ? `\\x1b[${open}m${s}\\x1b[${close}m` : s\n\nexport const bold = wrap(1, 22)\nexport const dim = wrap(2, 22)\nexport const red = wrap(31, 39)\nexport const green = wrap(32, 39)\nexport const yellow = wrap(33, 39)\nexport const cyan = wrap(36, 39)\nexport const magenta = wrap(35, 39)\n\n/** \u94FE\u63A5:\u9752\u8272 + \u4E0B\u5212\u7EBF,\u73B0\u4EE3\u7EC8\u7AEF\u53EF\u70B9 */\nexport const link = (s: string): string => (on ? `\\x1b[36;4m${s}\\x1b[39;24m` : s)\n\nexport const ok = (s: string): string => `${green(\"\u2713\")} ${s}`\nexport const warn = (s: string): string => `${yellow(\"\u26A0\")} ${yellow(s)}`\nexport const fail = (s: string): string => `${red(\"\u2716\")} ${s}`\n\n/** \u77ED\u6682\u7684\u884C\u5185 spinner:\u6BCF\u6B21\u8C03\u7528\u63A8\u8FDB\u4E00\u5E27,\u884C\u5C3E\u7528 \\r \u539F\u5730\u5237\u65B0\u3002\u975E TTY \u4E0B\u9759\u9ED8 */\nconst FRAMES = [\"\u280B\", \"\u2819\", \"\u2839\", \"\u2838\", \"\u283C\", \"\u2834\", \"\u2826\", \"\u2827\", \"\u2807\", \"\u280F\"]\nlet frame = 0\nexport function spin(text: string): void {\n if (!on) return\n process.stdout.write(`\\r${cyan(FRAMES[frame++ % FRAMES.length])} ${text}\\x1b[K`)\n}\nexport function spinDone(): void {\n if (!on) return\n process.stdout.write(\"\\r\\x1b[K\")\n}\n", "// \u5916\u58F3 HTTP \u670D\u52A1:\u53EA\u5360 /__cs \u524D\u7F00,\u5176\u4F59\u4E00\u5207(\u542B WebSocket)\u4EE3\u7406\u5230\u7528\u6237\u7684 next dev\nimport fs from \"node:fs\"\nimport http from \"node:http\"\nimport httpProxy from \"http-proxy\"\nimport type { CsConfig, RegistryEntry } from \"../types.js\"\nimport type { McpServices } from \"../mcp/index.js\"\nimport { createMcpHandler } from \"../mcp/index.js\"\nimport { screenshot } from \"../shot/index.js\"\nimport { errText, handleApi, pushToken, sendText } from \"./api.js\"\nimport { findUiFile, mimeOf, pkgVersion } from \"./assets.js\"\nimport { createProxyLog } from \"./proxy-log.js\"\nimport { startHealthMonitor } from \"./health.js\"\nimport { cyan, dim, link, warn } from \"../term.js\"\nimport * as sse from \"./sse.js\"\nimport * as store from \"./store.js\"\n\n// SSE hub \u662F\u6A21\u5757\u7EA7\u7684(startServer \u7684\u8FD4\u56DE\u503C\u7B7E\u540D\u51BB\u7ED3,\u63A8\u4E8B\u4EF6\u53EA\u80FD\u8D70\u8FD9\u4E2A\u989D\u5916\u5BFC\u51FA)\nexport { broadcast } from \"./sse.js\"\n\ntype McpHandler = (req: http.IncomingMessage, res: http.ServerResponse) => Promise<void>\n\nexport async function startServer(cfg: CsConfig): Promise<{ port: number; close(): Promise<void> }> {\n const proxy = httpProxy.createProxyServer({ target: cfg.target, ws: true, changeOrigin: true })\n\n // next dev \u6CA1\u8D77\u65F6\u7ED9\u4E00\u5F20\u8BF4\u660E\u9875,\u753B\u5E03\u81EA\u8EAB\u7167\u5E38\u53EF\u5F00\u3002\u65E5\u5FD7\u8D70 proxyLog \u53BB\u91CD\u9650\u6D41:\n // HMR \u5BA2\u6237\u7AEF\u91CD\u8FDE\u65F6\u6BCF\u79D2\u51E0\u5341\u6B21\u5931\u8D25,\u9010\u6761\u6253\u4F1A\u628A\u771F\u9519\u8BEF\u51B2\u8D70\n const proxyLog = createProxyLog(cfg.target)\n proxy.on(\"error\", (err, req, res) => {\n proxyLog.fail(err as NodeJS.ErrnoException, req?.url)\n if (!res) return\n if (\"writeHead\" in res) {\n if (!res.headersSent) res.writeHead(502, { \"content-type\": \"text/html; charset=utf-8\" })\n res.end(downPage(cfg.target))\n } else {\n // ws \u5347\u7EA7\u5931\u8D25:http-proxy \u53EA end() \u4E86\u5BA2\u6237\u7AEF socket,\u8FD9\u91CC\u8865\u4E00\u5200,\u522B\u7559\u534A\u5F00\u8FDE\u63A5\n res.destroy()\n }\n })\n // \u5BA2\u6237\u7AEF\u534A\u8DEF\u653E\u5F03\u65F6,\u4E0A\u6E38\u8FDE\u63A5\u5FC5\u987B\u8DDF\u7740\u62C6\u3002\u4E0D\u62C6\u7684\u8BDD\u6BCF\u6B21\u4E2D\u65AD\u90FD\u5728\u5916\u58F3\u91CC\u7559\u4E00\u4E2A\u540A\u6B7B fd\n // (\u5B9E\u6D4B 300 \u6B21\u4E2D\u65AD\u6CC4\u6F0F 300 \u4E2A fd,\u6C38\u4E0D\u56DE\u6536),\u800C\u4E14\u5BF9 next dev \u90A3\u662F\u4E00\u4E2A\u6C38\u8FDC\"\u6E32\u67D3\u4E2D\"\u7684\n // in-flight \u8BF7\u6C42 \u2014\u2014 \u50F5\u6B7B\u671F\u7684 HMR \u91CD\u8BD5\u6D2A\u6C34\u4F1A\u628A\u8FD9\u79CD\u8BF7\u6C42\u5806\u6210\u5C71,\u53CD\u8FC7\u6765\u628A dev server \u538B\u5F97\u66F4\u6B7B\u3002\n // \u5224\u636E:res \u5173\u95ED\u4F46\u6CA1\u5199\u5B8C = \u5BA2\u6237\u7AEF\u4E2D\u65AD;\u6B63\u5E38\u5B8C\u6210\u7684\u8BF7\u6C42\u4E0D\u52A8\u5B83(\u522B\u8BEF\u6740 keep-alive \u8FDE\u63A5\u6C60)\u3002\n proxy.on(\"proxyReq\", (proxyReq, _req, res) => {\n res.on(\"close\", () => {\n if (!res.writableEnded) proxyReq.destroy()\n })\n })\n\n // \u76EE\u6807\u6709\u56DE\u5305\u5C31\u7B97\u6D3B\u8FC7\u6765\u4E86(http \u54CD\u5E94 / ws \u63E1\u624B),\u7528\u6765\u6253\"\u5DF2\u6062\u590D\"\u90A3\u4E00\u884C\n proxy.on(\"proxyRes\", () => proxyLog.alive())\n proxy.on(\"open\", () => proxyLog.alive())\n\n // MCP handler \u7531 Agent D \u63D0\u4F9B;\u8FD8\u662F stub \u5C31\u6302 501,\u4E0D\u5F71\u54CD\u5176\u4F59\u529F\u80FD\n let mcp: McpHandler | null = null\n try {\n mcp = createMcpHandler(makeServices(cfg))\n } catch (err) {\n console.warn(`[contactsheet] MCP \u672A\u5C31\u7EEA(/__cs/mcp \u8FD4\u56DE 501):${errText(err)}`)\n }\n\n const server = http.createServer((req, res) => {\n handle(cfg, proxy, mcp, req, res).catch((err) => {\n console.error(`[contactsheet] \u8BF7\u6C42\u5904\u7406\u5931\u8D25 ${req.url}`, err)\n if (!res.headersSent) sendText(res, 500, errText(err))\n else res.end()\n })\n })\n\n // HMR WebSocket \u8D70\u8FD9\u6761\n server.on(\"upgrade\", (req, socket, head) => proxy.ws(req, socket, head))\n\n // \u81EA\u5DF1\u8FFD\u8E2A\u5168\u90E8 socket:\u5347\u7EA7\u6210 WebSocket \u7684\u4EE3\u7406\u8FDE\u63A5\u4E0D\u5728 closeAllConnections \u7684\u6E05\u5355\u91CC,\n // \u4E0D\u5E72\u6389\u5B83\u4EEC server.close \u6C38\u8FDC\u4E0D\u56DE\u8C03 \u2014\u2014 Ctrl-C \u65F6\u753B\u5E03\u8FD8\u5F00\u7740\u5C31\u4F1A\u5361\u6B7B\u5728\u9000\u51FA\u534A\u9014\n const sockets = new Set<import(\"node:net\").Socket>()\n server.on(\"connection\", (s) => {\n sockets.add(s)\n s.on(\"close\", () => sockets.delete(s))\n })\n\n // \u53EA\u7ED1\u56DE\u73AF:\u753B\u5E03\u6CA1\u6709\u9274\u6743,\u800C /__cs/api/push \u80FD\u628A\u4EFB\u610F\u6587\u672C\u4EE5\"\u7528\u6237\u53D1\u8A00\"\u9001\u8FDB\u4F60\u7684 Claude Code\n // \u4F1A\u8BDD\u3002\u88F8\u7ED1 0.0.0.0 \u7B49\u4E8E\u628A\u8FD9\u6761\u6267\u884C\u94FE\u66B4\u9732\u7ED9\u540C\u4E00\u4E2A Wi-Fi \u4E0A\u7684\u4EFB\u4F55\u4EBA\u3002\u8981 LAN \u8BBF\u95EE\u5FC5\u987B\u663E\u5F0F --host\u3002\n const host = cfg.host ?? \"127.0.0.1\"\n let twin: http.Server | null = null\n const port = await listenWithFallback(server, cfg, host, (t) => {\n twin = t\n // \u5B6A\u751F\u7684\u8FDE\u63A5\u540C\u6837\u8981\u8FDB\u8FFD\u8E2A\u8868,\u5426\u5219 Ctrl-C \u4F1A\u5361\u5728\u5B83\u7684 keep-alive \u4E0A\n t.on(\"connection\", (sock) => {\n sockets.add(sock)\n sock.on(\"close\", () => sockets.delete(sock))\n })\n })\n if (host !== \"127.0.0.1\" && host !== \"localhost\") {\n console.warn(\n warn(`\u76D1\u542C\u5728 ${host}:${port} \u2014\u2014 \u753B\u5E03\u65E0\u9274\u6743,\u540C\u7F51\u7EDC\u7684\u4EFB\u4F55\u4EBA\u90FD\u80FD\u8BFB\u4F60\u7684\u6279\u6CE8\u3001\u5E76\u5411\u4F60\u7684 Claude Code \u4F1A\u8BDD\u63A8\u9001\u6D88\u606F\u3002\u53EA\u5728\u53EF\u4FE1\u7F51\u7EDC\u8FD9\u4E48\u505A\u3002`)\n )\n }\n\n const health = startHealthMonitor(cfg, sse.broadcast)\n\n return {\n port,\n async close() {\n health.close()\n sse.closeAll()\n proxyLog.close()\n proxy.close()\n if (twin) {\n await new Promise<void>((r) => twin!.close(() => r()))\n }\n await new Promise<void>((resolve) => {\n const fallback = setTimeout(resolve, 2000) // \u515C\u5E95:2 \u79D2\u5173\u4E0D\u5E72\u51C0\u4E5F\u7167\u6837\u9000\u51FA\n for (const s of sockets) s.destroy()\n server.closeAllConnections()\n server.close(() => {\n clearTimeout(fallback)\n resolve()\n })\n })\n },\n }\n}\n\nasync function handle(\n cfg: CsConfig,\n proxy: ReturnType<typeof httpProxy.createProxyServer>,\n mcp: McpHandler | null,\n req: http.IncomingMessage,\n res: http.ServerResponse\n): Promise<void> {\n // \u53EA\u6309 pathname \u8DEF\u7531,query \u7559\u7ED9\u5404 handler \u81EA\u5DF1\u770B\n const pathname = new URL(req.url ?? \"/\", \"http://localhost\").pathname\n\n if (pathname === \"/__cs\" || pathname === \"/__cs/\") return serveUi(res, \"index.html\")\n\n if (pathname.startsWith(\"/__cs/ui/\")) {\n const name = pathname.slice(\"/__cs/ui/\".length)\n if (!name || name.includes(\"..\")) return sendText(res, 400, \"bad asset path\")\n return serveUi(res, name)\n }\n\n if (pathname === \"/__cs/events\") return sse.attach(req, res)\n\n if (pathname === \"/__cs/mcp\") {\n if (!mcp) return sendText(res, 501, \"contactsheet: MCP \u6A21\u5757\u672A\u5C31\u7EEA\")\n return mcp(req, res)\n }\n\n if (pathname.startsWith(\"/__cs/api/\")) return handleApi(cfg, req, res, pathname)\n\n // \u5176\u4F59\u4E00\u5207\u653E\u884C\u7ED9\u4EE3\u7406,\u5305\u62EC\u6CE8\u5165\u8DEF\u7531 /__cs/ab/* \u3001/__cs/registry \u3001/__cs/tokens\n proxy.web(req, res)\n}\n\nfunction serveUi(res: http.ServerResponse, name: string): void {\n const file = findUiFile(name)\n if (!file) return sendText(res, 404, `contactsheet: \u627E\u4E0D\u5230\u753B\u5E03\u8D44\u4EA7 ${name},\u5148\u8DD1 node build.mjs`)\n let body = fs.readFileSync(file)\n // \u753B\u5E03\u9875(\u4E14\u53EA\u6709\u753B\u5E03\u9875)\u62FF\u5230\u672C\u6B21\u8FDB\u7A0B\u7684 push token\u3002iframe \u91CC\u8DD1\u7684\u7528\u6237\u9875\u9762\u62FF\u4E0D\u5230\u5B83,\n // \u6240\u4EE5\u5C31\u7B97 app \u91CC\u6DF7\u8FDB\u7B2C\u4E09\u65B9\u811A\u672C,\u4E5F\u6CA1\u6CD5\u5192\u7528\u4F60\u7684\u540D\u4E49\u5411 Claude Code \u4F1A\u8BDD\u8BF4\u8BDD\u3002\n if (name === \"index.html\") {\n body = Buffer.from(\n body.toString(\"utf8\").replace(\"</head>\", `<meta name=\"cs-token\" content=\"${pushToken()}\" />\\n</head>`)\n )\n }\n res.writeHead(200, { \"content-type\": mimeOf(file), \"cache-control\": \"no-store\" })\n res.end(body)\n}\n\n/** \u4F9B MCP \u7528\u7684\u53EA\u8BFB\u670D\u52A1\u9762 */\nfunction makeServices(cfg: CsConfig): McpServices {\n return {\n // registry \u7531\u6CE8\u5165\u8FDB\u7528\u6237 app \u7684\u8DEF\u7531\u63D0\u4F9B,\u76F4\u8FDE target(node fetch \u4E0D\u8D70\u7CFB\u7EDF\u4EE3\u7406)\n async getRegistry(): Promise<RegistryEntry[]> {\n try {\n const r = await fetch(`${cfg.target}/__cs/registry`)\n if (!r.ok) return []\n const data: unknown = await r.json()\n return Array.isArray(data) ? (data as RegistryEntry[]) : []\n } catch {\n return [] // next dev \u6CA1\u8D77\n }\n },\n getSelection: () => store.getSelection(),\n getAnnotations: () => store.readAnnotations(cfg),\n takeShot: async (req) => screenshot(cfg, req),\n }\n}\n\nfunction downPage(target: string): string {\n return `<!doctype html><html lang=\"zh\"><meta charset=\"utf-8\"><title>contactsheet</title>\n<body style=\"font:14px/1.7 ui-monospace,SFMono-Regular,Menlo,monospace;padding:48px;color:#333;background:#fafafa\">\n<h1 style=\"font-size:15px;margin:0 0 12px\">contactsheet:\u76EE\u6807 ${escapeHtml(target)} \u672A\u542F\u52A8</h1>\n<p style=\"margin:0 0 8px\">\u5148\u5728\u9879\u76EE\u91CC\u8DD1 <code>next dev</code>,\u518D\u5237\u65B0\u672C\u9875\u3002</p>\n<p style=\"margin:0\"><a href=\"/__cs\" style=\"color:#06c\">\u2190 \u56DE\u753B\u5E03</a></p>\n</body></html>`\n}\n\nfunction escapeHtml(s: string): string {\n return s.replace(/[&<>\"]/g, (c) => ({ \"&\": \"&amp;\", \"<\": \"&lt;\", \">\": \"&gt;\", '\"': \"&quot;\" })[c] as string)\n}\n\n/** \u5360\u7740\u914D\u7F6E\u7AEF\u53E3\u7684\u662F\u4E0D\u662F\"\u672C\u9879\u76EE\u7684\u53E6\u4E00\u4E2A contactsheet\"?\u662F\u7684\u8BDD\u62FF\u5230\u5B83\u7684\u7248\u672C\u3002\n * \u91CD\u8BD5\u4E24\u8F6E\u3001\u8D85\u65F6\u653E\u5BBD:\u65E7\u5B9E\u4F8B\u6B63\u5FD9(\u6CC4\u6F0F/\u9AD8\u8D1F\u8F7D)\u65F6 800ms \u4E00\u67AA\u6253\u7A7A\u4F1A\u628A\"\u540C\u9879\u76EE\"\u8BEF\u5224\u6210\n * \"\u964C\u751F\u8FDB\u7A0B\" \u2014\u2014 \u8FD9\u4E2A\u8BEF\u5224\u4E0A\u4E00\u6B21\u8BA9\u5347\u7EA7\u9759\u9ED8\u5931\u6548\u4E86 */\nasync function probeSameProject(\n cfg: CsConfig,\n port: number\n): Promise<{ version?: string } | null> {\n for (let i = 0; i < 2; i++) {\n try {\n const r = await fetch(`http://127.0.0.1:${port}/__cs/api/state`, {\n signal: AbortSignal.timeout(2500),\n })\n if (!r.ok) return null\n const data = (await r.json()) as { projectRoot?: string; version?: string }\n return data?.projectRoot === cfg.projectRoot ? { version: data.version } : null\n } catch {\n /* \u7B2C\u4E8C\u8F6E\u518D\u8BD5 */\n }\n }\n return null\n}\n\n/** \u5360\u7528\u7AEF\u53E3\u7684\u8FDB\u7A0B\u53F7,\u5C3D\u529B\u800C\u4E3A(\u62A5\u9519\u4FE1\u606F\u91CC\u80FD\u76F4\u63A5 kill \u6BD4\"\u81EA\u5DF1\u53BB lsof\"\u53CB\u597D\u4E00\u4E2A\u91CF\u7EA7) */\nfunction occupierPid(port: number): string | null {\n try {\n const { execSync } = require(\"node:child_process\") as typeof import(\"node:child_process\")\n const out = execSync(`lsof -t -nP -iTCP:${port} -sTCP:LISTEN`, { timeout: 3000 })\n .toString()\n .trim()\n return out.split(\"\\n\")[0] || null\n } catch {\n return null\n }\n}\n\n/**\n * \u7AEF\u53E3\u88AB\u5360\u65F6\u7684\u7B56\u7565(\u5B9E\u6D4B\u4E8B\u6545\u540E\u4ECE\"\u987A\u5EF6\"\u6539\u6210\"\u786C\u5931\u8D25\"):\n * - \u672C\u9879\u76EE\u7684\u53E6\u4E00\u4E2A contactsheet,\u7248\u672C\u76F8\u540C \u2192 \u6253\u5370\u5730\u5740\u76F4\u63A5\u9000\u51FA(\u5FD8\u4E86\u5DF2\u7ECF\u8D77\u8FC7);\n * - \u672C\u9879\u76EE\u4F46**\u7248\u672C\u4E0D\u540C** \u2192 \u9000\u51FA\u7801 1,\u63D0\u793A\u5148 kill \u65E7\u7684 \u2014\u2014 \u9759\u9ED8\u590D\u7528\u65E7\u5B9E\u4F8B = \u5347\u7EA7\u9759\u9ED8\u5931\u6548;\n * - \u5176\u4ED6\u8FDB\u7A0B\u5360\u7740 \u2192 **\u786C\u5931\u8D25**,\u5E26\u4E0A\u5360\u7528\u8005 PID\u3002\u4E0D\u518D\u987A\u5EF6:config/.mcp.json/hook \u5168\u90FD\u6307\u5411\n * \u8FD9\u4E2A\u7AEF\u53E3,\u987A\u5EF6\u540E\u6D4F\u89C8\u5668\u91CC\u770B\u7740\u4E00\u5207\u6B63\u5E38,\u4F46 agent \u4FA7\u63A5\u7EBF\u5168\u90E8\u6307\u7740\u522B\u7684\u8FDB\u7A0B,\n * \u800C\u4E14\u4EFB\u4F55\u4E00\u65B9\u90FD\u4E0D\u4F1A\u6536\u5230\u9519\u8BEF \u2014\u2014 \u8FD9\u6B21\u7684\u540E\u679C\u4E0D\u662F\"\u6362\u4E86\u4E2A\u7AEF\u53E3\",\u662F\"\u5347\u7EA7\u9759\u9ED8\u5730\u6CA1\u751F\u6548\"\u3002\n */\nasync function listenWithFallback(\n server: http.Server,\n cfg: CsConfig,\n host: string,\n onTwin: (t: http.Server) => void\n): Promise<number> {\n const listenOnce = (srv: http.Server, port: number, h: string): Promise<\"ok\" | \"busy\" | \"nofam\"> =>\n new Promise((resolve, reject) => {\n const onErr = (err: NodeJS.ErrnoException): void => {\n if (err.code === \"EADDRINUSE\") resolve(\"busy\")\n // \u673A\u5668\u6CA1\u542F IPv6 \u65F6 ::1 \u7ED1\u4E0D\u4E86,\u4E0D\u7B97\u51B2\u7A81\n else if (err.code === \"EADDRNOTAVAIL\" || err.code === \"EAFNOSUPPORT\") resolve(\"nofam\")\n else reject(err)\n }\n srv.once(\"error\", onErr)\n srv.listen(port, h, () => {\n srv.off(\"error\", onErr)\n resolve(\"ok\")\n })\n })\n\n /**\n * \u4E00\u4E2A\u7AEF\u53E3\u8981 127.0.0.1 \u548C ::1 **\u90FD**\u7ED1\u4E0A\u624D\u7B97\u771F\u7684\u7A7A\u95F2\u3002\n * \u6D4F\u89C8\u5668\u89E3\u6790 localhost \u666E\u904D\u4F18\u5148 ::1:\u53EA\u7ED1 v4 \u65F6,\u82E5 v6 \u4FA7\u88AB\u522B\u4EBA\u5360\u7740(\u5B9E\u6D4B Docker \u5E38\u5E74\n * \u7AEF\u53E3\u8F6C\u53D1\u5728 IPv6 \u901A\u914D\u4E0A),curl \u4E00\u5207\u6B63\u5E38\u3001\u6D4F\u89C8\u5668\u5374\u62FF\u5230\u5BF9\u65B9\u7684 502/\u7A7A\u54CD\u5E94 \u2014\u2014 \u8FD9\u7C7B\"\u534A\u778E\"\n * \u51B2\u7A81\u5FC5\u987B\u5F53\u6210\u7AEF\u53E3\u88AB\u5360\u5904\u7406\u3002::1 \u4E0A\u8D77\u7684\u662F\u5171\u4EAB\u540C\u4E00 handler \u7684\u5B6A\u751F server\u3002\n * \u7528\u6237\u663E\u5F0F\u6307\u5B9A\u4E86\u975E\u56DE\u73AF host(LAN)\u65F6\u4E0D\u505A\u5B6A\u751F:\u7ED1\u7684\u5DF2\u7ECF\u4E0D\u662F localhost \u8FD9\u4E2A\u540D\u5B57\u4E86\u3002\n */\n const tryListen = async (port: number): Promise<boolean> => {\n const main = await listenOnce(server, port, host)\n if (main !== \"ok\") return false\n if (host !== \"127.0.0.1\") return true\n const t = http.createServer(server.listeners(\"request\")[0] as http.RequestListener)\n for (const l of server.listeners(\"upgrade\")) t.on(\"upgrade\", l as (...a: unknown[]) => void)\n const r = await listenOnce(t, port, \"::1\")\n if (r === \"ok\") {\n onTwin(t)\n return true\n }\n if (r === \"nofam\") return true // \u6CA1\u6709 IPv6,\u5355\u6808\u5373\u53EF\n // v6 \u88AB\u522B\u4EBA\u5360:\u8FD9\u4E2A\u7AEF\u53E3\u5BF9\u6D4F\u89C8\u5668\u662F\u574F\u7684,\u6574\u4F53\u8BA9\u51FA\u53BB\u91CD\u8BD5\u4E0B\u4E00\u4E2A\n await new Promise<void>((res) => server.close(() => res()))\n return false\n }\n\n if (await tryListen(cfg.port)) return cfg.port\n\n const running = await probeSameProject(cfg, cfg.port)\n if (running) {\n if (running.version && running.version !== pkgVersion()) {\n const pid = occupierPid(cfg.port)\n console.error(\n warn(`\u672C\u9879\u76EE\u5DF2\u6709\u4E00\u4E2A contactsheet \u5728 ${cfg.port} \u4E0A,\u4F46\u5B83\u662F v${running.version},\u5F53\u524D\u662F v${pkgVersion()}\u3002`) +\n `\\n \u65E7\u5B9E\u4F8B\u4E0D\u4F1A\u81EA\u52A8\u5347\u7EA7 \u2014\u2014 \u5148\u505C\u6389\u5B83\u518D\u8D77:kill ${pid ?? \"<lsof -t -iTCP:\" + cfg.port + \">\"}`\n )\n process.exit(1)\n }\n console.log(\n `${cyan(\"\u25CF\")} \u672C\u9879\u76EE\u5DF2\u7ECF\u6709\u4E00\u4E2A contactsheet \u5728\u8DD1\u4E86,\u76F4\u63A5\u7528\u5B83:${link(`http://localhost:${cfg.port}/__cs`)}`\n )\n process.exit(0)\n }\n const pid = occupierPid(cfg.port)\n throw new Error(\n `\u7AEF\u53E3 ${cfg.port} \u88AB\u5176\u4ED6\u8FDB\u7A0B\u5360\u7528${pid ? `(PID ${pid})` : \"\"}\u3002` +\n `.mcp.json/hook/config \u90FD\u6307\u5411 ${cfg.port},\u6362\u7AEF\u53E3\u5B83\u4EEC\u4F1A\u5168\u90E8\u5931\u8054,\u6240\u4EE5\u4E0D\u81EA\u52A8\u987A\u5EF6 \u2014\u2014\\n` +\n ` \u91CA\u653E\u5B83:kill ${pid ?? `$(lsof -t -nP -iTCP:${cfg.port} -sTCP:LISTEN)`}\\n` +\n ` \u6216\u6362\u7AEF\u53E3:\u6539 contactsheet.config.json \u7684 port \u540E\u91CD\u8DD1 npx contactsheet init(MCP/hook \u4F1A\u8DDF\u7740\u6362)`\n )\n}\n", "// [Agent D] MCP \u7AEF\u70B9 \u2014\u2014 \u6302\u5728\u5916\u58F3\u7684 /__cs/mcp,\u7ED9 Claude Code \u63D0\u4F9B\u56DB\u4E2A\u53EA\u8BFB\u5DE5\u5177\n// stateless \u6A21\u5F0F:\u6BCF\u4E2A POST \u73B0\u5EFA\u4E00\u5957 McpServer + StreamableHTTPServerTransport,\u54CD\u5E94\u5B8C\u5373\u9500\u6BC1\nimport type { IncomingMessage, ServerResponse } from \"node:http\"\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\"\nimport { StreamableHTTPServerTransport } from \"@modelcontextprotocol/sdk/server/streamableHttp.js\"\nimport { z } from \"zod\"\nimport type { Annotation, RegistryEntry, Selection, ShotRequest, ShotResult } from \"../types.js\"\n\nexport interface McpServices {\n getRegistry(): Promise<RegistryEntry[]>\n getSelection(): Selection | null\n getAnnotations(): Promise<Annotation[]>\n takeShot(req: ShotRequest): Promise<ShotResult>\n}\n\n/** \u5DE5\u5177\u8FD4\u56DE\u503C:\u53EA\u7528\u5230 text / image \u4E24\u79CD content */\ntype ToolResult = {\n content: ({ type: \"text\"; text: string } | { type: \"image\"; data: string; mimeType: string })[]\n isError?: boolean\n}\n\n/** \u5DE5\u5177\u6267\u884C\u629B\u9519\u4E0D\u80FD\u5D29 handler:\u7EDF\u4E00\u8F6C\u6210 isError \u6587\u672C */\nasync function guard(run: () => Promise<ToolResult>): Promise<ToolResult> {\n try {\n return await run()\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n // shot \u6A21\u5757\u7684\u9519\u8BEF\u4FE1\u606F\u81EA\u5E26 \"contactsheet: \" \u524D\u7F00,\u522B\u53E0\u4E24\u5C42\n const text = msg.startsWith(\"contactsheet:\") ? msg : `contactsheet: ${msg}`\n return { isError: true, content: [{ type: \"text\", text }] }\n }\n}\n\nfunction text(value: unknown): ToolResult {\n return { content: [{ type: \"text\", text: typeof value === \"string\" ? value : JSON.stringify(value, null, 2) }] }\n}\n\n/** \u6BCF\u4E2A\u8BF7\u6C42\u73B0\u5EFA\u4E00\u53F0 server(stateless \u6A21\u5F0F\u4E0B server \u4E0E transport \u90FD\u4E0D\u80FD\u8DE8\u8BF7\u6C42\u590D\u7528) */\nfunction buildServer(services: McpServices): McpServer {\n const server = new McpServer(\n { name: \"contactsheet\", version: \"0.1.0\" },\n { capabilities: { tools: {} } }\n )\n\n server.registerTool(\n \"canvas_list\",\n {\n title: \"\u5217\u51FA\u753B\u677F\",\n description:\n \"\u5217\u51FA contactsheet \u753B\u5E03\u4E0A\u7684\u5168\u90E8\u753B\u677F(\u8BBE\u8BA1\u7A3F)\u3002\u8FD4\u56DE JSON \u6570\u7EC4,\u6BCF\u9879\u542B id\u3001file(\u6E90\u6587\u4EF6\u76F8\u5BF9\u8DEF\u5F84)\u3001exportName\u3001kind(component=\u7EC4\u4EF6\u753B\u677F / screen=\u9875\u9762\u753B\u677F)\u3001args(\u7EC4\u4EF6\u9ED8\u8BA4\u5165\u53C2)\u3001env(\u5BBD\u9AD8\u7B49)\u3002\u8981\u622A\u67D0\u5757\u753B\u677F\u524D\u5148\u7528\u5B83\u62FF\u5230\u51C6\u786E\u7684 id\u3002\",\n annotations: { readOnlyHint: true },\n },\n async () => guard(async () => text(await services.getRegistry()))\n )\n\n server.registerTool(\n \"canvas_screenshot\",\n {\n title: \"\u622A\u56FE\u753B\u677F\",\n description:\n \"\u7ED9\u753B\u677F\u622A\u56FE\u5E76\u628A\u56FE\u7247\u8FD4\u56DE\u7ED9\u4F60\u770B\u3002\u4F20 id \u622A\u5355\u5757\u753B\u677F(id \u4ECE canvas_list \u62FF,\u7EC4\u4EF6\u753B\u677F\u622A\u5168\u9875);\u4E0D\u4F20 id \u622A\u6574\u9762\u753B\u5E03\u5899\u7684\u6982\u89C8\u3002\u8FD4\u56DE\u4E00\u5F20 PNG \u56FE\u7247 + \u56FE\u7247\u5728 repo \u91CC\u7684\u4FDD\u5B58\u8DEF\u5F84\u3002\u60F3\u786E\u8BA4 UI \u6539\u52A8\u7684\u5B9E\u9645\u6548\u679C\u5C31\u7528\u5B83\u3002\",\n inputSchema: {\n id: z\n .string()\n .optional()\n .describe(\"\u753B\u677F id(\u6765\u81EA canvas_list);\u7701\u7565\u5219\u622A\u6574\u9762\u5899\u7684\u6982\u89C8\u56FE\"),\n },\n annotations: { readOnlyHint: true },\n },\n async ({ id }) =>\n guard(async () => {\n const shot = await services.takeShot(id ? { id } : {})\n return {\n content: [\n { type: \"image\", data: shot.base64, mimeType: \"image/png\" },\n { type: \"text\", text: `\u5DF2\u4FDD\u5B58:${shot.path}(${shot.width}\u00D7${shot.height})` },\n ],\n }\n })\n )\n\n server.registerTool(\n \"canvas_selection\",\n {\n title: \"\u5F53\u524D\u9009\u4E2D\u5143\u7D20\",\n description:\n \"\u8BFB\u7528\u6237\u6B64\u523B\u5728 contactsheet \u753B\u5E03\u4E0A\u70B9\u9009\u7684\u5143\u7D20:\u8FD4\u56DE JSON,\u542B artboardId(\u54EA\u5757\u753B\u677F)\u3001selector(\u753B\u677F\u6587\u6863\u5185\u7684 CSS \u9009\u62E9\u5668)\u3001x/y(\u5143\u7D20\u5185 0-1 \u76F8\u5BF9\u5750\u6807)\u3001ts(\u65F6\u95F4\u6233)\u3002\u7528\u6237\u8BF4\u300C\u8FD9\u4E2A\u6309\u94AE\u300D\u300C\u8FD9\u91CC\u300D\u7684\u65F6\u5019\u5148\u8C03\u5B83\u786E\u8BA4\u6307\u7684\u662F\u8C01\u3002\u6CA1\u6709\u9009\u4E2D\u65F6\u8FD4\u56DE no selection\u3002\",\n annotations: { readOnlyHint: true },\n },\n async () =>\n guard(async () => {\n const selection = services.getSelection()\n return selection ? text(selection) : text(\"no selection\")\n })\n )\n\n server.registerTool(\n \"canvas_annotations\",\n {\n title: \"\u672A\u5904\u7406\u6279\u6CE8\",\n description:\n \"\u5217\u51FA\u753B\u5E03\u4E0A\u72B6\u6001\u4E3A open(\u672A\u5904\u7406)\u7684\u6279\u6CE8:\u8FD4\u56DE JSON \u6570\u7EC4,\u6BCF\u9879\u542B id\u3001text(\u7528\u6237\u5199\u7684\u8BDD)\u3001artboardId\u3001anchor(\u951A\u5B9A\u7684\u5143\u7D20\u4E0E\u4F4D\u7F6E)\u3001refs(\u9644\u5E26\u7684\u53C2\u8003\u56FE\u8DEF\u5F84)\u3001createdAt\u3002\u8FD9\u4E9B\u5C31\u662F\u7528\u6237\u5E0C\u671B\u4F60\u6539\u7684\u5730\u65B9\u3002\",\n annotations: { readOnlyHint: true },\n },\n async () =>\n guard(async () => {\n const all = await services.getAnnotations()\n return text(all.filter(a => a.status === \"open\"))\n })\n )\n\n return server\n}\n\n/** JSON-RPC \u5F62\u5F0F\u7684\u9519\u8BEF\u54CD\u5E94(GET/DELETE \u4E0D\u652F\u6301,\u4EE5\u53CA\u5185\u90E8\u5F02\u5E38) */\nfunction sendJsonRpcError(res: ServerResponse, status: number, code: number, message: string): void {\n if (res.headersSent) {\n res.end()\n return\n }\n res.writeHead(status, { \"content-type\": \"application/json\" })\n res.end(JSON.stringify({ jsonrpc: \"2.0\", error: { code, message }, id: null }))\n}\n\nexport function createMcpHandler(\n services: McpServices\n): (req: IncomingMessage, res: ServerResponse) => Promise<void> {\n return async function handleMcpRequest(req: IncomingMessage, res: ServerResponse): Promise<void> {\n // \u65E0 session \u6301\u4E45\u5316 \u2192 \u6CA1\u6709 GET \u901A\u77E5\u6D41,\u4E5F\u6CA1\u6709 DELETE \u7EC8\u6B62 session\n if (req.method !== \"POST\") {\n sendJsonRpcError(res, 405, -32000, \"Method not allowed.\")\n return\n }\n\n const server = buildServer(services)\n const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined })\n // \u54CD\u5E94\u7ED3\u675F/\u5BA2\u6237\u7AEF\u65AD\u5F00\u90FD\u8981\u62C6\u6389\u8FD9\u5957\u4E00\u6B21\u6027\u5B9E\u4F8B\n res.on(\"close\", () => {\n void transport.close().catch(() => {})\n void server.close().catch(() => {})\n })\n\n try {\n await server.connect(transport)\n await transport.handleRequest(req, res)\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n sendJsonRpcError(res, 500, -32603, `Internal server error: ${msg}`)\n }\n }\n}\n", "// [Agent D] \u622A\u56FE\u6A21\u5757 \u2014\u2014 playwright-core \u9A71\u52A8\u672C\u673A Edge(headless),\u6D4F\u89C8\u5668\u5B9E\u4F8B\u61D2\u542F\u52A8+\u590D\u7528\n// \u5355\u677F:\u5F00\u6CE8\u5165\u7684\u753B\u677F\u8DEF\u7531\u622A\u5168\u9875;\u6574\u5899:\u5F00\u5916\u58F3\u753B\u5E03\u622A\u89C6\u53E3\u3002\u4EA7\u7269\u843D <designDir>/.canvas/shots/\nimport { mkdir, writeFile } from \"node:fs/promises\"\nimport path from \"node:path\"\nimport { chromium } from \"playwright-core\"\nimport type { Browser } from \"playwright-core\"\nimport type { CsConfig, RegistryEntry, ShotRequest, ShotResult } from \"../types.js\"\n\n/** \u7A7A\u95F2\u591A\u4E45\u81EA\u52A8\u5173\u6D4F\u89C8\u5668 */\nconst IDLE_MS = 60_000\n/** \u5BFC\u822A\u8D85\u65F6;networkidle \u5728 next dev \u4E0B\u5076\u5C14\u7B49\u4E0D\u5230,\u8D85\u65F6\u540E\u7167\u5E38\u622A\u56FE */\nconst NAV_TIMEOUT_MS = 30_000\n\nlet browserPromise: Promise<Browser> | null = null\nlet idleTimer: NodeJS.Timeout | null = null\n\n/** \u61D2\u542F\u52A8 + \u590D\u7528\u540C\u4E00\u4E2A\u6D4F\u89C8\u5668\u5B9E\u4F8B;\u542F\u52A8\u5931\u8D25\u4E0D\u7F13\u5B58,\u4E0B\u6B21\u8C03\u7528\u91CD\u8BD5 */\nasync function getBrowser(): Promise<Browser> {\n if (!browserPromise) {\n browserPromise = chromium.launch({ channel: \"msedge\", headless: true }).catch((err: unknown) => {\n browserPromise = null\n const msg = err instanceof Error ? err.message : String(err)\n throw new Error(\n `contactsheet: \u542F\u52A8 Microsoft Edge \u5931\u8D25(playwright-core channel=msedge)\u3002\u8BF7\u786E\u8BA4\u672C\u673A\u88C5\u4E86 Edge\u3002\u539F\u59CB\u9519\u8BEF:${msg}`\n )\n })\n }\n return browserPromise\n}\n\n/** \u6BCF\u6B21\u622A\u5B8C\u91CD\u7F6E 60s \u7A7A\u95F2\u8BA1\u65F6\u5668 */\nfunction scheduleIdleClose(): void {\n if (idleTimer) clearTimeout(idleTimer)\n idleTimer = setTimeout(() => {\n idleTimer = null\n void closeBrowser()\n }, IDLE_MS)\n // \u522B\u56E0\u4E3A\u8FD9\u4E2A\u8BA1\u65F6\u5668\u62D6\u4F4F\u8FDB\u7A0B\u9000\u51FA\n idleTimer.unref?.()\n}\n\n/** \u5173\u6D4F\u89C8\u5668,\u5E42\u7B49;CLI \u9000\u51FA\u94A9\u5B50\u8C03 */\nexport async function closeBrowser(): Promise<void> {\n if (idleTimer) {\n clearTimeout(idleTimer)\n idleTimer = null\n }\n const pending = browserPromise\n browserPromise = null\n if (!pending) return\n try {\n const browser = await pending\n await browser.close()\n } catch {\n // \u542F\u52A8\u672C\u6765\u5C31\u5931\u8D25 / \u5DF2\u7ECF\u5173\u6389:\u5FFD\u7565\n }\n}\n\nexport interface CaptureOptions {\n url: string\n width: number\n height: number\n /** true = \u622A\u5168\u9875,false = \u53EA\u622A\u89C6\u53E3 */\n fullPage: boolean\n /** \u5BFC\u822A\u5B8C\u6210\u540E\u989D\u5916\u9759\u7F6E\u6BEB\u79D2\u6570 */\n settleMs: number\n}\n\n/**\n * \u5185\u90E8\u80FD\u529B:\u5F00\u4E00\u4E2A\u65B0 context \u6253\u5F00 url \u5E76\u622A\u56FE,\u8FD4\u56DE PNG buffer\u3002\n * \u4E0D\u5C5E\u4E8E\u5BF9\u5916\u5951\u7EA6,\u5BFC\u51FA\u53EA\u4E3A selftest \u76F4\u63A5\u8C03\u7528\u3002\n */\nexport async function captureUrl(opts: CaptureOptions): Promise<Buffer> {\n const browser = await getBrowser()\n const context = await browser.newContext({ viewport: { width: opts.width, height: opts.height } })\n try {\n const page = await context.newPage()\n try {\n await page.goto(opts.url, { waitUntil: \"networkidle\", timeout: NAV_TIMEOUT_MS })\n } catch {\n // next dev \u7684\u957F\u8FDE\u63A5\u53EF\u80FD\u8BA9 networkidle \u7B49\u4E0D\u5230:\u9000\u800C\u6C42\u5176\u6B21,\u7B49 DOM \u5C31\u7EEA\u540E\u7167\u5E38\u622A\n await page.waitForLoadState(\"domcontentloaded\").catch(() => {})\n }\n if (opts.settleMs > 0) await page.waitForTimeout(opts.settleMs)\n return await page.screenshot({ fullPage: opts.fullPage, type: \"png\" })\n } finally {\n await context.close()\n scheduleIdleClose()\n }\n}\n\n/** \u53D6 Next \u4FA7\u6CE8\u518C\u8868(node fetch \u4E0D\u8D70\u7CFB\u7EDF\u4EE3\u7406,\u4E0D\u7528\u989D\u5916\u5904\u7406) */\nasync function fetchRegistry(cfg: CsConfig): Promise<RegistryEntry[]> {\n const url = `${cfg.target.replace(/\\/+$/, \"\")}/__cs/registry`\n let res: Response\n try {\n res = await fetch(url)\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n throw new Error(\n `contactsheet: \u8BFB\u4E0D\u5230\u6CE8\u518C\u8868 ${url}\u3002\u786E\u8BA4\u4F60\u7684 next dev \u6B63\u5728\u8DD1,\u5E76\u4E14 contactsheet \u5DF2\u6CE8\u5165\u8DEF\u7531(\u5728\u9879\u76EE\u91CC\u8DD1 npx contactsheet)\u3002\u539F\u59CB\u9519\u8BEF:${msg}`\n )\n }\n if (!res.ok) {\n throw new Error(\n `contactsheet: \u6CE8\u518C\u8868 ${url} \u8FD4\u56DE ${res.status}\u3002\u6CE8\u5165\u8DEF\u7531\u53EF\u80FD\u6CA1\u751F\u6548,\u91CD\u8DD1 npx contactsheet \u8BA9\u5B83\u91CD\u5199\u6CE8\u5165\u6587\u4EF6\u3002`\n )\n }\n return (await res.json()) as RegistryEntry[]\n}\n\n/** \u6587\u4EF6\u540D\u91CC\u53BB\u6389\u8DEF\u5F84\u5206\u9694\u7B26\u7B49\u4E0D\u5B89\u5168\u5B57\u7B26(id \u5F62\u5982 \"sub__Button.artboard--\u9ED8\u8BA4\") */\nfunction safeFileName(id: string): string {\n return id.replace(/[/\\\\:*?\"<>|]/g, \"_\")\n}\n\n/** PNG \u5C3A\u5BF8\u76F4\u63A5\u8BFB IHDR */\nfunction pngSize(buf: Buffer): { width: number; height: number } {\n return { width: buf.readUInt32BE(16), height: buf.readUInt32BE(20) }\n}\n\n/** \u843D\u76D8\u5230 <projectRoot>/<designDir>/.canvas/shots/<name>.png,\u8FD4\u56DE repo \u76F8\u5BF9\u8DEF\u5F84 */\nasync function save(cfg: CsConfig, name: string, buf: Buffer): Promise<string> {\n const file = `${safeFileName(name)}.png`\n const abs = path.join(cfg.projectRoot, cfg.designDir, \".canvas\", \"shots\", file)\n await mkdir(path.dirname(abs), { recursive: true })\n await writeFile(abs, buf)\n return `${cfg.designDir.split(path.sep).join(\"/\").replace(/\\/+$/, \"\")}/.canvas/shots/${file}`\n}\n\nexport async function screenshot(cfg: CsConfig, req: ShotRequest): Promise<ShotResult> {\n let buf: Buffer\n let name: string\n\n if (req.id) {\n const entries = await fetchRegistry(cfg)\n const entry = entries.find(e => e.id === req.id)\n if (!entry) {\n const known = entries.slice(0, 10).map(e => e.id).join(\", \")\n throw new Error(\n `contactsheet: \u6CE8\u518C\u8868\u91CC\u6CA1\u6709\u753B\u677F \"${req.id}\"\u3002\u5DF2\u77E5 id:${known || \"(\u7A7A)\"}${entries.length > 10 ? \" \u2026\" : \"\"}`\n )\n }\n const base = `http://localhost:${cfg.port}`\n let url: string\n if (entry.kind === \"screen\") {\n url = `${base}${entry.url ?? \"/\"}`\n } else {\n url = `${base}/__cs/ab/${encodeURIComponent(entry.id)}`\n if (req.args) url += `?args=${encodeURIComponent(JSON.stringify(req.args))}`\n }\n buf = await captureUrl({\n url,\n width: entry.env?.width ?? 480,\n height: 900,\n fullPage: true,\n settleMs: 50,\n })\n name = entry.id\n } else {\n // \u6574\u9762\u5899:\u753B\u5E03\u672C\u8EAB,\u56FA\u5B9A\u5927\u89C6\u53E3,\u7ED9\u61D2\u6302\u8F7D\u7684 iframe \u7559\u51FA\u52A0\u8F7D\u65F6\u95F4\n buf = await captureUrl({\n url: `http://localhost:${cfg.port}/__cs`,\n width: 2400,\n height: 1350,\n fullPage: false,\n settleMs: 3000,\n })\n name = \"wall\"\n }\n\n const relPath = await save(cfg, name, buf)\n const { width, height } = pngSize(buf)\n return { path: relPath, base64: buf.toString(\"base64\"), width, height }\n}\n", "// /__cs/api/* \u7684\u5168\u90E8\u5904\u7406:state / selection / annotations / refs / context / screenshot\nimport { randomUUID } from \"node:crypto\"\nimport type { IncomingMessage, ServerResponse } from \"node:http\"\nimport type { Annotation, CsConfig, Selection, ShotRequest, StateInfo } from \"../types.js\"\nimport { screenshot } from \"../shot/index.js\"\nimport { mimeOf, pkgVersion } from \"./assets.js\"\nimport { pushToSession } from \"./push.js\"\nimport { currentHealth } from \"./health.js\"\nimport { broadcast } from \"./sse.js\"\nimport * as store from \"./store.js\"\n\nconst ANN = \"/__cs/api/annotations\"\n\n/** \u672C\u6B21\u8FDB\u7A0B\u7684 push token:\u53EA\u53D1\u7ED9\u753B\u5E03\u9875(\u89C1 serveUi),iframe \u5185\u7684\u7528\u6237\u9875\u9762\u8BFB\u4E0D\u5230 */\nlet TOKEN: string | null = null\nexport function pushToken(): string {\n if (!TOKEN) TOKEN = randomUUID()\n return TOKEN\n}\n\n/**\n * \u8DE8\u6E90\u5199\u5165\u95F8\u95E8\u3002readJson \u4E0D\u770B content-type,\u6240\u4EE5\u8DE8\u6E90 fetch \u7684 POST \u5C5E\u4E8E\"\u7B80\u5355\u8BF7\u6C42\"\u3001\n * \u6CA1\u6709\u9884\u68C0\u5C31\u80FD\u4EA7\u751F\u526F\u4F5C\u7528\u2014\u2014\u4EFB\u610F\u7F51\u9875\u90FD\u80FD\u9489\u6279\u6CE8\u518D\u8C03 push,\u628A\u6587\u672C\u9001\u8FDB\u4F60\u7684 Claude Code \u4F1A\u8BDD\u3002\n * \u89C4\u5219:\u975E GET \u5FC5\u987B\u6765\u81EA\u672C\u673A\u753B\u5E03\u81EA\u8EAB(\u6216\u4E0D\u5E26 Origin \u7684 curl/\u811A\u672C)\u3002\n */\nfunction originAllowed(cfg: CsConfig, req: IncomingMessage): boolean {\n const origin = req.headers.origin\n if (!origin) return true // curl / node fetch / \u540C\u6E90\u5BFC\u822A,\u4E0D\u662F\u6D4F\u89C8\u5668\u53D1\u8D77\u7684\u8DE8\u6E90\u8BF7\u6C42\n const ok = new Set([\n `http://localhost:${cfg.port}`,\n `http://127.0.0.1:${cfg.port}`,\n `http://[::1]:${cfg.port}`,\n ])\n return ok.has(origin)\n}\n\nexport async function handleApi(\n cfg: CsConfig,\n req: IncomingMessage,\n res: ServerResponse,\n pathname: string\n): Promise<void> {\n const method = req.method ?? \"GET\"\n\n if (method !== \"GET\" && !originAllowed(cfg, req)) {\n return sendText(res, 403, \"contactsheet: \u62D2\u7EDD\u8DE8\u6E90\u5199\u5165(Origin \u4E0D\u662F\u672C\u673A\u753B\u5E03)\")\n }\n\n if (pathname === \"/__cs/api/state\") {\n if (method !== \"GET\") return sendText(res, 405, \"method not allowed\")\n const info: StateInfo = {\n version: pkgVersion(),\n target: cfg.target,\n designDir: cfg.designDir,\n projectRoot: cfg.projectRoot,\n }\n return sendJson(res, 200, info)\n }\n\n if (pathname === \"/__cs/api/selection\") {\n if (method === \"GET\") return sendJson(res, 200, store.getSelection())\n if (method === \"POST\") {\n const body = await readJson<Selection | null>(req)\n // \u4F20 null / \u7F3A artboardId \u90FD\u5F53\u4F5C\u6E05\u7A7A\n store.setSelection(body && typeof body.artboardId === \"string\" ? body : null)\n return sendEmpty(res, 204)\n }\n return sendText(res, 405, \"method not allowed\")\n }\n\n if (pathname === ANN || pathname.startsWith(ANN + \"/\")) {\n return handleAnnotations(cfg, req, res, pathname, method)\n }\n\n // \u53D6\u56FE:\u6279\u6CE8\u6C14\u6CE1\u91CC\u7684\u7F29\u7565\u56FE\u5237\u65B0\u540E\u8981\u80FD\u91CD\u65B0\u62FF\u5230\u5B57\u8282(\u5185\u5B58 dataURL \u53EA\u6D3B\u4E00\u6B21\u4F1A\u8BDD)\n if (pathname.startsWith(\"/__cs/api/refs/\")) {\n if (method !== \"GET\") return sendText(res, 405, \"method not allowed\")\n const rel = pathname.slice(\"/__cs/api/refs/\".length).split(\"/\").map(decodeURIComponent).join(\"/\")\n const hit = await store.readRef(cfg, rel)\n if (!hit) return sendText(res, 404, \"contactsheet: \u627E\u4E0D\u5230\u53C2\u8003\u56FE\")\n res.writeHead(200, { \"content-type\": mimeOf(hit.file), \"cache-control\": \"no-store\" })\n res.end(hit.body)\n return\n }\n\n if (pathname === \"/__cs/api/refs\") {\n if (method !== \"POST\") return sendText(res, 405, \"method not allowed\")\n const body = await readJson<{ name?: string; dataBase64?: string }>(req)\n if (!body?.dataBase64) return sendText(res, 400, \"\u7F3A\u5C11 dataBase64\")\n const rel = await store.saveRef(cfg, body.name || \"ref.png\", body.dataBase64)\n return sendJson(res, 200, { path: rel })\n }\n\n if (pathname === \"/__cs/api/health\") {\n if (method !== \"GET\") return sendText(res, 405, \"method not allowed\")\n return sendJson(res, 200, currentHealth())\n }\n\n if (pathname === \"/__cs/api/context\") {\n if (method !== \"GET\") return sendText(res, 405, \"method not allowed\")\n // \u7ED9 UserPromptSubmit hook \u7528:\u6CA1\u5185\u5BB9\u5C31\u662F\u7A7A body,hook \u90A3\u8FB9\u539F\u6837\u6CE8\u5165\u5373\u53EF\u3002\n // \u6279\u6CE8\u6587\u4EF6\u574F\u6389\u65F6\u4E5F\u8981 200\u2014\u2014\u8BA9\u7528\u6237\u5728\u81EA\u5DF1\u7684\u5BF9\u8BDD\u91CC\u770B\u89C1\u8FD9\u53E5\u8BDD,\u800C\u4E0D\u662F hook \u9759\u9ED8\u5931\u8D25\n try {\n return sendText(res, 200, await store.buildContextText(cfg))\n } catch (err) {\n return sendText(res, 200, `[contactsheet] \u8BFB\u6279\u6CE8\u5931\u8D25:${errText(err)}`)\n }\n }\n\n if (pathname === \"/__cs/api/push\") {\n if (method !== \"POST\") return sendText(res, 405, \"method not allowed\")\n // push \u662F\u552F\u4E00\u80FD\"\u4EE5\u4F60\u7684\u540D\u4E49\"\u5411 Claude Code \u4F1A\u8BDD\u8BF4\u8BDD\u7684\u7AEF\u70B9,\u989D\u5916\u8981 token\n if (req.headers[\"x-cs-token\"] !== pushToken()) {\n return sendText(res, 403, \"contactsheet: \u7F3A\u5C11\u753B\u5E03 token,\u62D2\u7EDD\u63A8\u9001(\u8BF7\u4ECE\u753B\u5E03\u9875\u64CD\u4F5C)\")\n }\n const body = await readJson<{ pid?: number }>(req)\n try {\n const text = await store.buildContextText(cfg)\n if (!text.trim()) return sendJson(res, 200, { ok: false, reason: \"\u6CA1\u6709\u5F85\u5904\u7406\u7684\u6279\u6CE8\u6216\u9009\u4E2D,\u5148\u6309 c \u9489\u4E00\u6761\" })\n return sendJson(res, 200, await pushToSession(cfg, text, body?.pid))\n } catch (err) {\n return sendJson(res, 200, { ok: false, reason: `\u6CE8\u5165\u5931\u8D25:${errText(err)}` })\n }\n }\n\n if (pathname === \"/__cs/api/screenshot\") {\n if (method !== \"POST\") return sendText(res, 405, \"method not allowed\")\n const body = await readJson<ShotRequest>(req)\n try {\n return sendJson(res, 200, await screenshot(cfg, body ?? {}))\n } catch (err) {\n // shot \u6A21\u5757\u8FD8\u662F stub / playwright \u8D77\u4E0D\u6765,\u90FD\u8D70\u8FD9\u91CC\n return sendText(res, 500, `screenshot \u5931\u8D25:${errText(err)}`)\n }\n }\n\n return sendText(res, 404, \"not found\")\n}\n\nasync function handleAnnotations(\n cfg: CsConfig,\n req: IncomingMessage,\n res: ServerResponse,\n pathname: string,\n method: string\n): Promise<void> {\n const id = pathname === ANN ? \"\" : decodeURIComponent(pathname.slice(ANN.length + 1))\n\n if (!id && method === \"GET\") {\n return sendJson(res, 200, await store.readAnnotations(cfg))\n }\n\n if (!id && method === \"POST\") {\n const body = await readJson<Partial<Annotation>>(req)\n const { result, list } = await store.updateAnnotations(cfg, (all) => {\n const ann: Annotation = {\n id: store.newAnnotationId(all),\n // \u6C38\u4E45\u5E8F\u53F7:\u5168\u8868 max+1,\u5305\u542B verified \u7684 \u2014\u2014 \u53F7\u53EA\u6DA8\u4E0D\u590D\u7528,\u6838\u9A8C\u6D88\u5931\u4E5F\u4E0D\u8BA9\u540E\u6765\u8005\u9876\u53F7\n seq: all.reduce((m, a) => Math.max(m, a.seq ?? 0), 0) + 1,\n artboardId: body?.artboardId,\n anchor: body?.anchor,\n text: typeof body?.text === \"string\" ? body.text : \"\",\n refs: Array.isArray(body?.refs) ? body.refs : [],\n status: body?.status === \"resolved\" ? \"resolved\" : \"open\",\n createdAt: new Date().toISOString(),\n }\n all.push(ann)\n return ann\n })\n broadcast({ type: \"annotations\", annotations: list })\n return sendJson(res, 201, result)\n }\n\n if (id && method === \"PATCH\") {\n const patch = await readJson<Partial<Annotation>>(req)\n const { result, list } = await store.updateAnnotations(cfg, (all) => {\n const hit = all.find((a) => a.id === id)\n if (!hit) return null\n // id / createdAt \u4E0D\u7ED9\u6539\n Object.assign(hit, patch, { id: hit.id, createdAt: hit.createdAt })\n return hit\n })\n if (!result) return sendText(res, 404, \"annotation not found\")\n broadcast({ type: \"annotations\", annotations: list })\n return sendJson(res, 200, result)\n }\n\n if (id && method === \"DELETE\") {\n const { result, list } = await store.updateAnnotations(cfg, (all) => {\n const i = all.findIndex((a) => a.id === id)\n if (i < 0) return false\n all.splice(i, 1)\n return true\n })\n if (!result) return sendText(res, 404, \"annotation not found\")\n broadcast({ type: \"annotations\", annotations: list })\n return sendEmpty(res, 204)\n }\n\n return sendText(res, 405, \"method not allowed\")\n}\n\n// ---------- \u5C0F\u5DE5\u5177 ----------\n\nexport function sendJson(res: ServerResponse, code: number, body: unknown): void {\n res.writeHead(code, { \"content-type\": \"application/json; charset=utf-8\", \"cache-control\": \"no-store\" })\n res.end(JSON.stringify(body ?? null))\n}\n\nexport function sendText(res: ServerResponse, code: number, body: string): void {\n res.writeHead(code, { \"content-type\": \"text/plain; charset=utf-8\", \"cache-control\": \"no-store\" })\n res.end(body)\n}\n\nfunction sendEmpty(res: ServerResponse, code: number): void {\n res.writeHead(code)\n res.end()\n}\n\nexport function errText(err: unknown): string {\n return err instanceof Error ? err.message : String(err)\n}\n\nasync function readJson<T>(req: IncomingMessage): Promise<T> {\n const chunks: Buffer[] = []\n for await (const c of req) chunks.push(c as Buffer)\n const raw = Buffer.concat(chunks).toString(\"utf8\").trim()\n if (!raw) return null as T\n return JSON.parse(raw) as T\n}\n", "// \u753B\u5E03\u9759\u6001\u8D44\u4EA7\u5B9A\u4F4D\u3002\u6253\u5305\u540E cli.js \u5728 dist/,\u8D44\u4EA7\u5728 dist/canvas/;\n// \u5F00\u53D1\u671F(app.js \u7531 build.mjs --watch \u4EA7\u51FA\u5230 dist)\u56DE\u843D\u5305\u6839\u7684 dist/canvas \u4E0E src/canvas\nimport fs from \"node:fs\"\nimport path from \"node:path\"\nimport { fileURLToPath } from \"node:url\"\n\nconst here = path.dirname(fileURLToPath(import.meta.url))\nconst pkgRoot = path.resolve(here, \"..\")\n\nconst DIRS = [\n path.join(here, \"canvas\"), // \u53D1\u5E03\u5F62\u6001:dist/cli.js \u65C1\u8FB9\u7684 dist/canvas\n path.join(pkgRoot, \"dist\", \"canvas\"),\n path.join(pkgRoot, \"src\", \"canvas\"), // \u5F00\u53D1\u671F\u76F4\u8BFB\u6E90\u7801\u91CC\u7684 index.html / style.css\n]\n\n/** \u9010\u4E2A\u5019\u9009\u76EE\u5F55\u627E\u8D44\u4EA7\u6587\u4EF6,\u627E\u4E0D\u5230\u8FD4\u56DE null */\nexport function findUiFile(name: string): string | null {\n for (const dir of DIRS) {\n const p = path.join(dir, name)\n if (fs.existsSync(p) && fs.statSync(p).isFile()) return p\n }\n return null\n}\n\nconst MIME: Record<string, string> = {\n \".html\": \"text/html; charset=utf-8\",\n \".js\": \"text/javascript; charset=utf-8\",\n \".css\": \"text/css; charset=utf-8\",\n \".map\": \"application/json; charset=utf-8\",\n \".json\": \"application/json; charset=utf-8\",\n \".png\": \"image/png\",\n \".svg\": \"image/svg+xml\",\n \".jpg\": \"image/jpeg\",\n \".jpeg\": \"image/jpeg\",\n \".gif\": \"image/gif\",\n \".webp\": \"image/webp\",\n}\n\nexport function mimeOf(file: string): string {\n return MIME[path.extname(file)] ?? \"application/octet-stream\"\n}\n\n/** StateInfo.version \u7528;\u8BFB\u4E0D\u5230\u5C31\u7ED9\u4E2A\u5360\u4F4D */\nexport function pkgVersion(): string {\n try {\n const pkg = JSON.parse(fs.readFileSync(path.join(pkgRoot, \"package.json\"), \"utf8\")) as { version?: string }\n return pkg.version ?? \"0.0.0\"\n } catch {\n return \"0.0.0\"\n }\n}\n", "// \u4E00\u952E\u63A8\u9001:\u628A\u753B\u5E03\u4E0A\u4E0B\u6587\u6CE8\u5165\u7ED1\u5B9A\u7684 Claude Code \u4F1A\u8BDD(inbox socket)\n//\n// \u901A\u9053\u8BF4\u660E:Claude Code \u7684 cross-session messaging \u4F1A\u7ED9\u6BCF\u4E2A\u4F1A\u8BDD\u5F00\u4E00\u4E2A UDS\n// (/tmp/cc-socks/<pid>.sock),\u534F\u8BAE\u4E3A\u6362\u884C\u5206\u9694 JSON,\u6CE8\u5165\u683C\u5F0F\u6765\u81EA Claude Code\n// \u81EA\u5DF1\u7684\u542F\u52A8\u65E5\u5FD7:{\"type\":\"user\",\"message\":{\"role\":\"user\",\"content\":\"...\"}}\n// \u8FD9\u662F\u534A\u516C\u5F00\u7684\u5185\u90E8\u901A\u9053(\u5B98\u65B9\u6587\u6863\u8BF4\u5B83\u670D\u52A1\u4E8E hooks/Bash),\u7248\u672C\u5347\u7EA7\u53EF\u80FD\u53D8\u2014\u2014\n// \u5931\u8D25\u65F6\u524D\u7AEF\u4F1A\u56DE\u843D\u5230\"\u590D\u5236\u5230\u526A\u8D34\u677F\"\u3002\u5B98\u65B9\u6B63\u95E8\u662F Channels(MCP),\u5217\u4E3A\u540E\u7EED\u8DEF\u5F84\u3002\n//\n// \u4F1A\u8BDD\u53D1\u73B0:~/.claude/sessions/<pid>.json \u662F Claude Code \u7684\u4F1A\u8BDD\u767B\u8BB0\u5904,\n// \u5E26 name(\u4F1A\u8BDD\u540D)/cwd/status/socket \u8DEF\u5F84;\u6309 cwd \u2208 \u9879\u76EE\u6839 \u8FC7\u6EE4,socket \u63A2\u6D3B\u53BB\u5C38\u4F53\u3002\nimport fs from \"node:fs/promises\"\nimport net from \"node:net\"\nimport os from \"node:os\"\nimport path from \"node:path\"\nimport type { CsConfig } from \"../types.js\"\n\nexport interface PushTarget {\n pid: number\n name: string\n status: string\n cwd: string\n socket: string\n updatedAt: number\n}\n\ninterface SessionRecord {\n pid?: number\n cwd?: string\n name?: string\n status?: string\n kind?: string\n messagingSocketPath?: string\n updatedAt?: number\n}\n\n/** 250ms \u8FDE\u63A5\u63A2\u6D3B(\u4E0E Claude Code \u81EA\u5DF1\u7684\u63A2\u6D3B\u903B\u8F91\u4E00\u81F4) */\nfunction isLive(sock: string): Promise<boolean> {\n return new Promise((resolve) => {\n const s = new net.Socket()\n const done = (ok: boolean): void => {\n s.destroy()\n resolve(ok)\n }\n s.on(\"connect\", () => done(true))\n s.on(\"error\", () => done(false))\n s.setTimeout(250, () => done(false))\n s.connect({ path: sock })\n })\n}\n\n/** \u5217\u51FA\u5019\u9009:\u767B\u8BB0\u5904\u91CC cwd \u5728\u672C\u9879\u76EE\u4E0B\u3001socket \u6D3B\u7740\u7684\u4EA4\u4E92\u5F0F\u4F1A\u8BDD,\u6700\u8FD1\u6D3B\u8DC3\u5728\u524D */\nexport async function listTargets(cfg: CsConfig): Promise<PushTarget[]> {\n const root = path.resolve(cfg.projectRoot)\n const dir = path.join(os.homedir(), \".claude\", \"sessions\")\n let names: string[]\n try {\n names = await fs.readdir(dir)\n } catch {\n return []\n }\n const out: PushTarget[] = []\n await Promise.all(\n names\n .filter((n) => n.endsWith(\".json\"))\n .map(async (n) => {\n let rec: SessionRecord\n try {\n rec = JSON.parse(await fs.readFile(path.join(dir, n), \"utf8\")) as SessionRecord\n } catch {\n return\n }\n if (!rec.pid || !rec.cwd || !rec.messagingSocketPath) return\n if (rec.kind && rec.kind !== \"interactive\") return\n const rel = path.relative(root, path.resolve(rec.cwd))\n if (rel.startsWith(\"..\") || path.isAbsolute(rel)) return // \u4E0D\u5728\u9879\u76EE\u5185\n if (!(await isLive(rec.messagingSocketPath))) return // \u767B\u8BB0\u5904\u6709\u5C38\u4F53,\u63A2\u6D3B\u8FC7\u6EE4\n out.push({\n pid: rec.pid,\n name: rec.name ?? `pid ${rec.pid}`,\n status: rec.status ?? \"unknown\",\n cwd: rec.cwd,\n socket: rec.messagingSocketPath,\n updatedAt: rec.updatedAt ?? 0,\n })\n })\n )\n out.sort((a, b) => b.updatedAt - a.updatedAt)\n return out\n}\n\n/** \u5199\u4E00\u884C JSONL \u8FDB\u4F1A\u8BDD inbox\u3002\u5199\u6210\u529F\u5373\u89C6\u4E3A\u9001\u8FBE(\u56DE\u6267\u8D70\u7684\u662F\u4F1A\u8BDD\u95F4\u534F\u8BAE,\u5916\u90E8\u8FDB\u7A0B\u6536\u4E0D\u5230) */\nexport function inject(sock: string, content: string): Promise<void> {\n return new Promise((resolve, reject) => {\n const s = net.createConnection({ path: sock })\n s.setTimeout(3000, () => {\n s.destroy()\n reject(new Error(\"\u5199\u5165\u8D85\u65F6\"))\n })\n s.on(\"error\", reject)\n s.on(\"connect\", () => {\n const line =\n JSON.stringify({ type: \"user\", message: { role: \"user\", content } }) + \"\\n\"\n s.end(line, () => resolve())\n })\n })\n}\n\nexport type PushResult =\n | { ok: true; pid: number; name: string }\n | { ok: false; reason: string }\n | { ok: false; choose: Array<Pick<PushTarget, \"pid\" | \"name\" | \"status\" | \"cwd\">> }\n\n/** \u63A8\u9001\u5165\u53E3:\u6307\u5B9A pid \u76F4\u53D1;\u552F\u4E00\u5019\u9009\u76F4\u53D1;\u591A\u4E2A\u5019\u9009\u8BA9\u524D\u7AEF\u51FA\u9009\u62E9\u5668 */\nexport async function pushToSession(\n cfg: CsConfig,\n text: string,\n pid?: number\n): Promise<PushResult> {\n const targets = await listTargets(cfg)\n if (!targets.length) {\n return {\n ok: false,\n reason: `\u6CA1\u627E\u5230\u5DE5\u4F5C\u76EE\u5F55\u5728 ${cfg.projectRoot} \u4E0B\u7684 Claude Code \u4F1A\u8BDD(\u8981\u5148\u5728\u9879\u76EE\u76EE\u5F55\u91CC\u5F00\u7740 claude)`,\n }\n }\n let target: PushTarget | undefined\n if (pid !== undefined) {\n target = targets.find((t) => t.pid === pid)\n if (!target) return { ok: false, reason: `\u4F1A\u8BDD pid ${pid} \u5DF2\u4E0D\u5728(\u53EF\u80FD\u521A\u5173\u6389),\u91CD\u6309 p \u91CD\u9009` }\n } else if (targets.length === 1) {\n target = targets[0]\n } else {\n return {\n ok: false,\n choose: targets.map(({ pid: p, name, status, cwd }) => ({ pid: p, name, status, cwd })),\n }\n }\n const body =\n `[contactsheet] \u7528\u6237\u5728\u753B\u5E03\u4E0A\u6309\u4E0B\u4E86\u63A8\u9001\u952E,\u4EE5\u4E0B\u662F\u5F53\u524D\u753B\u5E03\u4E0A\u4E0B\u6587,\u8BF7\u6309\u6279\u6CE8\u5904\u7406:\\n\\n` + text\n await inject(target!.socket, body)\n return { ok: true, pid: target!.pid, name: target!.name }\n}\n", "// \u76EE\u6807 dev server \u7684\u5065\u5EB7\u63A2\u6D4B\u3002\n// \u52A8\u673A(Synco \u5B9E\u6D4B\u73B0\u573A):\u753B\u5E03\u957F\u5F00 + \u7528\u6237\u6301\u7EED\u6539\u4EE3\u7801,next dev \u53EF\u80FD\u8FDB\u5165\u50F5\u6B7B\u6001 \u2014\u2014\n// \u8FDB\u7A0B\u6D3B\u7740\u3001\u7AEF\u53E3 LISTEN\u3001\u9759\u6001\u8D44\u6E90 200,\u4F46 SSR \u79D2 500\u3001API \u6C38\u4E45\u6302\u8D77\u3002\u6B64\u65F6\u753B\u5E03\u4E0A\n// \u6BCF\u5757\u753B\u677F\u5404\u81EA\u7834\u56FE,\u7528\u6237\u770B\u5230\u7684\u662F\"contactsheet \u5D29\u4E86\",\u5F52\u56E0\u5B8C\u5168\u9519\u4E86\u3002\n// \u8FD9\u91CC\u4E3B\u52A8\u63A2\u6D4B\u5E76\u5E7F\u64AD\u4E00\u4E2A**\u5168\u5C40**\u72B6\u6001,\u8BA9\u753B\u5E03\u7528\u4E00\u6761\u6A2A\u5E45\u628A\u8BDD\u8BF4\u6E05\u695A\u3002\n//\n// \u63A2\u6D4B\u76EE\u6807\u9009 /__cs/registry:\u5B83\u662F\u6CE8\u5165\u8FDB\u7528\u6237 app \u7684 RSC \u8DEF\u7531,\u8D70\u7684\u6B63\u662F\u50F5\u6B7B\u6307\u7EB9\u91CC\n// \u6302\u6389\u7684\u90A3\u6761 server \u6E32\u67D3\u8DEF\u5F84 \u2014\u2014 \u9759\u6001\u8D44\u6E90\u63A2\u6D4B\u5728\u8FD9\u79CD\u6545\u969C\u4E0B\u4F1A\u7ED9\u5047\u9634\u6027\u3002\nimport type { CsConfig, CsEvent } from \"../types.js\"\n\nexport interface HealthState {\n ok: boolean\n /** \u4E0D\u5065\u5EB7\u65F6\u7684\u4E00\u53E5\u8BDD\u8BCA\u65AD(\u8D85\u65F6/HTTP 5xx/\u8FDE\u4E0D\u4E0A) */\n detail?: string\n /** \u6700\u540E\u4E00\u6B21\u63A2\u6D4B\u6210\u529F\u7684\u65F6\u95F4\u6233(ms);\u4ECE\u672A\u6210\u529F\u8FC7\u5219\u7F3A\u7701 */\n lastOkAt?: number\n}\n\nconst INTERVAL_MS = Number(process.env.CS_HEALTH_INTERVAL_MS ?? 20000)\nconst TIMEOUT_MS = Number(process.env.CS_HEALTH_TIMEOUT_MS ?? 10000)\n/** \u8FDE\u7EED\u5931\u8D25\u8FD9\u4E48\u591A\u6B21\u624D\u7B97\u4E0D\u5065\u5EB7:\u5355\u6B21\u6296\u52A8(\u5927\u9879\u76EE\u51B7\u7F16\u8BD1\u3001\u77AC\u65F6\u9AD8\u8D1F\u8F7D)\u4E0D\u8BE5\u62C9\u6A2A\u5E45 */\nconst FAILS_TO_TRIP = 2\n\nlet current: HealthState = { ok: true }\n\nexport function currentHealth(): HealthState {\n return current\n}\n\nexport function startHealthMonitor(\n cfg: CsConfig,\n broadcast: (ev: CsEvent) => void\n): { close(): void } {\n let fails = 0\n let everOk = false\n let timer: NodeJS.Timeout | null = null\n\n const probe = async (): Promise<void> => {\n let failDetail: string | null = null\n try {\n const r = await fetch(`${cfg.target}/__cs/registry`, { signal: AbortSignal.timeout(TIMEOUT_MS) })\n if (r.ok || r.status === 404) {\n // 404 \u4E5F\u7B97\u6D3B\u7740:clean \u8FC7\u6CE8\u5165\u6587\u4EF6\u65F6\u8DEF\u7531\u4E0D\u5B58\u5728,\u4F46 server \u672C\u8EAB\u5728\u6B63\u5E38\u5E72\u6D3B\n everOk = true\n fails = 0\n if (!current.ok) {\n current = { ok: true, lastOkAt: Date.now() }\n broadcast({ type: \"health\", ok: true })\n } else {\n current = { ok: true, lastOkAt: Date.now() }\n }\n return\n }\n failDetail = `SSR \u63A2\u6D4B\u8FD4\u56DE HTTP ${r.status}`\n } catch (err) {\n const e = err as { name?: string; cause?: { code?: string } }\n failDetail =\n e.name === \"TimeoutError\"\n ? `SSR \u63A2\u6D4B ${TIMEOUT_MS / 1000}s \u65E0\u54CD\u5E94`\n : `\u8FDE\u4E0D\u4E0A(${e.cause?.code ?? \"network\"})`\n }\n // \u4ECE\u672A\u6210\u529F\u8FC7\u5C31\u4E0D\u5224\u6B7B\u5211:\u51B7\u542F\u52A8/\u5927\u9879\u76EE\u9996\u7F16\u671F\u95F4\u7684\u5931\u8D25\u7531\u753B\u5E03\u9519\u8BEF\u5361\u8D1F\u8D23,\u4E0D\u5F52\u6A2A\u5E45\n if (!everOk) return\n fails++\n if (fails >= FAILS_TO_TRIP && current.ok) {\n current = { ok: false, detail: failDetail ?? \"\u672A\u77E5\", lastOkAt: current.lastOkAt }\n broadcast({ type: \"health\", ok: false, detail: current.detail })\n console.warn(`[contactsheet] \u26A0 \u76EE\u6807 ${cfg.target} \u7591\u4F3C\u50F5\u6B7B:${current.detail}(\u9759\u6001\u53EF\u80FD\u4ECD 200)\u3002\u753B\u5E03\u5DF2\u6302\u6A2A\u5E45\u3002`)\n }\n }\n\n timer = setInterval(() => void probe(), INTERVAL_MS)\n timer.unref()\n void probe()\n return {\n close() {\n if (timer) clearInterval(timer)\n },\n }\n}\n", "// SSE hub \u2014\u2014 \u6A21\u5757\u7EA7\u5355\u4F8B\u3002startServer \u7684\u8FD4\u56DE\u503C\u7B7E\u540D\u51BB\u7ED3,\u63A8\u4E8B\u4EF6\u8D70\u8FD9\u91CC\u5BFC\u51FA\u7684 broadcast\nimport type { IncomingMessage, ServerResponse } from \"node:http\"\nimport type { CsEvent } from \"../types.js\"\n\nconst clients = new Set<ServerResponse>()\nlet heartbeat: NodeJS.Timeout | null = null\n\n/** \u6302\u4E00\u4E2A SSE \u5BA2\u6237\u7AEF(GET /__cs/events) */\nexport function attach(req: IncomingMessage, res: ServerResponse): void {\n res.writeHead(200, {\n \"content-type\": \"text/event-stream; charset=utf-8\",\n \"cache-control\": \"no-cache, no-transform\",\n connection: \"keep-alive\",\n \"x-accel-buffering\": \"no\",\n })\n res.write(\": contactsheet connected\\n\\n\")\n clients.add(res)\n\n // \u65AD\u5F00\u5C31\u6E05\u5F15\u7528,\u6CA1\u4EBA\u4E86\u5C31\u505C\u5FC3\u8DF3\n const drop = () => {\n clients.delete(res)\n if (clients.size === 0) stopHeartbeat()\n }\n req.on(\"close\", drop)\n req.on(\"error\", drop)\n res.on(\"close\", drop)\n\n startHeartbeat()\n}\n\n/** \u63A8\u4E00\u6761\u4E8B\u4EF6:\u4E8B\u4EF6\u540D = type,data = \u6574\u4E2A CsEvent \u7684 JSON */\nexport function broadcast(ev: CsEvent): void {\n const chunk = `event: ${ev.type}\\ndata: ${JSON.stringify(ev)}\\n\\n`\n for (const res of clients) {\n try {\n res.write(chunk)\n } catch {\n clients.delete(res)\n }\n }\n}\n\n/** \u9000\u51FA\u65F6\u65AD\u5F00\u5168\u90E8\u5BA2\u6237\u7AEF(\u5426\u5219 server.close \u6C38\u8FDC\u7B49\u4E0D\u5230) */\nexport function closeAll(): void {\n for (const res of clients) {\n try {\n res.end()\n } catch {\n // \u5DF2\u7ECF\u65AD\u4E86,\u65E0\u6240\u8C13\n }\n }\n clients.clear()\n stopHeartbeat()\n}\n\nfunction startHeartbeat(): void {\n if (heartbeat) return\n // 15s \u4E00\u6761\u6CE8\u91CA\u884C,\u9632\u4E2D\u95F4\u5C42\u6390\u6389\u7A7A\u95F2\u8FDE\u63A5\n heartbeat = setInterval(() => {\n for (const res of clients) res.write(\": ping\\n\\n\")\n }, 15000)\n heartbeat.unref()\n}\n\nfunction stopHeartbeat(): void {\n if (!heartbeat) return\n clearInterval(heartbeat)\n heartbeat = null\n}\n", "// \u72B6\u6001:selection \u53EA\u5728\u5185\u5B58,annotations / refs \u843D\u76D8\u5230 <designDir>/.canvas/\nimport fs from \"node:fs/promises\"\nimport path from \"node:path\"\nimport type { Annotation, CsConfig, Selection } from \"../types.js\"\n\n// ---------- selection(\u5185\u5B58\u6001,\u8FDB\u7A0B\u9000\u51FA\u5373\u4E22) ----------\n\nlet selection: Selection | null = null\n\nexport function getSelection(): Selection | null {\n return selection\n}\n\nexport function setSelection(next: Selection | null): void {\n selection = next\n}\n\n// ---------- annotations ----------\n\nfunction canvasDir(cfg: CsConfig): string {\n return path.join(cfg.projectRoot, cfg.designDir, \".canvas\")\n}\n\nfunction annotationsFile(cfg: CsConfig): string {\n return path.join(canvasDir(cfg), \"annotations.json\")\n}\n\n/**\n * \u8BFB\u6279\u6CE8\u3002**\u6587\u4EF6\u4E0D\u5B58\u5728**\u624D\u662F\u7A7A\u8868;**\u5185\u5BB9\u574F\u4E86\u8981\u629B\u9519**\u2014\u2014\u4E0D\u80FD\u628A\u89E3\u6790\u5931\u8D25\u5F53\u6210\u7A7A\u8868,\n * \u5426\u5219\u8BFB-\u6539-\u5199\u4F1A\u62FF\u8FD9\u4E2A\u7A7A\u6570\u7EC4\u5F53\u57FA\u7EBF,\u4E0B\u4E00\u6B21\u9489 pin \u5C31\u628A\u6574\u4EFD\u5386\u53F2\u6C38\u4E45\u62B9\u6389\u3002\n * \u800C README \u660E\u786E\u9080\u8BF7 Claude Code \u624B\u6539\u8FD9\u4E2A\u6587\u4EF6,\u6539\u51FA\u7ED3\u6784\u504F\u5DEE\u662F\u5E38\u4E8B\u3002\n */\nexport async function readAnnotations(cfg: CsConfig): Promise<Annotation[]> {\n let raw: string\n try {\n raw = await fs.readFile(annotationsFile(cfg), \"utf8\")\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") return [] // \u8FD8\u6CA1\u6709\u6279\u6CE8,\u6B63\u5E38\n throw err\n }\n if (!raw.trim()) return []\n let list: unknown\n try {\n list = JSON.parse(raw)\n } catch (err) {\n throw new Error(\n `annotations.json \u89E3\u6790\u5931\u8D25(${(err as Error).message})\u3002\u4E3A\u907F\u514D\u8986\u76D6\u5386\u53F2\u5DF2\u62D2\u7EDD\u5199\u5165\u2014\u2014` +\n `\u8BF7\u4FEE\u597D ${annotationsFile(cfg)} \u518D\u8BD5\u3002`\n )\n }\n if (!Array.isArray(list)) {\n throw new Error(`annotations.json \u9876\u5C42\u4E0D\u662F\u6570\u7EC4,\u62D2\u7EDD\u5199\u5165\u4EE5\u514D\u8986\u76D6\u5386\u53F2:${annotationsFile(cfg)}`)\n }\n // \u65E7\u6570\u636E\u6CA1\u6709 seq:\u6309\u6587\u4EF6\u987A\u5E8F\u4ECE max+1 \u8D77\u8865(\u786E\u5B9A\u6027,\u91CD\u542F\u4E0D\u53D8\u53F7)\u3002\n // \u8FD9\u91CC\u53EA\u8865\u5185\u5B58\u91CC\u7684,\u4E0B\u4E00\u6B21\u4EFB\u4F55\u5199\u64CD\u4F5C\u4F1A\u968F\u6574\u8868\u843D\u76D8\n const anns = list as Annotation[]\n let next = anns.reduce((m, a) => Math.max(m, a.seq ?? 0), 0)\n for (const a of anns) if (typeof a.seq !== \"number\") a.seq = ++next\n return anns\n}\n\n/** \u539F\u5B50\u5199:\u4E34\u65F6\u6587\u4EF6 + rename;\u8986\u76D6\u524D\u7559\u4E00\u4EFD .bak(\u5386\u53F2\u662F\u8FD9\u4E2A\u5DE5\u5177\u552F\u4E00\u7684\u6301\u4E45\u8D44\u4EA7) */\nasync function writeAnnotations(cfg: CsConfig, list: Annotation[]): Promise<void> {\n const file = annotationsFile(cfg)\n await fs.mkdir(path.dirname(file), { recursive: true })\n await fs.copyFile(file, `${file}.bak`).catch(() => undefined) // \u9996\u6B21\u5199\u5165\u65F6\u6CA1\u6709\u65E7\u6587\u4EF6,\u6B63\u5E38\n const tmp = `${file}.${process.pid}.tmp`\n await fs.writeFile(tmp, JSON.stringify(list, null, 2) + \"\\n\", \"utf8\")\n await fs.rename(tmp, file)\n}\n\n// \u8BFB-\u6539-\u5199\u4E32\u884C\u5316,\u907F\u514D\u5E76\u53D1\u8BF7\u6C42\u4E92\u76F8\u8986\u76D6\nlet chain: Promise<unknown> = Promise.resolve()\n\n/** fn \u76F4\u63A5\u6539\u4F20\u5165\u7684\u6570\u7EC4;\u8FD4\u56DE fn \u7684\u7ED3\u679C + \u5199\u76D8\u540E\u7684\u5B8C\u6574\u8868(\u7ED9 SSE \u7528) */\nexport function updateAnnotations<T>(\n cfg: CsConfig,\n fn: (list: Annotation[]) => T\n): Promise<{ result: T; list: Annotation[] }> {\n const run = chain.then(async () => {\n const list = await readAnnotations(cfg)\n const result = fn(list)\n await writeAnnotations(cfg, list)\n return { result, list }\n })\n chain = run.catch(() => undefined)\n return run\n}\n\n/** id = \"a\" + \u65F6\u95F4\u6233 36 \u8FDB\u5236;\u540C\u6BEB\u79D2\u649E\u4E86\u5C31\u8FFD\u52A0\u5E8F\u53F7 */\nexport function newAnnotationId(list: Annotation[]): string {\n const base = \"a\" + Date.now().toString(36)\n let id = base\n for (let n = 1; list.some((a) => a.id === id); n++) id = base + n.toString(36)\n return id\n}\n\n// ---------- refs(\u8D34\u56FE) ----------\n\n/** \u5B58\u53C2\u8003\u56FE,\u8FD4\u56DE repo \u76F8\u5BF9\u8DEF\u5F84 */\nexport async function saveRef(cfg: CsConfig, name: string, dataBase64: string): Promise<string> {\n // \u53EA\u53D6\u6587\u4EF6\u540D\u90E8\u5206\u518D\u6E05\u6D17,\u9632\u8DEF\u5F84\u7A7F\u8D8A(../\u3001\u7EDD\u5BF9\u8DEF\u5F84\u3001\u5947\u602A\u5B57\u7B26\u5168\u6CA1\u4E86)\n const safe = path.basename(name).replace(/[^\\w.-]+/g, \"-\").replace(/^[.-]+/, \"\") || \"ref.png\"\n const day = new Date().toISOString().slice(0, 10)\n const dir = path.join(canvasDir(cfg), \"refs\")\n await fs.mkdir(dir, { recursive: true })\n\n // \u540C\u540D\u540C\u65E5\u518D\u649E\u5C31\u52A0\u5E8F\u53F7\n const ext = path.extname(safe)\n const stem = safe.slice(0, safe.length - ext.length)\n let filename = `${day}-${safe}`\n for (let n = 2; await exists(path.join(dir, filename)); n++) filename = `${day}-${stem}-${n}${ext}`\n\n // \u753B\u5E03 paste \u8FC7\u6765\u7684\u53EF\u80FD\u5E26 data URL \u5934\n const body = dataBase64.replace(/^data:[^;,]*;base64,/, \"\")\n await fs.writeFile(path.join(dir, filename), Buffer.from(body, \"base64\"))\n return `${cfg.designDir}/.canvas/refs/${filename}`\n}\n\n/** \u8BFB\u53C2\u8003\u56FE\u3002rel \u6765\u81EA URL,\u662F\u4E0D\u53EF\u4FE1\u8F93\u5165:\u5148 resolve \u518D\u6BD4\u524D\u7F00,`..` \u5DF2\u88AB\u6298\u53E0,\u62FC\u4E32\u9A97\u4E0D\u8FC7\u53BB */\nexport async function readRef(cfg: CsConfig, rel: string): Promise<{ body: Buffer; file: string } | null> {\n const root = path.join(canvasDir(cfg), \"refs\")\n const abs = path.resolve(cfg.projectRoot, rel)\n if (abs !== root && !abs.startsWith(root + path.sep)) return null\n try {\n return { body: await fs.readFile(abs), file: abs }\n } catch {\n return null // \u4E0D\u5B58\u5728 / \u662F\u76EE\u5F55 / \u6CA1\u6743\u9650,\u5BF9\u5916\u4E00\u5F8B 404\n }\n}\n\nasync function exists(p: string): Promise<boolean> {\n try {\n await fs.access(p)\n return true\n } catch {\n return false\n }\n}\n\n// ---------- \u7ED9\u7EC8\u7AEF hook \u7684\u4E0A\u4E0B\u6587\u6458\u8981 ----------\n\n/** open \u6279\u6CE8 + \u5F53\u524D selection \u7684\u4EBA\u7C7B\u53EF\u8BFB\u6458\u8981;\u90FD\u4E3A\u7A7A\u8FD4\u56DE\u7A7A\u4E32 */\nexport async function buildContextText(cfg: CsConfig): Promise<string> {\n const open = (await readAnnotations(cfg)).filter((a) => a.status === \"open\")\n const sel = getSelection()\n if (!sel && open.length === 0) return \"\"\n\n const lines = [\"## contactsheet \u753B\u5E03\u4E0A\u4E0B\u6587\"]\n if (sel) {\n lines.push(`\u5F53\u524D\u9009\u4E2D:\u753B\u677F ${sel.artboardId} \u00B7 \u9009\u62E9\u5668 \\`${sel.selector}\\` \u00B7 \u70B9\u4F4D ${fmt(sel.x)},${fmt(sel.y)}`)\n }\n if (open.length > 0) {\n lines.push(`\u672A\u89E3\u51B3\u6279\u6CE8(${open.length} \u6761):`)\n for (const a of open) {\n const where = [a.artboardId, a.anchor?.selector].filter(Boolean).join(\" @ \")\n // #seq \u4E0E\u5899\u4E0A pin \u5706\u70B9\u7684\u6570\u5B57\u4E00\u81F4(\u4EBA\u8BF4\"\u6279\u6CE8 3\"\u5C31\u662F\u5B83);\u65B9\u62EC\u53F7\u91CC\u7684 id \u7ED9 PATCH \u7528\n lines.push(`- #${a.seq} [${a.id}] ${where ? where + \" \u2014\u2014 \" : \"\"}${a.text}`)\n // \u7F16\u53F7\u4E0E\u6B63\u6587\u91CC\u7684 [\u56FE\u7247 n] \u5360\u4F4D\u7B26\u4E00\u4E00\u5BF9\u5E94:Claude \u770B\u5230 [\u56FE\u7247 2] \u5C31\u53BB\u4E0B\u9762\u627E \u56FE\u7247 2 \u7684\u8DEF\u5F84\n ;(a.refs ?? []).forEach((ref, i) => lines.push(` \u56FE\u7247 ${i + 1}:${ref}`))\n }\n }\n return lines.join(\"\\n\") + \"\\n\"\n}\n\nfunction fmt(n: number): string {\n return typeof n === \"number\" && Number.isFinite(n) ? n.toFixed(2) : \"?\"\n}\n", "// \u4EE3\u7406\u9519\u8BEF\u65E5\u5FD7\u7684\u53BB\u91CD+\u9650\u6D41\u3002\n// next dev \u6302\u6389\u6216\u91CD\u542F\u65F6,\u6D4F\u89C8\u5668\u91CC Next \u7684 HMR \u5BA2\u6237\u7AEF\u4F1A\u75AF\u72C2\u91CD\u8FDE,\u6BCF\u6B21\u5E26\u4E00\u4E2A\u65B0\u7684 ?id= \u2014\u2014\n// \u9010\u6761\u6253\u5370\u5C31\u662F\u4E00\u79D2\u51E0\u5341\u884C,\u771F\u6B63\u7684\u9519\u8BEF\u5168\u88AB\u51B2\u8D70\u3002\u8FD9\u91CC\u628A\u540C\u7C7B\u5931\u8D25\u538B\u6210\u4E00\u6761,\u5E76\u628A\"\u76EE\u6807\u6574\u4E2A\u8FDE\u4E0D\u4E0A\"\n// \u5355\u72EC\u62CE\u51FA\u6765\u8BF4\u4E00\u53E5\u4EBA\u8BDD\u3002\n\nimport { dim, green, red, yellow } from \"../term.js\"\n\n/** \u540C\u7C7B\u5931\u8D25\u7684\u5408\u5E76\u7A97\u53E3 */\nconst WINDOW_MS = 5000\n\nexport interface ProxyLog {\n /** \u8BB0\u4E00\u6B21\u4EE3\u7406\u5931\u8D25(http \u4E0E ws \u5171\u7528),\u81EA\u884C\u51B3\u5B9A\u6253\u4E0D\u6253 */\n fail(err: NodeJS.ErrnoException, url: string | undefined): void\n /** \u76EE\u6807\u6709\u56DE\u5305(http \u54CD\u5E94 / ws \u63E1\u624B\u6210\u529F)\u2014\u2014 \u6D3B\u7740 */\n alive(): void\n /** \u9000\u51FA\u65F6\u6E05\u6389\u6302\u8D77\u7684\u7A97\u53E3\u5B9A\u65F6\u5668 */\n close(): void\n}\n\nexport function createProxyLog(target: string): ProxyLog {\n // key = \u9519\u8BEF\u7801 + \u53BB\u6389\u67E5\u8BE2\u4E32\u7684\u8DEF\u5F84;\u7A97\u53E3\u5185\u9996\u6761\u76F4\u63A5\u6253,\u5176\u4F59\u53EA\u8BA1\u6570\n const windows = new Map<string, { extra: number; timer: NodeJS.Timeout }>()\n let down = false // \u76EE\u6807\u6574\u4F53\u4E0D\u53EF\u8FBE(ECONNREFUSED)\n let silenced = 0 // \u4E0D\u53EF\u8FBE\u671F\u95F4\u538B\u6389\u7684\u5931\u8D25\u6B21\u6570\n\n return {\n fail(err, url) {\n const code = err.code ?? err.message\n\n // \u76EE\u6807\u6CA1\u8D77:\u7B2C\u4E00\u6B21\u8BF4\u4E00\u53E5\u6709\u7528\u7684,\u4E4B\u540E\u95ED\u5634\u5230\u6062\u590D\u4E3A\u6B62\u3002HMR \u91CD\u8FDE\u7684\u6D2A\u6C34\u7EDD\u5927\u591A\u6570\u662F\u8FD9\u4E00\u652F\n if (code === \"ECONNREFUSED\") {\n if (down) {\n silenced++\n return\n }\n down = true\n console.error(\n `${yellow(\"\u26A0\")} ${yellow(`\u76EE\u6807 ${target} \u8FDE\u4E0D\u4E0A\u4E86`)} \u2014\u2014 \u8D77 next dev \u540E\u4F1A\u81EA\u52A8\u6062\u590D(\u753B\u5E03\u4F1A\u81EA\u5DF1\u91CD\u8BD5)\u3002` +\n dim(\"\u671F\u95F4\u7684\u4EE3\u7406\u5931\u8D25\u4E0D\u518D\u9010\u6761\u6253\u5370\u3002\")\n )\n return\n }\n\n const key = `${code} ${pathOf(url)}`\n const win = windows.get(key)\n if (win) {\n win.extra++\n return\n }\n console.error(`${red(\"\u2716\")} \u4EE3\u7406\u5931\u8D25 ${pathOf(url)} ${red(String(code))}`)\n const timer = setTimeout(() => {\n const extra = windows.get(key)?.extra ?? 0\n windows.delete(key)\n if (extra > 0) {\n console.error(dim(` (\u8FC7\u53BB ${WINDOW_MS / 1000} \u79D2\u8FD8\u6709 ${extra} \u6B21\u540C\u7C7B\u5931\u8D25:${key})`))\n }\n }, WINDOW_MS)\n timer.unref()\n windows.set(key, { extra: 0, timer })\n },\n\n alive() {\n if (!down) return\n down = false\n const n = silenced\n silenced = 0\n console.log(`${green(\"\u2713\")} ${green(`\u76EE\u6807 ${target} \u5DF2\u6062\u590D`)}${n > 0 ? dim(`(\u4E0D\u53EF\u8FBE\u671F\u95F4\u538B\u6389 ${n} \u6761\u4EE3\u7406\u5931\u8D25)`) : \"\"}`)\n },\n\n close() {\n for (const win of windows.values()) clearTimeout(win.timer)\n windows.clear()\n },\n }\n}\n\n/** \u53BB\u6389\u67E5\u8BE2\u4E32:HMR \u91CD\u8FDE\u6BCF\u6B21\u5E26\u65B0\u7684 ?id=,\u4E0D\u53BB\u6389\u5C31\u6C38\u8FDC\u5408\u5E76\u4E0D\u5230\u4E00\u8D77 */\nfunction pathOf(url: string | undefined): string {\n if (!url) return \"(\u65E0 url)\"\n const q = url.indexOf(\"?\")\n return q < 0 ? url : url.slice(0, q)\n}\n", "// ============================================================\n// [Agent B] \u753B\u677F\u6587\u4EF6 watcher \u2014\u2014 \u53D8\u66F4 \u2192 \u91CD\u5EFA registry \u2192 \u56DE\u8C03\n// \u7B7E\u540D\u51BB\u7ED3,\u89C1 CONTRACTS.md\n// ============================================================\nimport path from \"node:path\"\nimport { watch } from \"chokidar\"\nimport type { CsConfig, RegistryEntry } from \"../types.js\"\nimport { regenerateRegistry } from \"../inject/index.js\"\n\n/** \u8FDE\u7EED\u53D8\u66F4\u5408\u5E76\u6210\u4E00\u6B21\u91CD\u5EFA */\nconst DEBOUNCE_MS = 200\n\nfunction isArtboard(p: string): boolean {\n return /\\.artboard\\.tsx?$/.test(p)\n}\n\nexport async function startWatcher(\n cfg: CsConfig,\n onChange: (entries: RegistryEntry[]) => void\n): Promise<{ close(): Promise<void> }> {\n const designAbs = path.join(cfg.projectRoot, cfg.designDir.replace(/\\\\/g, \"/\").replace(/\\/+$/, \"\"))\n let timer: ReturnType<typeof setTimeout> | null = null\n let closed = false\n\n const flush = () => {\n timer = null\n regenerateRegistry(cfg)\n .then((entries) => {\n if (!closed) onChange(entries)\n })\n .catch((err) => {\n console.error(\"[contactsheet] \u91CD\u5EFA registry \u5931\u8D25:\", err)\n })\n }\n const schedule = () => {\n if (closed) return\n if (timer) clearTimeout(timer)\n timer = setTimeout(flush, DEBOUNCE_MS)\n }\n\n const watcher = watch(designAbs, {\n ignoreInitial: false, // \u9996\u6B21\u4E5F\u7B97\u4E00\u6B21\u53D8\u66F4\n ignored: (p: string) => {\n const rel = path.relative(designAbs, p)\n if (!rel) return false\n // \u751F\u6210\u7269\u4E0E\u753B\u5E03\u6570\u636E\u4E0D\u53C2\u4E0E\u76D1\u542C\n return rel.split(path.sep).some((seg) => seg === \"__generated__\" || seg === \".canvas\" || seg === \"node_modules\")\n },\n })\n watcher.on(\"add\", (p) => isArtboard(p) && schedule())\n watcher.on(\"change\", (p) => isArtboard(p) && schedule())\n watcher.on(\"unlink\", (p) => isArtboard(p) && schedule())\n watcher.on(\"error\", (err) => console.error(\"[contactsheet] watcher \u51FA\u9519:\", err))\n\n // design \u76EE\u5F55\u4E3A\u7A7A\u6216\u4E0D\u5B58\u5728\u65F6\u4E5F\u8981\u7ED9\u4E00\u6B21\u521D\u59CB\u56DE\u8C03\n schedule()\n\n return {\n async close() {\n closed = true\n if (timer) {\n clearTimeout(timer)\n timer = null\n }\n await watcher.close()\n },\n }\n}\n"],
5
- "mappings": ";;;;;;;;;;AAGA,SAAS,iBAAiB;;;ACF1B,OAAO,QAAQ;AACf,OAAO,UAAU;AAGjB,IAAM,iBAAiB;AACvB,IAAM,eAAe;AACrB,IAAM,qBAAqB;AAEpB,SAAS,WAAW,KAAa,OAAoC;AAC1E,QAAM,cAAc,KAAK,QAAQ,GAAG;AACpC,QAAM,OAAO,KAAK,KAAK,aAAa,0BAA0B;AAG9D,MAAI,WAA8B,CAAC;AACnC,MAAI,GAAG,WAAW,IAAI,GAAG;AACvB,QAAI;AACF,iBAAW,KAAK,MAAM,GAAG,aAAa,MAAM,MAAM,CAAC;AAAA,IACrD,SAAS,KAAK;AACZ,YAAM,IAAI,MAAM,qDAAkC,IAAc,OAAO,EAAE;AAAA,IAC3E;AAAA,EACF;AAGA,QAAM,OAAO,CAA2B,QAAoC,MAAM,GAAG,KAAK,SAAS,GAAG;AAEtG,QAAM,OAAO,OAAO,KAAK,MAAM,KAAK,YAAY;AAChD,MAAI,CAAC,OAAO,UAAU,IAAI,KAAK,QAAQ,KAAK,OAAO,MAAO,OAAM,IAAI,MAAM,kCAAS,OAAO,KAAK,MAAM,CAAC,CAAC,EAAE;AAEzG,SAAO;AAAA,IACL;AAAA;AAAA,IAEA,QAAQ,OAAO,KAAK,QAAQ,KAAK,cAAc,EAAE,QAAQ,QAAQ,EAAE;AAAA,IACnE;AAAA,IACA,QAAQ,KAAK,QAAQ,KAAK,aAAa,WAAW;AAAA,IAClD,WAAW,KAAK,WAAW,KAAK;AAAA,EAClC;AACF;AAGA,SAAS,aAAa,aAA6B;AACjD,SAAO,GAAG,WAAW,KAAK,KAAK,aAAa,OAAO,KAAK,CAAC,IAAI,YAAY;AAC3E;;;ACtCA,SAAS,YAAYA,WAAU;AAC/B,OAAOC,WAAU;;;ACcjB,IAAM,SAAS;AAGR,SAAS,aAAa,gBAAgC;AAC3D,SACE,SACA,OAAO;AAAA;AAAA,2BAEgB,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAuGzC;AAGO,SAAS,mBAA2B;AACzC,SACE,SACA,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsCX;AAGO,SAAS,cAAc,gBAAgC;AAC5D,SACE,SACA,OAAO,sCAAsC,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmC/D;AAGO,SAAS,iBAAyB;AACvC,SACE,SACA,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA4HX;AAGO,SAAS,iBAAiB,OAA+B;AAC9D,QAAM,UAAU,MAAM,IAAI,CAAC,OAAO,iBAAiB,GAAG,UAAU,YAAY,GAAG,aAAa,GAAG,EAAE,KAAK,IAAI;AAC1G,QAAM,OAAO,MAAM,IAAI,CAAC,OAAO,QAAQ,GAAG,OAAO,QAAQ,GAAG,UAAU,GAAG,EAAE,KAAK,IAAI;AACpF,QAAM,UAAU,MAAM,IAAI,CAAC,OAAO,QAAQ,GAAG,OAAO,SAAS,GAAG,OAAO,IAAI,EAAE,KAAK,IAAI;AACtF,SACE,sKACC,UAAU,UAAU,SAAS,MAC9B,sEACC,MAAM,SAAS,QAAQ,OAAO,UAAU,UACzC,uJAEC,MAAM,SAAS,QAAQ,UAAU,UAAU;AAEhD;;;ADxVA,IAAM,SAAS;AAEf,IAAM,kBAAkB;AACxB,IAAM,gBAAgB;AAGtB,SAAS,QAAQ,GAAmB;AAClC,SAAO,EAAE,QAAQ,OAAO,GAAG,EAAE,QAAQ,SAAS,EAAE,EAAE,QAAQ,QAAQ,EAAE;AACtE;AAGA,SAAS,SAAS,KAAuB;AACvC,SAAO,QAAQ,IAAI,MAAM,IAAI,MAAM;AACrC;AAGA,SAAS,mBAAmB,YAAoB,KAAuB;AACrE,QAAM,SAAS,QAAQ,IAAI,SAAS,IAAI;AACxC,QAAM,MAAMC,MAAK,MAAM,SAAS,YAAY,MAAM;AAClD,SAAO,IAAI,WAAW,GAAG,IAAI,MAAM,OAAO;AAC5C;AAEA,eAAe,OAAO,MAAc,UAAiD;AACnF,MAAI;AACF,WAAO,MAAMC,IAAG,SAAS,MAAM,MAAM;AAAA,EACvC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAGA,eAAe,eAAe,MAAc,SAAmC;AAC7E,MAAK,MAAM,OAAO,MAAM,IAAI,MAAO,QAAS,QAAO;AACnD,QAAMA,IAAG,MAAMD,MAAK,QAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;AACtD,QAAMC,IAAG,UAAU,MAAM,SAAS,MAAM;AACxC,SAAO;AACT;AAGA,SAAS,UAAUC,OAAqD;AACtE,QAAM,QAAQA,MAAK,QAAQ,eAAe;AAC1C,MAAI,QAAQ,EAAG,QAAO;AACtB,QAAM,KAAKA,MAAK,QAAQ,eAAe,KAAK;AAC5C,MAAI,KAAK,EAAG,QAAO;AACnB,SAAO,EAAE,OAAO,KAAK,KAAK,cAAc,OAAO;AACjD;AAEA,SAAS,eAAe,KAAuB;AAC7C,QAAM,SAAS,QAAQ,IAAI,SAAS;AACpC,SAAO,CAAC,iBAAiB,SAAS,GAAG,IAAI,KAAK,SAAS,mBAAmB,SAAS,aAAa,aAAa,EAAE;AAAA,IAC7G;AAAA,EACF;AACF;AAGA,eAAe,gBAAgB,KAA8B;AAC3D,QAAM,OAAOF,MAAK,KAAK,IAAI,aAAa,YAAY;AACpD,QAAM,MAAO,MAAM,OAAO,MAAM,EAAE;AAClC,QAAM,QAAQ,eAAe,GAAG;AAChC,QAAM,QAAQ,UAAU,GAAG;AAC3B,QAAM,OAAO,QACT,IAAI,MAAM,GAAG,MAAM,KAAK,IAAI,QAAQ,IAAI,MAAM,MAAM,GAAG,KACtD,IAAI,QAAQ,IAAI,IAAI,QAAQ,IAAI,SAAS,MAAM,QAAQ;AAC5D,QAAM,eAAe,MAAM,IAAI;AACjC;AAEA,eAAe,qBAAqB,KAA8B;AAChE,QAAM,OAAOA,MAAK,KAAK,IAAI,aAAa,YAAY;AACpD,QAAM,MAAM,MAAM,OAAO,MAAM,IAAI;AACnC,MAAI,QAAQ,KAAM;AAClB,QAAM,QAAQ,UAAU,GAAG;AAC3B,MAAI,CAAC,MAAO;AACZ,QAAM,QAAQ,IAAI,MAAM,GAAG,MAAM,KAAK,IAAI,IAAI,MAAM,MAAM,GAAG,GAAG,QAAQ,WAAW,MAAM,EAAE,QAAQ;AACnG,QAAM,eAAe,MAAM,OAAO,OAAO,OAAO,EAAE;AACpD;AAGA,eAAsB,eAAe,KAA8B;AACjE,QAAM,OAAO,IAAI;AACjB,QAAM,YAAYA,MAAK,KAAK,MAAM,QAAQ,IAAI,SAAS,CAAC;AACxD,QAAMC,IAAG,MAAM,WAAW,EAAE,WAAW,KAAK,CAAC;AAC7C,QAAMA,IAAG,MAAMD,MAAK,KAAK,WAAW,SAAS,GAAG,EAAE,WAAW,KAAK,CAAC;AAEnE,QAAM,WAAW,SAAS,GAAG,IAAI;AACjC,QAAM,eAAeA,MAAK,KAAK,MAAM,UAAU,UAAU,GAAG,aAAa,mBAAmB,UAAU,GAAG,CAAC,CAAC;AAC3G,QAAM,eAAeA,MAAK,KAAK,MAAM,UAAU,cAAc,GAAG,iBAAiB,CAAC;AAElF,QAAM,cAAc,SAAS,GAAG,IAAI;AACpC,QAAM,eAAeA,MAAK,KAAK,MAAM,aAAa,UAAU,GAAG,cAAc,mBAAmB,aAAa,GAAG,CAAC,CAAC;AAElH,QAAM,eAAeA,MAAK,KAAK,MAAM,SAAS,GAAG,GAAG,UAAU,UAAU,GAAG,eAAe,CAAC;AAE3F,QAAM,gBAAgB,GAAG;AAEzB,QAAM,mBAAmB,GAAG;AAC9B;AAGA,eAAsB,eAAe,KAA8B;AACjE,QAAMC,IAAG,GAAGD,MAAK,KAAK,IAAI,aAAa,SAAS,GAAG,CAAC,GAAG,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AACvF,QAAMC,IAAG,GAAGD,MAAK,KAAK,IAAI,aAAa,QAAQ,IAAI,SAAS,GAAG,eAAe,GAAG,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AACjH,QAAM,qBAAqB,GAAG;AAChC;AAGA,eAAe,cAAc,WAAmB,MAAM,IAAuB;AAC3E,MAAI;AACJ,MAAI;AACF,cAAU,MAAMC,IAAG,QAAQD,MAAK,KAAK,WAAW,GAAG,GAAG,EAAE,eAAe,KAAK,CAAC;AAAA,EAC/E,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACA,QAAM,MAAgB,CAAC;AACvB,aAAW,KAAK,SAAS;AACvB,UAAM,MAAM,MAAM,MAAM,MAAM,EAAE,OAAO,EAAE;AACzC,QAAI,EAAE,YAAY,GAAG;AAEnB,UAAI,EAAE,SAAS,mBAAmB,EAAE,SAAS,kBAAkB,EAAE,KAAK,WAAW,GAAG,EAAG;AACvF,UAAI,KAAK,GAAI,MAAM,cAAc,WAAW,GAAG,CAAE;AAAA,IACnD,WAAW,oBAAoB,KAAK,EAAE,IAAI,GAAG;AAC3C,UAAI,KAAK,GAAG;AAAA,IACd;AAAA,EACF;AACA,SAAO;AACT;AAGA,SAAS,eAAe,QAA0B;AAChD,QAAM,KAAK;AACX,QAAM,QAAkB,CAAC;AACzB,MAAI;AACJ,UAAQ,IAAI,GAAG,KAAK,MAAM,OAAO,MAAM;AACrC,QAAI,CAAC,MAAM,SAAS,EAAE,CAAC,CAAC,EAAG,OAAM,KAAK,EAAE,CAAC,CAAC;AAAA,EAC5C;AACA,SAAO;AACT;AAGA,SAAS,OAAO,KAAqB;AACnC,SAAO,IAAI,QAAQ,qBAAqB,EAAE,EAAE,QAAQ,OAAO,IAAI;AACjE;AAGA,eAAsB,mBAAmB,KAAyC;AAChF,QAAM,YAAY,QAAQ,IAAI,SAAS;AACvC,QAAM,YAAYA,MAAK,KAAK,IAAI,aAAa,SAAS;AACtD,QAAM,QAAQ,MAAM,cAAc,SAAS,GAAG,KAAK;AAEnD,QAAM,QAAwB,CAAC;AAC/B,QAAM,UAA2B,CAAC;AAClC,aAAW,OAAO,MAAM;AACtB,UAAM,SAAS,MAAM,OAAOA,MAAK,KAAK,WAAW,GAAG,GAAG,IAAI;AAC3D,QAAI,WAAW,KAAM;AACrB,UAAM,QAAQ,eAAe,MAAM;AACnC,QAAI,MAAM,WAAW,EAAG;AACxB,UAAM,OAAO,OAAO,GAAG;AACvB,UAAM,OAAO,YAAY,MAAM;AAC/B,UAAM,KAAK;AAAA,MACT,SAAS,MAAM,MAAM;AAAA;AAAA,MAErB,YAAY,QAAQ,IAAI,QAAQ,WAAW,EAAE;AAAA,MAC7C;AAAA,MACA;AAAA,IACF,CAAC;AACD,eAAW,cAAc,OAAO;AAE9B,cAAQ,KAAK,EAAE,IAAI,OAAO,OAAO,YAAY,MAAM,YAAY,MAAM,YAAY,CAAC;AAAA,IACpF;AAAA,EACF;AAEA,QAAM,eAAeA,MAAK,KAAK,WAAW,iBAAiB,cAAc,GAAG,iBAAiB,KAAK,CAAC;AACnG,SAAO;AACT;;;AEzLA,SAAS,YAAY,WAAW,aAAa,cAAc,UAAU,qBAAqB;AAC1F,SAAS,SAAS,MAAM,UAAU,eAAe;;;ACDjD,IAAM,KAAK,QAAQ,OAAO,UAAU,QAAQ,CAAC,QAAQ,IAAI,YAAY,QAAQ,IAAI,SAAS;AAE1F,IAAM,OAAO,CAAC,MAAc,UAAkB,CAAC,MAC7C,KAAK,QAAQ,IAAI,IAAI,CAAC,QAAQ,KAAK,MAAM;AAEpC,IAAM,OAAO,KAAK,GAAG,EAAE;AACvB,IAAM,MAAM,KAAK,GAAG,EAAE;AACtB,IAAM,MAAM,KAAK,IAAI,EAAE;AACvB,IAAM,QAAQ,KAAK,IAAI,EAAE;AACzB,IAAM,SAAS,KAAK,IAAI,EAAE;AAC1B,IAAM,OAAO,KAAK,IAAI,EAAE;AACxB,IAAM,UAAU,KAAK,IAAI,EAAE;AAG3B,IAAM,OAAO,CAAC,MAAuB,KAAK,aAAa,CAAC,gBAAgB;AAExE,IAAM,KAAK,CAAC,MAAsB,GAAG,MAAM,QAAG,CAAC,IAAI,CAAC;AACpD,IAAM,OAAO,CAAC,MAAsB,GAAG,OAAO,QAAG,CAAC,IAAI,OAAO,CAAC,CAAC;;;ADZtE,IAAMG,kBAAiB;AACvB,IAAMC,gBAAe;AACrB,IAAMC,sBAAqB;AAG3B,IAAM,oBAAoB,CAAC,iBAAiB,mBAAmB;AAM/D,eAAsB,QAAQ,KAAa,OAAyC;AAClF,QAAM,OAAO,QAAQ,GAAG;AAGxB,oBAAkB,IAAI;AAGtB,QAAM,SAASC,cAAa,IAAI;AAChC,QAAM,MAAM,gBAAgB,MAAM,QAAQ,KAAK;AAC/C,UAAQ,IAAI,GAAG,KAAK,KAAK,QAAG,CAAC,CAAC,IAAI,KAAK,mBAAmB,CAAC,IAAI,IAAI,cAAI,CAAC,IAAI,IAAI,EAAE;AAClF,UAAQ,IAAI,GAAG,oBAAU,IAAI,MAAM,EAAE,CAAC;AACtC,UAAQ,IAAI,GAAG,gDAAsC,IAAI,MAAM,SAAS,IAAI,IAAI,6BAAS,IAAI,SAAS,GAAG,CAAC;AAK1G,gBAAc,MAAM,IAAI,SAAS;AAGjC,eAAa,MAAM,IAAI,IAAI;AAG3B,kBAAgB,MAAM,IAAI,IAAI;AAG9B,UAAQ,IAAI,EAAE;AACd,UAAQ,IAAI,KAAK,qBAAM,CAAC;AACxB,UAAQ,IAAI,iGAA0C,KAAK,IAAI,MAAM,CAAC,EAAE;AACxE,UAAQ,IAAI,6CAAe,KAAK,kBAAkB,CAAC,EAAE;AACrD,UAAQ,IAAI,qBAAW,KAAK,oBAAoB,IAAI,IAAI,OAAO,CAAC,EAAE;AAClE,UAAQ,IAAI,EAAE;AACd,UAAQ,IAAI,IAAI,+DAAuB,IAAI,IAAI,SAAS,IAAI,yBAAoB,CAAC;AACjF,UAAQ,IAAI,IAAI,KAAK,IAAI,IAAI,uIAAsE,CAAC;AACpG,UAAQ,IAAI,IAAI,KAAK,IAAI,IAAI,uKAA0C,CAAC;AAC1E;AAMA,SAAS,kBAAkB,MAAoB;AAC7C,QAAM,UAAU,KAAK,MAAM,cAAc;AACzC,MAAI,CAAC,WAAW,OAAO,GAAG;AACxB,UAAM,IAAI;AAAA,MACR,kCAAwB,IAAI;AAAA;AAAA,IAE9B;AAAA,EACF;AACA,QAAM,MAAM,eAAe,OAAO,KAAK,CAAC;AACxC,QAAM,OAAO,EAAE,GAAG,SAAS,IAAI,cAAc,CAAC,GAAG,GAAG,SAAS,IAAI,iBAAiB,CAAC,EAAE;AACrF,MAAI,EAAE,UAAU,OAAO;AACrB,UAAM,IAAI;AAAA,MACR,kCAAwB,OAAO;AAAA;AAAA;AAAA,IAGjC;AAAA,EACF;AACF;AAOA,SAASA,cAAa,MAAsB;AAC1C,aAAW,aAAa,CAAC,WAAW,KAAK,GAAG;AAC1C,QAAI,MAAM,KAAK,MAAM,SAAS,CAAC,EAAG,QAAO;AAAA,EAC3C;AACA,QAAM,IAAI;AAAA,IACR,kCAAwB,IAAI;AAAA;AAAA,EAE9B;AACF;AAIA,SAAS,gBAAgB,MAA6B;AACpD,MAAI;AACF,UAAM,MAAM,KAAK,MAAM,aAAa,KAAK,MAAM,cAAc,GAAG,MAAM,CAAC;AAGvE,UAAM,MAAM,IAAI,UAAU,KAAK,KAAK;AACpC,UAAM,IAAI,IAAI,MAAM,4BAA4B,KAAK,IAAI,MAAM,kBAAkB;AACjF,QAAI,KAAK,EAAE,CAAC,MAAM,OAAQ,QAAO,oBAAoB,EAAE,CAAC,CAAC;AAAA,EAC3D,QAAQ;AAAA,EAER;AACA,SAAO;AACT;AAEA,SAAS,gBAAgB,MAAc,QAAgB,OAAoC;AACzF,QAAM,OAAO,KAAK,MAAM,0BAA0B;AAClD,QAAM,WAAW,eAAe,IAAI,KAAK,CAAC;AAG1C,QAAM,WAAW;AAAA,IACf,QAAQ,WAAW,MAAM,QAAQ,SAAS,QAAQ,GAAG,gBAAgB,IAAI,KAAKH,eAAc;AAAA,IAC5F,MAAM,WAAW,MAAM,MAAM,SAAS,MAAM,GAAGC,aAAY;AAAA,IAC3D,QAAQ,WAAW,MAAM,QAAQ,SAAS,QAAQ,GAAG,MAAM;AAAA,IAC3D,WAAW,WAAW,MAAM,WAAW,SAAS,WAAW,GAAGC,mBAAkB;AAAA,EAClF;AAGA,gBAAc,MAAM,EAAE,GAAG,UAAU,GAAG,SAAS,CAAC;AAEhD,SAAO,EAAE,aAAa,MAAM,GAAG,SAAS;AAC1C;AAMA,SAAS,cAAc,MAAc,WAAyB;AAC5D,QAAM,QAAQ,kBAAkB,IAAI,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,EAAE,KAAK,KAAK;AACpE,MAAI,CAAC,OAAO;AACV,YAAQ,IAAI,4GAAsC,SAAS,qCAAsB;AACjF;AAAA,EACF;AAEA,QAAM,QAAQ,YAAY,KAAK,EAC5B,OAAO,CAAC,MAAM,EAAE,SAAS,MAAM,CAAC,EAChC,KAAK;AACR,QAAM,YAAY,KAAK,MAAM,SAAS;AAEtC,MAAI,UAAU;AACd,MAAI,UAAU;AACd,MAAI,aAAa;AAEjB,aAAW,QAAQ,OAAO;AACxB,UAAM,gBAAgB,KAAK,OAAO,IAAI;AACtC,UAAM,OAAO,qBAAqB,aAAa,eAAe,MAAM,CAAC;AACrE,QAAI,CAAC,MAAM;AACT;AACA;AAAA,IACF;AACA,UAAM,WAAW,KAAK,WAAW,GAAG,IAAI,eAAe;AACvD,QAAI,WAAW,QAAQ,GAAG;AACxB;AACA;AAAA,IACF;AACA,cAAU,WAAW,EAAE,WAAW,KAAK,CAAC;AACxC,kBAAc,UAAU,iBAAiB,MAAM,cAAc,MAAM,WAAW,aAAa,CAAC,GAAG,MAAM;AACrG;AAAA,EACF;AAEA,UAAQ,IAAI,GAAG,6BAAS,MAAM,OAAO,OAAO,CAAC,CAAC,wBAAS,OAAO,2BAAO,KAAK,aAAa,IAAI,UAAU,kEAAgB,GAAG;AAC1H;AAOA,SAAS,qBAAqB,QAA+B;AAC3D,QAAM,OAA+C,CAAC;AAEtD,QAAM,SAAS;AACf,aAAW,KAAK,OAAO,SAAS,MAAM,GAAG;AACvC,QAAI,SAAS,EAAE,CAAC,CAAE,EAAG,MAAK,KAAK,EAAE,OAAO,EAAE,SAAS,GAAG,MAAM,EAAE,CAAC,EAAG,CAAC;AAAA,EACrE;AAEA,QAAM,SAAS;AACf,aAAW,KAAK,OAAO,SAAS,MAAM,GAAG;AACvC,eAAW,OAAO,EAAE,CAAC,EAAG,MAAM,GAAG,GAAG;AAClC,YAAM,OAAO,IAAI,KAAK;AACtB,UAAI,CAAC,QAAQ,KAAK,WAAW,OAAO,EAAG;AAEvC,YAAM,QAAQ,KAAK,MAAM,UAAU;AACnC,YAAM,OAAO,MAAM,MAAM,SAAS,CAAC,EAAG,KAAK;AAC3C,UAAI,SAAS,IAAI,GAAG;AAClB,aAAK,KAAK,EAAE,OAAO,EAAE,SAAS,GAAG,KAAK,CAAC;AACvC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,MAAI,KAAK,WAAW,EAAG,QAAO;AAC9B,OAAK,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK;AACrC,SAAO,KAAK,CAAC,EAAG;AAClB;AAEA,SAAS,SAAS,MAAuB;AACvC,SAAO,wBAAwB,KAAK,IAAI;AAC1C;AAGA,SAAS,cAAc,MAAc,WAAmB,eAA+B;AACrF,QAAM,YAAY,cAAc,IAAI;AACpC,MAAI,aAAa,QAAQ,aAAa,EAAE,WAAW,QAAQ,SAAS,IAAI,GAAG,GAAG;AAC5E,WAAO,OAAO,QAAQ,SAAS,WAAW,aAAa,CAAC,EAAE,QAAQ,UAAU,EAAE;AAAA,EAChF;AACA,QAAM,MAAM,QAAQ,SAAS,KAAK,MAAM,SAAS,GAAG,aAAa,CAAC,EAAE,QAAQ,UAAU,EAAE;AACxF,SAAO,IAAI,WAAW,GAAG,IAAI,MAAM,OAAO;AAC5C;AAGA,SAAS,cAAc,MAA6B;AAClD,QAAM,OAAO,KAAK,MAAM,eAAe;AACvC,MAAI,CAAC,WAAW,IAAI,EAAG,QAAO;AAC9B,MAAI;AACJ,MAAI;AACF,aAAS,KAAK,MAAM,aAAa,MAAM,MAAM,CAAC;AAAA,EAChD,QAAQ;AACN,WAAO;AAAA,EACT;AACA,QAAM,QAAQ,SAAS,SAAS,SAAS,MAAM,EAAE,iBAAiB,CAAC,EAAE,OAAO,CAAC;AAC7E,QAAM,QAAQ,MAAM,KAAK;AACzB,QAAM,QAAQ,MAAM,QAAQ,KAAK,IAAI,MAAM,CAAC,IAAI;AAChD,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,SAAO,QAAQ,MAAM,MAAM,QAAQ,UAAU,EAAE,CAAC;AAClD;AAEA,SAAS,iBAAiB,MAAc,YAA4B;AAClE,SACE;AAAA,WACY,IAAI,YAAY,UAAU;AAAA;AAAA;AAAA,mBAGlB,IAAI,kBAAQ,IAAI;AAAA;AAAA;AAGxC;AAMA,SAAS,aAAa,MAAc,MAAoB;AACtD,QAAM,OAAO,KAAK,MAAM,WAAW;AACnC,QAAM,MAAM,eAAe,IAAI,KAAK,CAAC;AACrC,QAAM,UAAU,SAAS,IAAI,YAAY,CAAC;AAC1C,QAAM,MAAM,kBAAkB;AAE9B,UAAQ,cAAc,IAAI,EAAE,MAAM,QAAQ,KAAK,oBAAoB,IAAI,YAAY;AACnF,MAAI,YAAY,IAAI;AACpB,gBAAc,MAAM,GAAG;AAEvB,QAAM,SAAS,OAAO,KAAK,OAAO,EAAE,OAAO,CAAC,MAAM,MAAM,cAAc,EAAE;AACxE,UAAQ;AAAA,IACN,eAAe,MAAM,iBAAO,cAAI,8BAA8B,SAAS,iBAAO,MAAM,6CAAoB;AAAA,EAC1G;AACF;AAMA,SAAS,gBAAgB,MAAc,MAAoB;AACzD,QAAM,OAAO,KAAK,MAAM,WAAW,eAAe;AAClD,QAAM,MAAM,eAAe,IAAI,KAAK,CAAC;AACrC,QAAM,QAAQ,SAAS,IAAI,OAAO,CAAC;AACnC,QAAM,OAAO,MAAM,QAAQ,MAAM,kBAAkB,CAAC,IAAK,MAAM,kBAAkB,IAAkB,CAAC;AAGpG,QAAM,mBAA6B,CAAC;AACpC,aAAW,SAAS,MAAM;AACxB,eAAW,KAAK,MAAM,QAAQ,SAAS,KAAK,EAAE,OAAO,CAAC,IAAK,SAAS,KAAK,EAAE,OAAO,IAAkB,CAAC,GAAG;AACtG,YAAM,MAAM,SAAS,CAAC,EAAE,SAAS;AACjC,UAAI,OAAO,QAAQ,SAAU,kBAAiB,KAAK,GAAG;AAAA,IACxD;AAAA,EACF;AACA,QAAM,UAAU,iBAAiB,OAAO,CAAC,MAAM,EAAE,SAAS,mBAAmB,CAAC;AAC9E,MAAI,QAAQ,SAAS,GAAG;AACtB,YAAQ,IAAI,wFAAgD;AAC5D,QAAI,CAAC,QAAQ,KAAK,CAAC,MAAM,EAAE,SAAS,aAAa,IAAI,GAAG,CAAC,GAAG;AAC1D,cAAQ,IAAI,sEAAyB,IAAI,6EAAsB;AAAA,IACjE;AACA;AAAA,EACF;AAEA,QAAM,UAAU,uDAAuD,IAAI;AAC3E,OAAK,KAAK,EAAE,OAAO,CAAC,EAAE,MAAM,WAAW,QAAQ,CAAC,EAAE,CAAC;AACnD,QAAM,kBAAkB,IAAI;AAC5B,MAAI,OAAO,IAAI;AACf,gBAAc,MAAM,GAAG;AACvB,UAAQ,IAAI,6IAAuE;AACrF;AAMA,SAAS,MAAM,GAAoB;AACjC,MAAI;AACF,WAAO,SAAS,CAAC,EAAE,YAAY;AAAA,EACjC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,QAAQ,GAAmB;AAClC,SAAO,EAAE,MAAM,IAAI,EAAE,KAAK,GAAG;AAC/B;AAEA,SAAS,SAAS,GAAqC;AACrD,SAAO,MAAM,QAAQ,OAAO,MAAM,YAAY,CAAC,MAAM,QAAQ,CAAC,IAAK,IAAgC,CAAC;AACtG;AAEA,SAAS,cAAc,YAA+B;AACpD,aAAW,KAAK,WAAY,KAAI,OAAO,MAAM,YAAY,MAAM,GAAI,QAAO;AAC1E,SAAO;AACT;AAEA,SAAS,cAAc,YAA+B;AACpD,aAAW,KAAK,WAAY,KAAI,OAAO,MAAM,YAAY,OAAO,SAAS,CAAC,EAAG,QAAO;AACpF,SAAO;AACT;AAGA,SAAS,eAAe,MAA8C;AACpE,MAAI,CAAC,WAAW,IAAI,EAAG,QAAO;AAC9B,QAAM,MAAM,aAAa,MAAM,MAAM;AACrC,MAAI,IAAI,KAAK,MAAM,GAAI,QAAO,CAAC;AAC/B,MAAI;AACJ,MAAI;AACF,aAAS,KAAK,MAAM,GAAG;AAAA,EACzB,SAAS,KAAK;AACZ,UAAM,IAAI;AAAA,MACR,kCAAwB,IAAI,wCAAgB,IAAc,OAAO;AAAA;AAAA,IAEnE;AAAA,EACF;AACA,MAAI,WAAW,QAAQ,OAAO,WAAW,YAAY,MAAM,QAAQ,MAAM,GAAG;AAC1E,UAAM,IAAI,MAAM,kCAAwB,IAAI,6FAA4B;AAAA,EAC1E;AACA,SAAO;AACT;AAEA,SAAS,cAAc,MAAc,OAAsB;AACzD,YAAU,QAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;AAC5C,gBAAc,MAAM,KAAK,UAAU,OAAO,MAAM,CAAC,IAAI,MAAM,MAAM;AACnE;;;AE9VA,OAAOE,SAAQ;AACf,OAAO,UAAU;AACjB,OAAO,eAAe;;;ACAtB,SAAS,iBAAiB;AAC1B,SAAS,qCAAqC;AAC9C,SAAS,SAAS;AAiBlB,eAAe,MAAM,KAAqD;AACxE,MAAI;AACF,WAAO,MAAM,IAAI;AAAA,EACnB,SAAS,KAAK;AACZ,UAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAE3D,UAAMC,QAAO,IAAI,WAAW,eAAe,IAAI,MAAM,iBAAiB,GAAG;AACzE,WAAO,EAAE,SAAS,MAAM,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAAA,MAAK,CAAC,EAAE;AAAA,EAC5D;AACF;AAEA,SAAS,KAAK,OAA4B;AACxC,SAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,OAAO,UAAU,WAAW,QAAQ,KAAK,UAAU,OAAO,MAAM,CAAC,EAAE,CAAC,EAAE;AACjH;AAGA,SAAS,YAAY,UAAkC;AACrD,QAAM,SAAS,IAAI;AAAA,IACjB,EAAE,MAAM,gBAAgB,SAAS,QAAQ;AAAA,IACzC,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,EAAE;AAAA,EAChC;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,OAAO;AAAA,MACP,aACE;AAAA,MACF,aAAa,EAAE,cAAc,KAAK;AAAA,IACpC;AAAA,IACA,YAAY,MAAM,YAAY,KAAK,MAAM,SAAS,YAAY,CAAC,CAAC;AAAA,EAClE;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,OAAO;AAAA,MACP,aACE;AAAA,MACF,aAAa;AAAA,QACX,IAAI,EACD,OAAO,EACP,SAAS,EACT,SAAS,8GAAmC;AAAA,MACjD;AAAA,MACA,aAAa,EAAE,cAAc,KAAK;AAAA,IACpC;AAAA,IACA,OAAO,EAAE,GAAG,MACV,MAAM,YAAY;AAChB,YAAM,OAAO,MAAM,SAAS,SAAS,KAAK,EAAE,GAAG,IAAI,CAAC,CAAC;AACrD,aAAO;AAAA,QACL,SAAS;AAAA,UACP,EAAE,MAAM,SAAS,MAAM,KAAK,QAAQ,UAAU,YAAY;AAAA,UAC1D,EAAE,MAAM,QAAQ,MAAM,sBAAO,KAAK,IAAI,IAAI,KAAK,KAAK,OAAI,KAAK,MAAM,IAAI;AAAA,QACzE;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACL;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,OAAO;AAAA,MACP,aACE;AAAA,MACF,aAAa,EAAE,cAAc,KAAK;AAAA,IACpC;AAAA,IACA,YACE,MAAM,YAAY;AAChB,YAAMC,aAAY,SAAS,aAAa;AACxC,aAAOA,aAAY,KAAKA,UAAS,IAAI,KAAK,cAAc;AAAA,IAC1D,CAAC;AAAA,EACL;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,OAAO;AAAA,MACP,aACE;AAAA,MACF,aAAa,EAAE,cAAc,KAAK;AAAA,IACpC;AAAA,IACA,YACE,MAAM,YAAY;AAChB,YAAM,MAAM,MAAM,SAAS,eAAe;AAC1C,aAAO,KAAK,IAAI,OAAO,OAAK,EAAE,WAAW,MAAM,CAAC;AAAA,IAClD,CAAC;AAAA,EACL;AAEA,SAAO;AACT;AAGA,SAAS,iBAAiB,KAAqB,QAAgB,MAAc,SAAuB;AAClG,MAAI,IAAI,aAAa;AACnB,QAAI,IAAI;AACR;AAAA,EACF;AACA,MAAI,UAAU,QAAQ,EAAE,gBAAgB,mBAAmB,CAAC;AAC5D,MAAI,IAAI,KAAK,UAAU,EAAE,SAAS,OAAO,OAAO,EAAE,MAAM,QAAQ,GAAG,IAAI,KAAK,CAAC,CAAC;AAChF;AAEO,SAAS,iBACd,UAC8D;AAC9D,SAAO,eAAe,iBAAiB,KAAsB,KAAoC;AAE/F,QAAI,IAAI,WAAW,QAAQ;AACzB,uBAAiB,KAAK,KAAK,OAAQ,qBAAqB;AACxD;AAAA,IACF;AAEA,UAAM,SAAS,YAAY,QAAQ;AACnC,UAAM,YAAY,IAAI,8BAA8B,EAAE,oBAAoB,OAAU,CAAC;AAErF,QAAI,GAAG,SAAS,MAAM;AACpB,WAAK,UAAU,MAAM,EAAE,MAAM,MAAM;AAAA,MAAC,CAAC;AACrC,WAAK,OAAO,MAAM,EAAE,MAAM,MAAM;AAAA,MAAC,CAAC;AAAA,IACpC,CAAC;AAED,QAAI;AACF,YAAM,OAAO,QAAQ,SAAS;AAC9B,YAAM,UAAU,cAAc,KAAK,GAAG;AAAA,IACxC,SAAS,KAAK;AACZ,YAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,uBAAiB,KAAK,KAAK,QAAQ,0BAA0B,GAAG,EAAE;AAAA,IACpE;AAAA,EACF;AACF;;;ACpJA,SAAS,OAAO,iBAAiB;AACjC,OAAOC,WAAU;AACjB,SAAS,gBAAgB;AAKzB,IAAM,UAAU;AAEhB,IAAM,iBAAiB;AAEvB,IAAI,iBAA0C;AAC9C,IAAI,YAAmC;AAGvC,eAAe,aAA+B;AAC5C,MAAI,CAAC,gBAAgB;AACnB,qBAAiB,SAAS,OAAO,EAAE,SAAS,UAAU,UAAU,KAAK,CAAC,EAAE,MAAM,CAAC,QAAiB;AAC9F,uBAAiB;AACjB,YAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,YAAM,IAAI;AAAA,QACR,6KAAwF,GAAG;AAAA,MAC7F;AAAA,IACF,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAGA,SAAS,oBAA0B;AACjC,MAAI,UAAW,cAAa,SAAS;AACrC,cAAY,WAAW,MAAM;AAC3B,gBAAY;AACZ,SAAK,aAAa;AAAA,EACpB,GAAG,OAAO;AAEV,YAAU,QAAQ;AACpB;AAGA,eAAsB,eAA8B;AAClD,MAAI,WAAW;AACb,iBAAa,SAAS;AACtB,gBAAY;AAAA,EACd;AACA,QAAM,UAAU;AAChB,mBAAiB;AACjB,MAAI,CAAC,QAAS;AACd,MAAI;AACF,UAAM,UAAU,MAAM;AACtB,UAAM,QAAQ,MAAM;AAAA,EACtB,QAAQ;AAAA,EAER;AACF;AAgBA,eAAsB,WAAW,MAAuC;AACtE,QAAM,UAAU,MAAM,WAAW;AACjC,QAAM,UAAU,MAAM,QAAQ,WAAW,EAAE,UAAU,EAAE,OAAO,KAAK,OAAO,QAAQ,KAAK,OAAO,EAAE,CAAC;AACjG,MAAI;AACF,UAAM,OAAO,MAAM,QAAQ,QAAQ;AACnC,QAAI;AACF,YAAM,KAAK,KAAK,KAAK,KAAK,EAAE,WAAW,eAAe,SAAS,eAAe,CAAC;AAAA,IACjF,QAAQ;AAEN,YAAM,KAAK,iBAAiB,kBAAkB,EAAE,MAAM,MAAM;AAAA,MAAC,CAAC;AAAA,IAChE;AACA,QAAI,KAAK,WAAW,EAAG,OAAM,KAAK,eAAe,KAAK,QAAQ;AAC9D,WAAO,MAAM,KAAK,WAAW,EAAE,UAAU,KAAK,UAAU,MAAM,MAAM,CAAC;AAAA,EACvE,UAAE;AACA,UAAM,QAAQ,MAAM;AACpB,sBAAkB;AAAA,EACpB;AACF;AAGA,eAAe,cAAc,KAAyC;AACpE,QAAM,MAAM,GAAG,IAAI,OAAO,QAAQ,QAAQ,EAAE,CAAC;AAC7C,MAAI;AACJ,MAAI;AACF,UAAM,MAAM,MAAM,GAAG;AAAA,EACvB,SAAS,KAAK;AACZ,UAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,UAAM,IAAI;AAAA,MACR,sDAAwB,GAAG,sMAAyE,GAAG;AAAA,IACzG;AAAA,EACF;AACA,MAAI,CAAC,IAAI,IAAI;AACX,UAAM,IAAI;AAAA,MACR,oCAAqB,GAAG,iBAAO,IAAI,MAAM;AAAA,IAC3C;AAAA,EACF;AACA,SAAQ,MAAM,IAAI,KAAK;AACzB;AAGA,SAAS,aAAa,IAAoB;AACxC,SAAO,GAAG,QAAQ,iBAAiB,GAAG;AACxC;AAGA,SAAS,QAAQ,KAAgD;AAC/D,SAAO,EAAE,OAAO,IAAI,aAAa,EAAE,GAAG,QAAQ,IAAI,aAAa,EAAE,EAAE;AACrE;AAGA,eAAe,KAAK,KAAe,MAAc,KAA8B;AAC7E,QAAM,OAAO,GAAG,aAAa,IAAI,CAAC;AAClC,QAAM,MAAMA,MAAK,KAAK,IAAI,aAAa,IAAI,WAAW,WAAW,SAAS,IAAI;AAC9E,QAAM,MAAMA,MAAK,QAAQ,GAAG,GAAG,EAAE,WAAW,KAAK,CAAC;AAClD,QAAM,UAAU,KAAK,GAAG;AACxB,SAAO,GAAG,IAAI,UAAU,MAAMA,MAAK,GAAG,EAAE,KAAK,GAAG,EAAE,QAAQ,QAAQ,EAAE,CAAC,kBAAkB,IAAI;AAC7F;AAEA,eAAsB,WAAW,KAAe,KAAuC;AACrF,MAAI;AACJ,MAAI;AAEJ,MAAI,IAAI,IAAI;AACV,UAAM,UAAU,MAAM,cAAc,GAAG;AACvC,UAAM,QAAQ,QAAQ,KAAK,OAAK,EAAE,OAAO,IAAI,EAAE;AAC/C,QAAI,CAAC,OAAO;AACV,YAAM,QAAQ,QAAQ,MAAM,GAAG,EAAE,EAAE,IAAI,OAAK,EAAE,EAAE,EAAE,KAAK,IAAI;AAC3D,YAAM,IAAI;AAAA,QACR,mEAA2B,IAAI,EAAE,0BAAW,SAAS,UAAK,GAAG,QAAQ,SAAS,KAAK,YAAO,EAAE;AAAA,MAC9F;AAAA,IACF;AACA,UAAM,OAAO,oBAAoB,IAAI,IAAI;AACzC,QAAI;AACJ,QAAI,MAAM,SAAS,UAAU;AAC3B,YAAM,GAAG,IAAI,GAAG,MAAM,OAAO,GAAG;AAAA,IAClC,OAAO;AACL,YAAM,GAAG,IAAI,YAAY,mBAAmB,MAAM,EAAE,CAAC;AACrD,UAAI,IAAI,KAAM,QAAO,SAAS,mBAAmB,KAAK,UAAU,IAAI,IAAI,CAAC,CAAC;AAAA,IAC5E;AACA,UAAM,MAAM,WAAW;AAAA,MACrB;AAAA,MACA,OAAO,MAAM,KAAK,SAAS;AAAA,MAC3B,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,UAAU;AAAA,IACZ,CAAC;AACD,WAAO,MAAM;AAAA,EACf,OAAO;AAEL,UAAM,MAAM,WAAW;AAAA,MACrB,KAAK,oBAAoB,IAAI,IAAI;AAAA,MACjC,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,UAAU;AAAA,IACZ,CAAC;AACD,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,MAAM,KAAK,KAAK,MAAM,GAAG;AACzC,QAAM,EAAE,OAAO,OAAO,IAAI,QAAQ,GAAG;AACrC,SAAO,EAAE,MAAM,SAAS,QAAQ,IAAI,SAAS,QAAQ,GAAG,OAAO,OAAO;AACxE;;;AC7KA,SAAS,kBAAkB;;;ACC3B,OAAOC,SAAQ;AACf,OAAOC,WAAU;AACjB,SAAS,qBAAqB;AAE9B,IAAM,OAAOA,MAAK,QAAQ,cAAc,YAAY,GAAG,CAAC;AACxD,IAAM,UAAUA,MAAK,QAAQ,MAAM,IAAI;AAEvC,IAAM,OAAO;AAAA,EACXA,MAAK,KAAK,MAAM,QAAQ;AAAA;AAAA,EACxBA,MAAK,KAAK,SAAS,QAAQ,QAAQ;AAAA,EACnCA,MAAK,KAAK,SAAS,OAAO,QAAQ;AAAA;AACpC;AAGO,SAAS,WAAW,MAA6B;AACtD,aAAW,OAAO,MAAM;AACtB,UAAM,IAAIA,MAAK,KAAK,KAAK,IAAI;AAC7B,QAAID,IAAG,WAAW,CAAC,KAAKA,IAAG,SAAS,CAAC,EAAE,OAAO,EAAG,QAAO;AAAA,EAC1D;AACA,SAAO;AACT;AAEA,IAAM,OAA+B;AAAA,EACnC,SAAS;AAAA,EACT,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,SAAS;AACX;AAEO,SAAS,OAAO,MAAsB;AAC3C,SAAO,KAAKC,MAAK,QAAQ,IAAI,CAAC,KAAK;AACrC;AAGO,SAAS,aAAqB;AACnC,MAAI;AACF,UAAM,MAAM,KAAK,MAAMD,IAAG,aAAaC,MAAK,KAAK,SAAS,cAAc,GAAG,MAAM,CAAC;AAClF,WAAO,IAAI,WAAW;AAAA,EACxB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;ACxCA,OAAOC,SAAQ;AACf,OAAO,SAAS;AAChB,OAAO,QAAQ;AACf,OAAOC,WAAU;AAuBjB,SAAS,OAAO,MAAgC;AAC9C,SAAO,IAAI,QAAQ,CAACC,aAAY;AAC9B,UAAM,IAAI,IAAI,IAAI,OAAO;AACzB,UAAM,OAAO,CAACC,QAAsB;AAClC,QAAE,QAAQ;AACV,MAAAD,SAAQC,GAAE;AAAA,IACZ;AACA,MAAE,GAAG,WAAW,MAAM,KAAK,IAAI,CAAC;AAChC,MAAE,GAAG,SAAS,MAAM,KAAK,KAAK,CAAC;AAC/B,MAAE,WAAW,KAAK,MAAM,KAAK,KAAK,CAAC;AACnC,MAAE,QAAQ,EAAE,MAAM,KAAK,CAAC;AAAA,EAC1B,CAAC;AACH;AAGA,eAAsB,YAAY,KAAsC;AACtE,QAAM,OAAOF,MAAK,QAAQ,IAAI,WAAW;AACzC,QAAM,MAAMA,MAAK,KAAK,GAAG,QAAQ,GAAG,WAAW,UAAU;AACzD,MAAI;AACJ,MAAI;AACF,YAAQ,MAAMD,IAAG,QAAQ,GAAG;AAAA,EAC9B,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACA,QAAM,MAAoB,CAAC;AAC3B,QAAM,QAAQ;AAAA,IACZ,MACG,OAAO,CAAC,MAAM,EAAE,SAAS,OAAO,CAAC,EACjC,IAAI,OAAO,MAAM;AAChB,UAAI;AACJ,UAAI;AACF,cAAM,KAAK,MAAM,MAAMA,IAAG,SAASC,MAAK,KAAK,KAAK,CAAC,GAAG,MAAM,CAAC;AAAA,MAC/D,QAAQ;AACN;AAAA,MACF;AACA,UAAI,CAAC,IAAI,OAAO,CAAC,IAAI,OAAO,CAAC,IAAI,oBAAqB;AACtD,UAAI,IAAI,QAAQ,IAAI,SAAS,cAAe;AAC5C,YAAM,MAAMA,MAAK,SAAS,MAAMA,MAAK,QAAQ,IAAI,GAAG,CAAC;AACrD,UAAI,IAAI,WAAW,IAAI,KAAKA,MAAK,WAAW,GAAG,EAAG;AAClD,UAAI,CAAE,MAAM,OAAO,IAAI,mBAAmB,EAAI;AAC9C,UAAI,KAAK;AAAA,QACP,KAAK,IAAI;AAAA,QACT,MAAM,IAAI,QAAQ,OAAO,IAAI,GAAG;AAAA,QAChC,QAAQ,IAAI,UAAU;AAAA,QACtB,KAAK,IAAI;AAAA,QACT,QAAQ,IAAI;AAAA,QACZ,WAAW,IAAI,aAAa;AAAA,MAC9B,CAAC;AAAA,IACH,CAAC;AAAA,EACL;AACA,MAAI,KAAK,CAAC,GAAG,MAAM,EAAE,YAAY,EAAE,SAAS;AAC5C,SAAO;AACT;AAGO,SAAS,OAAO,MAAc,SAAgC;AACnE,SAAO,IAAI,QAAQ,CAACC,UAAS,WAAW;AACtC,UAAM,IAAI,IAAI,iBAAiB,EAAE,MAAM,KAAK,CAAC;AAC7C,MAAE,WAAW,KAAM,MAAM;AACvB,QAAE,QAAQ;AACV,aAAO,IAAI,MAAM,0BAAM,CAAC;AAAA,IAC1B,CAAC;AACD,MAAE,GAAG,SAAS,MAAM;AACpB,MAAE,GAAG,WAAW,MAAM;AACpB,YAAM,OACJ,KAAK,UAAU,EAAE,MAAM,QAAQ,SAAS,EAAE,MAAM,QAAQ,QAAQ,EAAE,CAAC,IAAI;AACzE,QAAE,IAAI,MAAM,MAAMA,SAAQ,CAAC;AAAA,IAC7B,CAAC;AAAA,EACH,CAAC;AACH;AAQA,eAAsB,cACpB,KACAE,OACA,KACqB;AACrB,QAAM,UAAU,MAAM,YAAY,GAAG;AACrC,MAAI,CAAC,QAAQ,QAAQ;AACnB,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,QAAQ,oDAAY,IAAI,WAAW;AAAA,IACrC;AAAA,EACF;AACA,MAAI;AACJ,MAAI,QAAQ,QAAW;AACrB,aAAS,QAAQ,KAAK,CAAC,MAAM,EAAE,QAAQ,GAAG;AAC1C,QAAI,CAAC,OAAQ,QAAO,EAAE,IAAI,OAAO,QAAQ,oBAAU,GAAG,kFAAsB;AAAA,EAC9E,WAAW,QAAQ,WAAW,GAAG;AAC/B,aAAS,QAAQ,CAAC;AAAA,EACpB,OAAO;AACL,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,QAAQ,QAAQ,IAAI,CAAC,EAAE,KAAK,GAAG,MAAM,QAAQ,IAAI,OAAO,EAAE,KAAK,GAAG,MAAM,QAAQ,IAAI,EAAE;AAAA,IACxF;AAAA,EACF;AACA,QAAM,OACJ;AAAA;AAAA,IAAuDA;AACzD,QAAM,OAAO,OAAQ,QAAQ,IAAI;AACjC,SAAO,EAAE,IAAI,MAAM,KAAK,OAAQ,KAAK,MAAM,OAAQ,KAAK;AAC1D;;;AC3HA,IAAM,cAAc,OAAO,QAAQ,IAAI,yBAAyB,GAAK;AACrE,IAAM,aAAa,OAAO,QAAQ,IAAI,wBAAwB,GAAK;AAEnE,IAAM,gBAAgB;AAEtB,IAAI,UAAuB,EAAE,IAAI,KAAK;AAE/B,SAAS,gBAA6B;AAC3C,SAAO;AACT;AAEO,SAAS,mBACd,KACAC,YACmB;AACnB,MAAI,QAAQ;AACZ,MAAI,SAAS;AACb,MAAI,QAA+B;AAEnC,QAAM,QAAQ,YAA2B;AACvC,QAAI,aAA4B;AAChC,QAAI;AACF,YAAM,IAAI,MAAM,MAAM,GAAG,IAAI,MAAM,kBAAkB,EAAE,QAAQ,YAAY,QAAQ,UAAU,EAAE,CAAC;AAChG,UAAI,EAAE,MAAM,EAAE,WAAW,KAAK;AAE5B,iBAAS;AACT,gBAAQ;AACR,YAAI,CAAC,QAAQ,IAAI;AACf,oBAAU,EAAE,IAAI,MAAM,UAAU,KAAK,IAAI,EAAE;AAC3C,UAAAA,WAAU,EAAE,MAAM,UAAU,IAAI,KAAK,CAAC;AAAA,QACxC,OAAO;AACL,oBAAU,EAAE,IAAI,MAAM,UAAU,KAAK,IAAI,EAAE;AAAA,QAC7C;AACA;AAAA,MACF;AACA,mBAAa,qCAAiB,EAAE,MAAM;AAAA,IACxC,SAAS,KAAK;AACZ,YAAM,IAAI;AACV,mBACE,EAAE,SAAS,iBACP,oBAAU,aAAa,GAAI,yBAC3B,sBAAO,EAAE,OAAO,QAAQ,SAAS;AAAA,IACzC;AAEA,QAAI,CAAC,OAAQ;AACb;AACA,QAAI,SAAS,iBAAiB,QAAQ,IAAI;AACxC,gBAAU,EAAE,IAAI,OAAO,QAAQ,cAAc,gBAAM,UAAU,QAAQ,SAAS;AAC9E,MAAAA,WAAU,EAAE,MAAM,UAAU,IAAI,OAAO,QAAQ,QAAQ,OAAO,CAAC;AAC/D,cAAQ,KAAK,sCAAuB,IAAI,MAAM,6BAAS,QAAQ,MAAM,sFAAqB;AAAA,IAC5F;AAAA,EACF;AAEA,UAAQ,YAAY,MAAM,KAAK,MAAM,GAAG,WAAW;AACnD,QAAM,MAAM;AACZ,OAAK,MAAM;AACX,SAAO;AAAA,IACL,QAAQ;AACN,UAAI,MAAO,eAAc,KAAK;AAAA,IAChC;AAAA,EACF;AACF;;;AC3EA,IAAM,UAAU,oBAAI,IAAoB;AACxC,IAAI,YAAmC;AAGhC,SAAS,OAAO,KAAsB,KAA2B;AACtE,MAAI,UAAU,KAAK;AAAA,IACjB,gBAAgB;AAAA,IAChB,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,qBAAqB;AAAA,EACvB,CAAC;AACD,MAAI,MAAM,8BAA8B;AACxC,UAAQ,IAAI,GAAG;AAGf,QAAM,OAAO,MAAM;AACjB,YAAQ,OAAO,GAAG;AAClB,QAAI,QAAQ,SAAS,EAAG,eAAc;AAAA,EACxC;AACA,MAAI,GAAG,SAAS,IAAI;AACpB,MAAI,GAAG,SAAS,IAAI;AACpB,MAAI,GAAG,SAAS,IAAI;AAEpB,iBAAe;AACjB;AAGO,SAAS,UAAU,IAAmB;AAC3C,QAAM,QAAQ,UAAU,GAAG,IAAI;AAAA,QAAW,KAAK,UAAU,EAAE,CAAC;AAAA;AAAA;AAC5D,aAAW,OAAO,SAAS;AACzB,QAAI;AACF,UAAI,MAAM,KAAK;AAAA,IACjB,QAAQ;AACN,cAAQ,OAAO,GAAG;AAAA,IACpB;AAAA,EACF;AACF;AAGO,SAAS,WAAiB;AAC/B,aAAW,OAAO,SAAS;AACzB,QAAI;AACF,UAAI,IAAI;AAAA,IACV,QAAQ;AAAA,IAER;AAAA,EACF;AACA,UAAQ,MAAM;AACd,gBAAc;AAChB;AAEA,SAAS,iBAAuB;AAC9B,MAAI,UAAW;AAEf,cAAY,YAAY,MAAM;AAC5B,eAAW,OAAO,QAAS,KAAI,MAAM,YAAY;AAAA,EACnD,GAAG,IAAK;AACR,YAAU,MAAM;AAClB;AAEA,SAAS,gBAAsB;AAC7B,MAAI,CAAC,UAAW;AAChB,gBAAc,SAAS;AACvB,cAAY;AACd;;;ACnEA,OAAOC,SAAQ;AACf,OAAOC,WAAU;AAKjB,IAAI,YAA8B;AAE3B,SAAS,eAAiC;AAC/C,SAAO;AACT;AAEO,SAAS,aAAa,MAA8B;AACzD,cAAY;AACd;AAIA,SAAS,UAAU,KAAuB;AACxC,SAAOA,MAAK,KAAK,IAAI,aAAa,IAAI,WAAW,SAAS;AAC5D;AAEA,SAAS,gBAAgB,KAAuB;AAC9C,SAAOA,MAAK,KAAK,UAAU,GAAG,GAAG,kBAAkB;AACrD;AAOA,eAAsB,gBAAgB,KAAsC;AAC1E,MAAI;AACJ,MAAI;AACF,UAAM,MAAMD,IAAG,SAAS,gBAAgB,GAAG,GAAG,MAAM;AAAA,EACtD,SAAS,KAAK;AACZ,QAAK,IAA8B,SAAS,SAAU,QAAO,CAAC;AAC9D,UAAM;AAAA,EACR;AACA,MAAI,CAAC,IAAI,KAAK,EAAG,QAAO,CAAC;AACzB,MAAI;AACJ,MAAI;AACF,WAAO,KAAK,MAAM,GAAG;AAAA,EACvB,SAAS,KAAK;AACZ,UAAM,IAAI;AAAA,MACR,6CAA0B,IAAc,OAAO,iHACtC,gBAAgB,GAAG,CAAC;AAAA,IAC/B;AAAA,EACF;AACA,MAAI,CAAC,MAAM,QAAQ,IAAI,GAAG;AACxB,UAAM,IAAI,MAAM,sHAAsC,gBAAgB,GAAG,CAAC,EAAE;AAAA,EAC9E;AAGA,QAAM,OAAO;AACb,MAAI,OAAO,KAAK,OAAO,CAAC,GAAG,MAAM,KAAK,IAAI,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC;AAC3D,aAAW,KAAK,KAAM,KAAI,OAAO,EAAE,QAAQ,SAAU,GAAE,MAAM,EAAE;AAC/D,SAAO;AACT;AAGA,eAAe,iBAAiB,KAAe,MAAmC;AAChF,QAAM,OAAO,gBAAgB,GAAG;AAChC,QAAMA,IAAG,MAAMC,MAAK,QAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;AACtD,QAAMD,IAAG,SAAS,MAAM,GAAG,IAAI,MAAM,EAAE,MAAM,MAAM,MAAS;AAC5D,QAAM,MAAM,GAAG,IAAI,IAAI,QAAQ,GAAG;AAClC,QAAMA,IAAG,UAAU,KAAK,KAAK,UAAU,MAAM,MAAM,CAAC,IAAI,MAAM,MAAM;AACpE,QAAMA,IAAG,OAAO,KAAK,IAAI;AAC3B;AAGA,IAAI,QAA0B,QAAQ,QAAQ;AAGvC,SAAS,kBACd,KACA,IAC4C;AAC5C,QAAM,MAAM,MAAM,KAAK,YAAY;AACjC,UAAM,OAAO,MAAM,gBAAgB,GAAG;AACtC,UAAM,SAAS,GAAG,IAAI;AACtB,UAAM,iBAAiB,KAAK,IAAI;AAChC,WAAO,EAAE,QAAQ,KAAK;AAAA,EACxB,CAAC;AACD,UAAQ,IAAI,MAAM,MAAM,MAAS;AACjC,SAAO;AACT;AAGO,SAAS,gBAAgB,MAA4B;AAC1D,QAAM,OAAO,MAAM,KAAK,IAAI,EAAE,SAAS,EAAE;AACzC,MAAI,KAAK;AACT,WAAS,IAAI,GAAG,KAAK,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,IAAK,MAAK,OAAO,EAAE,SAAS,EAAE;AAC7E,SAAO;AACT;AAKA,eAAsB,QAAQ,KAAe,MAAc,YAAqC;AAE9F,QAAM,OAAOC,MAAK,SAAS,IAAI,EAAE,QAAQ,aAAa,GAAG,EAAE,QAAQ,UAAU,EAAE,KAAK;AACpF,QAAM,OAAM,oBAAI,KAAK,GAAE,YAAY,EAAE,MAAM,GAAG,EAAE;AAChD,QAAM,MAAMA,MAAK,KAAK,UAAU,GAAG,GAAG,MAAM;AAC5C,QAAMD,IAAG,MAAM,KAAK,EAAE,WAAW,KAAK,CAAC;AAGvC,QAAM,MAAMC,MAAK,QAAQ,IAAI;AAC7B,QAAM,OAAO,KAAK,MAAM,GAAG,KAAK,SAAS,IAAI,MAAM;AACnD,MAAI,WAAW,GAAG,GAAG,IAAI,IAAI;AAC7B,WAAS,IAAI,GAAG,MAAM,OAAOA,MAAK,KAAK,KAAK,QAAQ,CAAC,GAAG,IAAK,YAAW,GAAG,GAAG,IAAI,IAAI,IAAI,CAAC,GAAG,GAAG;AAGjG,QAAM,OAAO,WAAW,QAAQ,wBAAwB,EAAE;AAC1D,QAAMD,IAAG,UAAUC,MAAK,KAAK,KAAK,QAAQ,GAAG,OAAO,KAAK,MAAM,QAAQ,CAAC;AACxE,SAAO,GAAG,IAAI,SAAS,iBAAiB,QAAQ;AAClD;AAGA,eAAsB,QAAQ,KAAe,KAA6D;AACxG,QAAM,OAAOA,MAAK,KAAK,UAAU,GAAG,GAAG,MAAM;AAC7C,QAAM,MAAMA,MAAK,QAAQ,IAAI,aAAa,GAAG;AAC7C,MAAI,QAAQ,QAAQ,CAAC,IAAI,WAAW,OAAOA,MAAK,GAAG,EAAG,QAAO;AAC7D,MAAI;AACF,WAAO,EAAE,MAAM,MAAMD,IAAG,SAAS,GAAG,GAAG,MAAM,IAAI;AAAA,EACnD,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAe,OAAO,GAA6B;AACjD,MAAI;AACF,UAAMA,IAAG,OAAO,CAAC;AACjB,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAKA,eAAsB,iBAAiB,KAAgC;AACrE,QAAM,QAAQ,MAAM,gBAAgB,GAAG,GAAG,OAAO,CAAC,MAAM,EAAE,WAAW,MAAM;AAC3E,QAAM,MAAM,aAAa;AACzB,MAAI,CAAC,OAAO,KAAK,WAAW,EAAG,QAAO;AAEtC,QAAM,QAAQ,CAAC,gDAAuB;AACtC,MAAI,KAAK;AACP,UAAM,KAAK,yCAAW,IAAI,UAAU,8BAAY,IAAI,QAAQ,wBAAW,IAAI,IAAI,CAAC,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC,EAAE;AAAA,EACnG;AACA,MAAI,KAAK,SAAS,GAAG;AACnB,UAAM,KAAK,kCAAS,KAAK,MAAM,WAAM;AACrC,eAAW,KAAK,MAAM;AACpB,YAAM,QAAQ,CAAC,EAAE,YAAY,EAAE,QAAQ,QAAQ,EAAE,OAAO,OAAO,EAAE,KAAK,KAAK;AAE3E,YAAM,KAAK,MAAM,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,QAAQ,QAAQ,mBAAS,EAAE,GAAG,EAAE,IAAI,EAAE;AAEzE,OAAC,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,KAAK,MAAM,MAAM,KAAK,kBAAQ,IAAI,CAAC,IAAI,GAAG,EAAE,CAAC;AAAA,IACxE;AAAA,EACF;AACA,SAAO,MAAM,KAAK,IAAI,IAAI;AAC5B;AAEA,SAAS,IAAI,GAAmB;AAC9B,SAAO,OAAO,MAAM,YAAY,OAAO,SAAS,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI;AACtE;;;AL5JA,IAAM,MAAM;AAGZ,IAAI,QAAuB;AACpB,SAAS,YAAoB;AAClC,MAAI,CAAC,MAAO,SAAQ,WAAW;AAC/B,SAAO;AACT;AAOA,SAAS,cAAc,KAAe,KAA+B;AACnE,QAAM,SAAS,IAAI,QAAQ;AAC3B,MAAI,CAAC,OAAQ,QAAO;AACpB,QAAME,MAAK,oBAAI,IAAI;AAAA,IACjB,oBAAoB,IAAI,IAAI;AAAA,IAC5B,oBAAoB,IAAI,IAAI;AAAA,IAC5B,gBAAgB,IAAI,IAAI;AAAA,EAC1B,CAAC;AACD,SAAOA,IAAG,IAAI,MAAM;AACtB;AAEA,eAAsB,UACpB,KACA,KACA,KACA,UACe;AACf,QAAM,SAAS,IAAI,UAAU;AAE7B,MAAI,WAAW,SAAS,CAAC,cAAc,KAAK,GAAG,GAAG;AAChD,WAAO,SAAS,KAAK,KAAK,iGAAqC;AAAA,EACjE;AAEA,MAAI,aAAa,mBAAmB;AAClC,QAAI,WAAW,MAAO,QAAO,SAAS,KAAK,KAAK,oBAAoB;AACpE,UAAM,OAAkB;AAAA,MACtB,SAAS,WAAW;AAAA,MACpB,QAAQ,IAAI;AAAA,MACZ,WAAW,IAAI;AAAA,MACf,aAAa,IAAI;AAAA,IACnB;AACA,WAAO,SAAS,KAAK,KAAK,IAAI;AAAA,EAChC;AAEA,MAAI,aAAa,uBAAuB;AACtC,QAAI,WAAW,MAAO,QAAO,SAAS,KAAK,KAAW,aAAa,CAAC;AACpE,QAAI,WAAW,QAAQ;AACrB,YAAM,OAAO,MAAM,SAA2B,GAAG;AAEjD,MAAM,aAAa,QAAQ,OAAO,KAAK,eAAe,WAAW,OAAO,IAAI;AAC5E,aAAO,UAAU,KAAK,GAAG;AAAA,IAC3B;AACA,WAAO,SAAS,KAAK,KAAK,oBAAoB;AAAA,EAChD;AAEA,MAAI,aAAa,OAAO,SAAS,WAAW,MAAM,GAAG,GAAG;AACtD,WAAO,kBAAkB,KAAK,KAAK,KAAK,UAAU,MAAM;AAAA,EAC1D;AAGA,MAAI,SAAS,WAAW,iBAAiB,GAAG;AAC1C,QAAI,WAAW,MAAO,QAAO,SAAS,KAAK,KAAK,oBAAoB;AACpE,UAAM,MAAM,SAAS,MAAM,kBAAkB,MAAM,EAAE,MAAM,GAAG,EAAE,IAAI,kBAAkB,EAAE,KAAK,GAAG;AAChG,UAAM,MAAM,MAAY,QAAQ,KAAK,GAAG;AACxC,QAAI,CAAC,IAAK,QAAO,SAAS,KAAK,KAAK,oDAAsB;AAC1D,QAAI,UAAU,KAAK,EAAE,gBAAgB,OAAO,IAAI,IAAI,GAAG,iBAAiB,WAAW,CAAC;AACpF,QAAI,IAAI,IAAI,IAAI;AAChB;AAAA,EACF;AAEA,MAAI,aAAa,kBAAkB;AACjC,QAAI,WAAW,OAAQ,QAAO,SAAS,KAAK,KAAK,oBAAoB;AACrE,UAAM,OAAO,MAAM,SAAiD,GAAG;AACvE,QAAI,CAAC,MAAM,WAAY,QAAO,SAAS,KAAK,KAAK,yBAAe;AAChE,UAAM,MAAM,MAAY,QAAQ,KAAK,KAAK,QAAQ,WAAW,KAAK,UAAU;AAC5E,WAAO,SAAS,KAAK,KAAK,EAAE,MAAM,IAAI,CAAC;AAAA,EACzC;AAEA,MAAI,aAAa,oBAAoB;AACnC,QAAI,WAAW,MAAO,QAAO,SAAS,KAAK,KAAK,oBAAoB;AACpE,WAAO,SAAS,KAAK,KAAK,cAAc,CAAC;AAAA,EAC3C;AAEA,MAAI,aAAa,qBAAqB;AACpC,QAAI,WAAW,MAAO,QAAO,SAAS,KAAK,KAAK,oBAAoB;AAGpE,QAAI;AACF,aAAO,SAAS,KAAK,KAAK,MAAY,iBAAiB,GAAG,CAAC;AAAA,IAC7D,SAAS,KAAK;AACZ,aAAO,SAAS,KAAK,KAAK,iDAAwB,QAAQ,GAAG,CAAC,EAAE;AAAA,IAClE;AAAA,EACF;AAEA,MAAI,aAAa,kBAAkB;AACjC,QAAI,WAAW,OAAQ,QAAO,SAAS,KAAK,KAAK,oBAAoB;AAErE,QAAI,IAAI,QAAQ,YAAY,MAAM,UAAU,GAAG;AAC7C,aAAO,SAAS,KAAK,KAAK,mHAAwC;AAAA,IACpE;AACA,UAAM,OAAO,MAAM,SAA2B,GAAG;AACjD,QAAI;AACF,YAAMC,QAAO,MAAY,iBAAiB,GAAG;AAC7C,UAAI,CAACA,MAAK,KAAK,EAAG,QAAO,SAAS,KAAK,KAAK,EAAE,IAAI,OAAO,QAAQ,uGAAuB,CAAC;AACzF,aAAO,SAAS,KAAK,KAAK,MAAM,cAAc,KAAKA,OAAM,MAAM,GAAG,CAAC;AAAA,IACrE,SAAS,KAAK;AACZ,aAAO,SAAS,KAAK,KAAK,EAAE,IAAI,OAAO,QAAQ,4BAAQ,QAAQ,GAAG,CAAC,GAAG,CAAC;AAAA,IACzE;AAAA,EACF;AAEA,MAAI,aAAa,wBAAwB;AACvC,QAAI,WAAW,OAAQ,QAAO,SAAS,KAAK,KAAK,oBAAoB;AACrE,UAAM,OAAO,MAAM,SAAsB,GAAG;AAC5C,QAAI;AACF,aAAO,SAAS,KAAK,KAAK,MAAM,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC;AAAA,IAC7D,SAAS,KAAK;AAEZ,aAAO,SAAS,KAAK,KAAK,2BAAiB,QAAQ,GAAG,CAAC,EAAE;AAAA,IAC3D;AAAA,EACF;AAEA,SAAO,SAAS,KAAK,KAAK,WAAW;AACvC;AAEA,eAAe,kBACb,KACA,KACA,KACA,UACA,QACe;AACf,QAAM,KAAK,aAAa,MAAM,KAAK,mBAAmB,SAAS,MAAM,IAAI,SAAS,CAAC,CAAC;AAEpF,MAAI,CAAC,MAAM,WAAW,OAAO;AAC3B,WAAO,SAAS,KAAK,KAAK,MAAY,gBAAgB,GAAG,CAAC;AAAA,EAC5D;AAEA,MAAI,CAAC,MAAM,WAAW,QAAQ;AAC5B,UAAM,OAAO,MAAM,SAA8B,GAAG;AACpD,UAAM,EAAE,QAAQ,KAAK,IAAI,MAAY,kBAAkB,KAAK,CAAC,QAAQ;AACnE,YAAM,MAAkB;AAAA,QACtB,IAAU,gBAAgB,GAAG;AAAA;AAAA,QAE7B,KAAK,IAAI,OAAO,CAAC,GAAG,MAAM,KAAK,IAAI,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,IAAI;AAAA,QACxD,YAAY,MAAM;AAAA,QAClB,QAAQ,MAAM;AAAA,QACd,MAAM,OAAO,MAAM,SAAS,WAAW,KAAK,OAAO;AAAA,QACnD,MAAM,MAAM,QAAQ,MAAM,IAAI,IAAI,KAAK,OAAO,CAAC;AAAA,QAC/C,QAAQ,MAAM,WAAW,aAAa,aAAa;AAAA,QACnD,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MACpC;AACA,UAAI,KAAK,GAAG;AACZ,aAAO;AAAA,IACT,CAAC;AACD,cAAU,EAAE,MAAM,eAAe,aAAa,KAAK,CAAC;AACpD,WAAO,SAAS,KAAK,KAAK,MAAM;AAAA,EAClC;AAEA,MAAI,MAAM,WAAW,SAAS;AAC5B,UAAM,QAAQ,MAAM,SAA8B,GAAG;AACrD,UAAM,EAAE,QAAQ,KAAK,IAAI,MAAY,kBAAkB,KAAK,CAAC,QAAQ;AACnE,YAAM,MAAM,IAAI,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE;AACvC,UAAI,CAAC,IAAK,QAAO;AAEjB,aAAO,OAAO,KAAK,OAAO,EAAE,IAAI,IAAI,IAAI,WAAW,IAAI,UAAU,CAAC;AAClE,aAAO;AAAA,IACT,CAAC;AACD,QAAI,CAAC,OAAQ,QAAO,SAAS,KAAK,KAAK,sBAAsB;AAC7D,cAAU,EAAE,MAAM,eAAe,aAAa,KAAK,CAAC;AACpD,WAAO,SAAS,KAAK,KAAK,MAAM;AAAA,EAClC;AAEA,MAAI,MAAM,WAAW,UAAU;AAC7B,UAAM,EAAE,QAAQ,KAAK,IAAI,MAAY,kBAAkB,KAAK,CAAC,QAAQ;AACnE,YAAM,IAAI,IAAI,UAAU,CAAC,MAAM,EAAE,OAAO,EAAE;AAC1C,UAAI,IAAI,EAAG,QAAO;AAClB,UAAI,OAAO,GAAG,CAAC;AACf,aAAO;AAAA,IACT,CAAC;AACD,QAAI,CAAC,OAAQ,QAAO,SAAS,KAAK,KAAK,sBAAsB;AAC7D,cAAU,EAAE,MAAM,eAAe,aAAa,KAAK,CAAC;AACpD,WAAO,UAAU,KAAK,GAAG;AAAA,EAC3B;AAEA,SAAO,SAAS,KAAK,KAAK,oBAAoB;AAChD;AAIO,SAAS,SAAS,KAAqB,MAAc,MAAqB;AAC/E,MAAI,UAAU,MAAM,EAAE,gBAAgB,mCAAmC,iBAAiB,WAAW,CAAC;AACtG,MAAI,IAAI,KAAK,UAAU,QAAQ,IAAI,CAAC;AACtC;AAEO,SAAS,SAAS,KAAqB,MAAc,MAAoB;AAC9E,MAAI,UAAU,MAAM,EAAE,gBAAgB,6BAA6B,iBAAiB,WAAW,CAAC;AAChG,MAAI,IAAI,IAAI;AACd;AAEA,SAAS,UAAU,KAAqB,MAAoB;AAC1D,MAAI,UAAU,IAAI;AAClB,MAAI,IAAI;AACV;AAEO,SAAS,QAAQ,KAAsB;AAC5C,SAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AACxD;AAEA,eAAe,SAAY,KAAkC;AAC3D,QAAM,SAAmB,CAAC;AAC1B,mBAAiB,KAAK,IAAK,QAAO,KAAK,CAAW;AAClD,QAAM,MAAM,OAAO,OAAO,MAAM,EAAE,SAAS,MAAM,EAAE,KAAK;AACxD,MAAI,CAAC,IAAK,QAAO;AACjB,SAAO,KAAK,MAAM,GAAG;AACvB;;;AM7NA,IAAM,YAAY;AAWX,SAAS,eAAe,QAA0B;AAEvD,QAAM,UAAU,oBAAI,IAAsD;AAC1E,MAAI,OAAO;AACX,MAAI,WAAW;AAEf,SAAO;AAAA,IACL,KAAK,KAAK,KAAK;AACb,YAAM,OAAO,IAAI,QAAQ,IAAI;AAG7B,UAAI,SAAS,gBAAgB;AAC3B,YAAI,MAAM;AACR;AACA;AAAA,QACF;AACA,eAAO;AACP,gBAAQ;AAAA,UACN,GAAG,OAAO,QAAG,CAAC,IAAI,OAAO,gBAAM,MAAM,2BAAO,CAAC,yHAC3C,IAAI,sFAAgB;AAAA,QACxB;AACA;AAAA,MACF;AAEA,YAAM,MAAM,GAAG,IAAI,IAAI,OAAO,GAAG,CAAC;AAClC,YAAM,MAAM,QAAQ,IAAI,GAAG;AAC3B,UAAI,KAAK;AACP,YAAI;AACJ;AAAA,MACF;AACA,cAAQ,MAAM,GAAG,IAAI,QAAG,CAAC,6BAAS,OAAO,GAAG,CAAC,IAAI,IAAI,OAAO,IAAI,CAAC,CAAC,EAAE;AACpE,YAAM,QAAQ,WAAW,MAAM;AAC7B,cAAM,QAAQ,QAAQ,IAAI,GAAG,GAAG,SAAS;AACzC,gBAAQ,OAAO,GAAG;AAClB,YAAI,QAAQ,GAAG;AACb,kBAAQ,MAAM,IAAI,mBAAS,YAAY,GAAI,uBAAQ,KAAK,mCAAU,GAAG,GAAG,CAAC;AAAA,QAC3E;AAAA,MACF,GAAG,SAAS;AACZ,YAAM,MAAM;AACZ,cAAQ,IAAI,KAAK,EAAE,OAAO,GAAG,MAAM,CAAC;AAAA,IACtC;AAAA,IAEA,QAAQ;AACN,UAAI,CAAC,KAAM;AACX,aAAO;AACP,YAAM,IAAI;AACV,iBAAW;AACX,cAAQ,IAAI,GAAG,MAAM,QAAG,CAAC,IAAI,MAAM,gBAAM,MAAM,qBAAM,CAAC,GAAG,IAAI,IAAI,IAAI,+CAAY,CAAC,kCAAS,IAAI,EAAE,EAAE;AAAA,IACrG;AAAA,IAEA,QAAQ;AACN,iBAAW,OAAO,QAAQ,OAAO,EAAG,cAAa,IAAI,KAAK;AAC1D,cAAQ,MAAM;AAAA,IAChB;AAAA,EACF;AACF;AAGA,SAAS,OAAO,KAAiC;AAC/C,MAAI,CAAC,IAAK,QAAO;AACjB,QAAM,IAAI,IAAI,QAAQ,GAAG;AACzB,SAAO,IAAI,IAAI,MAAM,IAAI,MAAM,GAAG,CAAC;AACrC;;;AT5DA,eAAsB,YAAY,KAAkE;AAClG,QAAM,QAAQ,UAAU,kBAAkB,EAAE,QAAQ,IAAI,QAAQ,IAAI,MAAM,cAAc,KAAK,CAAC;AAI9F,QAAM,WAAW,eAAe,IAAI,MAAM;AAC1C,QAAM,GAAG,SAAS,CAAC,KAAK,KAAK,QAAQ;AACnC,aAAS,KAAK,KAA8B,KAAK,GAAG;AACpD,QAAI,CAAC,IAAK;AACV,QAAI,eAAe,KAAK;AACtB,UAAI,CAAC,IAAI,YAAa,KAAI,UAAU,KAAK,EAAE,gBAAgB,2BAA2B,CAAC;AACvF,UAAI,IAAI,SAAS,IAAI,MAAM,CAAC;AAAA,IAC9B,OAAO;AAEL,UAAI,QAAQ;AAAA,IACd;AAAA,EACF,CAAC;AAKD,QAAM,GAAG,YAAY,CAAC,UAAU,MAAM,QAAQ;AAC5C,QAAI,GAAG,SAAS,MAAM;AACpB,UAAI,CAAC,IAAI,cAAe,UAAS,QAAQ;AAAA,IAC3C,CAAC;AAAA,EACH,CAAC;AAGD,QAAM,GAAG,YAAY,MAAM,SAAS,MAAM,CAAC;AAC3C,QAAM,GAAG,QAAQ,MAAM,SAAS,MAAM,CAAC;AAGvC,MAAI,MAAyB;AAC7B,MAAI;AACF,UAAM,iBAAiB,aAAa,GAAG,CAAC;AAAA,EAC1C,SAAS,KAAK;AACZ,YAAQ,KAAK,qEAA4C,QAAQ,GAAG,CAAC,EAAE;AAAA,EACzE;AAEA,QAAM,SAAS,KAAK,aAAa,CAAC,KAAK,QAAQ;AAC7C,WAAO,KAAK,OAAO,KAAK,KAAK,GAAG,EAAE,MAAM,CAAC,QAAQ;AAC/C,cAAQ,MAAM,uDAAyB,IAAI,GAAG,IAAI,GAAG;AACrD,UAAI,CAAC,IAAI,YAAa,UAAS,KAAK,KAAK,QAAQ,GAAG,CAAC;AAAA,UAChD,KAAI,IAAI;AAAA,IACf,CAAC;AAAA,EACH,CAAC;AAGD,SAAO,GAAG,WAAW,CAAC,KAAK,QAAQ,SAAS,MAAM,GAAG,KAAK,QAAQ,IAAI,CAAC;AAIvE,QAAM,UAAU,oBAAI,IAA+B;AACnD,SAAO,GAAG,cAAc,CAAC,MAAM;AAC7B,YAAQ,IAAI,CAAC;AACb,MAAE,GAAG,SAAS,MAAM,QAAQ,OAAO,CAAC,CAAC;AAAA,EACvC,CAAC;AAID,QAAM,OAAO,IAAI,QAAQ;AACzB,MAAI,OAA2B;AAC/B,QAAM,OAAO,MAAM,mBAAmB,QAAQ,KAAK,MAAM,CAAC,MAAM;AAC9D,WAAO;AAEP,MAAE,GAAG,cAAc,CAAC,SAAS;AAC3B,cAAQ,IAAI,IAAI;AAChB,WAAK,GAAG,SAAS,MAAM,QAAQ,OAAO,IAAI,CAAC;AAAA,IAC7C,CAAC;AAAA,EACH,CAAC;AACD,MAAI,SAAS,eAAe,SAAS,aAAa;AAChD,YAAQ;AAAA,MACN,KAAK,sBAAO,IAAI,IAAI,IAAI,oRAA6D;AAAA,IACvF;AAAA,EACF;AAEA,QAAM,SAAS,mBAAmB,KAAS,SAAS;AAEpD,SAAO;AAAA,IACL;AAAA,IACA,MAAM,QAAQ;AACZ,aAAO,MAAM;AACb,MAAI,SAAS;AACb,eAAS,MAAM;AACf,YAAM,MAAM;AACZ,UAAI,MAAM;AACR,cAAM,IAAI,QAAc,CAAC,MAAM,KAAM,MAAM,MAAM,EAAE,CAAC,CAAC;AAAA,MACvD;AACA,YAAM,IAAI,QAAc,CAACC,aAAY;AACnC,cAAM,WAAW,WAAWA,UAAS,GAAI;AACzC,mBAAW,KAAK,QAAS,GAAE,QAAQ;AACnC,eAAO,oBAAoB;AAC3B,eAAO,MAAM,MAAM;AACjB,uBAAa,QAAQ;AACrB,UAAAA,SAAQ;AAAA,QACV,CAAC;AAAA,MACH,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAEA,eAAe,OACb,KACA,OACA,KACA,KACA,KACe;AAEf,QAAM,WAAW,IAAI,IAAI,IAAI,OAAO,KAAK,kBAAkB,EAAE;AAE7D,MAAI,aAAa,WAAW,aAAa,SAAU,QAAO,QAAQ,KAAK,YAAY;AAEnF,MAAI,SAAS,WAAW,WAAW,GAAG;AACpC,UAAM,OAAO,SAAS,MAAM,YAAY,MAAM;AAC9C,QAAI,CAAC,QAAQ,KAAK,SAAS,IAAI,EAAG,QAAO,SAAS,KAAK,KAAK,gBAAgB;AAC5E,WAAO,QAAQ,KAAK,IAAI;AAAA,EAC1B;AAEA,MAAI,aAAa,eAAgB,QAAW,OAAO,KAAK,GAAG;AAE3D,MAAI,aAAa,aAAa;AAC5B,QAAI,CAAC,IAAK,QAAO,SAAS,KAAK,KAAK,kDAAyB;AAC7D,WAAO,IAAI,KAAK,GAAG;AAAA,EACrB;AAEA,MAAI,SAAS,WAAW,YAAY,EAAG,QAAO,UAAU,KAAK,KAAK,KAAK,QAAQ;AAG/E,QAAM,IAAI,KAAK,GAAG;AACpB;AAEA,SAAS,QAAQ,KAA0B,MAAoB;AAC7D,QAAM,OAAO,WAAW,IAAI;AAC5B,MAAI,CAAC,KAAM,QAAO,SAAS,KAAK,KAAK,4DAAyB,IAAI,8BAAoB;AACtF,MAAI,OAAOC,IAAG,aAAa,IAAI;AAG/B,MAAI,SAAS,cAAc;AACzB,WAAO,OAAO;AAAA,MACZ,KAAK,SAAS,MAAM,EAAE,QAAQ,WAAW,kCAAkC,UAAU,CAAC;AAAA,QAAe;AAAA,IACvG;AAAA,EACF;AACA,MAAI,UAAU,KAAK,EAAE,gBAAgB,OAAO,IAAI,GAAG,iBAAiB,WAAW,CAAC;AAChF,MAAI,IAAI,IAAI;AACd;AAGA,SAAS,aAAa,KAA4B;AAChD,SAAO;AAAA;AAAA,IAEL,MAAM,cAAwC;AAC5C,UAAI;AACF,cAAM,IAAI,MAAM,MAAM,GAAG,IAAI,MAAM,gBAAgB;AACnD,YAAI,CAAC,EAAE,GAAI,QAAO,CAAC;AACnB,cAAM,OAAgB,MAAM,EAAE,KAAK;AACnC,eAAO,MAAM,QAAQ,IAAI,IAAK,OAA2B,CAAC;AAAA,MAC5D,QAAQ;AACN,eAAO,CAAC;AAAA,MACV;AAAA,IACF;AAAA,IACA,cAAc,MAAY,aAAa;AAAA,IACvC,gBAAgB,MAAY,gBAAgB,GAAG;AAAA,IAC/C,UAAU,OAAO,QAAQ,WAAW,KAAK,GAAG;AAAA,EAC9C;AACF;AAEA,SAAS,SAAS,QAAwB;AACxC,SAAO;AAAA;AAAA,uEAEoD,WAAW,MAAM,CAAC;AAAA;AAAA;AAAA;AAI/E;AAEA,SAAS,WAAW,GAAmB;AACrC,SAAO,EAAE,QAAQ,WAAW,CAAC,OAAO,EAAE,KAAK,SAAS,KAAK,QAAQ,KAAK,QAAQ,KAAK,SAAS,GAAG,CAAC,CAAW;AAC7G;AAKA,eAAe,iBACb,KACA,MACsC;AACtC,WAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,QAAI;AACF,YAAM,IAAI,MAAM,MAAM,oBAAoB,IAAI,mBAAmB;AAAA,QAC/D,QAAQ,YAAY,QAAQ,IAAI;AAAA,MAClC,CAAC;AACD,UAAI,CAAC,EAAE,GAAI,QAAO;AAClB,YAAM,OAAQ,MAAM,EAAE,KAAK;AAC3B,aAAO,MAAM,gBAAgB,IAAI,cAAc,EAAE,SAAS,KAAK,QAAQ,IAAI;AAAA,IAC7E,QAAQ;AAAA,IAER;AAAA,EACF;AACA,SAAO;AACT;AAGA,SAAS,YAAY,MAA6B;AAChD,MAAI;AACF,UAAM,EAAE,SAAS,IAAI,UAAQ,oBAAoB;AACjD,UAAM,MAAM,SAAS,qBAAqB,IAAI,iBAAiB,EAAE,SAAS,IAAK,CAAC,EAC7E,SAAS,EACT,KAAK;AACR,WAAO,IAAI,MAAM,IAAI,EAAE,CAAC,KAAK;AAAA,EAC/B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAUA,eAAe,mBACb,QACA,KACA,MACA,QACiB;AACjB,QAAM,aAAa,CAAC,KAAkB,MAAc,MAClD,IAAI,QAAQ,CAACD,UAAS,WAAW;AAC/B,UAAM,QAAQ,CAAC,QAAqC;AAClD,UAAI,IAAI,SAAS,aAAc,CAAAA,SAAQ,MAAM;AAAA,eAEpC,IAAI,SAAS,mBAAmB,IAAI,SAAS,eAAgB,CAAAA,SAAQ,OAAO;AAAA,UAChF,QAAO,GAAG;AAAA,IACjB;AACA,QAAI,KAAK,SAAS,KAAK;AACvB,QAAI,OAAO,MAAM,GAAG,MAAM;AACxB,UAAI,IAAI,SAAS,KAAK;AACtB,MAAAA,SAAQ,IAAI;AAAA,IACd,CAAC;AAAA,EACH,CAAC;AASH,QAAM,YAAY,OAAO,SAAmC;AAC1D,UAAME,QAAO,MAAM,WAAW,QAAQ,MAAM,IAAI;AAChD,QAAIA,UAAS,KAAM,QAAO;AAC1B,QAAI,SAAS,YAAa,QAAO;AACjC,UAAM,IAAI,KAAK,aAAa,OAAO,UAAU,SAAS,EAAE,CAAC,CAAyB;AAClF,eAAW,KAAK,OAAO,UAAU,SAAS,EAAG,GAAE,GAAG,WAAW,CAA8B;AAC3F,UAAM,IAAI,MAAM,WAAW,GAAG,MAAM,KAAK;AACzC,QAAI,MAAM,MAAM;AACd,aAAO,CAAC;AACR,aAAO;AAAA,IACT;AACA,QAAI,MAAM,QAAS,QAAO;AAE1B,UAAM,IAAI,QAAc,CAAC,QAAQ,OAAO,MAAM,MAAM,IAAI,CAAC,CAAC;AAC1D,WAAO;AAAA,EACT;AAEA,MAAI,MAAM,UAAU,IAAI,IAAI,EAAG,QAAO,IAAI;AAE1C,QAAM,UAAU,MAAM,iBAAiB,KAAK,IAAI,IAAI;AACpD,MAAI,SAAS;AACX,QAAI,QAAQ,WAAW,QAAQ,YAAY,WAAW,GAAG;AACvD,YAAMC,OAAM,YAAY,IAAI,IAAI;AAChC,cAAQ;AAAA,QACN,KAAK,kEAA0B,IAAI,IAAI,+BAAW,QAAQ,OAAO,wBAAS,WAAW,CAAC,QAAG,IACvF;AAAA,kHAAgCA,QAAO,oBAAoB,IAAI,OAAO,GAAG;AAAA,MAC7E;AACA,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,YAAQ;AAAA,MACN,GAAG,KAAK,QAAG,CAAC,8GAAmC,KAAK,oBAAoB,IAAI,IAAI,OAAO,CAAC;AAAA,IAC1F;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,QAAM,MAAM,YAAY,IAAI,IAAI;AAChC,QAAM,IAAI;AAAA,IACR,gBAAM,IAAI,IAAI,8CAAW,MAAM,QAAQ,GAAG,MAAM,EAAE,kDACnB,IAAI,IAAI;AAAA,4BACvB,OAAO,uBAAuB,IAAI,IAAI,gBAAgB;AAAA;AAAA,EAExE;AACF;;;AUrTA,OAAOC,WAAU;AACjB,SAAS,aAAa;AAKtB,IAAM,cAAc;AAEpB,SAAS,WAAW,GAAoB;AACtC,SAAO,oBAAoB,KAAK,CAAC;AACnC;AAEA,eAAsB,aACpB,KACA,UACqC;AACrC,QAAM,YAAYC,MAAK,KAAK,IAAI,aAAa,IAAI,UAAU,QAAQ,OAAO,GAAG,EAAE,QAAQ,QAAQ,EAAE,CAAC;AAClG,MAAI,QAA8C;AAClD,MAAI,SAAS;AAEb,QAAM,QAAQ,MAAM;AAClB,YAAQ;AACR,uBAAmB,GAAG,EACnB,KAAK,CAAC,YAAY;AACjB,UAAI,CAAC,OAAQ,UAAS,OAAO;AAAA,IAC/B,CAAC,EACA,MAAM,CAAC,QAAQ;AACd,cAAQ,MAAM,sDAAkC,GAAG;AAAA,IACrD,CAAC;AAAA,EACL;AACA,QAAM,WAAW,MAAM;AACrB,QAAI,OAAQ;AACZ,QAAI,MAAO,cAAa,KAAK;AAC7B,YAAQ,WAAW,OAAO,WAAW;AAAA,EACvC;AAEA,QAAM,UAAU,MAAM,WAAW;AAAA,IAC/B,eAAe;AAAA;AAAA,IACf,SAAS,CAAC,MAAc;AACtB,YAAM,MAAMA,MAAK,SAAS,WAAW,CAAC;AACtC,UAAI,CAAC,IAAK,QAAO;AAEjB,aAAO,IAAI,MAAMA,MAAK,GAAG,EAAE,KAAK,CAAC,QAAQ,QAAQ,mBAAmB,QAAQ,aAAa,QAAQ,cAAc;AAAA,IACjH;AAAA,EACF,CAAC;AACD,UAAQ,GAAG,OAAO,CAAC,MAAM,WAAW,CAAC,KAAK,SAAS,CAAC;AACpD,UAAQ,GAAG,UAAU,CAAC,MAAM,WAAW,CAAC,KAAK,SAAS,CAAC;AACvD,UAAQ,GAAG,UAAU,CAAC,MAAM,WAAW,CAAC,KAAK,SAAS,CAAC;AACvD,UAAQ,GAAG,SAAS,CAAC,QAAQ,QAAQ,MAAM,wCAA8B,GAAG,CAAC;AAG7E,WAAS;AAET,SAAO;AAAA,IACL,MAAM,QAAQ;AACZ,eAAS;AACT,UAAI,OAAO;AACT,qBAAa,KAAK;AAClB,gBAAQ;AAAA,MACV;AACA,YAAM,QAAQ,MAAM;AAAA,IACtB;AAAA,EACF;AACF;;;AhBjEA,QAAQ,gBAAgB;AAWxB,IAAM,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWb,KAAK,EAAE,MAAM,CAAC,QAAiB;AAC7B,UAAQ,MAAM,kBAAkB,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,EAAE;AAClF,UAAQ,KAAK,CAAC;AAChB,CAAC;AAED,eAAe,OAAsB;AACnC,QAAM,EAAE,QAAQ,YAAY,IAAI,UAAU;AAAA,IACxC,MAAM,QAAQ,KAAK,MAAM,CAAC;AAAA,IAC1B,SAAS;AAAA,MACP,MAAM,EAAE,MAAM,SAAS;AAAA,MACvB,QAAQ,EAAE,MAAM,SAAS;AAAA,MACzB,cAAc,EAAE,MAAM,SAAS;AAAA,MAC/B,MAAM,EAAE,MAAM,WAAW,OAAO,IAAI;AAAA,IACtC;AAAA,IACA,kBAAkB;AAAA,EACpB,CAAC;AAED,MAAI,OAAO,MAAM;AACf,YAAQ,IAAI,IAAI;AAChB;AAAA,EACF;AAEA,QAAM,QAA2B,CAAC;AAClC,MAAI,OAAO,SAAS,QAAW;AAC7B,UAAM,OAAO,OAAO,OAAO,IAAI;AAC/B,QAAI,CAAC,OAAO,UAAU,IAAI,EAAG,OAAM,IAAI,MAAM,mCAAe,OAAO,IAAI,EAAE;AACzE,UAAM,OAAO;AAAA,EACf;AACA,MAAI,OAAO,WAAW,OAAW,OAAM,SAAS,OAAO;AACvD,MAAI,OAAO,YAAY,MAAM,OAAW,OAAM,YAAY,OAAO,YAAY;AAE7E,QAAM,MAAM,YAAY,CAAC,KAAK;AAC9B,MAAI,QAAQ,KAAM,QAAO,GAAG,KAAK;AACjC,MAAI,QAAQ,OAAQ,QAAO,QAAQ,QAAQ,IAAI,GAAG,KAAK;AACvD,MAAI,QAAQ,QAAS,QAAO,eAAe,WAAW,QAAQ,IAAI,GAAG,KAAK,CAAC;AAE3E,UAAQ,MAAM,4BAAQ,GAAG;AAAA;AAAA,EAAO,IAAI,EAAE;AACtC,UAAQ,KAAK,CAAC;AAChB;AAEA,eAAe,GAAG,OAAyC;AACzD,QAAM,MAAM,WAAW,QAAQ,IAAI,GAAG,KAAK;AAG3C,QAAM,WAAW,MAAM,QAAQ,wCAAU,MAAM,eAAe,GAAG,CAAC;AAClE,MAAI,aAAa,KAAM,SAAQ,IAAI,GAAG,IAAI,4CAAS,CAAC,CAAC;AACrD,QAAM,UAAU,MAAM;AAAA,IAAQ;AAAA,IAAU,MACtC,aAAa,KAAK,CAAC,YAAY,UAAU,EAAE,MAAM,YAAY,QAAQ,CAAC,CAAC;AAAA,EACzE;AACA,MAAI,QAAS,SAAQ,IAAI,GAAG,IAAI,gBAAM,IAAI,SAAS,yBAAyB,CAAC,CAAC;AAE9E,QAAM,SAAS,MAAM,YAAY,GAAG;AACpC,SAAO,KAAK,OAAO,IAAI;AAEvB,MAAI,UAAU;AACd,QAAM,WAAW,OAAO,QAA+B;AACrD,QAAI,QAAS;AACb,cAAU;AACV,YAAQ,IAAI,IAAI;AAAA,8BAAuB,GAAG,iCAAQ,CAAC;AACnD,QAAI,QAAS,OAAM,MAAM,MAAM,QAAQ,MAAM,CAAC;AAC9C,UAAM,MAAM,MAAM,OAAO,MAAM,CAAC;AAChC,UAAM,MAAM,MAAM,aAAa,CAAC;AAChC,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,UAAQ,GAAG,UAAU,MAAM,KAAK,SAAS,QAAQ,CAAC;AAClD,UAAQ,GAAG,WAAW,MAAM,KAAK,SAAS,SAAS,CAAC;AACtD;AAGA,eAAe,QAAW,OAAe,IAAyC;AAChF,MAAI;AACF,WAAO,MAAM,GAAG;AAAA,EAClB,SAAS,KAAK;AACZ,YAAQ,KAAK,KAAK,GAAG,KAAK,mCAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,EAAE,CAAC;AACvF,WAAO;AAAA,EACT;AACF;AAGA,eAAe,MAAM,IAA2C;AAC9D,MAAI;AACF,UAAM,GAAG;AAAA,EACX,QAAQ;AAAA,EAER;AACF;AAEA,SAAS,OAAO,KAAe,MAAoB;AACjD,UAAQ,IAAI;AAAA,IACV,KAAK,KAAK,QAAG,CAAC,CAAC,IAAI,KAAK,cAAc,CAAC,MAAM,KAAK,oBAAoB,IAAI,OAAO,CAAC;AAAA,IAClF,IAAI,0BAAM,CAAC,UAAU,IAAI,MAAM;AAAA,IAC/B,IAAI,0BAAM,CAAC,UAAU,IAAI,SAAS,KAAK,IAAI,MAAG,CAAC,qBAAW,IAAI,MAAM;AAAA,IACpE,IAAI,qBAAW,CAAC;AAAA,CACnB;AACD;",
4
+ "sourcesContent": ["// contactsheet CLI:\u9ED8\u8BA4 up(\u6CE8\u5165 \u2192 \u76D1\u542C \u2192 \u8D77\u5916\u58F3),\u53E6\u6709 init / clean\n// http-proxy \u5185\u90E8\u7528 util._extend \u4F1A\u89E6\u53D1 DEP0060,\u7528\u6237\u5BF9\u4F9D\u8D56\u7684\u5F03\u7528\u8B66\u544A\u65E0\u80FD\u4E3A\u529B,\u53EA\u4F1A\u5F04\u810F\u8F93\u51FA\nprocess.noDeprecation = true\nimport { parseArgs } from \"node:util\"\nimport { loadConfig } from \"./config.js\"\nimport { ensureInjected, removeInjected } from \"./inject/index.js\"\nimport { runInit } from \"./init/index.js\"\nimport { broadcast, startServer } from \"./server/index.js\"\nimport { closeBrowser } from \"./shot/index.js\"\nimport { startWatcher } from \"./watch/index.js\"\nimport { bold, cyan, dim, link, ok, warn } from \"./term.js\"\nimport type { CsConfig } from \"./types.js\"\n\nconst HELP = `contactsheet \u2014\u2014 \u628A UI \u7684\u5404\u79CD\u72B6\u6001\u644A\u5728\u4E00\u9762\u53EF\u7F29\u653E\u7684\u5899\u4E0A\n\n contactsheet [up] \u9644\u7740\u5230\u5F53\u524D Next.js repo:\u6CE8\u5165\u753B\u677F\u8DEF\u7531 + \u8D77\u5916\u58F3(\u9ED8\u8BA4\u547D\u4EE4)\n contactsheet init \u521D\u59CB\u5316\u914D\u7F6E\u3001.mcp.json\u3001hook,\u5E76\u81EA\u52A8\u94FA\u4E00\u6279\u753B\u677F\n contactsheet clean \u79FB\u9664\u6CE8\u5165\u7684\u6587\u4EF6\n\n --port <n> \u5916\u58F3\u7AEF\u53E3(\u9ED8\u8BA4 5199)\n --target <url> next dev \u5730\u5740(\u9ED8\u8BA4 http://localhost:3000)\n --design-dir <dir> \u753B\u677F\u76EE\u5F55(\u9ED8\u8BA4 design)\n -h, --help \u663E\u793A\u672C\u5E2E\u52A9`\n\nmain().catch((err: unknown) => {\n console.error(`[contactsheet] ${err instanceof Error ? err.message : String(err)}`)\n process.exit(1)\n})\n\nasync function main(): Promise<void> {\n const { values, positionals } = parseArgs({\n args: process.argv.slice(2),\n options: {\n port: { type: \"string\" },\n target: { type: \"string\" },\n \"design-dir\": { type: \"string\" },\n help: { type: \"boolean\", short: \"h\" },\n },\n allowPositionals: true,\n })\n\n if (values.help) {\n console.log(HELP)\n return\n }\n\n const flags: Partial<CsConfig> = {}\n if (values.port !== undefined) {\n const port = Number(values.port)\n if (!Number.isInteger(port)) throw new Error(`--port \u4E0D\u662F\u6574\u6570:${values.port}`)\n flags.port = port\n }\n if (values.target !== undefined) flags.target = values.target\n if (values[\"design-dir\"] !== undefined) flags.designDir = values[\"design-dir\"]\n\n const cmd = positionals[0] ?? \"up\"\n if (cmd === \"up\") return up(flags)\n if (cmd === \"init\") return runInit(process.cwd(), flags)\n if (cmd === \"clean\") return removeInjected(loadConfig(process.cwd(), flags))\n\n console.error(`\u672A\u77E5\u547D\u4EE4:${cmd}\\n\\n${HELP}`)\n process.exit(1)\n}\n\nasync function up(flags: Partial<CsConfig>): Promise<void> {\n const cfg = loadConfig(process.cwd(), flags)\n\n // \u6CE8\u5165\u4E0E\u6587\u4EF6\u76D1\u542C\u5F52 Agent B;\u8FD9\u4E24\u6B65\u5931\u8D25\u53EA\u544A\u8B66,\u5916\u58F3\u7167\u5E38\u8D77(\u753B\u5E03\u672C\u8EAB\u4E0D\u4F9D\u8D56\u5B83\u4EEC)\n const injected = await tryStep(\"\u6CE8\u5165\u753B\u677F\u8DEF\u7531\", () => ensureInjected(cfg))\n if (injected !== null) console.log(ok(dim(\"\u753B\u677F\u8DEF\u7531\u5DF2\u6CE8\u5165\")))\n const watcher = await tryStep(\"\u542F\u52A8\u6587\u4EF6\u76D1\u542C\", () =>\n startWatcher(cfg, (entries) => broadcast({ type: \"registry\", entries }))\n )\n if (watcher) console.log(ok(dim(`\u76D1\u542C ${cfg.designDir}/**/*.artboard.{tsx,ts}`)))\n\n const server = await startServer(cfg)\n banner(cfg, server.port)\n\n let closing = false\n const shutdown = async (sig: string): Promise<void> => {\n if (closing) return\n closing = true\n console.log(dim(`\\n[contactsheet] \u6536\u5230 ${sig},\u6B63\u5728\u9000\u51FA\u2026`))\n // \u6574\u4E2A\u9000\u51FA\u6D41\u7A0B\u7684\u786C\u65F6\u9650:watcher/browser \u7684 close \u4EFB\u4F55\u4E00\u6B65\u6302\u6B7B,\u90FD\u4E0D\u80FD\u628A\u8FDB\u7A0B\u53D8\u6210\n // \"\u6536\u8FC7 TERM \u5374\u8FD8\u5728\u76D1\u542C\"\u7684\u6D3B\u5C38 \u2014\u2014 \u5B9E\u6D4B\u8FD9\u79CD\u6D3B\u5C38\u4F1A\u5E94\u7B54\u540C\u9879\u76EE\u63A2\u6D4B,\u628A\u5347\u7EA7\u91CD\u542F\u529D\u9000\n const deadline = setTimeout(() => process.exit(0), 5000)\n deadline.unref()\n if (watcher) await quiet(() => watcher.close())\n await quiet(() => server.close())\n await quiet(() => closeBrowser())\n process.exit(0)\n }\n process.on(\"SIGINT\", () => void shutdown(\"SIGINT\"))\n process.on(\"SIGTERM\", () => void shutdown(\"SIGTERM\"))\n}\n\n/** \u8DD1\u4E00\u6B65,\u5931\u8D25\u53EA\u544A\u8B66\u4E0D\u4E2D\u65AD(\u5BF9\u9762\u6A21\u5757\u53EF\u80FD\u8FD8\u662F stub) */\nasync function tryStep<T>(label: string, fn: () => Promise<T>): Promise<T | null> {\n try {\n return await fn()\n } catch (err) {\n console.warn(warn(`${label}\u5931\u8D25,\u5DF2\u8DF3\u8FC7:${err instanceof Error ? err.message : String(err)}`))\n return null\n }\n}\n\n/** \u9000\u51FA\u8DEF\u5F84\u4E0A\u7684\u8C03\u7528,\u51FA\u9519\u4E0D\u8FFD\u7A76 */\nasync function quiet(fn: () => Promise<unknown>): Promise<void> {\n try {\n await fn()\n } catch {\n // \u6B63\u5728\u9000\u51FA,\u5FFD\u7565\n }\n}\n\nfunction banner(cfg: CsConfig, port: number): void {\n console.log(`\n ${bold(cyan(\"\u25C6\"))} ${bold(\"contactsheet\")} ${link(`http://localhost:${port}/__cs`)}\n ${dim(\"\u4EE3\u7406\u76EE\u6807\")} ${cfg.target}\n ${dim(\"\u753B\u677F\u76EE\u5F55\")} ${cfg.designDir}/ ${dim(\"\u00B7\")} app \u76EE\u5F55 ${cfg.appDir}/\n ${dim(\"Ctrl-C \u9000\u51FA\")}\n`)\n}\n", "// \u914D\u7F6E\u52A0\u8F7D:<cwd>/contactsheet.config.json + CLI flags \u5408\u5E76,\u7F3A\u7701\u503C\u515C\u5E95\nimport fs from \"node:fs\"\nimport path from \"node:path\"\nimport type { CsConfig } from \"./types.js\"\n\nconst DEFAULT_TARGET = \"http://localhost:3000\"\nconst DEFAULT_PORT = 5199\nconst DEFAULT_DESIGN_DIR = \"design\"\n\nexport function loadConfig(cwd: string, flags: Partial<CsConfig>): CsConfig {\n const projectRoot = path.resolve(cwd)\n const file = path.join(projectRoot, \"contactsheet.config.json\")\n\n // \u914D\u7F6E\u6587\u4EF6\u53EF\u4EE5\u4E0D\u5B58\u5728;\u5B58\u5728\u4F46\u5185\u5BB9\u574F\u4E86\u8981\u663E\u5F0F\u62A5\u9519,\u522B\u9759\u9ED8\u9000\u56DE\u9ED8\u8BA4\u503C\n let fromFile: Partial<CsConfig> = {}\n if (fs.existsSync(file)) {\n try {\n fromFile = JSON.parse(fs.readFileSync(file, \"utf8\")) as Partial<CsConfig>\n } catch (err) {\n throw new Error(`contactsheet.config.json \u89E3\u6790\u5931\u8D25:${(err as Error).message}`)\n }\n }\n\n // \u4F18\u5148\u7EA7:CLI flags > \u914D\u7F6E\u6587\u4EF6 > \u9ED8\u8BA4\u503C\n const pick = <K extends keyof CsConfig>(key: K): CsConfig[K] | undefined => flags[key] ?? fromFile[key]\n\n const port = Number(pick(\"port\") ?? DEFAULT_PORT)\n if (!Number.isInteger(port) || port <= 0 || port > 65535) throw new Error(`\u7AEF\u53E3\u4E0D\u5408\u6CD5:${String(pick(\"port\"))}`)\n\n return {\n projectRoot,\n // \u672B\u5C3E\u659C\u6760\u53BB\u6389,\u540E\u9762\u4E00\u5F8B\u9760 `${target}/xxx` \u62FC\n target: String(pick(\"target\") ?? DEFAULT_TARGET).replace(/\\/+$/, \"\"),\n port,\n appDir: pick(\"appDir\") ?? detectAppDir(projectRoot),\n designDir: pick(\"designDir\") ?? DEFAULT_DESIGN_DIR,\n }\n}\n\n/** app \u76EE\u5F55\u63A2\u6D4B:\u5B58\u5728 src/app \u7528 src/app,\u5426\u5219 app */\nfunction detectAppDir(projectRoot: string): string {\n return fs.existsSync(path.join(projectRoot, \"src\", \"app\")) ? \"src/app\" : \"app\"\n}\n", "// ============================================================\n// [Agent B] \u6CE8\u5165 / \u5378\u8F7D Next \u4FA7\u6587\u4EF6 + \u751F\u6210\u753B\u677F registry\n// \u7B7E\u540D\u51BB\u7ED3,\u89C1 CONTRACTS.md\n// ============================================================\nimport { promises as fs } from \"node:fs\"\nimport path from \"node:path\"\nimport type { CsConfig, RegistryEntry } from \"../types.js\"\nimport {\n boundaryTemplate,\n pageTemplate,\n registryTemplate,\n routeTemplate,\n tokensTemplate,\n type RegistryItem,\n} from \"./templates.js\"\n\n/** \u6CE8\u5165\u8DEF\u7531\u7684\u6587\u4EF6\u5939\u540D:App Router \u91CC\u4E0B\u5212\u7EBF\u5F00\u5934\u662F private folder,\u5FC5\u987B\u5199\u6210 %5F \u8F6C\u4E49,URL \u5373 /__cs/... */\nconst CS_DIR = \"%5F%5Fcs\"\n\nconst GITIGNORE_BEGIN = \"# contactsheet begin\"\nconst GITIGNORE_END = \"# contactsheet end\"\n\n/** \u914D\u7F6E\u91CC\u7684\u76F8\u5BF9\u8DEF\u5F84\u7EDF\u4E00\u6210 posix\u3001\u65E0\u524D\u5BFC \"./\"\u3001\u65E0\u5C3E\u659C\u6760 */\nfunction normRel(p: string): string {\n return p.replace(/\\\\/g, \"/\").replace(/^\\.\\//, \"\").replace(/\\/+$/, \"\")\n}\n\n/** \u6CE8\u5165\u6839\u76EE\u5F55(repo \u76F8\u5BF9,posix) */\nfunction csDirRel(cfg: CsConfig): string {\n return normRel(cfg.appDir) + \"/\" + CS_DIR\n}\n\n/** \u4ECE\u67D0\u4E2A\u6CE8\u5165\u6587\u4EF6\u6240\u5728\u76EE\u5F55 import \u5230 <designDir>/__generated__/registry \u7684\u76F8\u5BF9\u8BF4\u660E\u7B26 */\nfunction registryImportFrom(fromDirRel: string, cfg: CsConfig): string {\n const target = normRel(cfg.designDir) + \"/__generated__/registry\"\n const rel = path.posix.relative(fromDirRel, target)\n return rel.startsWith(\".\") ? rel : \"./\" + rel\n}\n\nasync function readOr(file: string, fallback: string | null): Promise<string | null> {\n try {\n return await fs.readFile(file, \"utf8\")\n } catch {\n return fallback\n }\n}\n\n/** \u5185\u5BB9\u76F8\u540C\u5C31\u4E0D\u5199:\u907F\u514D\u52A8 mtime \u89E6\u53D1 Next \u65E0\u8C13\u91CD\u7F16\u8BD1 */\nasync function writeIfChanged(file: string, content: string): Promise<boolean> {\n if ((await readOr(file, null)) === content) return false\n await fs.mkdir(path.dirname(file), { recursive: true })\n await fs.writeFile(file, content, \"utf8\")\n return true\n}\n\n/** \u5B9A\u4F4D .gitignore \u91CC\u7684 contactsheet \u5757(\u542B\u9996\u5C3E\u6807\u8BB0) */\nfunction findBlock(text: string): { start: number; end: number } | null {\n const start = text.indexOf(GITIGNORE_BEGIN)\n if (start < 0) return null\n const at = text.indexOf(GITIGNORE_END, start)\n if (at < 0) return null\n return { start, end: at + GITIGNORE_END.length }\n}\n\nfunction gitignoreBlock(cfg: CsConfig): string {\n const design = normRel(cfg.designDir)\n return [GITIGNORE_BEGIN, csDirRel(cfg) + \"/\", design + \"/__generated__/\", design + \"/.canvas/\", GITIGNORE_END].join(\n \"\\n\"\n )\n}\n\n/** \u5E42\u7B49\u5199 .gitignore:\u6709\u65E7\u5757\u6574\u5757\u66FF\u6362(\u6A21\u677F\u5347\u7EA7),\u6CA1\u6709\u5C31\u8FFD\u52A0 */\nasync function updateGitignore(cfg: CsConfig): Promise<void> {\n const file = path.join(cfg.projectRoot, \".gitignore\")\n const old = (await readOr(file, \"\")) as string\n const block = gitignoreBlock(cfg)\n const found = findBlock(old)\n const next = found\n ? old.slice(0, found.start) + block + old.slice(found.end)\n : (old.trimEnd() ? old.trimEnd() + \"\\n\\n\" : \"\") + block + \"\\n\"\n await writeIfChanged(file, next)\n}\n\nasync function removeGitignoreBlock(cfg: CsConfig): Promise<void> {\n const file = path.join(cfg.projectRoot, \".gitignore\")\n const old = await readOr(file, null)\n if (old === null) return\n const found = findBlock(old)\n if (!found) return\n const left = (old.slice(0, found.start) + old.slice(found.end)).replace(/\\n{3,}/g, \"\\n\\n\").trimEnd()\n await writeIfChanged(file, left ? left + \"\\n\" : \"\")\n}\n\n/** \u5199/\u66F4\u65B0\u5168\u90E8\u6CE8\u5165\u6587\u4EF6 + gitignore */\nexport async function ensureInjected(cfg: CsConfig): Promise<void> {\n const root = cfg.projectRoot\n const designAbs = path.join(root, normRel(cfg.designDir))\n await fs.mkdir(designAbs, { recursive: true })\n await fs.mkdir(path.join(designAbs, \".canvas\"), { recursive: true })\n\n const abDirRel = csDirRel(cfg) + \"/ab/[id]\"\n await writeIfChanged(path.join(root, abDirRel, \"page.tsx\"), pageTemplate(registryImportFrom(abDirRel, cfg)))\n await writeIfChanged(path.join(root, abDirRel, \"boundary.tsx\"), boundaryTemplate())\n\n const routeDirRel = csDirRel(cfg) + \"/registry\"\n await writeIfChanged(path.join(root, routeDirRel, \"route.ts\"), routeTemplate(registryImportFrom(routeDirRel, cfg)))\n\n await writeIfChanged(path.join(root, csDirRel(cfg), \"tokens\", \"page.tsx\"), tokensTemplate())\n\n await updateGitignore(cfg)\n // \u5148\u4FDD\u8BC1 page/route \u7684 import \u76EE\u6807\u5B58\u5728,\u514D\u5F97 watcher \u9996\u6B21\u5237\u65B0\u524D\u6253\u5F00\u753B\u677F\u62A5\u89E3\u6790\u5931\u8D25\n await regenerateRegistry(cfg)\n}\n\n/** clean \u547D\u4EE4:\u5220\u6CE8\u5165\u76EE\u5F55\u4E0E\u751F\u6210\u7269,design \u4E0B\u7684\u7528\u6237\u753B\u677F\u4E0D\u52A8 */\nexport async function removeInjected(cfg: CsConfig): Promise<void> {\n await fs.rm(path.join(cfg.projectRoot, csDirRel(cfg)), { recursive: true, force: true })\n await fs.rm(path.join(cfg.projectRoot, normRel(cfg.designDir), \"__generated__\"), { recursive: true, force: true })\n await removeGitignoreBlock(cfg)\n}\n\n/** \u9012\u5F52\u626B designDir,\u8FD4\u56DE *.artboard.{tsx,ts} \u7684 posix \u76F8\u5BF9\u8DEF\u5F84 */\nasync function scanArtboards(designAbs: string, sub = \"\"): Promise<string[]> {\n let dirents\n try {\n dirents = await fs.readdir(path.join(designAbs, sub), { withFileTypes: true })\n } catch {\n return [] // design \u76EE\u5F55\u4E0D\u5B58\u5728\n }\n const out: string[] = []\n for (const d of dirents) {\n const rel = sub ? sub + \"/\" + d.name : d.name\n if (d.isDirectory()) {\n // \u5FFD\u7565\u751F\u6210\u7269\u3001\u753B\u5E03\u6570\u636E(.canvas)\u4E0E\u4EFB\u4F55\u9690\u85CF\u76EE\u5F55\n if (d.name === \"__generated__\" || d.name === \"node_modules\" || d.name.startsWith(\".\")) continue\n out.push(...(await scanArtboards(designAbs, rel)))\n } else if (/\\.artboard\\.tsx?$/.test(d.name)) {\n out.push(rel)\n }\n }\n return out\n}\n\n/** \u6B63\u5219\u63D0\u53D6 export const \u540D(v1 \u63A5\u53D7\u5176\u5C40\u9650,\u89C1 CONTRACTS) */\nfunction extractExports(source: string): string[] {\n const re = /^export\\s+const\\s+([\\p{L}\\w$]+)/gmu\n const names: string[] = []\n let m: RegExpExecArray | null\n while ((m = re.exec(source)) !== null) {\n if (!names.includes(m[1])) names.push(m[1])\n }\n return names\n}\n\n/** fileSlug:designDir \u4E0B\u76F8\u5BF9\u8DEF\u5F84\u53BB\u6389 .artboard.tsx?,\"/\" \u2192 \"__\" */\nfunction slugOf(rel: string): string {\n return rel.replace(/\\.artboard\\.tsx?$/, \"\").replace(/\\//g, \"__\")\n}\n\n/** \u626B\u63CF + \u91CD\u5199 <designDir>/__generated__/registry.tsx,\u8FD4\u56DE\u6761\u76EE(args/env \u7559 undefined,\u771F\u503C\u7531 Next \u4FA7 route \u7ED9) */\nexport async function regenerateRegistry(cfg: CsConfig): Promise<RegistryEntry[]> {\n const designRel = normRel(cfg.designDir)\n const designAbs = path.join(cfg.projectRoot, designRel)\n const rels = (await scanArtboards(designAbs)).sort()\n\n const items: RegistryItem[] = []\n const entries: RegistryEntry[] = []\n for (const rel of rels) {\n const source = await readOr(path.join(designAbs, rel), null)\n if (source === null) continue // \u626B\u63CF\u540E\u88AB\u5220,\u8DF3\u8FC7\n const names = extractExports(source)\n if (names.length === 0) continue // \u6CA1\u6709 export const \u7684\u6587\u4EF6\u4E0D\u8FDB registry\n const slug = slugOf(rel)\n const file = designRel + \"/\" + rel\n items.push({\n varName: \"m\" + items.length,\n // registry.tsx \u5728 <designDir>/__generated__/ \u4E0B,\u4E0A\u4E00\u7EA7\u5C31\u662F designDir\n importPath: \"../\" + rel.replace(/\\.tsx?$/, \"\"),\n slug,\n file,\n })\n for (const exportName of names) {\n // kind \u8FD9\u91CC\u4E00\u5F8B component,screen \u7531 Next \u4FA7 registry route \u6309\u6709\u6CA1\u6709 url \u5224\u771F\u503C\n entries.push({ id: slug + \"--\" + exportName, file, exportName, kind: \"component\" })\n }\n }\n\n await writeIfChanged(path.join(designAbs, \"__generated__\", \"registry.tsx\"), registryTemplate(items))\n return entries\n}\n", "// ============================================================\n// [Agent B] \u6CE8\u5165\u5230\u7528\u6237 Next \u9879\u76EE\u7684\u6587\u4EF6\u6A21\u677F\n// \u672C\u4ED3\u5E93 tsconfig \u4E0D\u7F16\u8BD1 JSX,\u6240\u4EE5\u5168\u90E8\u4EE5\u6A21\u677F\u5B57\u7B26\u4E32\u5F62\u5F0F\u5B58\u653E\u3002\n// \u4E00\u5F8B\u7528 String.raw:\u6A21\u677F\u91CC\u51FA\u73B0\u7684\u53CD\u659C\u6760(\u5982 \"\\\\u003c\")\u539F\u6837\u843D\u5230\u751F\u6210\u6587\u4EF6,\n// \u53EA\u6709 ${...} \u4F1A\u88AB\u66FF\u6362 \u2014\u2014 \u751F\u6210\u7684\u4EE3\u7801\u91CC\u4E0D\u8981\u51FA\u73B0\u53CD\u5F15\u53F7\u548C\u5176\u5B83 ${\u3002\n// ============================================================\n\n/** design/__generated__/registry \u91CC\u7684\u4E00\u6761 import \u63CF\u8FF0 */\nexport interface RegistryItem {\n /** \u6A21\u5757\u53D8\u91CF\u540D m0 / m1 \u2026 */\n varName: string\n /** \u76F8\u5BF9 __generated__ \u76EE\u5F55\u7684 import \u8BF4\u660E\u7B26,\u5982 \"../Button.artboard\" */\n importPath: string\n /** modules / files \u7684 key,\u5373 fileSlug */\n slug: string\n /** repo \u76F8\u5BF9\u8DEF\u5F84,\u5982 \"design/Button.artboard.tsx\" */\n file: string\n}\n\nconst HEADER = \"// \u7531 contactsheet \u81EA\u52A8\u751F\u6210 \u2014\u2014 \u8BF7\u52FF\u7F16\u8F91,\u4E0B\u6B21\u542F\u52A8\u4F1A\u88AB\u8986\u76D6\\n\"\n\n/** <appDir>/%5F%5Fcs/ab/[id]/page.tsx \u2014\u2014 \u753B\u677F\u8DEF\u7531(server component) */\nexport function pageTemplate(registryImport: string): string {\n return (\n HEADER +\n String.raw`import { Suspense } from \"react\"\nimport { notFound } from \"next/navigation\"\nimport { modules } from \"${registryImport}\"\nimport { CsErrorBoundary, CsErrorCard } from \"./boundary\"\n\n// \u7C7B\u578B\u4E00\u5F8B\u7528 any:\u4E0D\u4F9D\u8D56\u7528\u6237\u9879\u76EE\u7684 Next typegen(PageProps<\"...\"> \u8981\u6C42 .next/types \u5DF2\u751F\u6210)\n\n// Next 16 \u7684 params \u4E0D\u89E3\u7801\u767E\u5206\u53F7\u8F6C\u4E49(\u5B9E\u6D4B params.id = \"Button--%E9%BB%98%E8%AE%A4\"),\u8FD9\u91CC\u81EA\u5DF1\u89E3\nfunction decodeId(raw: string): string {\n try {\n return decodeURIComponent(raw)\n } catch {\n return raw // \u6587\u4EF6\u540D\u91CC\u771F\u5E26 % \u65F6 decode \u4F1A\u629B,\u9000\u56DE\u539F\u4E32\n }\n}\n\n// id = fileSlug + \"--\" + exportName;exportName \u4E0D\u542B \"-\",\u6240\u4EE5\u6309\u6700\u540E\u4E00\u4E2A \"--\" \u5207\nfunction lookupEntry(id: string): any {\n const i = id.lastIndexOf(\"--\")\n if (i <= 0) return null\n const mod: any = (modules as any)[id.slice(0, i)]\n if (!mod) return null\n return mod[id.slice(i + 2)] ?? null\n}\n\n// ?args= \u662F encodeURIComponent(JSON.stringify(args)),Next \u5DF2\u89E3\u7801\u4E00\u5C42,\u8FD9\u91CC\u53EA\u9700 JSON.parse\nfunction parseArgs(raw: any): any {\n if (typeof raw !== \"string\" || raw.length === 0) return {}\n try {\n const v = JSON.parse(raw)\n return v && typeof v === \"object\" ? v : {}\n } catch {\n return {}\n }\n}\n\n// \u9ED8\u8BA4\u65E0\u5E95\u8272(\u88F8\u653E\u753B\u5E03);\u5E95\u8272\u7531\u5916\u58F3\u6309\u6BCF\u677F\u5F00\u5173\u6CE8\u5165(\u5927\u90E8\u5206\u7EC4\u4EF6\u81EA\u5E26 surface,\u65E0\u5E95\u8272\u7684\u4E00\u952E\u5207\u6362)\n// \u4E0D\u7559\u5185\u8FB9\u8DDD:wrapper \u4E00\u65E6\u6709 padding,\u7EC4\u4EF6\u7684\u9AD8\u4EAE\u6846\u5C31\u6C38\u8FDC\u6BD4\u53EF\u89C1\u7684\u767D\u5E95\u5C0F\u4E00\u5708(\u5B9E\u6D4B 390 \u5BBD\u7684\u677F\n// \u56DB\u5468\u5404\u5DEE 16px),\u4E24\u8005\u5BF9\u4E0D\u9F50\u3002\u7559\u767D\u4EA4\u7ED9\u7EC4\u4EF6\u81EA\u5DF1,\u753B\u677F\u7684\u5E95\u5C31\u7B49\u4E8E\u7EC4\u4EF6\u7684\u76D2\u5B50\u3002\nconst wrap: any = {}\n// \u63D0\u793A\u4E0E\u9519\u8BEF\u5361\u4E0D\u662F\u88AB\u5BA1\u89C6\u7684\u7EC4\u4EF6,\u8D34\u8FB9\u53CD\u800C\u6324,\u5355\u72EC\u7559\u5185\u8FB9\u8DDD\nconst padded: any = { padding: 16 }\nconst hint: any = { font: \"13px/1.6 ui-monospace, SFMono-Regular, Menlo, monospace\", color: \"#666\" }\nconst loading: any = { font: \"12px/1.5 ui-monospace, SFMono-Regular, Menlo, monospace\", opacity: 0.5 }\n\nexport default async function Page(props: any) {\n if (process.env.NODE_ENV === \"production\") notFound() // \u751F\u4EA7\u6784\u5EFA\u91CC\u8FD9\u6761\u8DEF\u4E0D\u5B58\u5728\n const params: any = await props.params\n const searchParams: any = await props.searchParams\n const id: string = decodeId(String(params?.id ?? \"\"))\n const entry: any = lookupEntry(id)\n if (!entry) notFound()\n\n const kind: string = typeof entry.url === \"string\" ? \"screen\" : \"component\"\n const args: any = { ...(entry.args ?? {}), ...parseArgs(searchParams?.args) }\n // \u8F6C\u4E49 \"<\" \u9632\u6B62 args \u91CC\u7684\u5B57\u7B26\u4E32\u63D0\u524D\u95ED\u5408 script \u6807\u7B7E(JSON \u91CC < \u89E3\u6790\u56DE \"<\")\n const meta: string = JSON.stringify({ id, args, env: entry.env, kind }).replace(/</g, \"\\\\u003c\")\n const metaTag = <script type=\"application/json\" id=\"__cs_meta\" dangerouslySetInnerHTML={{ __html: meta }} />\n\n // \u9875\u9762\u753B\u677F\u7531\u5916\u58F3\u76F4\u63A5 iframe \u76EE\u6807 url,\u4E0D\u5728\u8FD9\u6761\u8DEF\u7531\u6E32\u67D3\n if (kind === \"screen\") {\n return (\n <div data-cs-artboard={id} style={padded}>\n {metaTag}\n <p style={hint}>\u9875\u9762\u753B\u677F:\u8BF7\u76F4\u63A5\u6253\u5F00 {entry.url}</p>\n </div>\n )\n }\n\n if (typeof entry.render !== \"function\") {\n return (\n <div data-cs-artboard={id} style={padded}>\n {metaTag}\n <CsErrorCard name={id} error=\"\u753B\u677F\u65E2\u6CA1\u6709 render(args) \u4E5F\u6CA1\u6709 url\" />\n </div>\n )\n }\n\n // render \u81EA\u5DF1\u540C\u6B65\u629B\u9519\u65F6 ErrorBoundary \u591F\u4E0D\u7740,\u8FD9\u91CC\u515C\u4E00\u5C42\n let node: any = null\n try {\n node = entry.render(args)\n } catch (err: any) {\n return (\n <div data-cs-artboard={id} style={padded}>\n {metaTag}\n <CsErrorCard name={id} error={String(err?.message ?? err)} />\n </div>\n )\n }\n\n // \u6CA1\u58F0\u660E env.width \u7684\u7EC4\u4EF6\u753B\u677F\u6536\u7F29\u5230\u5185\u5BB9\u5BBD(shrink-wrap),\u5916\u58F3\u6309\u5B83\u5B9A iframe \u5BBD \u2014\u2014 \"\u88F8\u653E\u5728\u753B\u5E03\u4E0A\"\n const wrapStyle: any = entry.env && entry.env.width ? wrap : { ...wrap, width: \"fit-content\" }\n\n return (\n <div data-cs-artboard={id} style={wrapStyle}>\n {metaTag}\n <CsErrorBoundary name={id}>\n <Suspense fallback={<div style={loading}>loading\u2026</div>}>{node}</Suspense>\n </CsErrorBoundary>\n </div>\n )\n}\n`\n )\n}\n\n/** <appDir>/%5F%5Fcs/ab/[id]/boundary.tsx \u2014\u2014 \u753B\u677F\u5D29\u6E83\u65F6\u663E\u793A\u7EA2\u8272\u865A\u7EBF\u9519\u8BEF\u5361 */\nexport function boundaryTemplate(): string {\n return (\n HEADER +\n String.raw`\"use client\"\nimport React from \"react\"\n\nconst cardStyle: any = {\n border: \"1px dashed #e5484d\",\n borderRadius: 6,\n background: \"#fff5f5\",\n color: \"#c62a2f\",\n padding: \"10px 12px\",\n font: \"12px/1.5 ui-monospace, SFMono-Regular, Menlo, monospace\",\n whiteSpace: \"pre-wrap\",\n wordBreak: \"break-word\",\n}\n\nexport function CsErrorCard(props: any) {\n return (\n <div style={cardStyle} data-cs-error=\"1\">\n <div style={{ fontWeight: 700, marginBottom: 4 }}>{props.name}</div>\n <div>{props.error}</div>\n </div>\n )\n}\n\nexport class CsErrorBoundary extends React.Component<any, any> {\n constructor(props: any) {\n super(props)\n this.state = { error: null }\n }\n static getDerivedStateFromError(error: any) {\n return { error: String(error?.message ?? error) }\n }\n render() {\n if (this.state.error) return <CsErrorCard name={this.props.name} error={this.state.error} />\n return this.props.children\n }\n}\n`\n )\n}\n\n/** <appDir>/%5F%5Fcs/registry/route.ts \u2014\u2014 GET \u8FD4\u56DE RegistryEntry[] */\nexport function routeTemplate(registryImport: string): string {\n return (\n HEADER +\n String.raw`import { modules, files } from \"${registryImport}\"\n\n// \u4E0D\u8981\u52A0 export const dynamic = \"force-dynamic\":\u5B83\u4E0E Next 16 \u7684 cacheComponents \u4E92\u65A5,\n// \u7528\u6237\u5F00\u4E86\u90A3\u4E2A\u914D\u7F6E\u4F1A\u8BA9 registry/ab/tokens \u4E09\u6761\u8DEF\u7531\u540C\u65F6 500,\u4E14\u62A5\u9519\u6307\u5411\u7528\u6237\u81EA\u5DF1\u7684 next.config\u3002\n// dev \u4E0B route handler \u672C\u6765\u5C31\u4E0D\u7F13\u5B58,production \u4E0B\u8FD9\u6761\u8DEF\u7531\u76F4\u63A5 404,\u52A0\u5B83\u6CA1\u6709\u6536\u76CA\u3002\n\n// GET /__cs/registry \u2192 RegistryEntry[];kind \u5728\u8FD9\u91CC\u5224\u771F\u503C:\u6709 url \u662F screen,\u6709 render \u662F component\nexport async function GET() {\n if (process.env.NODE_ENV === \"production\") return new Response(\"Not Found\", { status: 404 })\n\n const entries: any[] = []\n for (const slug of Object.keys(modules as any)) {\n const mod: any = (modules as any)[slug]\n if (!mod) continue\n for (const exportName of Object.keys(mod)) {\n const v: any = mod[exportName]\n if (!v || typeof v !== \"object\") continue\n // \u6CA1\u6709 render \u4E5F\u6CA1\u6709 url \u7684\u5BF9\u8C61\u7167\u6837\u8FDB\u6CE8\u518C\u8868(\u6309 component):\u5899\u4E0A\u51FA\u9519\u8BEF\u5361,\n // \u800C\u4E0D\u662F\u9759\u9ED8\u6D88\u5931 \u2014\u2014 \u7528\u6237\u628A render \u6572\u9519\u65F6\u5FC5\u987B\u6709\u53CD\u9988\n const kind = typeof v.url === \"string\" ? \"screen\" : \"component\"\n entries.push({\n id: slug + \"--\" + exportName,\n file: (files as any)[slug] ?? \"\",\n exportName,\n kind,\n args: v.args,\n env: v.env,\n url: v.url,\n })\n }\n }\n return Response.json(entries)\n}\n`\n )\n}\n\n/** <appDir>/%5F%5Fcs/tokens/page.tsx \u2014\u2014 \u8BBE\u8BA1\u53D8\u91CF\u603B\u89C8(client) */\nexport function tokensTemplate(): string {\n return (\n HEADER +\n String.raw`\"use client\"\nimport { useEffect, useState } from \"react\"\n\ntype Token = { name: string; value: string }\n\n// \u679A\u4E3E\u540C\u6E90\u6837\u5F0F\u8868\u91CC :root / :host / html \u4E0B\u7684\u81EA\u5B9A\u4E49\u5C5E\u6027\n// (Tailwind v4 \u7684 @theme \u7F16\u8BD1\u540E\u5C31\u662F @layer theme \u91CC\u7684 \":root, :host\",\u9760\u9012\u5F52 cssRules \u62FF\u5230)\nfunction collectTokens(): Token[] {\n const found = new Map<string, string>()\n const visit = (rules: any) => {\n if (!rules) return\n for (let i = 0; i < rules.length; i++) {\n const rule: any = rules[i]\n if (rule.cssRules) visit(rule.cssRules)\n const style: any = rule.style\n if (!style) continue\n const sel: string = typeof rule.selectorText === \"string\" ? rule.selectorText : \"\"\n if (sel && !/:root|:host|(^|,)\\s*html\\b/.test(sel)) continue\n for (let k = 0; k < style.length; k++) {\n const prop: string = style[k]\n if (prop && prop.slice(0, 2) === \"--\") found.set(prop, String(style.getPropertyValue(prop)).trim())\n }\n }\n }\n for (let i = 0; i < document.styleSheets.length; i++) {\n try {\n visit((document.styleSheets[i] as any).cssRules)\n } catch {\n // \u8DE8\u57DF\u6837\u5F0F\u8868\u8BFB\u4E0D\u5230 cssRules,\u8DF3\u8FC7\n }\n }\n return Array.from(found, ([name, value]) => ({ name, value })).sort((a, b) => a.name.localeCompare(b.name))\n}\n\n// \u503C\u672C\u8EAB\u5C31\u662F\u989C\u8272\u7684(shadcn \u7684 --primary / --background \u8FD9\u4E9B\u6CA1\u6709 --color- \u524D\u7F00)\u4E5F\u7ED9\u65B9\u5757\nfunction isColorValue(v: string): boolean {\n return /^(#|rgba?\\(|hsla?\\(|hwb\\(|lab\\(|lch\\(|oklab\\(|oklch\\(|color\\()/i.test(v)\n}\n\nconst mono = \"12px/1.5 ui-monospace, SFMono-Regular, Menlo, monospace\"\nconst page: any = { padding: 24, font: mono, color: \"#111\", background: \"#fff\", minHeight: \"100vh\" }\nconst h2: any = { font: \"600 13px/1.5 ui-monospace, SFMono-Regular, Menlo, monospace\", margin: \"24px 0 10px\", color: \"#555\" }\nconst grid: any = { display: \"grid\", gridTemplateColumns: \"repeat(auto-fill, minmax(190px, 1fr))\", gap: 12 }\nconst cell: any = { border: \"1px solid #eee\", borderRadius: 6, padding: 10, overflow: \"hidden\" }\nconst nameStyle: any = { fontWeight: 600, wordBreak: \"break-all\" }\nconst valueStyle: any = { color: \"#888\", wordBreak: \"break-all\" }\n\nfunction Cell(props: any) {\n return (\n <div style={cell}>\n {props.children}\n <div style={nameStyle}>{props.token.name}</div>\n <div style={valueStyle}>{props.token.value}</div>\n </div>\n )\n}\n\nfunction Group(props: any) {\n if (props.tokens.length === 0) return null\n return (\n <section>\n <h2 style={h2}>\n {props.title} \u00B7 {props.tokens.length}\n </h2>\n <div style={grid}>\n {props.tokens.map((t: Token) => (\n <Cell key={t.name} token={t}>\n {props.kind === \"color\" || isColorValue(t.value) ? (\n <div\n style={{\n height: 44,\n marginBottom: 8,\n borderRadius: 4,\n border: \"1px solid rgba(0,0,0,.1)\",\n background: \"var(\" + t.name + \")\",\n }}\n />\n ) : null}\n {props.kind === \"radius\" ? (\n <div\n style={{\n height: 44,\n marginBottom: 8,\n border: \"1px solid #ddd\",\n background: \"#f6f6f6\",\n borderRadius: \"var(\" + t.name + \")\",\n }}\n />\n ) : null}\n </Cell>\n ))}\n </div>\n </section>\n )\n}\n\nexport default function TokensPage() {\n const [tokens, setTokens] = useState<Token[]>([])\n useEffect(() => {\n setTokens(collectTokens())\n }, [])\n\n if (process.env.NODE_ENV === \"production\") return null // \u751F\u4EA7\u91CC\u8FD9\u9875\u4E0D\u51FA\u73B0\n\n const pick = (p: string) => tokens.filter((t) => t.name.indexOf(p) === 0)\n const known = [\"--color-\", \"--radius-\", \"--font-\", \"--spacing-\"]\n const rest = tokens.filter((t) => !known.some((p) => t.name.indexOf(p) === 0))\n\n return (\n <main style={page}>\n <div style={{ font: mono, color: \"#888\" }}>contactsheet \u00B7 design tokens \u00B7 \u5171 {tokens.length} \u4E2A\u81EA\u5B9A\u4E49\u5C5E\u6027</div>\n {tokens.length === 0 ? (\n <p style={{ color: \"#888\", marginTop: 16 }}>\u6CA1\u8BFB\u5230\u81EA\u5B9A\u4E49\u5C5E\u6027(\u6837\u5F0F\u8868\u53EF\u80FD\u8FD8\u6CA1\u52A0\u8F7D\u5B8C,\u6216\u90FD\u662F\u8DE8\u57DF\u7684)\u3002</p>\n ) : null}\n <Group title=\"\u989C\u8272 --color-*\" kind=\"color\" tokens={pick(\"--color-\")} />\n <Group title=\"\u5706\u89D2 --radius-*\" kind=\"radius\" tokens={pick(\"--radius-\")} />\n <Group title=\"\u5B57\u4F53 --font-*\" kind=\"text\" tokens={pick(\"--font-\")} />\n <Group title=\"\u95F4\u8DDD --spacing-*\" kind=\"text\" tokens={pick(\"--spacing-\")} />\n <Group title=\"\u5176\u5B83\" kind=\"text\" tokens={rest} />\n </main>\n )\n}\n`\n )\n}\n\n/** <designDir>/__generated__/registry.tsx \u2014\u2014 watcher \u751F\u6210\u7684\u753B\u677F\u7D22\u5F15 */\nexport function registryTemplate(items: RegistryItem[]): string {\n const imports = items.map((it) => 'import * as ' + it.varName + ' from \"' + it.importPath + '\"').join(\"\\n\")\n const mods = items.map((it) => ' \"' + it.slug + '\": ' + it.varName + \",\").join(\"\\n\")\n const fileMap = items.map((it) => ' \"' + it.slug + '\": \"' + it.file + '\",').join(\"\\n\")\n return (\n \"// \u7531 contactsheet \u81EA\u52A8\u751F\u6210 \u2014\u2014 \u8BF7\u52FF\u7F16\u8F91,\u753B\u677F\u6587\u4EF6\u589E\u5220\u6539\u540E\u4F1A\u88AB\u91CD\u5199\\n\" +\n (imports ? imports + \"\\n\\n\" : \"\") +\n \"export const modules: Record<string, Record<string, unknown>> = \" +\n (items.length ? \"{\\n\" + mods + \"\\n}\\n\" : \"{}\\n\") +\n \"\\n// fileSlug \u2192 repo \u76F8\u5BF9\u8DEF\u5F84,\u7ED9 /__cs/registry \u586B RegistryEntry.file\\n\" +\n \"export const files: Record<string, string> = \" +\n (items.length ? \"{\\n\" + fileMap + \"\\n}\\n\" : \"{}\\n\")\n )\n}\n", "// [Agent E] contactsheet init \u2014\u2014 \u628A contactsheet \u63A5\u5230\u4E00\u4E2A\u5DF2\u6709\u7684 Next.js \u9879\u76EE\u4E0A\n// \u94C1\u5F8B:\u6240\u6709 JSON \u90FD\u662F\u5408\u5E76\u5199\u5165,\u7528\u6237\u5DF2\u6709\u7684\u5185\u5BB9\u4E00\u4E2A\u5B57\u90FD\u4E0D\u80FD\u4E22;\u770B\u4E0D\u61C2\u7684\u6587\u4EF6\u5B81\u53EF\u4E2D\u6B62\u4E5F\u4E0D\u8986\u76D6\u3002\n// \u53EA\u7528 node \u5185\u5EFA\u3002\n\nimport { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from \"node:fs\"\nimport { dirname, join, relative, resolve } from \"node:path\"\nimport type { CsConfig } from \"../types.js\"\nimport { bold, cyan, dim, green, link, ok } from \"../term.js\"\n\nconst DEFAULT_TARGET = \"http://localhost:3000\"\nconst DEFAULT_PORT = 5199\nconst DEFAULT_DESIGN_DIR = \"design\"\n\n/** \u7528\u6237\u9879\u76EE\u91CC shadcn \u7EC4\u4EF6\u7684\u5E38\u89C1\u843D\u70B9,\u6309\u987A\u5E8F\u63A2\u6D4B */\nconst UI_DIR_CANDIDATES = [\"components/ui\", \"src/components/ui\"]\n\n// ============================================================\n// \u5165\u53E3\n// ============================================================\n\nexport async function runInit(cwd: string, flags: Partial<CsConfig>): Promise<void> {\n const root = resolve(cwd)\n\n // a. \u5FC5\u987B\u662F\u4E2A Next.js \u9879\u76EE\n assertNextProject(root)\n\n // b. \u63A2\u6D4B appDir + \u5199\u914D\u7F6E\n const appDir = detectAppDir(root)\n const cfg = writeConfigFile(root, appDir, flags)\n console.log(`${bold(cyan(\"\u25C6\"))} ${bold(\"contactsheet init\")} ${dim(\"\u2014\u2014\")} ${root}`)\n console.log(ok(`app \u76EE\u5F55:${cfg.appDir}`))\n console.log(ok(`\u914D\u7F6E:contactsheet.config.json(target ${cfg.target},port ${cfg.port},\u753B\u677F\u76EE\u5F55 ${cfg.designDir})`))\n\n // c. .gitignore \u7531\u6CE8\u5165\u5668(contactsheet \u8FD0\u884C\u65F6)\u8D1F\u8D23,init \u4E0D\u78B0\n\n // d. \u81EA\u52A8\u94FA\u753B\u677F\n seedArtboards(root, cfg.designDir)\n\n // e. .mcp.json\n writeMcpJson(root, cfg.port)\n\n // f. .claude/settings.json \u7684 UserPromptSubmit hook\n writeClaudeHook(root, cfg.port)\n\n // g. \u4E0B\u4E00\u6B65\n console.log(\"\")\n console.log(bold(\"\u4E0B\u4E00\u6B65:\"))\n console.log(` 1. \u7167\u5E38\u8D77\u4F60\u81EA\u5DF1\u7684 dev server(next dev),\u786E\u8BA4\u5B83\u5728 ${cyan(cfg.target)}`)\n console.log(` 2. \u53E6\u5F00\u4E00\u4E2A\u7EC8\u7AEF:${cyan(\"npx contactsheet\")}`)\n console.log(` 3. \u6253\u5F00 ${link(`http://localhost:${cfg.port}/__cs`)}`)\n console.log(\"\")\n console.log(dim(\"\u7AEF\u53E3\u90FD\u53EF\u4EE5\u6362:dev server \u4E0D\u5728 \") + cfg.target + dim(\" \u5C31 --target <url>,\"))\n console.log(dim(` ${cfg.port} \u88AB\u5360\u5C31 --port <n>(\u6216\u6539 contactsheet.config.json \u540E\u91CD\u8DD1 init,MCP/hook \u4F1A\u8DDF\u7740\u6362)\u3002`))\n console.log(dim(` ${cfg.port} \u88AB\u522B\u7684\u8FDB\u7A0B\u5360\u7740\u65F6,contactsheet \u4F1A\u81EA\u52A8\u987A\u5EF6\u5230\u4E0B\u4E00\u4E2A\u7A7A\u95F2\u7AEF\u53E3\u5E76\u63D0\u793A\u3002`))\n}\n\n// ============================================================\n// a. Next \u9879\u76EE\u6821\u9A8C\n// ============================================================\n\nfunction assertNextProject(root: string): void {\n const pkgPath = join(root, \"package.json\")\n if (!existsSync(pkgPath)) {\n throw new Error(\n `contactsheet init \u4E2D\u6B62:${root} \u4E0B\u6CA1\u6709 package.json\u3002\\n` +\n `contactsheet \u662F\u9644\u7740\u5728\u4F60\u81EA\u5DF1\u7684 Next.js \u9879\u76EE\u4E0A\u8DD1\u7684,\u8BF7\u5230\u9879\u76EE\u6839\u76EE\u5F55\u518D\u6267\u884C\u4E00\u6B21\u3002`,\n )\n }\n const pkg = readJsonObject(pkgPath) ?? {}\n const deps = { ...asRecord(pkg[\"dependencies\"]), ...asRecord(pkg[\"devDependencies\"]) }\n if (!(\"next\" in deps)) {\n throw new Error(\n `contactsheet init \u4E2D\u6B62:${pkgPath} \u7684 dependencies / devDependencies \u91CC\u6CA1\u6709 next\u3002\\n` +\n `contactsheet v1 \u53EA\u8BA4 Next.js App Router \u9879\u76EE \u2014\u2014 \u5B83\u9760\u5F80\u4F60\u7684 app \u76EE\u5F55\u6CE8\u5165\u4E00\u6761\u753B\u677F\u8DEF\u7531\u5E72\u6D3B,\\n` +\n `\u6E32\u67D3\u540E\u7AEF\u5C31\u662F\u4F60\u81EA\u5DF1\u7684 next dev,\u6CA1\u6709 Next \u5C31\u6CA1\u6709\u753B\u677F\u3002`,\n )\n }\n}\n\n// ============================================================\n// b. appDir \u63A2\u6D4B + \u914D\u7F6E\u6587\u4EF6\n// ============================================================\n\n/** src/app \u4F18\u5148\u4E8E app;\u90FD\u6CA1\u6709\u8BF4\u660E\u4E0D\u662F App Router \u9879\u76EE */\nfunction detectAppDir(root: string): string {\n for (const candidate of [\"src/app\", \"app\"]) {\n if (isDir(join(root, candidate))) return candidate\n }\n throw new Error(\n `contactsheet init \u4E2D\u6B62:${root} \u4E0B\u65E2\u6CA1\u6709 src/app/ \u4E5F\u6CA1\u6709 app/\u3002\\n` +\n `contactsheet v1 \u53EA\u652F\u6301 App Router(\u753B\u677F\u8DEF\u7531\u8981\u6CE8\u5165\u5230 app \u76EE\u5F55\u91CC)\u3002Pages Router \u9879\u76EE\u6682\u65F6\u7528\u4E0D\u4E86\u3002`,\n )\n}\n\n/** \u4ECE package.json \u7684 dev script \u91CC\u8BA4\u7AEF\u53E3(next dev -p 3100 / --port 3100 / PORT=3100),\n * \u8BA4\u51FA\u6765\u975E 3000 \u5C31\u5F53\u9ED8\u8BA4 target \u2014\u2014 \u7528\u6237\u8DD1\u7684\u672C\u6765\u5C31\u4E0D\u662F 3000 \u65F6,\u522B\u518D\u8BA9\u4ED6\u624B\u6539\u914D\u7F6E */\nfunction detectDevTarget(root: string): string | null {\n try {\n const pkg = JSON.parse(readFileSync(join(root, \"package.json\"), \"utf8\")) as {\n scripts?: Record<string, string>\n }\n const dev = pkg.scripts?.[\"dev\"] ?? \"\"\n const m = dev.match(/(?:-p|--port)[ =](\\d{2,5})/) ?? dev.match(/\\bPORT=(\\d{2,5})/)\n if (m && m[1] !== \"3000\") return `http://localhost:${m[1]}`\n } catch {\n /* \u8BFB\u4E0D\u5230\u5C31\u7528\u9ED8\u8BA4 */\n }\n return null\n}\n\nfunction writeConfigFile(root: string, appDir: string, flags: Partial<CsConfig>): CsConfig {\n const file = join(root, \"contactsheet.config.json\")\n const existing = readJsonObject(file) ?? {}\n\n // \u4F18\u5148\u7EA7:CLI flags > \u7528\u6237\u5DF2\u6709\u914D\u7F6E > \u63A2\u6D4B/\u9ED8\u8BA4\u503C\u3002\u7528\u6237\u624B\u6539\u8FC7\u7684\u503C\u4E0D\u4F1A\u88AB init \u62B9\u6389\u3002\n const resolved = {\n target: pickString(flags.target, existing[\"target\"], detectDevTarget(root) ?? DEFAULT_TARGET),\n port: pickNumber(flags.port, existing[\"port\"], DEFAULT_PORT),\n appDir: pickString(flags.appDir, existing[\"appDir\"], appDir),\n designDir: pickString(flags.designDir, existing[\"designDir\"], DEFAULT_DESIGN_DIR),\n }\n\n // \u5C55\u5F00 existing \u5728\u524D:\u7528\u6237\u52A0\u7684\u989D\u5916\u5B57\u6BB5\u539F\u6837\u4FDD\u7559,\u952E\u987A\u5E8F\u4E5F\u7A33\u5B9A(\u91CD\u590D\u8DD1 init \u5185\u5BB9\u4E0D\u53D8)\n writeJsonFile(file, { ...existing, ...resolved })\n\n return { projectRoot: root, ...resolved }\n}\n\n// ============================================================\n// d. \u81EA\u52A8\u94FA\u753B\u677F\n// ============================================================\n\nfunction seedArtboards(root: string, designDir: string): void {\n const uiDir = UI_DIR_CANDIDATES.map((p) => join(root, p)).find(isDir)\n if (!uiDir) {\n console.log(` \u753B\u677F:\u6CA1\u627E\u5230 components/ui/,\u8DF3\u8FC7\u81EA\u52A8\u94FA\u753B\u677F(\u624B\u5199 ${designDir}/*.artboard.tsx \u4E00\u6837\u7528)`)\n return\n }\n\n const files = readdirSync(uiDir)\n .filter((f) => f.endsWith(\".tsx\"))\n .sort()\n const targetDir = join(root, designDir)\n\n let created = 0\n let skipped = 0\n let unreadable = 0\n\n for (const base of files) {\n const componentFile = join(uiDir, base)\n const name = firstComponentExport(readFileSync(componentFile, \"utf8\"))\n if (!name) {\n unreadable++\n continue\n }\n const artboard = join(targetDir, `${name}.artboard.tsx`)\n if (existsSync(artboard)) {\n skipped++\n continue\n }\n mkdirSync(targetDir, { recursive: true })\n writeFileSync(artboard, artboardTemplate(name, importPathFor(root, designDir, componentFile)), \"utf8\")\n created++\n }\n\n console.log(ok(`\u753B\u677F:\u94FA\u4E86 ${green(String(created))} \u5757,\u8DF3\u8FC7 ${skipped} \u4E2A\u5DF2\u5B58\u5728`) + (unreadable ? `,${unreadable} \u4E2A\u6587\u4EF6\u6CA1\u8BA4\u51FA\u7EC4\u4EF6\u5BFC\u51FA` : \"\"))\n}\n\n/**\n * \u53D6\u6587\u4EF6\u91CC\u51FA\u73B0\u4F4D\u7F6E\u6700\u9760\u524D\u7684 PascalCase \u5BFC\u51FA\u3002\n * \u8BA4\u4E09\u79CD\u5199\u6CD5:export const X / export function X / export { X, Y }(\u542B\u8DE8\u884C\u4E0E as \u91CD\u547D\u540D)\u3002\n * v1 \u63A5\u53D7\u8FD9\u4E2A\u6B63\u5219\u7684\u5C40\u9650 \u2014\u2014 \u8BA4\u9519\u4E86\u5C31\u624B\u6539\u751F\u6210\u51FA\u6765\u7684\u753B\u677F\u6587\u4EF6\u3002\n */\nfunction firstComponentExport(source: string): string | null {\n const hits: Array<{ index: number; name: string }> = []\n\n const declRe = /^export\\s+(?:async\\s+)?(?:const|let|var|function|class)\\s+([A-Za-z_$][\\w$]*)/gm\n for (const m of source.matchAll(declRe)) {\n if (isPascal(m[1]!)) hits.push({ index: m.index ?? 0, name: m[1]! })\n }\n\n const listRe = /^export\\s*\\{([^}]*)\\}/gm\n for (const m of source.matchAll(listRe)) {\n for (const raw of m[1]!.split(\",\")) {\n const item = raw.trim()\n if (!item || item.startsWith(\"type \")) continue\n // `A as B` \u5BF9\u5916\u5BFC\u51FA\u7684\u662F B\n const parts = item.split(/\\s+as\\s+/)\n const name = parts[parts.length - 1]!.trim()\n if (isPascal(name)) {\n hits.push({ index: m.index ?? 0, name })\n break\n }\n }\n }\n\n if (hits.length === 0) return null\n hits.sort((a, b) => a.index - b.index)\n return hits[0]!.name\n}\n\nfunction isPascal(name: string): boolean {\n return /^[A-Z][A-Za-z0-9_$]*$/.test(name)\n}\n\n/** \u6709 @/* alias \u4E14\u7EC4\u4EF6\u786E\u5B9E\u5728 alias \u6307\u5411\u7684\u76EE\u5F55\u4E0B\u624D\u7528 alias,\u5426\u5219\u8001\u5B9E\u7528\u76F8\u5BF9\u8DEF\u5F84 */\nfunction importPathFor(root: string, designDir: string, componentFile: string): string {\n const aliasBase = readAliasBase(root)\n if (aliasBase && toPosix(componentFile).startsWith(toPosix(aliasBase) + \"/\")) {\n return \"@/\" + toPosix(relative(aliasBase, componentFile)).replace(/\\.tsx$/, \"\")\n }\n const rel = toPosix(relative(join(root, designDir), componentFile)).replace(/\\.tsx$/, \"\")\n return rel.startsWith(\".\") ? rel : \"./\" + rel\n}\n\n/** \u8BFB tsconfig.json \u7684 paths[\"@/*\"],\u8FD4\u56DE\u5B83\u6307\u5411\u7684\u7EDD\u5BF9\u76EE\u5F55;\u6CA1\u914D(\u6216 tsconfig \u89E3\u6790\u4E0D\u52A8)\u2192 null,\u8D70\u76F8\u5BF9\u8DEF\u5F84 */\nfunction readAliasBase(root: string): string | null {\n const file = join(root, \"tsconfig.json\")\n if (!existsSync(file)) return null\n let parsed: unknown\n try {\n parsed = JSON.parse(readFileSync(file, \"utf8\"))\n } catch {\n return null\n }\n const paths = asRecord(asRecord(asRecord(parsed)[\"compilerOptions\"])[\"paths\"])\n const entry = paths[\"@/*\"]\n const first = Array.isArray(entry) ? entry[0] : undefined\n if (typeof first !== \"string\") return null\n return resolve(root, first.replace(/\\/?\\*$/, \"\"))\n}\n\nfunction artboardTemplate(name: string, importPath: string): string {\n return (\n `// contactsheet \u81EA\u52A8\u751F\u6210\u7684\u753B\u677F\u9AA8\u67B6 \u2014\u2014 \u968F\u4FBF\u6539,init \u4E0D\u4F1A\u518D\u8986\u76D6\u5B83\\n` +\n `import { ${name} } from '${importPath}'\\n` +\n `\\n` +\n `export const \u9ED8\u8BA4 = {\\n` +\n ` render: () => <${name}>\u793A\u4F8B</${name}>,\\n` +\n `}\\n`\n )\n}\n\n// ============================================================\n// e. .mcp.json\n// ============================================================\n\nfunction writeMcpJson(root: string, port: number): void {\n const file = join(root, \".mcp.json\")\n const doc = readJsonObject(file) ?? {}\n const servers = asRecord(doc[\"mcpServers\"])\n const had = \"contactsheet\" in servers\n\n servers[\"contactsheet\"] = { type: \"http\", url: `http://localhost:${port}/__cs/mcp` }\n doc[\"mcpServers\"] = servers\n writeJsonFile(file, doc)\n\n const others = Object.keys(servers).filter((k) => k !== \"contactsheet\").length\n console.log(\n ` .mcp.json:${had ? \"\u66F4\u65B0\" : \"\u5199\u5165\"} mcpServers.contactsheet` + (others ? `(\u53E6\u5916 ${others} \u4E2A server \u539F\u6837\u4FDD\u7559)` : \"\"),\n )\n}\n\n// ============================================================\n// f. .claude/settings.json \u7684 UserPromptSubmit hook\n// ============================================================\n\nfunction writeClaudeHook(root: string, port: number): void {\n const file = join(root, \".claude\", \"settings.json\")\n const doc = readJsonObject(file) ?? {}\n const hooks = asRecord(doc[\"hooks\"])\n const list = Array.isArray(hooks[\"UserPromptSubmit\"]) ? (hooks[\"UserPromptSubmit\"] as unknown[]) : []\n\n // \u5E42\u7B49:\u5DF2\u7ECF\u6709\u4E00\u6761\u4F1A\u53BB\u6253 /__cs/api/context \u7684 command \u5C31\u4E0D\u518D\u52A0\n const existingCommands: string[] = []\n for (const group of list) {\n for (const h of Array.isArray(asRecord(group)[\"hooks\"]) ? (asRecord(group)[\"hooks\"] as unknown[]) : []) {\n const cmd = asRecord(h)[\"command\"]\n if (typeof cmd === \"string\") existingCommands.push(cmd)\n }\n }\n const already = existingCommands.filter((c) => c.includes(\"/__cs/api/context\"))\n if (already.length > 0) {\n console.log(` .claude/settings.json:context hook \u5DF2\u5B58\u5728,\u4E0D\u91CD\u590D\u6DFB\u52A0`)\n if (!already.some((c) => c.includes(`localhost:${port}/`))) {\n console.log(` \u6CE8\u610F:\u5DF2\u6709\u7684 hook \u6253\u7684\u4E0D\u662F :${port},\u7AEF\u53E3\u6362\u8FC7\u7684\u8BDD\u8BF7\u624B\u6539\u8FD9\u6761 command`)\n }\n return\n }\n\n const command = `curl -s --noproxy '*' --max-time 1 http://localhost:${port}/__cs/api/context || true`\n list.push({ hooks: [{ type: \"command\", command }] })\n hooks[\"UserPromptSubmit\"] = list\n doc[\"hooks\"] = hooks\n writeJsonFile(file, doc)\n console.log(` .claude/settings.json:\u52A0\u4E86 UserPromptSubmit hook(\u81EA\u52A8\u628A\u6279\u6CE8\u548C\u9009\u4E2D\u5143\u7D20\u5E26\u7ED9 Claude)`)\n}\n\n// ============================================================\n// \u5C0F\u5DE5\u5177\n// ============================================================\n\nfunction isDir(p: string): boolean {\n try {\n return statSync(p).isDirectory()\n } catch {\n return false\n }\n}\n\nfunction toPosix(p: string): string {\n return p.split(\"\\\\\").join(\"/\")\n}\n\nfunction asRecord(v: unknown): Record<string, unknown> {\n return v !== null && typeof v === \"object\" && !Array.isArray(v) ? (v as Record<string, unknown>) : {}\n}\n\nfunction pickString(...candidates: unknown[]): string {\n for (const c of candidates) if (typeof c === \"string\" && c !== \"\") return c\n return \"\"\n}\n\nfunction pickNumber(...candidates: unknown[]): number {\n for (const c of candidates) if (typeof c === \"number\" && Number.isFinite(c)) return c\n return 0\n}\n\n/** \u8BFB JSON \u5BF9\u8C61;\u6587\u4EF6\u4E0D\u5B58\u5728 \u2192 null;\u5185\u5BB9\u4E0D\u662F\u5408\u6CD5 JSON \u5BF9\u8C61 \u2192 \u4E2D\u6B62(\u7EDD\u4E0D\u8986\u76D6) */\nfunction readJsonObject(file: string): Record<string, unknown> | null {\n if (!existsSync(file)) return null\n const raw = readFileSync(file, \"utf8\")\n if (raw.trim() === \"\") return {}\n let parsed: unknown\n try {\n parsed = JSON.parse(raw)\n } catch (err) {\n throw new Error(\n `contactsheet init \u4E2D\u6B62:${file} \u4E0D\u662F\u5408\u6CD5\u7684 JSON(${(err as Error).message})\u3002\\n` +\n `init \u53EA\u4F1A\u5F80\u91CC\u5408\u5E76\u3001\u4E0D\u4F1A\u91CD\u5199,\u6240\u4EE5\u770B\u4E0D\u61C2\u7684\u6587\u4EF6\u4E00\u5F8B\u4E0D\u52A8 \u2014\u2014 \u8BF7\u5148\u4FEE\u597D\u5B83\u518D\u8DD1\u4E00\u6B21\u3002`,\n )\n }\n if (parsed === null || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n throw new Error(`contactsheet init \u4E2D\u6B62:${file} \u7684\u9876\u5C42\u4E0D\u662F\u4E00\u4E2A JSON \u5BF9\u8C61,init \u4E0D\u52A8\u5B83\u3002`)\n }\n return parsed as Record<string, unknown>\n}\n\nfunction writeJsonFile(file: string, value: unknown): void {\n mkdirSync(dirname(file), { recursive: true })\n writeFileSync(file, JSON.stringify(value, null, 2) + \"\\n\", \"utf8\")\n}\n", "// \u7EC8\u7AEF\u8F93\u51FA\u7684\u8272\u5F69\u4E0E\u7B26\u53F7:\u96F6\u4F9D\u8D56 ANSI\u3002\n// \u7EA6\u5B9A:\u2713 \u7EFF = \u5B8C\u6210;\u26A0 \u9EC4 = \u8981\u6CE8\u610F\u4F46\u4E0D\u81F4\u547D;\u2716 \u7EA2 = \u5931\u8D25;\u25CF \u9752 = \u5730\u5740/\u5165\u53E3;\u6697\u6DE1 = \u6B21\u8981\u4FE1\u606F\u3002\n// \u5C0A\u91CD NO_COLOR(https://no-color.org)\u4E0E\u975E TTY(\u7BA1\u9053/\u91CD\u5B9A\u5411\u65F6\u8F93\u51FA\u7EAF\u6587\u672C,\u65E5\u5FD7\u4E0D\u5E26\u8F6C\u4E49\u7801)\u3002\n\nconst on = process.stdout.isTTY === true && !process.env.NO_COLOR && process.env.TERM !== \"dumb\"\n\nconst wrap = (open: number, close: number) => (s: string) =>\n on ? `\\x1b[${open}m${s}\\x1b[${close}m` : s\n\nexport const bold = wrap(1, 22)\nexport const dim = wrap(2, 22)\nexport const red = wrap(31, 39)\nexport const green = wrap(32, 39)\nexport const yellow = wrap(33, 39)\nexport const cyan = wrap(36, 39)\nexport const magenta = wrap(35, 39)\n\n/** \u94FE\u63A5:\u9752\u8272 + \u4E0B\u5212\u7EBF,\u73B0\u4EE3\u7EC8\u7AEF\u53EF\u70B9 */\nexport const link = (s: string): string => (on ? `\\x1b[36;4m${s}\\x1b[39;24m` : s)\n\nexport const ok = (s: string): string => `${green(\"\u2713\")} ${s}`\nexport const warn = (s: string): string => `${yellow(\"\u26A0\")} ${yellow(s)}`\nexport const fail = (s: string): string => `${red(\"\u2716\")} ${s}`\n\n/** \u77ED\u6682\u7684\u884C\u5185 spinner:\u6BCF\u6B21\u8C03\u7528\u63A8\u8FDB\u4E00\u5E27,\u884C\u5C3E\u7528 \\r \u539F\u5730\u5237\u65B0\u3002\u975E TTY \u4E0B\u9759\u9ED8 */\nconst FRAMES = [\"\u280B\", \"\u2819\", \"\u2839\", \"\u2838\", \"\u283C\", \"\u2834\", \"\u2826\", \"\u2827\", \"\u2807\", \"\u280F\"]\nlet frame = 0\nexport function spin(text: string): void {\n if (!on) return\n process.stdout.write(`\\r${cyan(FRAMES[frame++ % FRAMES.length])} ${text}\\x1b[K`)\n}\nexport function spinDone(): void {\n if (!on) return\n process.stdout.write(\"\\r\\x1b[K\")\n}\n", "// \u5916\u58F3 HTTP \u670D\u52A1:\u53EA\u5360 /__cs \u524D\u7F00,\u5176\u4F59\u4E00\u5207(\u542B WebSocket)\u4EE3\u7406\u5230\u7528\u6237\u7684 next dev\nimport fs from \"node:fs\"\nimport http from \"node:http\"\nimport httpProxy from \"http-proxy\"\nimport type { CsConfig, RegistryEntry } from \"../types.js\"\nimport type { McpServices } from \"../mcp/index.js\"\nimport { createMcpHandler } from \"../mcp/index.js\"\nimport { screenshot } from \"../shot/index.js\"\nimport { errText, handleApi, pushToken, sendText } from \"./api.js\"\nimport { findUiFile, mimeOf, pkgVersion } from \"./assets.js\"\nimport { createProxyLog } from \"./proxy-log.js\"\nimport { startHealthMonitor } from \"./health.js\"\nimport { cyan, dim, link, warn } from \"../term.js\"\nimport * as sse from \"./sse.js\"\nimport * as store from \"./store.js\"\n\n// SSE hub \u662F\u6A21\u5757\u7EA7\u7684(startServer \u7684\u8FD4\u56DE\u503C\u7B7E\u540D\u51BB\u7ED3,\u63A8\u4E8B\u4EF6\u53EA\u80FD\u8D70\u8FD9\u4E2A\u989D\u5916\u5BFC\u51FA)\nexport { broadcast } from \"./sse.js\"\n\ntype McpHandler = (req: http.IncomingMessage, res: http.ServerResponse) => Promise<void>\n\nexport async function startServer(cfg: CsConfig): Promise<{ port: number; close(): Promise<void> }> {\n const proxy = httpProxy.createProxyServer({ target: cfg.target, ws: true, changeOrigin: true })\n\n // next dev \u6CA1\u8D77\u65F6\u7ED9\u4E00\u5F20\u8BF4\u660E\u9875,\u753B\u5E03\u81EA\u8EAB\u7167\u5E38\u53EF\u5F00\u3002\u65E5\u5FD7\u8D70 proxyLog \u53BB\u91CD\u9650\u6D41:\n // HMR \u5BA2\u6237\u7AEF\u91CD\u8FDE\u65F6\u6BCF\u79D2\u51E0\u5341\u6B21\u5931\u8D25,\u9010\u6761\u6253\u4F1A\u628A\u771F\u9519\u8BEF\u51B2\u8D70\n const proxyLog = createProxyLog(cfg.target)\n proxy.on(\"error\", (err, req, res) => {\n proxyLog.fail(err as NodeJS.ErrnoException, req?.url)\n if (!res) return\n if (\"writeHead\" in res) {\n if (!res.headersSent) res.writeHead(502, { \"content-type\": \"text/html; charset=utf-8\" })\n res.end(downPage(cfg.target))\n } else {\n // ws \u5347\u7EA7\u5931\u8D25:http-proxy \u53EA end() \u4E86\u5BA2\u6237\u7AEF socket,\u8FD9\u91CC\u8865\u4E00\u5200,\u522B\u7559\u534A\u5F00\u8FDE\u63A5\n res.destroy()\n }\n })\n // \u5BA2\u6237\u7AEF\u534A\u8DEF\u653E\u5F03\u65F6,\u4E0A\u6E38\u8FDE\u63A5\u5FC5\u987B\u8DDF\u7740\u62C6\u3002\u4E0D\u62C6\u7684\u8BDD\u6BCF\u6B21\u4E2D\u65AD\u90FD\u5728\u5916\u58F3\u91CC\u7559\u4E00\u4E2A\u540A\u6B7B fd\n // (\u5B9E\u6D4B 300 \u6B21\u4E2D\u65AD\u6CC4\u6F0F 300 \u4E2A fd,\u6C38\u4E0D\u56DE\u6536),\u800C\u4E14\u5BF9 next dev \u90A3\u662F\u4E00\u4E2A\u6C38\u8FDC\"\u6E32\u67D3\u4E2D\"\u7684\n // in-flight \u8BF7\u6C42 \u2014\u2014 \u50F5\u6B7B\u671F\u7684 HMR \u91CD\u8BD5\u6D2A\u6C34\u4F1A\u628A\u8FD9\u79CD\u8BF7\u6C42\u5806\u6210\u5C71,\u53CD\u8FC7\u6765\u628A dev server \u538B\u5F97\u66F4\u6B7B\u3002\n // \u5224\u636E:res \u5173\u95ED\u4F46\u6CA1\u5199\u5B8C = \u5BA2\u6237\u7AEF\u4E2D\u65AD;\u6B63\u5E38\u5B8C\u6210\u7684\u8BF7\u6C42\u4E0D\u52A8\u5B83(\u522B\u8BEF\u6740 keep-alive \u8FDE\u63A5\u6C60)\u3002\n proxy.on(\"proxyReq\", (proxyReq, _req, res) => {\n res.on(\"close\", () => {\n if (!res.writableEnded) proxyReq.destroy()\n })\n })\n\n // \u76EE\u6807\u6709\u56DE\u5305\u5C31\u7B97\u6D3B\u8FC7\u6765\u4E86(http \u54CD\u5E94 / ws \u63E1\u624B),\u7528\u6765\u6253\"\u5DF2\u6062\u590D\"\u90A3\u4E00\u884C\n proxy.on(\"proxyRes\", () => proxyLog.alive())\n proxy.on(\"open\", () => proxyLog.alive())\n\n // MCP handler \u7531 Agent D \u63D0\u4F9B;\u8FD8\u662F stub \u5C31\u6302 501,\u4E0D\u5F71\u54CD\u5176\u4F59\u529F\u80FD\n let mcp: McpHandler | null = null\n try {\n mcp = createMcpHandler(makeServices(cfg))\n } catch (err) {\n console.warn(`[contactsheet] MCP \u672A\u5C31\u7EEA(/__cs/mcp \u8FD4\u56DE 501):${errText(err)}`)\n }\n\n const server = http.createServer((req, res) => {\n handle(cfg, proxy, mcp, req, res).catch((err) => {\n console.error(`[contactsheet] \u8BF7\u6C42\u5904\u7406\u5931\u8D25 ${req.url}`, err)\n if (!res.headersSent) sendText(res, 500, errText(err))\n else res.end()\n })\n })\n\n // HMR WebSocket \u8D70\u8FD9\u6761\n server.on(\"upgrade\", (req, socket, head) => proxy.ws(req, socket, head))\n\n // \u81EA\u5DF1\u8FFD\u8E2A\u5168\u90E8 socket:\u5347\u7EA7\u6210 WebSocket \u7684\u4EE3\u7406\u8FDE\u63A5\u4E0D\u5728 closeAllConnections \u7684\u6E05\u5355\u91CC,\n // \u4E0D\u5E72\u6389\u5B83\u4EEC server.close \u6C38\u8FDC\u4E0D\u56DE\u8C03 \u2014\u2014 Ctrl-C \u65F6\u753B\u5E03\u8FD8\u5F00\u7740\u5C31\u4F1A\u5361\u6B7B\u5728\u9000\u51FA\u534A\u9014\n const sockets = new Set<import(\"node:net\").Socket>()\n server.on(\"connection\", (s) => {\n sockets.add(s)\n s.on(\"close\", () => sockets.delete(s))\n })\n\n // \u53EA\u7ED1\u56DE\u73AF:\u753B\u5E03\u6CA1\u6709\u9274\u6743,\u800C /__cs/api/push \u80FD\u628A\u4EFB\u610F\u6587\u672C\u4EE5\"\u7528\u6237\u53D1\u8A00\"\u9001\u8FDB\u4F60\u7684 Claude Code\n // \u4F1A\u8BDD\u3002\u88F8\u7ED1 0.0.0.0 \u7B49\u4E8E\u628A\u8FD9\u6761\u6267\u884C\u94FE\u66B4\u9732\u7ED9\u540C\u4E00\u4E2A Wi-Fi \u4E0A\u7684\u4EFB\u4F55\u4EBA\u3002\u8981 LAN \u8BBF\u95EE\u5FC5\u987B\u663E\u5F0F --host\u3002\n const host = cfg.host ?? \"127.0.0.1\"\n let twin: http.Server | null = null\n const port = await listenWithFallback(server, cfg, host, (t) => {\n twin = t\n // \u5B6A\u751F\u7684\u8FDE\u63A5\u540C\u6837\u8981\u8FDB\u8FFD\u8E2A\u8868,\u5426\u5219 Ctrl-C \u4F1A\u5361\u5728\u5B83\u7684 keep-alive \u4E0A\n t.on(\"connection\", (sock) => {\n sockets.add(sock)\n sock.on(\"close\", () => sockets.delete(sock))\n })\n })\n if (host !== \"127.0.0.1\" && host !== \"localhost\") {\n console.warn(\n warn(`\u76D1\u542C\u5728 ${host}:${port} \u2014\u2014 \u753B\u5E03\u65E0\u9274\u6743,\u540C\u7F51\u7EDC\u7684\u4EFB\u4F55\u4EBA\u90FD\u80FD\u8BFB\u4F60\u7684\u6279\u6CE8\u3001\u5E76\u5411\u4F60\u7684 Claude Code \u4F1A\u8BDD\u63A8\u9001\u6D88\u606F\u3002\u53EA\u5728\u53EF\u4FE1\u7F51\u7EDC\u8FD9\u4E48\u505A\u3002`)\n )\n }\n\n const health = startHealthMonitor(cfg, sse.broadcast)\n\n return {\n port,\n async close() {\n health.close()\n sse.closeAll()\n proxyLog.close()\n proxy.close()\n if (twin) {\n await new Promise<void>((r) => twin!.close(() => r()))\n }\n await new Promise<void>((resolve) => {\n const fallback = setTimeout(resolve, 2000) // \u515C\u5E95:2 \u79D2\u5173\u4E0D\u5E72\u51C0\u4E5F\u7167\u6837\u9000\u51FA\n for (const s of sockets) s.destroy()\n server.closeAllConnections()\n server.close(() => {\n clearTimeout(fallback)\n resolve()\n })\n })\n },\n }\n}\n\nasync function handle(\n cfg: CsConfig,\n proxy: ReturnType<typeof httpProxy.createProxyServer>,\n mcp: McpHandler | null,\n req: http.IncomingMessage,\n res: http.ServerResponse\n): Promise<void> {\n // \u53EA\u6309 pathname \u8DEF\u7531,query \u7559\u7ED9\u5404 handler \u81EA\u5DF1\u770B\n const pathname = new URL(req.url ?? \"/\", \"http://localhost\").pathname\n\n if (pathname === \"/__cs\" || pathname === \"/__cs/\") return serveUi(res, \"index.html\")\n\n if (pathname.startsWith(\"/__cs/ui/\")) {\n const name = pathname.slice(\"/__cs/ui/\".length)\n if (!name || name.includes(\"..\")) return sendText(res, 400, \"bad asset path\")\n return serveUi(res, name)\n }\n\n if (pathname === \"/__cs/events\") return sse.attach(req, res)\n\n if (pathname === \"/__cs/mcp\") {\n if (!mcp) return sendText(res, 501, \"contactsheet: MCP \u6A21\u5757\u672A\u5C31\u7EEA\")\n return mcp(req, res)\n }\n\n if (pathname.startsWith(\"/__cs/api/\")) return handleApi(cfg, req, res, pathname)\n\n // \u5176\u4F59\u4E00\u5207\u653E\u884C\u7ED9\u4EE3\u7406,\u5305\u62EC\u6CE8\u5165\u8DEF\u7531 /__cs/ab/* \u3001/__cs/registry \u3001/__cs/tokens\n proxy.web(req, res)\n}\n\nfunction serveUi(res: http.ServerResponse, name: string): void {\n const file = findUiFile(name)\n if (!file) return sendText(res, 404, `contactsheet: \u627E\u4E0D\u5230\u753B\u5E03\u8D44\u4EA7 ${name},\u5148\u8DD1 node build.mjs`)\n let body = fs.readFileSync(file)\n // \u753B\u5E03\u9875(\u4E14\u53EA\u6709\u753B\u5E03\u9875)\u62FF\u5230\u672C\u6B21\u8FDB\u7A0B\u7684 push token\u3002iframe \u91CC\u8DD1\u7684\u7528\u6237\u9875\u9762\u62FF\u4E0D\u5230\u5B83,\n // \u6240\u4EE5\u5C31\u7B97 app \u91CC\u6DF7\u8FDB\u7B2C\u4E09\u65B9\u811A\u672C,\u4E5F\u6CA1\u6CD5\u5192\u7528\u4F60\u7684\u540D\u4E49\u5411 Claude Code \u4F1A\u8BDD\u8BF4\u8BDD\u3002\n if (name === \"index.html\") {\n body = Buffer.from(\n body.toString(\"utf8\").replace(\"</head>\", `<meta name=\"cs-token\" content=\"${pushToken()}\" />\\n</head>`)\n )\n }\n res.writeHead(200, { \"content-type\": mimeOf(file), \"cache-control\": \"no-store\" })\n res.end(body)\n}\n\n/** \u4F9B MCP \u7528\u7684\u53EA\u8BFB\u670D\u52A1\u9762 */\nfunction makeServices(cfg: CsConfig): McpServices {\n return {\n // registry \u7531\u6CE8\u5165\u8FDB\u7528\u6237 app \u7684\u8DEF\u7531\u63D0\u4F9B,\u76F4\u8FDE target(node fetch \u4E0D\u8D70\u7CFB\u7EDF\u4EE3\u7406)\n async getRegistry(): Promise<RegistryEntry[]> {\n try {\n const r = await fetch(`${cfg.target}/__cs/registry`)\n if (!r.ok) return []\n const data: unknown = await r.json()\n return Array.isArray(data) ? (data as RegistryEntry[]) : []\n } catch {\n return [] // next dev \u6CA1\u8D77\n }\n },\n getSelection: () => store.getSelection(),\n getAnnotations: () => store.readAnnotations(cfg),\n takeShot: async (req) => screenshot(cfg, req),\n }\n}\n\nfunction downPage(target: string): string {\n return `<!doctype html><html lang=\"zh\"><meta charset=\"utf-8\"><title>contactsheet</title>\n<body style=\"font:14px/1.7 ui-monospace,SFMono-Regular,Menlo,monospace;padding:48px;color:#333;background:#fafafa\">\n<h1 style=\"font-size:15px;margin:0 0 12px\">contactsheet:\u76EE\u6807 ${escapeHtml(target)} \u672A\u542F\u52A8</h1>\n<p style=\"margin:0 0 8px\">\u5148\u5728\u9879\u76EE\u91CC\u8DD1 <code>next dev</code>,\u518D\u5237\u65B0\u672C\u9875\u3002</p>\n<p style=\"margin:0\"><a href=\"/__cs\" style=\"color:#06c\">\u2190 \u56DE\u753B\u5E03</a></p>\n</body></html>`\n}\n\nfunction escapeHtml(s: string): string {\n return s.replace(/[&<>\"]/g, (c) => ({ \"&\": \"&amp;\", \"<\": \"&lt;\", \">\": \"&gt;\", '\"': \"&quot;\" })[c] as string)\n}\n\n/** \u5360\u7740\u914D\u7F6E\u7AEF\u53E3\u7684\u662F\u4E0D\u662F\"\u672C\u9879\u76EE\u7684\u53E6\u4E00\u4E2A contactsheet\"?\u662F\u7684\u8BDD\u62FF\u5230\u5B83\u7684\u7248\u672C\u3002\n * \u91CD\u8BD5\u4E24\u8F6E\u3001\u8D85\u65F6\u653E\u5BBD:\u65E7\u5B9E\u4F8B\u6B63\u5FD9(\u6CC4\u6F0F/\u9AD8\u8D1F\u8F7D)\u65F6 800ms \u4E00\u67AA\u6253\u7A7A\u4F1A\u628A\"\u540C\u9879\u76EE\"\u8BEF\u5224\u6210\n * \"\u964C\u751F\u8FDB\u7A0B\" \u2014\u2014 \u8FD9\u4E2A\u8BEF\u5224\u4E0A\u4E00\u6B21\u8BA9\u5347\u7EA7\u9759\u9ED8\u5931\u6548\u4E86 */\nasync function probeSameProject(\n cfg: CsConfig,\n port: number\n): Promise<{ version?: string } | null> {\n for (let i = 0; i < 2; i++) {\n try {\n const r = await fetch(`http://127.0.0.1:${port}/__cs/api/state`, {\n signal: AbortSignal.timeout(2500),\n })\n if (!r.ok) return null\n const data = (await r.json()) as { projectRoot?: string; version?: string }\n return data?.projectRoot === cfg.projectRoot ? { version: data.version } : null\n } catch {\n /* \u7B2C\u4E8C\u8F6E\u518D\u8BD5 */\n }\n }\n return null\n}\n\n/** \u5360\u7528\u7AEF\u53E3\u7684\u8FDB\u7A0B\u53F7,\u5C3D\u529B\u800C\u4E3A(\u62A5\u9519\u4FE1\u606F\u91CC\u80FD\u76F4\u63A5 kill \u6BD4\"\u81EA\u5DF1\u53BB lsof\"\u53CB\u597D\u4E00\u4E2A\u91CF\u7EA7) */\nfunction occupierPid(port: number): string | null {\n try {\n const { execSync } = require(\"node:child_process\") as typeof import(\"node:child_process\")\n const out = execSync(`lsof -t -nP -iTCP:${port} -sTCP:LISTEN`, { timeout: 3000 })\n .toString()\n .trim()\n return out.split(\"\\n\")[0] || null\n } catch {\n return null\n }\n}\n\n/**\n * \u7AEF\u53E3\u88AB\u5360\u65F6\u7684\u7B56\u7565(\u5B9E\u6D4B\u4E8B\u6545\u540E\u4ECE\"\u987A\u5EF6\"\u6539\u6210\"\u786C\u5931\u8D25\"):\n * - \u672C\u9879\u76EE\u7684\u53E6\u4E00\u4E2A contactsheet,\u7248\u672C\u76F8\u540C \u2192 \u6253\u5370\u5730\u5740\u76F4\u63A5\u9000\u51FA(\u5FD8\u4E86\u5DF2\u7ECF\u8D77\u8FC7);\n * - \u672C\u9879\u76EE\u4F46**\u7248\u672C\u4E0D\u540C** \u2192 \u9000\u51FA\u7801 1,\u63D0\u793A\u5148 kill \u65E7\u7684 \u2014\u2014 \u9759\u9ED8\u590D\u7528\u65E7\u5B9E\u4F8B = \u5347\u7EA7\u9759\u9ED8\u5931\u6548;\n * - \u5176\u4ED6\u8FDB\u7A0B\u5360\u7740 \u2192 **\u786C\u5931\u8D25**,\u5E26\u4E0A\u5360\u7528\u8005 PID\u3002\u4E0D\u518D\u987A\u5EF6:config/.mcp.json/hook \u5168\u90FD\u6307\u5411\n * \u8FD9\u4E2A\u7AEF\u53E3,\u987A\u5EF6\u540E\u6D4F\u89C8\u5668\u91CC\u770B\u7740\u4E00\u5207\u6B63\u5E38,\u4F46 agent \u4FA7\u63A5\u7EBF\u5168\u90E8\u6307\u7740\u522B\u7684\u8FDB\u7A0B,\n * \u800C\u4E14\u4EFB\u4F55\u4E00\u65B9\u90FD\u4E0D\u4F1A\u6536\u5230\u9519\u8BEF \u2014\u2014 \u8FD9\u6B21\u7684\u540E\u679C\u4E0D\u662F\"\u6362\u4E86\u4E2A\u7AEF\u53E3\",\u662F\"\u5347\u7EA7\u9759\u9ED8\u5730\u6CA1\u751F\u6548\"\u3002\n */\nasync function listenWithFallback(\n server: http.Server,\n cfg: CsConfig,\n host: string,\n onTwin: (t: http.Server) => void\n): Promise<number> {\n const listenOnce = (srv: http.Server, port: number, h: string): Promise<\"ok\" | \"busy\" | \"nofam\"> =>\n new Promise((resolve, reject) => {\n const onErr = (err: NodeJS.ErrnoException): void => {\n if (err.code === \"EADDRINUSE\") resolve(\"busy\")\n // \u673A\u5668\u6CA1\u542F IPv6 \u65F6 ::1 \u7ED1\u4E0D\u4E86,\u4E0D\u7B97\u51B2\u7A81\n else if (err.code === \"EADDRNOTAVAIL\" || err.code === \"EAFNOSUPPORT\") resolve(\"nofam\")\n else reject(err)\n }\n srv.once(\"error\", onErr)\n srv.listen(port, h, () => {\n srv.off(\"error\", onErr)\n resolve(\"ok\")\n })\n })\n\n /**\n * \u4E00\u4E2A\u7AEF\u53E3\u8981 127.0.0.1 \u548C ::1 **\u90FD**\u7ED1\u4E0A\u624D\u7B97\u771F\u7684\u7A7A\u95F2\u3002\n * \u6D4F\u89C8\u5668\u89E3\u6790 localhost \u666E\u904D\u4F18\u5148 ::1:\u53EA\u7ED1 v4 \u65F6,\u82E5 v6 \u4FA7\u88AB\u522B\u4EBA\u5360\u7740(\u5B9E\u6D4B Docker \u5E38\u5E74\n * \u7AEF\u53E3\u8F6C\u53D1\u5728 IPv6 \u901A\u914D\u4E0A),curl \u4E00\u5207\u6B63\u5E38\u3001\u6D4F\u89C8\u5668\u5374\u62FF\u5230\u5BF9\u65B9\u7684 502/\u7A7A\u54CD\u5E94 \u2014\u2014 \u8FD9\u7C7B\"\u534A\u778E\"\n * \u51B2\u7A81\u5FC5\u987B\u5F53\u6210\u7AEF\u53E3\u88AB\u5360\u5904\u7406\u3002::1 \u4E0A\u8D77\u7684\u662F\u5171\u4EAB\u540C\u4E00 handler \u7684\u5B6A\u751F server\u3002\n * \u7528\u6237\u663E\u5F0F\u6307\u5B9A\u4E86\u975E\u56DE\u73AF host(LAN)\u65F6\u4E0D\u505A\u5B6A\u751F:\u7ED1\u7684\u5DF2\u7ECF\u4E0D\u662F localhost \u8FD9\u4E2A\u540D\u5B57\u4E86\u3002\n */\n const tryListen = async (port: number): Promise<boolean> => {\n const main = await listenOnce(server, port, host)\n if (main !== \"ok\") return false\n if (host !== \"127.0.0.1\") return true\n const t = http.createServer(server.listeners(\"request\")[0] as http.RequestListener)\n for (const l of server.listeners(\"upgrade\")) t.on(\"upgrade\", l as (...a: unknown[]) => void)\n const r = await listenOnce(t, port, \"::1\")\n if (r === \"ok\") {\n onTwin(t)\n return true\n }\n if (r === \"nofam\") return true // \u6CA1\u6709 IPv6,\u5355\u6808\u5373\u53EF\n // v6 \u88AB\u522B\u4EBA\u5360:\u8FD9\u4E2A\u7AEF\u53E3\u5BF9\u6D4F\u89C8\u5668\u662F\u574F\u7684,\u6574\u4F53\u8BA9\u51FA\u53BB\u91CD\u8BD5\u4E0B\u4E00\u4E2A\n await new Promise<void>((res) => server.close(() => res()))\n return false\n }\n\n if (await tryListen(cfg.port)) return cfg.port\n\n const running = await probeSameProject(cfg, cfg.port)\n if (running) {\n if (running.version && running.version !== pkgVersion()) {\n const pid = occupierPid(cfg.port)\n console.error(\n warn(`\u672C\u9879\u76EE\u5DF2\u6709\u4E00\u4E2A contactsheet \u5728 ${cfg.port} \u4E0A,\u4F46\u5B83\u662F v${running.version},\u5F53\u524D\u662F v${pkgVersion()}\u3002`) +\n `\\n \u65E7\u5B9E\u4F8B\u4E0D\u4F1A\u81EA\u52A8\u5347\u7EA7 \u2014\u2014 \u5148\u505C\u6389\u5B83\u518D\u8D77:kill ${pid ?? \"<lsof -t -iTCP:\" + cfg.port + \">\"}`\n )\n process.exit(1)\n }\n console.log(\n `${cyan(\"\u25CF\")} \u672C\u9879\u76EE\u5DF2\u7ECF\u6709\u4E00\u4E2A contactsheet \u5728\u8DD1\u4E86,\u76F4\u63A5\u7528\u5B83:${link(`http://localhost:${cfg.port}/__cs`)}`\n )\n process.exit(0)\n }\n const pid = occupierPid(cfg.port)\n throw new Error(\n `\u7AEF\u53E3 ${cfg.port} \u88AB\u5176\u4ED6\u8FDB\u7A0B\u5360\u7528${pid ? `(PID ${pid})` : \"\"}\u3002` +\n `.mcp.json/hook/config \u90FD\u6307\u5411 ${cfg.port},\u6362\u7AEF\u53E3\u5B83\u4EEC\u4F1A\u5168\u90E8\u5931\u8054,\u6240\u4EE5\u4E0D\u81EA\u52A8\u987A\u5EF6 \u2014\u2014\\n` +\n ` \u91CA\u653E\u5B83:kill ${pid ?? `$(lsof -t -nP -iTCP:${cfg.port} -sTCP:LISTEN)`}\\n` +\n ` \u6216\u6362\u7AEF\u53E3:\u6539 contactsheet.config.json \u7684 port \u540E\u91CD\u8DD1 npx contactsheet init(MCP/hook \u4F1A\u8DDF\u7740\u6362)`\n )\n}\n", "// [Agent D] MCP \u7AEF\u70B9 \u2014\u2014 \u6302\u5728\u5916\u58F3\u7684 /__cs/mcp,\u7ED9 Claude Code \u63D0\u4F9B\u56DB\u4E2A\u53EA\u8BFB\u5DE5\u5177\n// stateless \u6A21\u5F0F:\u6BCF\u4E2A POST \u73B0\u5EFA\u4E00\u5957 McpServer + StreamableHTTPServerTransport,\u54CD\u5E94\u5B8C\u5373\u9500\u6BC1\nimport type { IncomingMessage, ServerResponse } from \"node:http\"\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\"\nimport { StreamableHTTPServerTransport } from \"@modelcontextprotocol/sdk/server/streamableHttp.js\"\nimport { z } from \"zod\"\nimport type { Annotation, RegistryEntry, Selection, ShotRequest, ShotResult } from \"../types.js\"\n\nexport interface McpServices {\n getRegistry(): Promise<RegistryEntry[]>\n getSelection(): Selection | null\n getAnnotations(): Promise<Annotation[]>\n takeShot(req: ShotRequest): Promise<ShotResult>\n}\n\n/** \u5DE5\u5177\u8FD4\u56DE\u503C:\u53EA\u7528\u5230 text / image \u4E24\u79CD content */\ntype ToolResult = {\n content: ({ type: \"text\"; text: string } | { type: \"image\"; data: string; mimeType: string })[]\n isError?: boolean\n}\n\n/** \u5DE5\u5177\u6267\u884C\u629B\u9519\u4E0D\u80FD\u5D29 handler:\u7EDF\u4E00\u8F6C\u6210 isError \u6587\u672C */\nasync function guard(run: () => Promise<ToolResult>): Promise<ToolResult> {\n try {\n return await run()\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n // shot \u6A21\u5757\u7684\u9519\u8BEF\u4FE1\u606F\u81EA\u5E26 \"contactsheet: \" \u524D\u7F00,\u522B\u53E0\u4E24\u5C42\n const text = msg.startsWith(\"contactsheet:\") ? msg : `contactsheet: ${msg}`\n return { isError: true, content: [{ type: \"text\", text }] }\n }\n}\n\nfunction text(value: unknown): ToolResult {\n return { content: [{ type: \"text\", text: typeof value === \"string\" ? value : JSON.stringify(value, null, 2) }] }\n}\n\n/** \u6BCF\u4E2A\u8BF7\u6C42\u73B0\u5EFA\u4E00\u53F0 server(stateless \u6A21\u5F0F\u4E0B server \u4E0E transport \u90FD\u4E0D\u80FD\u8DE8\u8BF7\u6C42\u590D\u7528) */\nfunction buildServer(services: McpServices): McpServer {\n const server = new McpServer(\n { name: \"contactsheet\", version: \"0.1.0\" },\n { capabilities: { tools: {} } }\n )\n\n server.registerTool(\n \"canvas_list\",\n {\n title: \"\u5217\u51FA\u753B\u677F\",\n description:\n \"\u5217\u51FA contactsheet \u753B\u5E03\u4E0A\u7684\u5168\u90E8\u753B\u677F(\u8BBE\u8BA1\u7A3F)\u3002\u8FD4\u56DE JSON \u6570\u7EC4,\u6BCF\u9879\u542B id\u3001file(\u6E90\u6587\u4EF6\u76F8\u5BF9\u8DEF\u5F84)\u3001exportName\u3001kind(component=\u7EC4\u4EF6\u753B\u677F / screen=\u9875\u9762\u753B\u677F)\u3001args(\u7EC4\u4EF6\u9ED8\u8BA4\u5165\u53C2)\u3001env(\u5BBD\u9AD8\u7B49)\u3002\u8981\u622A\u67D0\u5757\u753B\u677F\u524D\u5148\u7528\u5B83\u62FF\u5230\u51C6\u786E\u7684 id\u3002\",\n annotations: { readOnlyHint: true },\n },\n async () => guard(async () => text(await services.getRegistry()))\n )\n\n server.registerTool(\n \"canvas_screenshot\",\n {\n title: \"\u622A\u56FE\u753B\u677F\",\n description:\n \"\u7ED9\u753B\u677F\u622A\u56FE\u5E76\u628A\u56FE\u7247\u8FD4\u56DE\u7ED9\u4F60\u770B\u3002\u4F20 id \u622A\u5355\u5757\u753B\u677F(id \u4ECE canvas_list \u62FF,\u7EC4\u4EF6\u753B\u677F\u622A\u5168\u9875);\u4E0D\u4F20 id \u622A\u6574\u9762\u753B\u5E03\u5899\u7684\u6982\u89C8\u3002\u8FD4\u56DE\u4E00\u5F20 PNG \u56FE\u7247 + \u56FE\u7247\u5728 repo \u91CC\u7684\u4FDD\u5B58\u8DEF\u5F84\u3002\u60F3\u786E\u8BA4 UI \u6539\u52A8\u7684\u5B9E\u9645\u6548\u679C\u5C31\u7528\u5B83\u3002\",\n inputSchema: {\n id: z\n .string()\n .optional()\n .describe(\"\u753B\u677F id(\u6765\u81EA canvas_list);\u7701\u7565\u5219\u622A\u6574\u9762\u5899\u7684\u6982\u89C8\u56FE\"),\n },\n annotations: { readOnlyHint: true },\n },\n async ({ id }) =>\n guard(async () => {\n const shot = await services.takeShot(id ? { id } : {})\n return {\n content: [\n { type: \"image\", data: shot.base64, mimeType: \"image/png\" },\n { type: \"text\", text: `\u5DF2\u4FDD\u5B58:${shot.path}(${shot.width}\u00D7${shot.height})` },\n ],\n }\n })\n )\n\n server.registerTool(\n \"canvas_selection\",\n {\n title: \"\u5F53\u524D\u9009\u4E2D\u5143\u7D20\",\n description:\n \"\u8BFB\u7528\u6237\u6B64\u523B\u5728 contactsheet \u753B\u5E03\u4E0A\u70B9\u9009\u7684\u5143\u7D20:\u8FD4\u56DE JSON,\u542B artboardId(\u54EA\u5757\u753B\u677F)\u3001selector(\u753B\u677F\u6587\u6863\u5185\u7684 CSS \u9009\u62E9\u5668)\u3001x/y(\u5143\u7D20\u5185 0-1 \u76F8\u5BF9\u5750\u6807)\u3001ts(\u65F6\u95F4\u6233)\u3002\u7528\u6237\u8BF4\u300C\u8FD9\u4E2A\u6309\u94AE\u300D\u300C\u8FD9\u91CC\u300D\u7684\u65F6\u5019\u5148\u8C03\u5B83\u786E\u8BA4\u6307\u7684\u662F\u8C01\u3002\u6CA1\u6709\u9009\u4E2D\u65F6\u8FD4\u56DE no selection\u3002\",\n annotations: { readOnlyHint: true },\n },\n async () =>\n guard(async () => {\n const selection = services.getSelection()\n return selection ? text(selection) : text(\"no selection\")\n })\n )\n\n server.registerTool(\n \"canvas_annotations\",\n {\n title: \"\u672A\u5904\u7406\u6279\u6CE8\",\n description:\n \"\u5217\u51FA\u753B\u5E03\u4E0A\u72B6\u6001\u4E3A open(\u672A\u5904\u7406)\u7684\u6279\u6CE8:\u8FD4\u56DE JSON \u6570\u7EC4,\u6BCF\u9879\u542B id\u3001text(\u7528\u6237\u5199\u7684\u8BDD)\u3001artboardId\u3001anchor(\u951A\u5B9A\u7684\u5143\u7D20\u4E0E\u4F4D\u7F6E)\u3001refs(\u9644\u5E26\u7684\u53C2\u8003\u56FE\u8DEF\u5F84)\u3001createdAt\u3002\u8FD9\u4E9B\u5C31\u662F\u7528\u6237\u5E0C\u671B\u4F60\u6539\u7684\u5730\u65B9\u3002\",\n annotations: { readOnlyHint: true },\n },\n async () =>\n guard(async () => {\n const all = await services.getAnnotations()\n return text(all.filter(a => a.status === \"open\"))\n })\n )\n\n return server\n}\n\n/** JSON-RPC \u5F62\u5F0F\u7684\u9519\u8BEF\u54CD\u5E94(GET/DELETE \u4E0D\u652F\u6301,\u4EE5\u53CA\u5185\u90E8\u5F02\u5E38) */\nfunction sendJsonRpcError(res: ServerResponse, status: number, code: number, message: string): void {\n if (res.headersSent) {\n res.end()\n return\n }\n res.writeHead(status, { \"content-type\": \"application/json\" })\n res.end(JSON.stringify({ jsonrpc: \"2.0\", error: { code, message }, id: null }))\n}\n\nexport function createMcpHandler(\n services: McpServices\n): (req: IncomingMessage, res: ServerResponse) => Promise<void> {\n return async function handleMcpRequest(req: IncomingMessage, res: ServerResponse): Promise<void> {\n // \u65E0 session \u6301\u4E45\u5316 \u2192 \u6CA1\u6709 GET \u901A\u77E5\u6D41,\u4E5F\u6CA1\u6709 DELETE \u7EC8\u6B62 session\n if (req.method !== \"POST\") {\n sendJsonRpcError(res, 405, -32000, \"Method not allowed.\")\n return\n }\n\n const server = buildServer(services)\n const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined })\n // \u54CD\u5E94\u7ED3\u675F/\u5BA2\u6237\u7AEF\u65AD\u5F00\u90FD\u8981\u62C6\u6389\u8FD9\u5957\u4E00\u6B21\u6027\u5B9E\u4F8B\n res.on(\"close\", () => {\n void transport.close().catch(() => {})\n void server.close().catch(() => {})\n })\n\n try {\n await server.connect(transport)\n await transport.handleRequest(req, res)\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n sendJsonRpcError(res, 500, -32603, `Internal server error: ${msg}`)\n }\n }\n}\n", "// [Agent D] \u622A\u56FE\u6A21\u5757 \u2014\u2014 playwright-core \u9A71\u52A8\u672C\u673A Edge(headless),\u6D4F\u89C8\u5668\u5B9E\u4F8B\u61D2\u542F\u52A8+\u590D\u7528\n// \u5355\u677F:\u5F00\u6CE8\u5165\u7684\u753B\u677F\u8DEF\u7531\u622A\u5168\u9875;\u6574\u5899:\u5F00\u5916\u58F3\u753B\u5E03\u622A\u89C6\u53E3\u3002\u4EA7\u7269\u843D <designDir>/.canvas/shots/\nimport { mkdir, writeFile } from \"node:fs/promises\"\nimport path from \"node:path\"\nimport { chromium } from \"playwright-core\"\nimport type { Browser } from \"playwright-core\"\nimport type { CsConfig, RegistryEntry, ShotRequest, ShotResult } from \"../types.js\"\n\n/** \u7A7A\u95F2\u591A\u4E45\u81EA\u52A8\u5173\u6D4F\u89C8\u5668 */\nconst IDLE_MS = 60_000\n/** \u5BFC\u822A\u8D85\u65F6;networkidle \u5728 next dev \u4E0B\u5076\u5C14\u7B49\u4E0D\u5230,\u8D85\u65F6\u540E\u7167\u5E38\u622A\u56FE */\nconst NAV_TIMEOUT_MS = 30_000\n\nlet browserPromise: Promise<Browser> | null = null\nlet idleTimer: NodeJS.Timeout | null = null\n\n/** \u61D2\u542F\u52A8 + \u590D\u7528\u540C\u4E00\u4E2A\u6D4F\u89C8\u5668\u5B9E\u4F8B;\u542F\u52A8\u5931\u8D25\u4E0D\u7F13\u5B58,\u4E0B\u6B21\u8C03\u7528\u91CD\u8BD5 */\nasync function getBrowser(): Promise<Browser> {\n if (!browserPromise) {\n browserPromise = chromium.launch({ channel: \"msedge\", headless: true }).catch((err: unknown) => {\n browserPromise = null\n const msg = err instanceof Error ? err.message : String(err)\n throw new Error(\n `contactsheet: \u542F\u52A8 Microsoft Edge \u5931\u8D25(playwright-core channel=msedge)\u3002\u8BF7\u786E\u8BA4\u672C\u673A\u88C5\u4E86 Edge\u3002\u539F\u59CB\u9519\u8BEF:${msg}`\n )\n })\n }\n return browserPromise\n}\n\n/** \u6BCF\u6B21\u622A\u5B8C\u91CD\u7F6E 60s \u7A7A\u95F2\u8BA1\u65F6\u5668 */\nfunction scheduleIdleClose(): void {\n if (idleTimer) clearTimeout(idleTimer)\n idleTimer = setTimeout(() => {\n idleTimer = null\n void closeBrowser()\n }, IDLE_MS)\n // \u522B\u56E0\u4E3A\u8FD9\u4E2A\u8BA1\u65F6\u5668\u62D6\u4F4F\u8FDB\u7A0B\u9000\u51FA\n idleTimer.unref?.()\n}\n\n/** \u5173\u6D4F\u89C8\u5668,\u5E42\u7B49;CLI \u9000\u51FA\u94A9\u5B50\u8C03 */\nexport async function closeBrowser(): Promise<void> {\n if (idleTimer) {\n clearTimeout(idleTimer)\n idleTimer = null\n }\n const pending = browserPromise\n browserPromise = null\n if (!pending) return\n try {\n const browser = await pending\n await browser.close()\n } catch {\n // \u542F\u52A8\u672C\u6765\u5C31\u5931\u8D25 / \u5DF2\u7ECF\u5173\u6389:\u5FFD\u7565\n }\n}\n\nexport interface CaptureOptions {\n url: string\n width: number\n height: number\n /** true = \u622A\u5168\u9875,false = \u53EA\u622A\u89C6\u53E3 */\n fullPage: boolean\n /** \u5BFC\u822A\u5B8C\u6210\u540E\u989D\u5916\u9759\u7F6E\u6BEB\u79D2\u6570 */\n settleMs: number\n}\n\n/**\n * \u5185\u90E8\u80FD\u529B:\u5F00\u4E00\u4E2A\u65B0 context \u6253\u5F00 url \u5E76\u622A\u56FE,\u8FD4\u56DE PNG buffer\u3002\n * \u4E0D\u5C5E\u4E8E\u5BF9\u5916\u5951\u7EA6,\u5BFC\u51FA\u53EA\u4E3A selftest \u76F4\u63A5\u8C03\u7528\u3002\n */\nexport async function captureUrl(opts: CaptureOptions): Promise<Buffer> {\n const browser = await getBrowser()\n const context = await browser.newContext({ viewport: { width: opts.width, height: opts.height } })\n try {\n const page = await context.newPage()\n try {\n await page.goto(opts.url, { waitUntil: \"networkidle\", timeout: NAV_TIMEOUT_MS })\n } catch {\n // next dev \u7684\u957F\u8FDE\u63A5\u53EF\u80FD\u8BA9 networkidle \u7B49\u4E0D\u5230:\u9000\u800C\u6C42\u5176\u6B21,\u7B49 DOM \u5C31\u7EEA\u540E\u7167\u5E38\u622A\n await page.waitForLoadState(\"domcontentloaded\").catch(() => {})\n }\n if (opts.settleMs > 0) await page.waitForTimeout(opts.settleMs)\n return await page.screenshot({ fullPage: opts.fullPage, type: \"png\" })\n } finally {\n await context.close()\n scheduleIdleClose()\n }\n}\n\n/** \u53D6 Next \u4FA7\u6CE8\u518C\u8868(node fetch \u4E0D\u8D70\u7CFB\u7EDF\u4EE3\u7406,\u4E0D\u7528\u989D\u5916\u5904\u7406) */\nasync function fetchRegistry(cfg: CsConfig): Promise<RegistryEntry[]> {\n const url = `${cfg.target.replace(/\\/+$/, \"\")}/__cs/registry`\n let res: Response\n try {\n res = await fetch(url)\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n throw new Error(\n `contactsheet: \u8BFB\u4E0D\u5230\u6CE8\u518C\u8868 ${url}\u3002\u786E\u8BA4\u4F60\u7684 next dev \u6B63\u5728\u8DD1,\u5E76\u4E14 contactsheet \u5DF2\u6CE8\u5165\u8DEF\u7531(\u5728\u9879\u76EE\u91CC\u8DD1 npx contactsheet)\u3002\u539F\u59CB\u9519\u8BEF:${msg}`\n )\n }\n if (!res.ok) {\n throw new Error(\n `contactsheet: \u6CE8\u518C\u8868 ${url} \u8FD4\u56DE ${res.status}\u3002\u6CE8\u5165\u8DEF\u7531\u53EF\u80FD\u6CA1\u751F\u6548,\u91CD\u8DD1 npx contactsheet \u8BA9\u5B83\u91CD\u5199\u6CE8\u5165\u6587\u4EF6\u3002`\n )\n }\n return (await res.json()) as RegistryEntry[]\n}\n\n/** \u6587\u4EF6\u540D\u91CC\u53BB\u6389\u8DEF\u5F84\u5206\u9694\u7B26\u7B49\u4E0D\u5B89\u5168\u5B57\u7B26(id \u5F62\u5982 \"sub__Button.artboard--\u9ED8\u8BA4\") */\nfunction safeFileName(id: string): string {\n return id.replace(/[/\\\\:*?\"<>|]/g, \"_\")\n}\n\n/** PNG \u5C3A\u5BF8\u76F4\u63A5\u8BFB IHDR */\nfunction pngSize(buf: Buffer): { width: number; height: number } {\n return { width: buf.readUInt32BE(16), height: buf.readUInt32BE(20) }\n}\n\n/** \u843D\u76D8\u5230 <projectRoot>/<designDir>/.canvas/shots/<name>.png,\u8FD4\u56DE repo \u76F8\u5BF9\u8DEF\u5F84 */\nasync function save(cfg: CsConfig, name: string, buf: Buffer): Promise<string> {\n const file = `${safeFileName(name)}.png`\n const abs = path.join(cfg.projectRoot, cfg.designDir, \".canvas\", \"shots\", file)\n await mkdir(path.dirname(abs), { recursive: true })\n await writeFile(abs, buf)\n return `${cfg.designDir.split(path.sep).join(\"/\").replace(/\\/+$/, \"\")}/.canvas/shots/${file}`\n}\n\nexport async function screenshot(cfg: CsConfig, req: ShotRequest): Promise<ShotResult> {\n let buf: Buffer\n let name: string\n\n if (req.id) {\n const entries = await fetchRegistry(cfg)\n const entry = entries.find(e => e.id === req.id)\n if (!entry) {\n const known = entries.slice(0, 10).map(e => e.id).join(\", \")\n throw new Error(\n `contactsheet: \u6CE8\u518C\u8868\u91CC\u6CA1\u6709\u753B\u677F \"${req.id}\"\u3002\u5DF2\u77E5 id:${known || \"(\u7A7A)\"}${entries.length > 10 ? \" \u2026\" : \"\"}`\n )\n }\n const base = `http://localhost:${cfg.port}`\n let url: string\n if (entry.kind === \"screen\") {\n url = `${base}${entry.url ?? \"/\"}`\n } else {\n url = `${base}/__cs/ab/${encodeURIComponent(entry.id)}`\n if (req.args) url += `?args=${encodeURIComponent(JSON.stringify(req.args))}`\n }\n buf = await captureUrl({\n url,\n width: entry.env?.width ?? 480,\n height: 900,\n fullPage: true,\n settleMs: 50,\n })\n name = entry.id\n } else {\n // \u6574\u9762\u5899:\u753B\u5E03\u672C\u8EAB,\u56FA\u5B9A\u5927\u89C6\u53E3,\u7ED9\u61D2\u6302\u8F7D\u7684 iframe \u7559\u51FA\u52A0\u8F7D\u65F6\u95F4\n buf = await captureUrl({\n url: `http://localhost:${cfg.port}/__cs`,\n width: 2400,\n height: 1350,\n fullPage: false,\n settleMs: 3000,\n })\n name = \"wall\"\n }\n\n const relPath = await save(cfg, name, buf)\n const { width, height } = pngSize(buf)\n return { path: relPath, base64: buf.toString(\"base64\"), width, height }\n}\n", "// /__cs/api/* \u7684\u5168\u90E8\u5904\u7406:state / selection / annotations / refs / context / screenshot\nimport { randomUUID } from \"node:crypto\"\nimport type { IncomingMessage, ServerResponse } from \"node:http\"\nimport type { Annotation, CsConfig, Selection, ShotRequest, StateInfo } from \"../types.js\"\nimport { screenshot } from \"../shot/index.js\"\nimport { mimeOf, pkgVersion } from \"./assets.js\"\nimport { pushToSession } from \"./push.js\"\nimport { currentHealth } from \"./health.js\"\nimport { broadcast } from \"./sse.js\"\nimport * as store from \"./store.js\"\n\nconst ANN = \"/__cs/api/annotations\"\n\n/** \u672C\u6B21\u8FDB\u7A0B\u7684 push token:\u53EA\u53D1\u7ED9\u753B\u5E03\u9875(\u89C1 serveUi),iframe \u5185\u7684\u7528\u6237\u9875\u9762\u8BFB\u4E0D\u5230 */\nlet TOKEN: string | null = null\nexport function pushToken(): string {\n if (!TOKEN) TOKEN = randomUUID()\n return TOKEN\n}\n\n/**\n * \u8DE8\u6E90\u5199\u5165\u95F8\u95E8\u3002readJson \u4E0D\u770B content-type,\u6240\u4EE5\u8DE8\u6E90 fetch \u7684 POST \u5C5E\u4E8E\"\u7B80\u5355\u8BF7\u6C42\"\u3001\n * \u6CA1\u6709\u9884\u68C0\u5C31\u80FD\u4EA7\u751F\u526F\u4F5C\u7528\u2014\u2014\u4EFB\u610F\u7F51\u9875\u90FD\u80FD\u9489\u6279\u6CE8\u518D\u8C03 push,\u628A\u6587\u672C\u9001\u8FDB\u4F60\u7684 Claude Code \u4F1A\u8BDD\u3002\n * \u89C4\u5219:\u975E GET \u5FC5\u987B\u6765\u81EA\u672C\u673A\u753B\u5E03\u81EA\u8EAB(\u6216\u4E0D\u5E26 Origin \u7684 curl/\u811A\u672C)\u3002\n */\nfunction originAllowed(cfg: CsConfig, req: IncomingMessage): boolean {\n const origin = req.headers.origin\n if (!origin) return true // curl / node fetch / \u540C\u6E90\u5BFC\u822A,\u4E0D\u662F\u6D4F\u89C8\u5668\u53D1\u8D77\u7684\u8DE8\u6E90\u8BF7\u6C42\n const ok = new Set([\n `http://localhost:${cfg.port}`,\n `http://127.0.0.1:${cfg.port}`,\n `http://[::1]:${cfg.port}`,\n ])\n return ok.has(origin)\n}\n\nexport async function handleApi(\n cfg: CsConfig,\n req: IncomingMessage,\n res: ServerResponse,\n pathname: string\n): Promise<void> {\n const method = req.method ?? \"GET\"\n\n if (method !== \"GET\" && !originAllowed(cfg, req)) {\n return sendText(res, 403, \"contactsheet: \u62D2\u7EDD\u8DE8\u6E90\u5199\u5165(Origin \u4E0D\u662F\u672C\u673A\u753B\u5E03)\")\n }\n\n if (pathname === \"/__cs/api/state\") {\n if (method !== \"GET\") return sendText(res, 405, \"method not allowed\")\n const info: StateInfo = {\n version: pkgVersion(),\n target: cfg.target,\n designDir: cfg.designDir,\n projectRoot: cfg.projectRoot,\n }\n return sendJson(res, 200, info)\n }\n\n if (pathname === \"/__cs/api/selection\") {\n if (method === \"GET\") return sendJson(res, 200, store.getSelection())\n if (method === \"POST\") {\n const body = await readJson<Selection | null>(req)\n // \u4F20 null / \u7F3A artboardId \u90FD\u5F53\u4F5C\u6E05\u7A7A\n store.setSelection(body && typeof body.artboardId === \"string\" ? body : null)\n return sendEmpty(res, 204)\n }\n return sendText(res, 405, \"method not allowed\")\n }\n\n if (pathname === ANN || pathname.startsWith(ANN + \"/\")) {\n return handleAnnotations(cfg, req, res, pathname, method)\n }\n\n // \u53D6\u56FE:\u6279\u6CE8\u6C14\u6CE1\u91CC\u7684\u7F29\u7565\u56FE\u5237\u65B0\u540E\u8981\u80FD\u91CD\u65B0\u62FF\u5230\u5B57\u8282(\u5185\u5B58 dataURL \u53EA\u6D3B\u4E00\u6B21\u4F1A\u8BDD)\n if (pathname.startsWith(\"/__cs/api/refs/\")) {\n if (method !== \"GET\") return sendText(res, 405, \"method not allowed\")\n const rel = pathname.slice(\"/__cs/api/refs/\".length).split(\"/\").map(decodeURIComponent).join(\"/\")\n const hit = await store.readRef(cfg, rel)\n if (!hit) return sendText(res, 404, \"contactsheet: \u627E\u4E0D\u5230\u53C2\u8003\u56FE\")\n res.writeHead(200, { \"content-type\": mimeOf(hit.file), \"cache-control\": \"no-store\" })\n res.end(hit.body)\n return\n }\n\n if (pathname === \"/__cs/api/refs\") {\n if (method !== \"POST\") return sendText(res, 405, \"method not allowed\")\n const body = await readJson<{ name?: string; dataBase64?: string }>(req)\n if (!body?.dataBase64) return sendText(res, 400, \"\u7F3A\u5C11 dataBase64\")\n const rel = await store.saveRef(cfg, body.name || \"ref.png\", body.dataBase64)\n return sendJson(res, 200, { path: rel })\n }\n\n if (pathname === \"/__cs/api/health\") {\n if (method !== \"GET\") return sendText(res, 405, \"method not allowed\")\n return sendJson(res, 200, currentHealth())\n }\n\n if (pathname === \"/__cs/api/context\") {\n if (method !== \"GET\") return sendText(res, 405, \"method not allowed\")\n // \u7ED9 UserPromptSubmit hook \u7528:\u6CA1\u5185\u5BB9\u5C31\u662F\u7A7A body,hook \u90A3\u8FB9\u539F\u6837\u6CE8\u5165\u5373\u53EF\u3002\n // \u6279\u6CE8\u6587\u4EF6\u574F\u6389\u65F6\u4E5F\u8981 200\u2014\u2014\u8BA9\u7528\u6237\u5728\u81EA\u5DF1\u7684\u5BF9\u8BDD\u91CC\u770B\u89C1\u8FD9\u53E5\u8BDD,\u800C\u4E0D\u662F hook \u9759\u9ED8\u5931\u8D25\n try {\n return sendText(res, 200, await store.buildContextText(cfg))\n } catch (err) {\n return sendText(res, 200, `[contactsheet] \u8BFB\u6279\u6CE8\u5931\u8D25:${errText(err)}`)\n }\n }\n\n if (pathname === \"/__cs/api/push\") {\n if (method !== \"POST\") return sendText(res, 405, \"method not allowed\")\n // push \u662F\u552F\u4E00\u80FD\"\u4EE5\u4F60\u7684\u540D\u4E49\"\u5411 Claude Code \u4F1A\u8BDD\u8BF4\u8BDD\u7684\u7AEF\u70B9,\u989D\u5916\u8981 token\n if (req.headers[\"x-cs-token\"] !== pushToken()) {\n return sendText(res, 403, \"contactsheet: \u7F3A\u5C11\u753B\u5E03 token,\u62D2\u7EDD\u63A8\u9001(\u8BF7\u4ECE\u753B\u5E03\u9875\u64CD\u4F5C)\")\n }\n const body = await readJson<{ pid?: number }>(req)\n try {\n const text = await store.buildContextText(cfg)\n if (!text.trim()) return sendJson(res, 200, { ok: false, reason: \"\u6CA1\u6709\u5F85\u5904\u7406\u7684\u6279\u6CE8\u6216\u9009\u4E2D,\u5148\u6309 c \u9489\u4E00\u6761\" })\n return sendJson(res, 200, await pushToSession(cfg, text, body?.pid))\n } catch (err) {\n return sendJson(res, 200, { ok: false, reason: `\u6CE8\u5165\u5931\u8D25:${errText(err)}` })\n }\n }\n\n if (pathname === \"/__cs/api/screenshot\") {\n if (method !== \"POST\") return sendText(res, 405, \"method not allowed\")\n const body = await readJson<ShotRequest>(req)\n try {\n return sendJson(res, 200, await screenshot(cfg, body ?? {}))\n } catch (err) {\n // shot \u6A21\u5757\u8FD8\u662F stub / playwright \u8D77\u4E0D\u6765,\u90FD\u8D70\u8FD9\u91CC\n return sendText(res, 500, `screenshot \u5931\u8D25:${errText(err)}`)\n }\n }\n\n return sendText(res, 404, \"not found\")\n}\n\nasync function handleAnnotations(\n cfg: CsConfig,\n req: IncomingMessage,\n res: ServerResponse,\n pathname: string,\n method: string\n): Promise<void> {\n const id = pathname === ANN ? \"\" : decodeURIComponent(pathname.slice(ANN.length + 1))\n\n if (!id && method === \"GET\") {\n return sendJson(res, 200, await store.readAnnotations(cfg))\n }\n\n if (!id && method === \"POST\") {\n const body = await readJson<Partial<Annotation>>(req)\n const { result, list } = await store.updateAnnotations(cfg, (all) => {\n const ann: Annotation = {\n id: store.newAnnotationId(all),\n // \u6C38\u4E45\u5E8F\u53F7:\u5168\u8868 max+1,\u5305\u542B verified \u7684 \u2014\u2014 \u53F7\u53EA\u6DA8\u4E0D\u590D\u7528,\u6838\u9A8C\u6D88\u5931\u4E5F\u4E0D\u8BA9\u540E\u6765\u8005\u9876\u53F7\n seq: all.reduce((m, a) => Math.max(m, a.seq ?? 0), 0) + 1,\n artboardId: body?.artboardId,\n anchor: body?.anchor,\n text: typeof body?.text === \"string\" ? body.text : \"\",\n refs: Array.isArray(body?.refs) ? body.refs : [],\n status: body?.status === \"resolved\" ? \"resolved\" : \"open\",\n createdAt: new Date().toISOString(),\n }\n all.push(ann)\n return ann\n })\n broadcast({ type: \"annotations\", annotations: list })\n return sendJson(res, 201, result)\n }\n\n if (id && method === \"PATCH\") {\n const patch = await readJson<Partial<Annotation>>(req)\n const { result, list } = await store.updateAnnotations(cfg, (all) => {\n const hit = all.find((a) => a.id === id)\n if (!hit) return null\n // id / createdAt \u4E0D\u7ED9\u6539\n Object.assign(hit, patch, { id: hit.id, createdAt: hit.createdAt })\n return hit\n })\n if (!result) return sendText(res, 404, \"annotation not found\")\n broadcast({ type: \"annotations\", annotations: list })\n return sendJson(res, 200, result)\n }\n\n if (id && method === \"DELETE\") {\n const { result, list } = await store.updateAnnotations(cfg, (all) => {\n const i = all.findIndex((a) => a.id === id)\n if (i < 0) return false\n all.splice(i, 1)\n return true\n })\n if (!result) return sendText(res, 404, \"annotation not found\")\n broadcast({ type: \"annotations\", annotations: list })\n return sendEmpty(res, 204)\n }\n\n return sendText(res, 405, \"method not allowed\")\n}\n\n// ---------- \u5C0F\u5DE5\u5177 ----------\n\nexport function sendJson(res: ServerResponse, code: number, body: unknown): void {\n res.writeHead(code, { \"content-type\": \"application/json; charset=utf-8\", \"cache-control\": \"no-store\" })\n res.end(JSON.stringify(body ?? null))\n}\n\nexport function sendText(res: ServerResponse, code: number, body: string): void {\n res.writeHead(code, { \"content-type\": \"text/plain; charset=utf-8\", \"cache-control\": \"no-store\" })\n res.end(body)\n}\n\nfunction sendEmpty(res: ServerResponse, code: number): void {\n res.writeHead(code)\n res.end()\n}\n\nexport function errText(err: unknown): string {\n return err instanceof Error ? err.message : String(err)\n}\n\nasync function readJson<T>(req: IncomingMessage): Promise<T> {\n const chunks: Buffer[] = []\n for await (const c of req) chunks.push(c as Buffer)\n const raw = Buffer.concat(chunks).toString(\"utf8\").trim()\n if (!raw) return null as T\n return JSON.parse(raw) as T\n}\n", "// \u753B\u5E03\u9759\u6001\u8D44\u4EA7\u5B9A\u4F4D\u3002\u6253\u5305\u540E cli.js \u5728 dist/,\u8D44\u4EA7\u5728 dist/canvas/;\n// \u5F00\u53D1\u671F(app.js \u7531 build.mjs --watch \u4EA7\u51FA\u5230 dist)\u56DE\u843D\u5305\u6839\u7684 dist/canvas \u4E0E src/canvas\nimport fs from \"node:fs\"\nimport path from \"node:path\"\nimport { fileURLToPath } from \"node:url\"\n\nconst here = path.dirname(fileURLToPath(import.meta.url))\nconst pkgRoot = path.resolve(here, \"..\")\n\nconst DIRS = [\n path.join(here, \"canvas\"), // \u53D1\u5E03\u5F62\u6001:dist/cli.js \u65C1\u8FB9\u7684 dist/canvas\n path.join(pkgRoot, \"dist\", \"canvas\"),\n path.join(pkgRoot, \"src\", \"canvas\"), // \u5F00\u53D1\u671F\u76F4\u8BFB\u6E90\u7801\u91CC\u7684 index.html / style.css\n]\n\n/** \u9010\u4E2A\u5019\u9009\u76EE\u5F55\u627E\u8D44\u4EA7\u6587\u4EF6,\u627E\u4E0D\u5230\u8FD4\u56DE null */\nexport function findUiFile(name: string): string | null {\n for (const dir of DIRS) {\n const p = path.join(dir, name)\n if (fs.existsSync(p) && fs.statSync(p).isFile()) return p\n }\n return null\n}\n\nconst MIME: Record<string, string> = {\n \".html\": \"text/html; charset=utf-8\",\n \".js\": \"text/javascript; charset=utf-8\",\n \".css\": \"text/css; charset=utf-8\",\n \".map\": \"application/json; charset=utf-8\",\n \".json\": \"application/json; charset=utf-8\",\n \".png\": \"image/png\",\n \".svg\": \"image/svg+xml\",\n \".jpg\": \"image/jpeg\",\n \".jpeg\": \"image/jpeg\",\n \".gif\": \"image/gif\",\n \".webp\": \"image/webp\",\n}\n\nexport function mimeOf(file: string): string {\n return MIME[path.extname(file)] ?? \"application/octet-stream\"\n}\n\n/** StateInfo.version \u7528;\u8BFB\u4E0D\u5230\u5C31\u7ED9\u4E2A\u5360\u4F4D\u3002\n * \u5FC5\u987B\u5728\u8FDB\u7A0B\u542F\u52A8\u65F6\u5B9A\u683C:\u6BCF\u6B21\u73B0\u8BFB\u7684\u8BDD,\u65E7\u8FDB\u7A0B\u4F1A\u62A5\u51FA\u78C1\u76D8\u4E0A\u7684**\u65B0**\u7248\u672C\u53F7,\n * \u7AEF\u53E3\u88AB\u5360\u65F6\u7684\u7248\u672C\u6BD4\u5BF9\u5728\"\u5347\u7EA7\"\u8FD9\u4E2A\u6700\u9700\u8981\u5B83\u7684\u573A\u666F\u6070\u597D\u5931\u660E(\u5B9E\u6D4B) */\nconst VERSION: string = (() => {\n try {\n const pkg = JSON.parse(fs.readFileSync(path.join(pkgRoot, \"package.json\"), \"utf8\")) as { version?: string }\n return pkg.version ?? \"0.0.0\"\n } catch {\n return \"0.0.0\"\n }\n})()\n\nexport function pkgVersion(): string {\n return VERSION\n}\n", "// \u4E00\u952E\u63A8\u9001:\u628A\u753B\u5E03\u4E0A\u4E0B\u6587\u6CE8\u5165\u7ED1\u5B9A\u7684 Claude Code \u4F1A\u8BDD(inbox socket)\n//\n// \u901A\u9053\u8BF4\u660E:Claude Code \u7684 cross-session messaging \u4F1A\u7ED9\u6BCF\u4E2A\u4F1A\u8BDD\u5F00\u4E00\u4E2A UDS\n// (/tmp/cc-socks/<pid>.sock),\u534F\u8BAE\u4E3A\u6362\u884C\u5206\u9694 JSON,\u6CE8\u5165\u683C\u5F0F\u6765\u81EA Claude Code\n// \u81EA\u5DF1\u7684\u542F\u52A8\u65E5\u5FD7:{\"type\":\"user\",\"message\":{\"role\":\"user\",\"content\":\"...\"}}\n// \u8FD9\u662F\u534A\u516C\u5F00\u7684\u5185\u90E8\u901A\u9053(\u5B98\u65B9\u6587\u6863\u8BF4\u5B83\u670D\u52A1\u4E8E hooks/Bash),\u7248\u672C\u5347\u7EA7\u53EF\u80FD\u53D8\u2014\u2014\n// \u5931\u8D25\u65F6\u524D\u7AEF\u4F1A\u56DE\u843D\u5230\"\u590D\u5236\u5230\u526A\u8D34\u677F\"\u3002\u5B98\u65B9\u6B63\u95E8\u662F Channels(MCP),\u5217\u4E3A\u540E\u7EED\u8DEF\u5F84\u3002\n//\n// \u4F1A\u8BDD\u53D1\u73B0:~/.claude/sessions/<pid>.json \u662F Claude Code \u7684\u4F1A\u8BDD\u767B\u8BB0\u5904,\n// \u5E26 name(\u4F1A\u8BDD\u540D)/cwd/status/socket \u8DEF\u5F84;\u6309 cwd \u2208 \u9879\u76EE\u6839 \u8FC7\u6EE4,socket \u63A2\u6D3B\u53BB\u5C38\u4F53\u3002\nimport fs from \"node:fs/promises\"\nimport net from \"node:net\"\nimport os from \"node:os\"\nimport path from \"node:path\"\nimport type { CsConfig } from \"../types.js\"\n\nexport interface PushTarget {\n pid: number\n name: string\n status: string\n cwd: string\n socket: string\n updatedAt: number\n}\n\ninterface SessionRecord {\n pid?: number\n cwd?: string\n name?: string\n status?: string\n kind?: string\n messagingSocketPath?: string\n updatedAt?: number\n}\n\n/** 250ms \u8FDE\u63A5\u63A2\u6D3B(\u4E0E Claude Code \u81EA\u5DF1\u7684\u63A2\u6D3B\u903B\u8F91\u4E00\u81F4) */\nfunction isLive(sock: string): Promise<boolean> {\n return new Promise((resolve) => {\n const s = new net.Socket()\n const done = (ok: boolean): void => {\n s.destroy()\n resolve(ok)\n }\n s.on(\"connect\", () => done(true))\n s.on(\"error\", () => done(false))\n s.setTimeout(250, () => done(false))\n s.connect({ path: sock })\n })\n}\n\n/** \u5217\u51FA\u5019\u9009:\u767B\u8BB0\u5904\u91CC cwd \u5728\u672C\u9879\u76EE\u4E0B\u3001socket \u6D3B\u7740\u7684\u4EA4\u4E92\u5F0F\u4F1A\u8BDD,\u6700\u8FD1\u6D3B\u8DC3\u5728\u524D */\nexport async function listTargets(cfg: CsConfig): Promise<PushTarget[]> {\n const root = path.resolve(cfg.projectRoot)\n const dir = path.join(os.homedir(), \".claude\", \"sessions\")\n let names: string[]\n try {\n names = await fs.readdir(dir)\n } catch {\n return []\n }\n const out: PushTarget[] = []\n await Promise.all(\n names\n .filter((n) => n.endsWith(\".json\"))\n .map(async (n) => {\n let rec: SessionRecord\n try {\n rec = JSON.parse(await fs.readFile(path.join(dir, n), \"utf8\")) as SessionRecord\n } catch {\n return\n }\n if (!rec.pid || !rec.cwd || !rec.messagingSocketPath) return\n if (rec.kind && rec.kind !== \"interactive\") return\n const rel = path.relative(root, path.resolve(rec.cwd))\n if (rel.startsWith(\"..\") || path.isAbsolute(rel)) return // \u4E0D\u5728\u9879\u76EE\u5185\n if (!(await isLive(rec.messagingSocketPath))) return // \u767B\u8BB0\u5904\u6709\u5C38\u4F53,\u63A2\u6D3B\u8FC7\u6EE4\n out.push({\n pid: rec.pid,\n name: rec.name ?? `pid ${rec.pid}`,\n status: rec.status ?? \"unknown\",\n cwd: rec.cwd,\n socket: rec.messagingSocketPath,\n updatedAt: rec.updatedAt ?? 0,\n })\n })\n )\n out.sort((a, b) => b.updatedAt - a.updatedAt)\n return out\n}\n\n/** \u5199\u4E00\u884C JSONL \u8FDB\u4F1A\u8BDD inbox\u3002\u5199\u6210\u529F\u5373\u89C6\u4E3A\u9001\u8FBE(\u56DE\u6267\u8D70\u7684\u662F\u4F1A\u8BDD\u95F4\u534F\u8BAE,\u5916\u90E8\u8FDB\u7A0B\u6536\u4E0D\u5230) */\nexport function inject(sock: string, content: string): Promise<void> {\n return new Promise((resolve, reject) => {\n const s = net.createConnection({ path: sock })\n s.setTimeout(3000, () => {\n s.destroy()\n reject(new Error(\"\u5199\u5165\u8D85\u65F6\"))\n })\n s.on(\"error\", reject)\n s.on(\"connect\", () => {\n const line =\n JSON.stringify({ type: \"user\", message: { role: \"user\", content } }) + \"\\n\"\n s.end(line, () => resolve())\n })\n })\n}\n\nexport type PushResult =\n | { ok: true; pid: number; name: string }\n | { ok: false; reason: string }\n | { ok: false; choose: Array<Pick<PushTarget, \"pid\" | \"name\" | \"status\" | \"cwd\">> }\n\n/** \u63A8\u9001\u5165\u53E3:\u6307\u5B9A pid \u76F4\u53D1;\u552F\u4E00\u5019\u9009\u76F4\u53D1;\u591A\u4E2A\u5019\u9009\u8BA9\u524D\u7AEF\u51FA\u9009\u62E9\u5668 */\nexport async function pushToSession(\n cfg: CsConfig,\n text: string,\n pid?: number\n): Promise<PushResult> {\n const targets = await listTargets(cfg)\n if (!targets.length) {\n return {\n ok: false,\n reason: `\u6CA1\u627E\u5230\u5DE5\u4F5C\u76EE\u5F55\u5728 ${cfg.projectRoot} \u4E0B\u7684 Claude Code \u4F1A\u8BDD(\u8981\u5148\u5728\u9879\u76EE\u76EE\u5F55\u91CC\u5F00\u7740 claude)`,\n }\n }\n let target: PushTarget | undefined\n if (pid !== undefined) {\n target = targets.find((t) => t.pid === pid)\n if (!target) return { ok: false, reason: `\u4F1A\u8BDD pid ${pid} \u5DF2\u4E0D\u5728(\u53EF\u80FD\u521A\u5173\u6389),\u91CD\u6309 p \u91CD\u9009` }\n } else if (targets.length === 1) {\n target = targets[0]\n } else {\n return {\n ok: false,\n choose: targets.map(({ pid: p, name, status, cwd }) => ({ pid: p, name, status, cwd })),\n }\n }\n const body =\n `[contactsheet] \u7528\u6237\u5728\u753B\u5E03\u4E0A\u6309\u4E0B\u4E86\u63A8\u9001\u952E,\u4EE5\u4E0B\u662F\u5F53\u524D\u753B\u5E03\u4E0A\u4E0B\u6587,\u8BF7\u6309\u6279\u6CE8\u5904\u7406:\\n\\n` + text\n await inject(target!.socket, body)\n return { ok: true, pid: target!.pid, name: target!.name }\n}\n", "// \u76EE\u6807 dev server \u7684\u5065\u5EB7\u63A2\u6D4B\u3002\n// \u52A8\u673A(Synco \u5B9E\u6D4B\u73B0\u573A):\u753B\u5E03\u957F\u5F00 + \u7528\u6237\u6301\u7EED\u6539\u4EE3\u7801,next dev \u53EF\u80FD\u8FDB\u5165\u50F5\u6B7B\u6001 \u2014\u2014\n// \u8FDB\u7A0B\u6D3B\u7740\u3001\u7AEF\u53E3 LISTEN\u3001\u9759\u6001\u8D44\u6E90 200,\u4F46 SSR \u79D2 500\u3001API \u6C38\u4E45\u6302\u8D77\u3002\u6B64\u65F6\u753B\u5E03\u4E0A\n// \u6BCF\u5757\u753B\u677F\u5404\u81EA\u7834\u56FE,\u7528\u6237\u770B\u5230\u7684\u662F\"contactsheet \u5D29\u4E86\",\u5F52\u56E0\u5B8C\u5168\u9519\u4E86\u3002\n// \u8FD9\u91CC\u4E3B\u52A8\u63A2\u6D4B\u5E76\u5E7F\u64AD\u4E00\u4E2A**\u5168\u5C40**\u72B6\u6001,\u8BA9\u753B\u5E03\u7528\u4E00\u6761\u6A2A\u5E45\u628A\u8BDD\u8BF4\u6E05\u695A\u3002\n//\n// \u63A2\u6D4B\u76EE\u6807\u9009 /__cs/registry:\u5B83\u662F\u6CE8\u5165\u8FDB\u7528\u6237 app \u7684 RSC \u8DEF\u7531,\u8D70\u7684\u6B63\u662F\u50F5\u6B7B\u6307\u7EB9\u91CC\n// \u6302\u6389\u7684\u90A3\u6761 server \u6E32\u67D3\u8DEF\u5F84 \u2014\u2014 \u9759\u6001\u8D44\u6E90\u63A2\u6D4B\u5728\u8FD9\u79CD\u6545\u969C\u4E0B\u4F1A\u7ED9\u5047\u9634\u6027\u3002\nimport type { CsConfig, CsEvent } from \"../types.js\"\n\nexport interface HealthState {\n ok: boolean\n /** \u4E0D\u5065\u5EB7\u65F6\u7684\u4E00\u53E5\u8BDD\u8BCA\u65AD(\u8D85\u65F6/HTTP 5xx/\u8FDE\u4E0D\u4E0A) */\n detail?: string\n /** \u6700\u540E\u4E00\u6B21\u63A2\u6D4B\u6210\u529F\u7684\u65F6\u95F4\u6233(ms);\u4ECE\u672A\u6210\u529F\u8FC7\u5219\u7F3A\u7701 */\n lastOkAt?: number\n}\n\nconst INTERVAL_MS = Number(process.env.CS_HEALTH_INTERVAL_MS ?? 20000)\nconst TIMEOUT_MS = Number(process.env.CS_HEALTH_TIMEOUT_MS ?? 10000)\n/** \u8FDE\u7EED\u5931\u8D25\u8FD9\u4E48\u591A\u6B21\u624D\u7B97\u4E0D\u5065\u5EB7:\u5355\u6B21\u6296\u52A8(\u5927\u9879\u76EE\u51B7\u7F16\u8BD1\u3001\u77AC\u65F6\u9AD8\u8D1F\u8F7D)\u4E0D\u8BE5\u62C9\u6A2A\u5E45 */\nconst FAILS_TO_TRIP = 2\n\nlet current: HealthState = { ok: true }\n\nexport function currentHealth(): HealthState {\n return current\n}\n\nexport function startHealthMonitor(\n cfg: CsConfig,\n broadcast: (ev: CsEvent) => void\n): { close(): void } {\n let fails = 0\n let everOk = false\n let timer: NodeJS.Timeout | null = null\n\n const probe = async (): Promise<void> => {\n let failDetail: string | null = null\n try {\n const r = await fetch(`${cfg.target}/__cs/registry`, { signal: AbortSignal.timeout(TIMEOUT_MS) })\n if (r.ok || r.status === 404) {\n // 404 \u4E5F\u7B97\u6D3B\u7740:clean \u8FC7\u6CE8\u5165\u6587\u4EF6\u65F6\u8DEF\u7531\u4E0D\u5B58\u5728,\u4F46 server \u672C\u8EAB\u5728\u6B63\u5E38\u5E72\u6D3B\n everOk = true\n fails = 0\n if (!current.ok) {\n current = { ok: true, lastOkAt: Date.now() }\n broadcast({ type: \"health\", ok: true })\n } else {\n current = { ok: true, lastOkAt: Date.now() }\n }\n return\n }\n failDetail = `SSR \u63A2\u6D4B\u8FD4\u56DE HTTP ${r.status}`\n } catch (err) {\n const e = err as { name?: string; cause?: { code?: string } }\n failDetail =\n e.name === \"TimeoutError\"\n ? `SSR \u63A2\u6D4B ${TIMEOUT_MS / 1000}s \u65E0\u54CD\u5E94`\n : `\u8FDE\u4E0D\u4E0A(${e.cause?.code ?? \"network\"})`\n }\n // \u4ECE\u672A\u6210\u529F\u8FC7\u5C31\u4E0D\u5224\u6B7B\u5211:\u51B7\u542F\u52A8/\u5927\u9879\u76EE\u9996\u7F16\u671F\u95F4\u7684\u5931\u8D25\u7531\u753B\u5E03\u9519\u8BEF\u5361\u8D1F\u8D23,\u4E0D\u5F52\u6A2A\u5E45\n if (!everOk) return\n fails++\n if (fails >= FAILS_TO_TRIP && current.ok) {\n current = { ok: false, detail: failDetail ?? \"\u672A\u77E5\", lastOkAt: current.lastOkAt }\n broadcast({ type: \"health\", ok: false, detail: current.detail })\n console.warn(`[contactsheet] \u26A0 \u76EE\u6807 ${cfg.target} \u7591\u4F3C\u50F5\u6B7B:${current.detail}(\u9759\u6001\u53EF\u80FD\u4ECD 200)\u3002\u753B\u5E03\u5DF2\u6302\u6A2A\u5E45\u3002`)\n }\n }\n\n timer = setInterval(() => void probe(), INTERVAL_MS)\n timer.unref()\n void probe()\n return {\n close() {\n if (timer) clearInterval(timer)\n },\n }\n}\n", "// SSE hub \u2014\u2014 \u6A21\u5757\u7EA7\u5355\u4F8B\u3002startServer \u7684\u8FD4\u56DE\u503C\u7B7E\u540D\u51BB\u7ED3,\u63A8\u4E8B\u4EF6\u8D70\u8FD9\u91CC\u5BFC\u51FA\u7684 broadcast\nimport type { IncomingMessage, ServerResponse } from \"node:http\"\nimport type { CsEvent } from \"../types.js\"\n\nconst clients = new Set<ServerResponse>()\nlet heartbeat: NodeJS.Timeout | null = null\n\n/** \u6302\u4E00\u4E2A SSE \u5BA2\u6237\u7AEF(GET /__cs/events) */\nexport function attach(req: IncomingMessage, res: ServerResponse): void {\n res.writeHead(200, {\n \"content-type\": \"text/event-stream; charset=utf-8\",\n \"cache-control\": \"no-cache, no-transform\",\n connection: \"keep-alive\",\n \"x-accel-buffering\": \"no\",\n })\n res.write(\": contactsheet connected\\n\\n\")\n clients.add(res)\n\n // \u65AD\u5F00\u5C31\u6E05\u5F15\u7528,\u6CA1\u4EBA\u4E86\u5C31\u505C\u5FC3\u8DF3\n const drop = () => {\n clients.delete(res)\n if (clients.size === 0) stopHeartbeat()\n }\n req.on(\"close\", drop)\n req.on(\"error\", drop)\n res.on(\"close\", drop)\n\n startHeartbeat()\n}\n\n/** \u63A8\u4E00\u6761\u4E8B\u4EF6:\u4E8B\u4EF6\u540D = type,data = \u6574\u4E2A CsEvent \u7684 JSON */\nexport function broadcast(ev: CsEvent): void {\n const chunk = `event: ${ev.type}\\ndata: ${JSON.stringify(ev)}\\n\\n`\n for (const res of clients) {\n try {\n res.write(chunk)\n } catch {\n clients.delete(res)\n }\n }\n}\n\n/** \u9000\u51FA\u65F6\u65AD\u5F00\u5168\u90E8\u5BA2\u6237\u7AEF(\u5426\u5219 server.close \u6C38\u8FDC\u7B49\u4E0D\u5230) */\nexport function closeAll(): void {\n for (const res of clients) {\n try {\n res.end()\n } catch {\n // \u5DF2\u7ECF\u65AD\u4E86,\u65E0\u6240\u8C13\n }\n }\n clients.clear()\n stopHeartbeat()\n}\n\nfunction startHeartbeat(): void {\n if (heartbeat) return\n // 15s \u4E00\u6761\u6CE8\u91CA\u884C,\u9632\u4E2D\u95F4\u5C42\u6390\u6389\u7A7A\u95F2\u8FDE\u63A5\n heartbeat = setInterval(() => {\n for (const res of clients) res.write(\": ping\\n\\n\")\n }, 15000)\n heartbeat.unref()\n}\n\nfunction stopHeartbeat(): void {\n if (!heartbeat) return\n clearInterval(heartbeat)\n heartbeat = null\n}\n", "// \u72B6\u6001:selection \u53EA\u5728\u5185\u5B58,annotations / refs \u843D\u76D8\u5230 <designDir>/.canvas/\nimport fs from \"node:fs/promises\"\nimport path from \"node:path\"\nimport type { Annotation, CsConfig, Selection } from \"../types.js\"\n\n// ---------- selection(\u5185\u5B58\u6001,\u8FDB\u7A0B\u9000\u51FA\u5373\u4E22) ----------\n\nlet selection: Selection | null = null\n\nexport function getSelection(): Selection | null {\n return selection\n}\n\nexport function setSelection(next: Selection | null): void {\n selection = next\n}\n\n// ---------- annotations ----------\n\nfunction canvasDir(cfg: CsConfig): string {\n return path.join(cfg.projectRoot, cfg.designDir, \".canvas\")\n}\n\nfunction annotationsFile(cfg: CsConfig): string {\n return path.join(canvasDir(cfg), \"annotations.json\")\n}\n\n/**\n * \u8BFB\u6279\u6CE8\u3002**\u6587\u4EF6\u4E0D\u5B58\u5728**\u624D\u662F\u7A7A\u8868;**\u5185\u5BB9\u574F\u4E86\u8981\u629B\u9519**\u2014\u2014\u4E0D\u80FD\u628A\u89E3\u6790\u5931\u8D25\u5F53\u6210\u7A7A\u8868,\n * \u5426\u5219\u8BFB-\u6539-\u5199\u4F1A\u62FF\u8FD9\u4E2A\u7A7A\u6570\u7EC4\u5F53\u57FA\u7EBF,\u4E0B\u4E00\u6B21\u9489 pin \u5C31\u628A\u6574\u4EFD\u5386\u53F2\u6C38\u4E45\u62B9\u6389\u3002\n * \u800C README \u660E\u786E\u9080\u8BF7 Claude Code \u624B\u6539\u8FD9\u4E2A\u6587\u4EF6,\u6539\u51FA\u7ED3\u6784\u504F\u5DEE\u662F\u5E38\u4E8B\u3002\n */\nexport async function readAnnotations(cfg: CsConfig): Promise<Annotation[]> {\n let raw: string\n try {\n raw = await fs.readFile(annotationsFile(cfg), \"utf8\")\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") return [] // \u8FD8\u6CA1\u6709\u6279\u6CE8,\u6B63\u5E38\n throw err\n }\n if (!raw.trim()) return []\n let list: unknown\n try {\n list = JSON.parse(raw)\n } catch (err) {\n throw new Error(\n `annotations.json \u89E3\u6790\u5931\u8D25(${(err as Error).message})\u3002\u4E3A\u907F\u514D\u8986\u76D6\u5386\u53F2\u5DF2\u62D2\u7EDD\u5199\u5165\u2014\u2014` +\n `\u8BF7\u4FEE\u597D ${annotationsFile(cfg)} \u518D\u8BD5\u3002`\n )\n }\n if (!Array.isArray(list)) {\n throw new Error(`annotations.json \u9876\u5C42\u4E0D\u662F\u6570\u7EC4,\u62D2\u7EDD\u5199\u5165\u4EE5\u514D\u8986\u76D6\u5386\u53F2:${annotationsFile(cfg)}`)\n }\n // \u65E7\u6570\u636E\u6CA1\u6709 seq:\u6309\u6587\u4EF6\u987A\u5E8F\u4ECE max+1 \u8D77\u8865(\u786E\u5B9A\u6027,\u91CD\u542F\u4E0D\u53D8\u53F7)\u3002\n // \u8FD9\u91CC\u53EA\u8865\u5185\u5B58\u91CC\u7684,\u4E0B\u4E00\u6B21\u4EFB\u4F55\u5199\u64CD\u4F5C\u4F1A\u968F\u6574\u8868\u843D\u76D8\n const anns = list as Annotation[]\n let next = anns.reduce((m, a) => Math.max(m, a.seq ?? 0), 0)\n for (const a of anns) if (typeof a.seq !== \"number\") a.seq = ++next\n return anns\n}\n\n/** \u539F\u5B50\u5199:\u4E34\u65F6\u6587\u4EF6 + rename;\u8986\u76D6\u524D\u7559\u4E00\u4EFD .bak(\u5386\u53F2\u662F\u8FD9\u4E2A\u5DE5\u5177\u552F\u4E00\u7684\u6301\u4E45\u8D44\u4EA7) */\nasync function writeAnnotations(cfg: CsConfig, list: Annotation[]): Promise<void> {\n const file = annotationsFile(cfg)\n await fs.mkdir(path.dirname(file), { recursive: true })\n await fs.copyFile(file, `${file}.bak`).catch(() => undefined) // \u9996\u6B21\u5199\u5165\u65F6\u6CA1\u6709\u65E7\u6587\u4EF6,\u6B63\u5E38\n const tmp = `${file}.${process.pid}.tmp`\n await fs.writeFile(tmp, JSON.stringify(list, null, 2) + \"\\n\", \"utf8\")\n await fs.rename(tmp, file)\n}\n\n// \u8BFB-\u6539-\u5199\u4E32\u884C\u5316,\u907F\u514D\u5E76\u53D1\u8BF7\u6C42\u4E92\u76F8\u8986\u76D6\nlet chain: Promise<unknown> = Promise.resolve()\n\n/** fn \u76F4\u63A5\u6539\u4F20\u5165\u7684\u6570\u7EC4;\u8FD4\u56DE fn \u7684\u7ED3\u679C + \u5199\u76D8\u540E\u7684\u5B8C\u6574\u8868(\u7ED9 SSE \u7528) */\nexport function updateAnnotations<T>(\n cfg: CsConfig,\n fn: (list: Annotation[]) => T\n): Promise<{ result: T; list: Annotation[] }> {\n const run = chain.then(async () => {\n const list = await readAnnotations(cfg)\n const result = fn(list)\n await writeAnnotations(cfg, list)\n return { result, list }\n })\n chain = run.catch(() => undefined)\n return run\n}\n\n/** id = \"a\" + \u65F6\u95F4\u6233 36 \u8FDB\u5236;\u540C\u6BEB\u79D2\u649E\u4E86\u5C31\u8FFD\u52A0\u5E8F\u53F7 */\nexport function newAnnotationId(list: Annotation[]): string {\n const base = \"a\" + Date.now().toString(36)\n let id = base\n for (let n = 1; list.some((a) => a.id === id); n++) id = base + n.toString(36)\n return id\n}\n\n// ---------- refs(\u8D34\u56FE) ----------\n\n/** \u5B58\u53C2\u8003\u56FE,\u8FD4\u56DE repo \u76F8\u5BF9\u8DEF\u5F84 */\nexport async function saveRef(cfg: CsConfig, name: string, dataBase64: string): Promise<string> {\n // \u53EA\u53D6\u6587\u4EF6\u540D\u90E8\u5206\u518D\u6E05\u6D17,\u9632\u8DEF\u5F84\u7A7F\u8D8A(../\u3001\u7EDD\u5BF9\u8DEF\u5F84\u3001\u5947\u602A\u5B57\u7B26\u5168\u6CA1\u4E86)\n const safe = path.basename(name).replace(/[^\\w.-]+/g, \"-\").replace(/^[.-]+/, \"\") || \"ref.png\"\n const day = new Date().toISOString().slice(0, 10)\n const dir = path.join(canvasDir(cfg), \"refs\")\n await fs.mkdir(dir, { recursive: true })\n\n // \u540C\u540D\u540C\u65E5\u518D\u649E\u5C31\u52A0\u5E8F\u53F7\n const ext = path.extname(safe)\n const stem = safe.slice(0, safe.length - ext.length)\n let filename = `${day}-${safe}`\n for (let n = 2; await exists(path.join(dir, filename)); n++) filename = `${day}-${stem}-${n}${ext}`\n\n // \u753B\u5E03 paste \u8FC7\u6765\u7684\u53EF\u80FD\u5E26 data URL \u5934\n const body = dataBase64.replace(/^data:[^;,]*;base64,/, \"\")\n await fs.writeFile(path.join(dir, filename), Buffer.from(body, \"base64\"))\n return `${cfg.designDir}/.canvas/refs/${filename}`\n}\n\n/** \u8BFB\u53C2\u8003\u56FE\u3002rel \u6765\u81EA URL,\u662F\u4E0D\u53EF\u4FE1\u8F93\u5165:\u5148 resolve \u518D\u6BD4\u524D\u7F00,`..` \u5DF2\u88AB\u6298\u53E0,\u62FC\u4E32\u9A97\u4E0D\u8FC7\u53BB */\nexport async function readRef(cfg: CsConfig, rel: string): Promise<{ body: Buffer; file: string } | null> {\n const root = path.join(canvasDir(cfg), \"refs\")\n const abs = path.resolve(cfg.projectRoot, rel)\n if (abs !== root && !abs.startsWith(root + path.sep)) return null\n try {\n return { body: await fs.readFile(abs), file: abs }\n } catch {\n return null // \u4E0D\u5B58\u5728 / \u662F\u76EE\u5F55 / \u6CA1\u6743\u9650,\u5BF9\u5916\u4E00\u5F8B 404\n }\n}\n\nasync function exists(p: string): Promise<boolean> {\n try {\n await fs.access(p)\n return true\n } catch {\n return false\n }\n}\n\n// ---------- \u7ED9\u7EC8\u7AEF hook \u7684\u4E0A\u4E0B\u6587\u6458\u8981 ----------\n\n/** open \u6279\u6CE8 + \u5F53\u524D selection \u7684\u4EBA\u7C7B\u53EF\u8BFB\u6458\u8981;\u90FD\u4E3A\u7A7A\u8FD4\u56DE\u7A7A\u4E32 */\nexport async function buildContextText(cfg: CsConfig): Promise<string> {\n const open = (await readAnnotations(cfg)).filter((a) => a.status === \"open\")\n const sel = getSelection()\n if (!sel && open.length === 0) return \"\"\n\n const lines = [\"## contactsheet \u753B\u5E03\u4E0A\u4E0B\u6587\"]\n if (sel) {\n lines.push(`\u5F53\u524D\u9009\u4E2D:\u753B\u677F ${sel.artboardId} \u00B7 \u9009\u62E9\u5668 \\`${sel.selector}\\` \u00B7 \u70B9\u4F4D ${fmt(sel.x)},${fmt(sel.y)}`)\n }\n if (open.length > 0) {\n lines.push(`\u672A\u89E3\u51B3\u6279\u6CE8(${open.length} \u6761):`)\n for (const a of open) {\n const where = [a.artboardId, a.anchor?.selector].filter(Boolean).join(\" @ \")\n // #seq \u4E0E\u5899\u4E0A pin \u5706\u70B9\u7684\u6570\u5B57\u4E00\u81F4(\u4EBA\u8BF4\"\u6279\u6CE8 3\"\u5C31\u662F\u5B83);\u65B9\u62EC\u53F7\u91CC\u7684 id \u7ED9 PATCH \u7528\n lines.push(`- #${a.seq} [${a.id}] ${where ? where + \" \u2014\u2014 \" : \"\"}${a.text}`)\n // \u7F16\u53F7\u4E0E\u6B63\u6587\u91CC\u7684 [\u56FE\u7247 n] \u5360\u4F4D\u7B26\u4E00\u4E00\u5BF9\u5E94:Claude \u770B\u5230 [\u56FE\u7247 2] \u5C31\u53BB\u4E0B\u9762\u627E \u56FE\u7247 2 \u7684\u8DEF\u5F84\n ;(a.refs ?? []).forEach((ref, i) => lines.push(` \u56FE\u7247 ${i + 1}:${ref}`))\n }\n }\n return lines.join(\"\\n\") + \"\\n\"\n}\n\nfunction fmt(n: number): string {\n return typeof n === \"number\" && Number.isFinite(n) ? n.toFixed(2) : \"?\"\n}\n", "// \u4EE3\u7406\u9519\u8BEF\u65E5\u5FD7\u7684\u53BB\u91CD+\u9650\u6D41\u3002\n// next dev \u6302\u6389\u6216\u91CD\u542F\u65F6,\u6D4F\u89C8\u5668\u91CC Next \u7684 HMR \u5BA2\u6237\u7AEF\u4F1A\u75AF\u72C2\u91CD\u8FDE,\u6BCF\u6B21\u5E26\u4E00\u4E2A\u65B0\u7684 ?id= \u2014\u2014\n// \u9010\u6761\u6253\u5370\u5C31\u662F\u4E00\u79D2\u51E0\u5341\u884C,\u771F\u6B63\u7684\u9519\u8BEF\u5168\u88AB\u51B2\u8D70\u3002\u8FD9\u91CC\u628A\u540C\u7C7B\u5931\u8D25\u538B\u6210\u4E00\u6761,\u5E76\u628A\"\u76EE\u6807\u6574\u4E2A\u8FDE\u4E0D\u4E0A\"\n// \u5355\u72EC\u62CE\u51FA\u6765\u8BF4\u4E00\u53E5\u4EBA\u8BDD\u3002\n\nimport { dim, green, red, yellow } from \"../term.js\"\n\n/** \u540C\u7C7B\u5931\u8D25\u7684\u5408\u5E76\u7A97\u53E3 */\nconst WINDOW_MS = 5000\n\nexport interface ProxyLog {\n /** \u8BB0\u4E00\u6B21\u4EE3\u7406\u5931\u8D25(http \u4E0E ws \u5171\u7528),\u81EA\u884C\u51B3\u5B9A\u6253\u4E0D\u6253 */\n fail(err: NodeJS.ErrnoException, url: string | undefined): void\n /** \u76EE\u6807\u6709\u56DE\u5305(http \u54CD\u5E94 / ws \u63E1\u624B\u6210\u529F)\u2014\u2014 \u6D3B\u7740 */\n alive(): void\n /** \u9000\u51FA\u65F6\u6E05\u6389\u6302\u8D77\u7684\u7A97\u53E3\u5B9A\u65F6\u5668 */\n close(): void\n}\n\nexport function createProxyLog(target: string): ProxyLog {\n // key = \u9519\u8BEF\u7801 + \u53BB\u6389\u67E5\u8BE2\u4E32\u7684\u8DEF\u5F84;\u7A97\u53E3\u5185\u9996\u6761\u76F4\u63A5\u6253,\u5176\u4F59\u53EA\u8BA1\u6570\n const windows = new Map<string, { extra: number; timer: NodeJS.Timeout }>()\n let down = false // \u76EE\u6807\u6574\u4F53\u4E0D\u53EF\u8FBE(ECONNREFUSED)\n let silenced = 0 // \u4E0D\u53EF\u8FBE\u671F\u95F4\u538B\u6389\u7684\u5931\u8D25\u6B21\u6570\n\n return {\n fail(err, url) {\n const code = err.code ?? err.message\n\n // \u76EE\u6807\u6CA1\u8D77:\u7B2C\u4E00\u6B21\u8BF4\u4E00\u53E5\u6709\u7528\u7684,\u4E4B\u540E\u95ED\u5634\u5230\u6062\u590D\u4E3A\u6B62\u3002HMR \u91CD\u8FDE\u7684\u6D2A\u6C34\u7EDD\u5927\u591A\u6570\u662F\u8FD9\u4E00\u652F\n if (code === \"ECONNREFUSED\") {\n if (down) {\n silenced++\n return\n }\n down = true\n console.error(\n `${yellow(\"\u26A0\")} ${yellow(`\u76EE\u6807 ${target} \u8FDE\u4E0D\u4E0A\u4E86`)} \u2014\u2014 \u8D77 next dev \u540E\u4F1A\u81EA\u52A8\u6062\u590D(\u753B\u5E03\u4F1A\u81EA\u5DF1\u91CD\u8BD5)\u3002` +\n dim(\"\u671F\u95F4\u7684\u4EE3\u7406\u5931\u8D25\u4E0D\u518D\u9010\u6761\u6253\u5370\u3002\")\n )\n return\n }\n\n const key = `${code} ${pathOf(url)}`\n const win = windows.get(key)\n if (win) {\n win.extra++\n return\n }\n console.error(`${red(\"\u2716\")} \u4EE3\u7406\u5931\u8D25 ${pathOf(url)} ${red(String(code))}`)\n const timer = setTimeout(() => {\n const extra = windows.get(key)?.extra ?? 0\n windows.delete(key)\n if (extra > 0) {\n console.error(dim(` (\u8FC7\u53BB ${WINDOW_MS / 1000} \u79D2\u8FD8\u6709 ${extra} \u6B21\u540C\u7C7B\u5931\u8D25:${key})`))\n }\n }, WINDOW_MS)\n timer.unref()\n windows.set(key, { extra: 0, timer })\n },\n\n alive() {\n if (!down) return\n down = false\n const n = silenced\n silenced = 0\n console.log(`${green(\"\u2713\")} ${green(`\u76EE\u6807 ${target} \u5DF2\u6062\u590D`)}${n > 0 ? dim(`(\u4E0D\u53EF\u8FBE\u671F\u95F4\u538B\u6389 ${n} \u6761\u4EE3\u7406\u5931\u8D25)`) : \"\"}`)\n },\n\n close() {\n for (const win of windows.values()) clearTimeout(win.timer)\n windows.clear()\n },\n }\n}\n\n/** \u53BB\u6389\u67E5\u8BE2\u4E32:HMR \u91CD\u8FDE\u6BCF\u6B21\u5E26\u65B0\u7684 ?id=,\u4E0D\u53BB\u6389\u5C31\u6C38\u8FDC\u5408\u5E76\u4E0D\u5230\u4E00\u8D77 */\nfunction pathOf(url: string | undefined): string {\n if (!url) return \"(\u65E0 url)\"\n const q = url.indexOf(\"?\")\n return q < 0 ? url : url.slice(0, q)\n}\n", "// ============================================================\n// [Agent B] \u753B\u677F\u6587\u4EF6 watcher \u2014\u2014 \u53D8\u66F4 \u2192 \u91CD\u5EFA registry \u2192 \u56DE\u8C03\n// \u7B7E\u540D\u51BB\u7ED3,\u89C1 CONTRACTS.md\n// ============================================================\nimport path from \"node:path\"\nimport { watch } from \"chokidar\"\nimport type { CsConfig, RegistryEntry } from \"../types.js\"\nimport { regenerateRegistry } from \"../inject/index.js\"\n\n/** \u8FDE\u7EED\u53D8\u66F4\u5408\u5E76\u6210\u4E00\u6B21\u91CD\u5EFA */\nconst DEBOUNCE_MS = 200\n\nfunction isArtboard(p: string): boolean {\n return /\\.artboard\\.tsx?$/.test(p)\n}\n\nexport async function startWatcher(\n cfg: CsConfig,\n onChange: (entries: RegistryEntry[]) => void\n): Promise<{ close(): Promise<void> }> {\n const designAbs = path.join(cfg.projectRoot, cfg.designDir.replace(/\\\\/g, \"/\").replace(/\\/+$/, \"\"))\n let timer: ReturnType<typeof setTimeout> | null = null\n let closed = false\n\n const flush = () => {\n timer = null\n regenerateRegistry(cfg)\n .then((entries) => {\n if (!closed) onChange(entries)\n })\n .catch((err) => {\n console.error(\"[contactsheet] \u91CD\u5EFA registry \u5931\u8D25:\", err)\n })\n }\n const schedule = () => {\n if (closed) return\n if (timer) clearTimeout(timer)\n timer = setTimeout(flush, DEBOUNCE_MS)\n }\n\n const watcher = watch(designAbs, {\n ignoreInitial: false, // \u9996\u6B21\u4E5F\u7B97\u4E00\u6B21\u53D8\u66F4\n ignored: (p: string) => {\n const rel = path.relative(designAbs, p)\n if (!rel) return false\n // \u751F\u6210\u7269\u4E0E\u753B\u5E03\u6570\u636E\u4E0D\u53C2\u4E0E\u76D1\u542C\n return rel.split(path.sep).some((seg) => seg === \"__generated__\" || seg === \".canvas\" || seg === \"node_modules\")\n },\n })\n watcher.on(\"add\", (p) => isArtboard(p) && schedule())\n watcher.on(\"change\", (p) => isArtboard(p) && schedule())\n watcher.on(\"unlink\", (p) => isArtboard(p) && schedule())\n watcher.on(\"error\", (err) => console.error(\"[contactsheet] watcher \u51FA\u9519:\", err))\n\n // design \u76EE\u5F55\u4E3A\u7A7A\u6216\u4E0D\u5B58\u5728\u65F6\u4E5F\u8981\u7ED9\u4E00\u6B21\u521D\u59CB\u56DE\u8C03\n schedule()\n\n return {\n async close() {\n closed = true\n if (timer) {\n clearTimeout(timer)\n timer = null\n }\n await watcher.close()\n },\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["fs", "path", "path", "fs", "text", "DEFAULT_TARGET", "DEFAULT_PORT", "DEFAULT_DESIGN_DIR", "detectAppDir", "fs", "text", "selection", "path", "fs", "path", "fs", "path", "resolve", "ok", "text", "broadcast", "fs", "path", "ok", "text", "resolve", "fs", "main", "pid", "path", "path"]
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "contactsheet",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "把你 UI 的各种状态摊在一面可缩放的墙上 —— 附着在 Next.js repo 上的联络表",
5
5
  "license": "MIT",
6
6
  "type": "module",