@nick848/fet 0.1.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +101 -44
- package/dist/chunk-FZOVNHE7.js +104 -0
- package/dist/chunk-FZOVNHE7.js.map +1 -0
- package/dist/cli/index.js +1795 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/package.json +43 -49
- package/dist/apply.d.ts +0 -1
- package/dist/apply.js +0 -172
- package/dist/approval.d.ts +0 -2
- package/dist/approval.js +0 -26
- package/dist/atomic-write.d.ts +0 -5
- package/dist/atomic-write.js +0 -41
- package/dist/cli.d.ts +0 -2
- package/dist/cli.js +0 -178
- package/dist/doctor.d.ts +0 -1
- package/dist/doctor.js +0 -93
- package/dist/fingerprint.d.ts +0 -6
- package/dist/fingerprint.js +0 -77
- package/dist/hooks.d.ts +0 -12
- package/dist/hooks.js +0 -47
- package/dist/init.d.ts +0 -4
- package/dist/init.js +0 -47
- package/dist/opencode-skills.d.ts +0 -3
- package/dist/opencode-skills.js +0 -236
- package/dist/openspec.d.ts +0 -16
- package/dist/openspec.js +0 -73
- package/dist/paths.d.ts +0 -9
- package/dist/paths.js +0 -20
- package/dist/prompt.d.ts +0 -4
- package/dist/prompt.js +0 -30
- package/dist/scanner.d.ts +0 -23
- package/dist/scanner.js +0 -352
- package/dist/skills.d.ts +0 -3
- package/dist/skills.js +0 -142
- package/dist/state.d.ts +0 -17
- package/dist/state.js +0 -126
- package/dist/tasks.d.ts +0 -13
- package/dist/tasks.js +0 -69
- package/dist/types.d.ts +0 -38
- package/dist/types.js +0 -1
- package/dist/validate.d.ts +0 -1
- package/dist/validate.js +0 -150
- package/dist/verify.d.ts +0 -6
- package/dist/verify.js +0 -193
- package/dist/watch-paths.d.ts +0 -2
- package/dist/watch-paths.js +0 -70
- package/dist/workflow-hints.d.ts +0 -2
- package/dist/workflow-hints.js +0 -9
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/cli/index.ts","../../src/commands/init.ts","../../src/fs/atomic-write.ts","../../src/fs/backup.ts","../../src/fs/lock.ts","../../src/fs/journal.ts","../../src/version.ts","../../src/templates/markers.ts","../../src/templates/agents-md.ts","../../src/templates/config-yaml.ts","../../src/templates/verify-instructions.ts","../../src/templates/gitignore.ts","../../src/commands/update-context.ts","../../src/config/yaml.ts","../../src/commands/doctor.ts","../../src/state/project.ts","../../src/state/store.ts","../../src/state/schema.ts","../../src/state/tasks.ts","../../src/commands/proxy.ts","../../src/commands/verify.ts","../../src/cli/context.ts","../../src/adapters/cursor/index.ts","../../src/adapters/cursor/templates.ts","../../src/openspec/adapter.ts","../../src/openspec/inspector.ts","../../src/openspec/resolver.ts","../../src/openspec/runner.ts","../../src/scanner/package.ts","../../src/scanner/routes.ts","../../src/scanner/index.ts","../../src/cli/output.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { initCommand } from \"../commands/init.js\";\nimport { doctorCommand } from \"../commands/doctor.js\";\nimport { proxyCommand, passthroughCommand } from \"../commands/proxy.js\";\nimport { updateContextCommand } from \"../commands/update-context.js\";\nimport { verifyCommand } from \"../commands/verify.js\";\nimport { toFetError } from \"../errors/fet-error.js\";\nimport { FET_VERSION } from \"../version.js\";\nimport { createCommandContext, type GlobalOptions } from \"./context.js\";\nimport { OutputWriter } from \"./output.js\";\n\nconst program = new Command();\n\nprogram\n .name(\"fet\")\n .description(\"Frontend workflow orchestration tool built around OpenSpec.\")\n .enablePositionalOptions()\n .version(FET_VERSION)\n .option(\"--cwd <path>\", \"指定项目根目录\")\n .option(\"--change <id>\", \"指定 OpenSpec change\")\n .option(\"--yes\", \"对低风险确认使用默认同意\")\n .option(\"--json\", \"输出机器可读 JSON\")\n .option(\"--verbose\", \"输出诊断细节\")\n .option(\"--no-color\", \"禁用终端颜色\");\n\naddGlobalOptions(program.command(\"init\")).description(\"初始化 FET + OpenSpec\").action(wrap(\"init\", initCommand));\naddGlobalOptions(program.command(\"update-context\")).description(\"更新项目上下文\").action(wrap(\"update-context\", updateContextCommand));\naddGlobalOptions(program\n .command(\"doctor\")\n .description(\"诊断状态、配置与一致性\")\n .option(\"--fix-lock\", \"清理 FET 锁文件\"))\n .action(\n wrap(\"doctor\", (ctx, options: { fixLock?: boolean }) => doctorCommand(ctx, { fixLock: Boolean(options.fixLock) }))\n );\n\naddGlobalOptions(program\n .command(\"verify\")\n .description(\"最终质量验证\")\n .option(\"--done\", \"声明手动验证已完成\")\n .option(\"--auto\", \"生成或执行自动验证计划\"))\n .action(wrap(\"verify\", verifyCommand));\n\nfor (const command of [\"explore\", \"propose\", \"new\", \"continue\", \"ff\", \"apply\", \"sync\", \"archive\", \"bulk-archive\", \"onboard\"]) {\n addGlobalOptions(program\n .command(`${command} [args...]`)\n .description(`代理执行 openspec ${command}`)\n .allowUnknownOption(true)\n .passThroughOptions())\n .action(wrap(command, (ctx, args: string[] = []) => proxyCommand(ctx, command, args)));\n}\n\naddGlobalOptions(program\n .command(\"passthrough <command> [args...]\")\n .description(\"透传暂未接管的 OpenSpec 命令\")\n .allowUnknownOption(true)\n .passThroughOptions())\n .action(wrap(\"passthrough\", (ctx, command: string, args: string[] = []) => passthroughCommand(ctx, command, args)));\n\nprogram.parseAsync(process.argv).catch((error) => {\n const json = process.argv.includes(\"--json\");\n const output = new OutputWriter(json);\n const fetError = toFetError(error);\n output.error(fetError);\n process.exitCode = fetError.exitCode;\n});\n\nfunction wrap<T extends unknown[]>(\n command: string,\n handler: (ctx: Awaited<ReturnType<typeof createCommandContext>>, ...args: T) => Promise<void>\n) {\n return async (...args: T) => {\n const maybeCommand = args[args.length - 1] as unknown;\n const opts = isCommandLike(maybeCommand)\n ? ({ ...(maybeCommand.parent?.opts() as GlobalOptions), ...(maybeCommand.opts() as GlobalOptions) } as GlobalOptions)\n : (program.opts() as GlobalOptions);\n const ctx = await createCommandContext(command, { ...opts, ...extractGlobalOptions(args) });\n try {\n await handler(ctx, ...args);\n } catch (error) {\n const fetError = toFetError(error);\n ctx.output.error(fetError);\n process.exitCode = fetError.exitCode;\n }\n };\n}\n\nfunction isCommandLike(value: unknown): value is Command {\n return value instanceof Command;\n}\n\nfunction addGlobalOptions(command: Command): Command {\n return command\n .option(\"--cwd <path>\", \"指定项目根目录\")\n .option(\"--change <id>\", \"指定 OpenSpec change\")\n .option(\"--yes\", \"对低风险确认使用默认同意\")\n .option(\"--json\", \"输出机器可读 JSON\")\n .option(\"--verbose\", \"输出诊断细节\")\n .option(\"--no-color\", \"禁用终端颜色\");\n}\n\nfunction extractGlobalOptions(args: unknown[]): GlobalOptions {\n const values = args.flatMap((arg) => (Array.isArray(arg) ? arg : []));\n const options: GlobalOptions = {};\n for (let index = 0; index < values.length; index += 1) {\n const value = values[index];\n if (typeof value !== \"string\") {\n continue;\n }\n if (value === \"--cwd\" && typeof values[index + 1] === \"string\") {\n options.cwd = values[index + 1];\n index += 1;\n } else if (value.startsWith(\"--cwd=\")) {\n options.cwd = value.slice(\"--cwd=\".length);\n } else if (value === \"--change\" && typeof values[index + 1] === \"string\") {\n options.change = values[index + 1];\n index += 1;\n } else if (value.startsWith(\"--change=\")) {\n options.change = value.slice(\"--change=\".length);\n } else if (value === \"--yes\") {\n options.yes = true;\n } else if (value === \"--json\") {\n options.json = true;\n } else if (value === \"--verbose\") {\n options.verbose = true;\n }\n }\n return options;\n}\n","import { readFile, stat } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport type { FetCommandContext } from \"../cli/context.js\";\nimport { atomicWrite, createInitJournal, withProjectLock, writeInitJournal } from \"../fs/index.js\";\nimport { mergeGitignore } from \"../templates/index.js\";\nimport { updateContextFiles } from \"./update-context.js\";\n\nexport async function initCommand(ctx: FetCommandContext): Promise<void> {\n const alreadyInitialized = await exists(join(ctx.projectRoot, \"openspec\", \"config.yaml\"));\n await withProjectLock(\n ctx.projectRoot,\n { command: \"init\", cwd: ctx.cwd, fetVersion: ctx.fetVersion },\n async () => {\n const journal = createInitJournal(ctx.fetVersion);\n await writeInitJournal(ctx.projectRoot, journal);\n\n const identity = await ctx.openSpec.resolveExecutable();\n if (!alreadyInitialized) {\n const result = await ctx.openSpec.run(\"init\", [\"--tools\", \"none\"], { cwd: ctx.projectRoot, stdio: \"inherit\" });\n if (result.exitCode !== 0) {\n process.exitCode = result.exitCode;\n return;\n }\n }\n\n const contextResult = await updateContextFiles(ctx);\n await ensureGitignore(ctx);\n\n const state = await ctx.stateStore.getOrCreateGlobal();\n state.openspec = identity;\n\n for (const adapter of ctx.toolAdapters) {\n const plan = await adapter.planInstall(ctx.projectRoot);\n const result = await adapter.install(ctx.projectRoot, plan, ctx.yes);\n state.toolAdapters[adapter.tool] = {\n adapterVersion: adapter.adapterVersion,\n installed: true,\n updatedAt: new Date().toISOString()\n };\n journal.steps.push(...result.written.map((path) => ({ operation: \"write\" as const, path, status: \"done\" as const })));\n }\n\n journal.completedAt = new Date().toISOString();\n await writeInitJournal(ctx.projectRoot, journal);\n await ctx.stateStore.writeGlobal(state);\n for (const warning of contextResult.warnings) {\n ctx.output.warn(warning);\n }\n }\n );\n\n ctx.output.result({\n ok: true,\n command: \"init\",\n summary: \"FET 初始化完成。\",\n nextSteps: [\"使用 fet propose/new 创建 OpenSpec change\", \"使用 fet doctor 检查项目状态\"]\n });\n}\n\nasync function ensureGitignore(ctx: FetCommandContext): Promise<void> {\n const gitignorePath = join(ctx.projectRoot, \".gitignore\");\n const existing = await readOptional(gitignorePath);\n await atomicWrite(gitignorePath, mergeGitignore(existing));\n}\n\nasync function readOptional(path: string): Promise<string | null> {\n try {\n return await readFile(path, \"utf8\");\n } catch {\n return null;\n }\n}\n\nasync function exists(path: string): Promise<boolean> {\n try {\n await stat(path);\n return true;\n } catch {\n return false;\n }\n}\n","import { dirname } from \"node:path\";\nimport { open, rename, mkdir } from \"node:fs/promises\";\n\nexport interface AtomicWriteResult {\n path: string;\n tempPath: string;\n}\n\nexport async function atomicWrite(\n targetPath: string,\n content: string | Uint8Array\n): Promise<AtomicWriteResult> {\n await mkdir(dirname(targetPath), { recursive: true });\n const tempPath = `${targetPath}.tmp-${process.pid}-${Date.now()}`;\n const handle = await open(tempPath, \"wx\");\n\n try {\n await handle.writeFile(content);\n await handle.sync();\n } finally {\n await handle.close();\n }\n\n await rename(tempPath, targetPath);\n return { path: targetPath, tempPath };\n}\n","import { copyFile, stat } from \"node:fs/promises\";\nimport { basename, dirname, join } from \"node:path\";\n\nexport async function createBackup(filePath: string): Promise<string | null> {\n try {\n await stat(filePath);\n } catch {\n return null;\n }\n\n const timestamp = new Date()\n .toISOString()\n .replace(/[-:]/g, \"\")\n .replace(/\\..+$/, \"\")\n .replace(\"T\", \"-\");\n const backupPath = join(dirname(filePath), `${basename(filePath)}.fet-backup-${timestamp}`);\n await copyFile(filePath, backupPath);\n return backupPath;\n}\n","import { hostname } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { mkdir, open, readFile, rm } from \"node:fs/promises\";\nimport { ErrorCode } from \"../errors/codes.js\";\nimport { FetError } from \"../errors/fet-error.js\";\n\nexport interface LockMetadata {\n command: string;\n cwd: string;\n fetVersion: string;\n}\n\ninterface LockFile {\n pid: number;\n hostname: string;\n cwd: string;\n command: string;\n startedAt: string;\n fetVersion: string;\n}\n\nexport async function withProjectLock<T>(\n projectRoot: string,\n metadata: LockMetadata,\n fn: () => Promise<T>\n): Promise<T> {\n const lockPath = join(projectRoot, \"openspec\", \".fet.lock\");\n const lock: LockFile = {\n pid: process.pid,\n hostname: hostname(),\n cwd: metadata.cwd,\n command: metadata.command,\n startedAt: new Date().toISOString(),\n fetVersion: metadata.fetVersion\n };\n\n let handle;\n try {\n await mkdir(dirname(lockPath), { recursive: true });\n handle = await open(lockPath, \"wx\");\n await handle.writeFile(JSON.stringify(lock, null, 2));\n } catch {\n throw new FetError({\n code: ErrorCode.LockHeld,\n message: \"另一个 FET 写命令正在运行\",\n details: await readExistingLock(lockPath),\n suggestedCommand: \"fet doctor --fix-lock\"\n });\n } finally {\n await handle?.close();\n }\n\n try {\n return await fn();\n } finally {\n await rm(lockPath, { force: true });\n }\n}\n\nasync function readExistingLock(lockPath: string): Promise<unknown> {\n try {\n return JSON.parse(await readFile(lockPath, \"utf8\"));\n } catch {\n return { path: lockPath };\n }\n}\n\nexport async function clearLock(projectRoot: string): Promise<boolean> {\n const lockPath = join(projectRoot, \"openspec\", \".fet.lock\");\n try {\n await rm(lockPath);\n return true;\n } catch {\n return false;\n }\n}\n","import { join } from \"node:path\";\nimport { readFile } from \"node:fs/promises\";\nimport { atomicWrite } from \"./atomic-write.js\";\n\nexport interface JournalStep {\n operation: \"write\" | \"backup\" | \"mkdir\" | \"skip\";\n path: string;\n backupPath?: string | null;\n status: \"done\" | \"failed\" | \"skipped\";\n message?: string;\n}\n\nexport interface InitJournal {\n schemaVersion: 1;\n startedAt: string;\n completedAt: string | null;\n fetVersion: string;\n steps: JournalStep[];\n}\n\nexport function createInitJournal(fetVersion: string): InitJournal {\n return {\n schemaVersion: 1,\n startedAt: new Date().toISOString(),\n completedAt: null,\n fetVersion,\n steps: []\n };\n}\n\nexport async function writeInitJournal(projectRoot: string, journal: InitJournal): Promise<void> {\n await atomicWrite(\n join(projectRoot, \"openspec\", \".fet-init-journal.json\"),\n `${JSON.stringify(journal, null, 2)}\\n`\n );\n}\n\nexport async function readInitJournal(projectRoot: string): Promise<InitJournal | null> {\n try {\n return JSON.parse(await readFile(join(projectRoot, \"openspec\", \".fet-init-journal.json\"), \"utf8\"));\n } catch {\n return null;\n }\n}\n","export const FET_VERSION = \"0.3.0-dev\";\n","export const AUTO_BEGIN = \"<!-- FET:BEGIN AUTO -->\";\nexport const AUTO_END = \"<!-- FET:END AUTO -->\";\nexport const USER_BEGIN = \"<!-- FET:BEGIN USER -->\";\nexport const USER_END = \"<!-- FET:END USER -->\";\n\nexport function hasManagedAutoRegion(content: string): boolean {\n return count(content, AUTO_BEGIN) === 1 && count(content, AUTO_END) === 1 && content.indexOf(AUTO_BEGIN) < content.indexOf(AUTO_END);\n}\n\nexport function hasInvalidManagedAutoRegion(content: string): boolean {\n const beginCount = count(content, AUTO_BEGIN);\n const endCount = count(content, AUTO_END);\n return beginCount !== endCount || beginCount > 1 || endCount > 1 || (beginCount === 1 && content.indexOf(AUTO_BEGIN) > content.indexOf(AUTO_END));\n}\n\nexport function replaceManagedRegion(existing: string | null, generated: string): string {\n if (!existing) {\n return generated;\n }\n\n const start = existing.indexOf(AUTO_BEGIN);\n const end = existing.indexOf(AUTO_END);\n if (start === -1 || end === -1 || end < start) {\n return generated;\n }\n\n const before = existing.slice(0, start);\n const after = existing.slice(end + AUTO_END.length);\n const generatedAuto = extractAuto(generated);\n return `${before}${AUTO_BEGIN}\\n${generatedAuto}\\n${AUTO_END}${after}`;\n}\n\nfunction extractAuto(content: string): string {\n const start = content.indexOf(AUTO_BEGIN);\n const end = content.indexOf(AUTO_END);\n if (start === -1 || end === -1 || end < start) {\n return content.trim();\n }\n return content.slice(start + AUTO_BEGIN.length, end).trim();\n}\n\nfunction count(content: string, needle: string): number {\n return content.split(needle).length - 1;\n}\n","import type { ProjectScanResult } from \"../scanner/index.js\";\nimport { FET_VERSION } from \"../version.js\";\nimport { AUTO_BEGIN, AUTO_END, USER_BEGIN, USER_END } from \"./markers.js\";\n\nexport function renderAgentsMd(scan: ProjectScanResult): string {\n const commands = Object.entries(scan.commands)\n .map(([name, command]) => `| ${name} | \\`${command.command}\\` | ${command.source} |`)\n .join(\"\\n\");\n const routes = scan.routes\n .map((route) => `| ${route.path} | ${route.source} | ${route.confidence}${route.inferred ? \" inferred\" : \"\"} |`)\n .join(\"\\n\");\n const workspaces = scan.project.workspaces.map((workspace) => `| ${workspace.name} | ${workspace.path} | ${workspace.source} |`).join(\"\\n\");\n\n return `# Project Context\n\n${AUTO_BEGIN}\n## Project Snapshot\n\n- Name: ${scan.project.name}\n- Package Manager: ${scan.project.packageManager} (${scan.project.packageManagerConfidence})\n- Framework: ${scan.project.framework.name} (${scan.project.framework.confidence})\n- Language: ${scan.project.language}\n- Monorepo: ${scan.project.monorepo ? \"yes\" : \"no\"}\n\n## Workspaces\n\n| Name | Path | Source |\n|------|------|--------|\n${workspaces || \"| root | . | inferred |\"}\n\n## Commands\n\n| Name | Command | Source |\n|------|---------|--------|\n${commands || \"| [NEEDS LLM INPUT] | [NEEDS LLM INPUT] | [NEEDS LLM INPUT] |\"}\n\n## Structure\n\n[NEEDS LLM INPUT]\n\n## Routes\n\n| Route | Source | Confidence |\n|-------|--------|------------|\n${routes || \"| [NEEDS LLM INPUT] | [NEEDS LLM INPUT] | low |\"}\n\n## Conventions\n\n[NEEDS LLM INPUT]\n\n## Scanner Metadata\n\n- Generated At: ${scan.generatedAt}\n- FET Version: ${FET_VERSION}\n- Scanner Version: ${scan.scannerVersion}\n- Warnings: ${scan.warnings.length ? scan.warnings.join(\"; \") : \"none\"}\n${AUTO_END}\n\n${USER_BEGIN}\n## Notes For AI\n\n[NEEDS LLM INPUT]\n${USER_END}\n`;\n}\n","import { stringify } from \"yaml\";\nimport type { ProjectScanResult } from \"../scanner/index.js\";\nimport { FET_VERSION } from \"../version.js\";\n\nexport function renderFetConfig(scan: ProjectScanResult): string {\n return stringify({\n fet: {\n schemaVersion: 1,\n generatedAt: scan.generatedAt,\n fetVersion: FET_VERSION,\n scannerVersion: scan.scannerVersion,\n project: {\n packageManager: scan.project.packageManager,\n packageManagerConfidence: scan.project.packageManagerConfidence,\n framework: scan.project.framework,\n language: scan.project.language,\n monorepo: scan.project.monorepo,\n workspaces: scan.project.workspaces\n },\n commands: scan.commands,\n validation: {\n monorepo: scan.project.monorepo,\n missing: {\n lint: \"warn\",\n typecheck: \"warn\",\n test: \"warn\"\n },\n workspaces: scan.project.workspaces\n }\n }\n });\n}\n","import { FET_VERSION } from \"../version.js\";\n\nexport function renderVerifyInstructions(changeId: string, generatedAt = new Date().toISOString()): string {\n return `---\nschemaVersion: 1\nfetVersion: ${FET_VERSION}\ngeneratedAt: ${generatedAt}\nchangeId: ${changeId}\npurpose: manual-verify\n---\n\n# Verify Instructions\n\n请按顺序完成以下检查:\n\n1. 运行 OpenSpec 规范校验:\\`openspec verify\\`\n2. 按项目约定运行 lint、typecheck、test。\n3. 检查本次 change 的 \\`tasks.md\\` 是否与实现状态一致。\n\n完成后运行:\n\n\\`\\`\\`sh\nfet verify --done --change ${changeId}\n\\`\\`\\`\n`;\n}\n","const BEGIN = \"# FET:BEGIN LOCAL STATE\";\nconst END = \"# FET:END LOCAL STATE\";\n\nconst RULES = [\n \"openspec/fet-state.json\",\n \"openspec/.fet.lock\",\n \"openspec/.fet-init-journal.json\",\n \"openspec/changes/*/fet-state.json\",\n \"openspec/changes/*/.fet/\"\n];\n\nexport function mergeGitignore(existing: string | null): string {\n const block = `${BEGIN}\\n${RULES.join(\"\\n\")}\\n${END}`;\n if (!existing || !existing.trim()) {\n return `${block}\\n`;\n }\n\n const start = existing.indexOf(BEGIN);\n const end = existing.indexOf(END);\n if (start !== -1 && end !== -1 && end > start) {\n return `${existing.slice(0, start)}${block}${existing.slice(end + END.length)}`;\n }\n\n return `${existing.replace(/\\s*$/, \"\")}\\n\\n${block}\\n`;\n}\n","import { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { mergeFetConfig } from \"../config/index.js\";\nimport { atomicWrite, createBackup, withProjectLock } from \"../fs/index.js\";\nimport { ErrorCode } from \"../errors/codes.js\";\nimport { FetError } from \"../errors/fet-error.js\";\nimport { hasInvalidManagedAutoRegion, hasManagedAutoRegion, renderAgentsMd, renderFetConfig, replaceManagedRegion } from \"../templates/index.js\";\nimport type { FetCommandContext } from \"../cli/context.js\";\n\nexport async function updateContextCommand(ctx: FetCommandContext): Promise<void> {\n await withProjectLock(\n ctx.projectRoot,\n { command: \"update-context\", cwd: ctx.cwd, fetVersion: ctx.fetVersion },\n async () => updateContextFiles(ctx)\n );\n\n ctx.output.result({\n ok: true,\n command: \"update-context\",\n summary: \"已更新 AGENTS.md 与 openspec/config.yaml 的 FET 托管区域。\"\n });\n}\n\nexport async function updateContextFiles(ctx: FetCommandContext): Promise<{ warnings: string[] }> {\n const scan = await ctx.scanner.scan(ctx.projectRoot, {});\n const agentsPath = join(ctx.projectRoot, \"AGENTS.md\");\n const configPath = join(ctx.projectRoot, \"openspec\", \"config.yaml\");\n\n const existingAgents = await readOptional(agentsPath);\n const warnings = [...scan.warnings];\n if (existingAgents && hasInvalidManagedAutoRegion(existingAgents)) {\n throw new FetError({\n code: ErrorCode.ConfigInvalid,\n message: \"AGENTS.md 的 FET 托管标记损坏或重复\",\n details: { path: \"AGENTS.md\" },\n suggestedCommand: \"手动修复 FET:BEGIN AUTO / FET:END AUTO 标记后重试\"\n });\n }\n if (existingAgents && !hasManagedAutoRegion(existingAgents)) {\n if (!ctx.yes) {\n throw new FetError({\n code: ErrorCode.ToolAdapterConflict,\n message: \"AGENTS.md 已存在且不包含 FET 托管区域\",\n details: { path: \"AGENTS.md\" },\n suggestedCommand: \"确认可备份并替换后运行 fet update-context --yes\"\n });\n }\n const backupPath = await createBackup(agentsPath);\n if (backupPath) {\n warnings.push(`已备份非托管 AGENTS.md 到 ${backupPath}`);\n }\n }\n await atomicWrite(agentsPath, replaceManagedRegion(existingAgents, renderAgentsMd(scan)));\n await atomicWrite(configPath, await mergeFetConfig(configPath, renderFetConfig(scan)));\n\n const state = await ctx.stateStore.getOrCreateGlobal();\n state.context = {\n agentsMdUpdatedAt: scan.generatedAt,\n configUpdatedAt: scan.generatedAt,\n scannerVersion: scan.scannerVersion\n };\n await ctx.stateStore.writeGlobal(state);\n\n return { warnings };\n}\n\nasync function readOptional(path: string): Promise<string | null> {\n try {\n return await readFile(path, \"utf8\");\n } catch {\n return null;\n }\n}\n","import { readFile } from \"node:fs/promises\";\nimport { parseDocument } from \"yaml\";\n\nexport async function mergeFetConfig(configPath: string, renderedFetYaml: string): Promise<string> {\n const fetDoc = parseDocument(renderedFetYaml);\n const nextFet = fetDoc.get(\"fet\", true);\n\n let existing = \"\";\n try {\n existing = await readFile(configPath, \"utf8\");\n } catch {\n return renderedFetYaml;\n }\n\n const doc = parseDocument(existing || \"{}\");\n doc.set(\"fet\", nextFet);\n return doc.toString();\n}\n","import { stat } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport type { FetCommandContext } from \"../cli/context.js\";\nimport { clearLock } from \"../fs/index.js\";\nimport type { DoctorCheck } from \"../adapters/index.js\";\n\nexport async function doctorCommand(ctx: FetCommandContext, options: { fixLock?: boolean } = {}): Promise<void> {\n const checks: DoctorCheck[] = [];\n\n checks.push(await checkOpenSpec(ctx));\n checks.push(await checkState(ctx));\n checks.push(await checkFile(\"agents\", join(ctx.projectRoot, \"AGENTS.md\"), \"AGENTS.md 缺失\", \"fet update-context\"));\n checks.push(await checkFile(\"config\", join(ctx.projectRoot, \"openspec\", \"config.yaml\"), \"openspec/config.yaml 缺失\", \"fet init\"));\n\n for (const adapter of ctx.toolAdapters) {\n checks.push(...(await adapter.doctor(ctx.projectRoot)));\n }\n\n const lockPath = join(ctx.projectRoot, \"openspec\", \".fet.lock\");\n if (await exists(lockPath)) {\n if (options.fixLock) {\n await clearLock(ctx.projectRoot);\n checks.push({ id: \"lock\", status: \"pass\", message: \"已清理 openspec/.fet.lock\" });\n } else {\n checks.push({ id: \"lock\", status: \"warn\", message: \"存在 openspec/.fet.lock\", suggestedCommand: \"fet doctor --fix-lock\" });\n }\n }\n\n const warnings = checks.filter((check) => check.status !== \"pass\").map((check) => check.message);\n ctx.output.result({\n ok: true,\n command: \"doctor\",\n summary: warnings.length ? `诊断完成,发现 ${warnings.length} 个需要关注的问题。` : \"诊断完成,未发现明显问题。\",\n warnings,\n data: checks\n });\n}\n\nasync function checkOpenSpec(ctx: FetCommandContext): Promise<DoctorCheck> {\n try {\n const identity = await ctx.openSpec.resolveExecutable();\n return { id: \"openspec\", status: \"pass\", message: `OpenSpec: ${identity.executablePath} (${identity.version})` };\n } catch (error) {\n return { id: \"openspec\", status: \"fail\", message: error instanceof Error ? error.message : \"OpenSpec 检测失败\" };\n }\n}\n\nasync function checkState(ctx: FetCommandContext): Promise<DoctorCheck> {\n try {\n const state = await ctx.stateStore.readGlobal();\n return state\n ? { id: \"state\", status: \"pass\", message: \"FET 全局状态可读取\" }\n : { id: \"state\", status: \"warn\", message: \"FET 全局状态尚未初始化\", suggestedCommand: \"fet init\" };\n } catch (error) {\n return { id: \"state\", status: \"fail\", message: error instanceof Error ? error.message : \"FET 状态读取失败\" };\n }\n}\n\nasync function checkFile(id: string, path: string, missing: string, suggestedCommand: string): Promise<DoctorCheck> {\n return (await exists(path))\n ? { id, status: \"pass\", message: `${id} 存在` }\n : { id, status: \"warn\", message: missing, suggestedCommand };\n}\n\nasync function exists(path: string): Promise<boolean> {\n try {\n await stat(path);\n return true;\n } catch {\n return false;\n }\n}\n","import { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport type { ProjectIdentity } from \"./types.js\";\n\nconst execFileAsync = promisify(execFile);\n\nexport async function detectProjectIdentity(projectRoot: string): Promise<ProjectIdentity> {\n const [gitRoot, branch, headCommit] = await Promise.all([\n git(projectRoot, [\"rev-parse\", \"--show-toplevel\"]),\n git(projectRoot, [\"branch\", \"--show-current\"]),\n git(projectRoot, [\"rev-parse\", \"HEAD\"])\n ]);\n\n return {\n gitRoot,\n worktreePath: projectRoot,\n branch,\n headCommit\n };\n}\n\nasync function git(cwd: string, args: string[]): Promise<string | null> {\n try {\n const { stdout } = await execFileAsync(\"git\", args, { cwd });\n return stdout.trim() || null;\n } catch {\n return null;\n }\n}\n","import { mkdir, readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { atomicWrite } from \"../fs/atomic-write.js\";\nimport { assertChangeState, assertGlobalState, createChangeState, createGlobalState } from \"./schema.js\";\nimport type { ChangePhase, ChangeState, GlobalState, ProjectIdentity } from \"./types.js\";\n\nexport class StateStore {\n constructor(\n private readonly projectRoot: string,\n private readonly fetVersion: string,\n private readonly project: ProjectIdentity\n ) {}\n\n async readGlobal(): Promise<GlobalState | null> {\n try {\n const value = JSON.parse(await readFile(this.globalPath(), \"utf8\"));\n assertGlobalState(value);\n return value;\n } catch (error) {\n if (isNotFound(error)) {\n return null;\n }\n throw error;\n }\n }\n\n async getOrCreateGlobal(): Promise<GlobalState> {\n return (await this.readGlobal()) ?? createGlobalState(this.fetVersion, this.project);\n }\n\n async writeGlobal(state: GlobalState): Promise<void> {\n state.updatedAt = new Date().toISOString();\n await mkdir(join(this.projectRoot, \"openspec\"), { recursive: true });\n await atomicWrite(this.globalPath(), `${JSON.stringify(state, null, 2)}\\n`);\n }\n\n async readChange(changeId: string): Promise<ChangeState | null> {\n try {\n const value = JSON.parse(await readFile(this.changePath(changeId), \"utf8\"));\n assertChangeState(value);\n return value;\n } catch (error) {\n if (isNotFound(error)) {\n return null;\n }\n throw error;\n }\n }\n\n async getOrCreateChange(changeId: string, phase: ChangePhase): Promise<ChangeState> {\n return (await this.readChange(changeId)) ?? createChangeState(this.fetVersion, changeId, phase);\n }\n\n async writeChange(state: ChangeState): Promise<void> {\n state.updatedAt = new Date().toISOString();\n await mkdir(join(this.projectRoot, \"openspec\", \"changes\", state.changeId), { recursive: true });\n await atomicWrite(this.changePath(state.changeId), `${JSON.stringify(state, null, 2)}\\n`);\n }\n\n private globalPath(): string {\n return join(this.projectRoot, \"openspec\", \"fet-state.json\");\n }\n\n private changePath(changeId: string): string {\n return join(this.projectRoot, \"openspec\", \"changes\", changeId, \"fet-state.json\");\n }\n}\n\nfunction isNotFound(error: unknown): boolean {\n return typeof error === \"object\" && error !== null && \"code\" in error && error.code === \"ENOENT\";\n}\n","import { ErrorCode } from \"../errors/codes.js\";\nimport { FetError } from \"../errors/fet-error.js\";\nimport type { ChangePhase, ChangeState, GlobalState, ProjectIdentity } from \"./types.js\";\n\nconst phases: ChangePhase[] = [\"explore\", \"propose\", \"implement\", \"verify\", \"sync\", \"archive\"];\n\nexport function createGlobalState(fetVersion: string, project: ProjectIdentity): GlobalState {\n const now = new Date().toISOString();\n return {\n schemaVersion: 1,\n fetVersion,\n createdAt: now,\n updatedAt: now,\n project,\n openspec: null,\n activeChangeId: null,\n openChangeIds: [],\n context: {\n agentsMdUpdatedAt: null,\n configUpdatedAt: null,\n scannerVersion: 1\n },\n toolAdapters: {},\n verifyAuthorization: null,\n lastDoctor: null\n };\n}\n\nexport function createChangeState(fetVersion: string, changeId: string, phase: ChangePhase): ChangeState {\n const now = new Date().toISOString();\n return {\n schemaVersion: 1,\n fetVersion,\n changeId,\n createdAt: now,\n updatedAt: now,\n currentPhase: phase,\n phases: Object.fromEntries(\n phases.map((item) => [item, { status: item === phase ? \"in_progress\" : \"not_started\" }])\n ) as ChangeState[\"phases\"],\n tasks: {\n source: \"tasks.md\",\n completedIds: [],\n lastSyncedAt: null\n },\n manualVerify: null,\n lastOpenSpecCommand: null,\n warnings: []\n };\n}\n\nexport function assertGlobalState(value: unknown): asserts value is GlobalState {\n if (!isRecord(value) || value.schemaVersion !== 1) {\n throw unsupportedSchema(\"全局状态 schema 不受支持\");\n }\n if (typeof value.fetVersion !== \"string\" || !isRecord(value.project)) {\n throw corruptedState(\"全局状态缺少必填字段\");\n }\n}\n\nexport function assertChangeState(value: unknown): asserts value is ChangeState {\n if (!isRecord(value) || value.schemaVersion !== 1) {\n throw unsupportedSchema(\"变更状态 schema 不受支持\");\n }\n if (typeof value.fetVersion !== \"string\" || typeof value.changeId !== \"string\") {\n throw corruptedState(\"变更状态缺少必填字段\");\n }\n}\n\nfunction unsupportedSchema(message: string): FetError {\n return new FetError({\n code: ErrorCode.StateSchemaUnsupported,\n message,\n suggestedCommand: \"npm update -g @nick848/fet\"\n });\n}\n\nfunction corruptedState(message: string): FetError {\n return new FetError({\n code: ErrorCode.StateCorrupted,\n message,\n suggestedCommand: \"fet doctor --fix\"\n });\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n","import { readFile } from \"node:fs/promises\";\n\nexport async function readCompletedTaskIds(tasksPath: string): Promise<string[]> {\n let content: string;\n try {\n content = await readFile(tasksPath, \"utf8\");\n } catch {\n return [];\n }\n\n const completed: string[] = [];\n const pattern = /^\\s*[-*]\\s+\\[[xX]\\]\\s+([0-9]+(?:\\.[0-9]+)*)/gm;\n let match: RegExpExecArray | null;\n while ((match = pattern.exec(content))) {\n if (match[1]) {\n completed.push(match[1]);\n }\n }\n return completed;\n}\n","import { ErrorCode } from \"../errors/codes.js\";\nimport { FetError } from \"../errors/fet-error.js\";\nimport { withProjectLock } from \"../fs/index.js\";\nimport { readCompletedTaskIds, type ChangePhase } from \"../state/index.js\";\nimport type { FetCommandContext } from \"../cli/context.js\";\n\nconst phaseByCommand: Record<string, ChangePhase> = {\n explore: \"explore\",\n propose: \"propose\",\n new: \"propose\",\n continue: \"propose\",\n ff: \"propose\",\n apply: \"implement\",\n verify: \"verify\",\n sync: \"sync\",\n archive: \"archive\",\n \"bulk-archive\": \"archive\",\n onboard: \"explore\"\n};\n\nexport async function proxyCommand(ctx: FetCommandContext, command: string, args: string[]): Promise<void> {\n const openSpecArgs = stripFetOptions(args);\n await withProjectLock(\n ctx.projectRoot,\n { command, cwd: ctx.cwd, fetVersion: ctx.fetVersion },\n async () => {\n if ([\"sync\", \"archive\", \"bulk-archive\"].includes(command)) {\n await assertVerified(ctx);\n }\n\n const mapped = await mapOpenSpecCommand(ctx, command, openSpecArgs);\n const result = await ctx.openSpec.run(mapped.command, mapped.args, { cwd: ctx.projectRoot, stdio: ctx.json ? \"pipe\" : \"inherit\" });\n if (result.exitCode !== 0) {\n throw new FetError({\n code: ErrorCode.OpenSpecCommandFailed,\n message: `OpenSpec ${command} 执行失败`,\n details: result,\n recoverable: true\n });\n }\n\n const inspection = await ctx.openSpec.inspectProject(ctx.projectRoot);\n const state = await ctx.stateStore.getOrCreateGlobal();\n state.openChangeIds = inspection.changes;\n if (ctx.changeId && inspection.changes.includes(ctx.changeId)) {\n state.activeChangeId = ctx.changeId;\n } else if (state.activeChangeId && !inspection.changes.includes(state.activeChangeId)) {\n state.activeChangeId = inspection.changes.length === 1 ? (inspection.changes[0] ?? null) : null;\n } else if (!state.activeChangeId && inspection.changes.length === 1) {\n state.activeChangeId = inspection.changes[0] ?? null;\n }\n await ctx.stateStore.writeGlobal(state);\n\n const changeId = ctx.changeId ?? state.activeChangeId;\n if (changeId && inspection.changes.includes(changeId)) {\n const changeInspection = await ctx.openSpec.inspectChange(ctx.projectRoot, changeId);\n const changeState = await ctx.stateStore.getOrCreateChange(changeId, phaseByCommand[command] ?? \"propose\");\n changeState.currentPhase = phaseByCommand[command] ?? changeState.currentPhase;\n changeState.phases[changeState.currentPhase] = {\n status: \"done\",\n updatedAt: new Date().toISOString()\n };\n changeState.lastOpenSpecCommand = {\n command: mapped.command,\n args: mapped.args,\n exitCode: result.exitCode,\n ranAt: new Date().toISOString()\n };\n changeState.tasks.completedIds = await readCompletedTaskIds(changeInspection.tasksPath);\n changeState.tasks.lastSyncedAt = new Date().toISOString();\n await ctx.stateStore.writeChange(changeState);\n }\n }\n );\n\n ctx.output.result({\n ok: true,\n command,\n summary: `fet ${command} 完成。`\n });\n}\n\nexport async function passthroughCommand(ctx: FetCommandContext, command: string, args: string[]): Promise<void> {\n const result = await ctx.openSpec.run(command, stripFetOptions(args), { cwd: ctx.projectRoot, stdio: ctx.json ? \"pipe\" : \"inherit\" });\n if (result.exitCode !== 0) {\n throw new FetError({\n code: ErrorCode.OpenSpecCommandFailed,\n message: `OpenSpec ${command} 执行失败`,\n details: result\n });\n }\n}\n\nfunction stripFetOptions(args: string[]): string[] {\n const result: string[] = [];\n for (let index = 0; index < args.length; index += 1) {\n const arg = args[index];\n if (arg === \"--cwd\" || arg === \"--change\") {\n index += 1;\n continue;\n }\n if (arg?.startsWith(\"--cwd=\") || arg?.startsWith(\"--change=\")) {\n continue;\n }\n if (arg === \"--yes\" || arg === \"--json\" || arg === \"--verbose\" || arg === \"--no-color\") {\n continue;\n }\n if (arg) {\n result.push(arg);\n }\n }\n return result;\n}\n\nasync function mapOpenSpecCommand(\n ctx: FetCommandContext,\n command: string,\n args: string[]\n): Promise<{ command: string; args: string[] }> {\n switch (command) {\n case \"propose\":\n case \"new\":\n return { command: \"new\", args: args[0] === \"change\" ? args : [\"change\", ...args] };\n case \"continue\":\n return { command: \"instructions\", args: [...withoutUndefined(args[0] ? [args[0]] : [\"proposal\"]), \"--change\", await requireChangeId(ctx)] };\n case \"ff\":\n return { command: \"status\", args: [\"--change\", await requireChangeId(ctx)] };\n case \"apply\":\n return { command: \"instructions\", args: [\"apply\", \"--change\", await requireChangeId(ctx)] };\n case \"sync\":\n return { command: \"validate\", args: [ctx.changeId ?? args[0] ?? (await requireChangeId(ctx)), \"--type\", \"change\", \"--strict\"] };\n case \"archive\":\n return { command: \"archive\", args: [ctx.changeId ?? args[0] ?? (await requireChangeId(ctx)), ...args.slice(ctx.changeId ? 0 : 1)] };\n case \"bulk-archive\":\n throw new FetError({\n code: ErrorCode.InvalidArguments,\n message: \"OpenSpec 1.2.0 不提供 bulk-archive 顶层命令\",\n suggestedCommand: \"逐个执行 fet archive --change <change-id>\"\n });\n case \"explore\":\n return { command: \"instructions\", args: [\"proposal\", \"--change\", await requireChangeId(ctx)] };\n case \"onboard\":\n return { command: \"instructions\", args: [] };\n default:\n return { command, args };\n }\n}\n\nasync function requireChangeId(ctx: FetCommandContext): Promise<string> {\n if (ctx.changeId) {\n return ctx.changeId;\n }\n const state = await ctx.stateStore.getOrCreateGlobal();\n if (state.activeChangeId) {\n return state.activeChangeId;\n }\n const inspection = await ctx.openSpec.inspectProject(ctx.projectRoot);\n if (inspection.changes.length === 1 && inspection.changes[0]) {\n return inspection.changes[0];\n }\n throw new FetError({\n code: ErrorCode.InvalidArguments,\n message: \"该命令需要明确的 change\",\n details: { openChangeIds: inspection.changes },\n suggestedCommand: \"添加 --change <change-id>\"\n });\n}\n\nfunction withoutUndefined(values: string[]): string[] {\n return values.filter(Boolean);\n}\n\nasync function assertVerified(ctx: FetCommandContext): Promise<void> {\n const global = await ctx.stateStore.getOrCreateGlobal();\n const changeId = ctx.changeId ?? global.activeChangeId;\n if (!changeId) {\n throw new FetError({\n code: ErrorCode.InvalidArguments,\n message: \"未指定 change,无法检查 verify 状态\",\n suggestedCommand: \"fet verify --done --change <change-id>\"\n });\n }\n const change = await ctx.stateStore.readChange(changeId);\n const inspection = await ctx.openSpec.inspectProject(ctx.projectRoot);\n if (!inspection.changes.includes(changeId)) {\n throw new FetError({\n code: ErrorCode.InvalidArguments,\n message: \"指定的 change 不存在或已归档\",\n details: { changeId, openChangeIds: inspection.changes },\n suggestedCommand: \"fet doctor\"\n });\n }\n if (change?.manualVerify?.status !== \"declared_done\") {\n throw new FetError({\n code: ErrorCode.StateCorrupted,\n message: \"当前 change 尚未通过 FET verify\",\n details: { changeId },\n suggestedCommand: `fet verify --change ${changeId}`\n });\n }\n}\n","import { createHash } from \"node:crypto\";\nimport { mkdir, readFile, stat } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport type { FetCommandContext } from \"../cli/context.js\";\nimport { ErrorCode } from \"../errors/codes.js\";\nimport { FetError } from \"../errors/fet-error.js\";\nimport { atomicWrite, withProjectLock } from \"../fs/index.js\";\nimport { renderVerifyInstructions } from \"../templates/index.js\";\n\nexport async function verifyCommand(ctx: FetCommandContext, options: { done?: boolean; auto?: boolean }): Promise<void> {\n if (options.auto) {\n const scan = await ctx.scanner.scan(ctx.projectRoot, {});\n const plan = {\n schemaVersion: 1,\n packageManager: scan.project.packageManager,\n workspaces: [\n {\n name: \"root\",\n cwd: \".\",\n commands: Object.entries(scan.commands)\n .filter(([name]) => [\"lint\", \"typecheck\", \"test\"].includes(name))\n .map(([dimension, command]) => ({\n dimension,\n command: command.command,\n source: command.source,\n required: command.required,\n statusIfMissing: command.required ? \"fail\" : \"warn\"\n }))\n }\n ],\n missing: [\"lint\", \"typecheck\", \"test\"].filter((name) => !scan.commands[name])\n };\n if (ctx.yes) {\n const global = await ctx.stateStore.getOrCreateGlobal();\n global.verifyAuthorization = {\n schemaVersion: 1,\n approvedAt: new Date().toISOString(),\n commandFingerprint: fingerprint(plan),\n packageManager: plan.packageManager,\n plan: plan.workspaces.flatMap((workspace) =>\n workspace.commands.map((command) => ({\n cwd: workspace.cwd,\n dimension: command.dimension,\n command: command.command,\n source: command.source,\n required: command.required\n }))\n )\n };\n await ctx.stateStore.writeGlobal(global);\n }\n\n ctx.output.result({\n ok: true,\n command: \"verify\",\n summary: ctx.yes ? \"已确认 verify --auto 执行计划;MVP 暂不执行仓库脚本。\" : \"已生成 verify --auto 执行计划;MVP 暂不执行仓库脚本。\",\n warnings: plan.missing.map((name) => `未发现 ${name} 脚本,将在自动执行版本中按配置处理。`),\n data: plan,\n nextSteps: ctx.yes ? [\"当前版本请运行 fet verify 进入手动验证模式\"] : [\"审核执行计划\", \"确认计划后可运行 fet verify --auto --yes\", \"当前版本请运行 fet verify 进入手动验证模式\"]\n });\n return;\n }\n\n await withProjectLock(\n ctx.projectRoot,\n { command: \"verify\", cwd: ctx.cwd, fetVersion: ctx.fetVersion },\n async () => {\n const changeId = await resolveChangeId(ctx);\n if (options.done) {\n await markDone(ctx, changeId);\n } else {\n await writeInstructions(ctx, changeId);\n }\n }\n );\n}\n\nasync function writeInstructions(ctx: FetCommandContext, changeId: string): Promise<void> {\n await assertChangeExists(ctx, changeId);\n const generatedAt = new Date().toISOString();\n const dir = join(ctx.projectRoot, \"openspec\", \"changes\", changeId, \".fet\");\n const instructionsPath = join(dir, \"verify-instructions.md\");\n await mkdir(dir, { recursive: true });\n await atomicWrite(instructionsPath, renderVerifyInstructions(changeId, generatedAt));\n\n const state = await ctx.stateStore.getOrCreateChange(changeId, \"verify\");\n state.currentPhase = \"verify\";\n state.phases.verify = { status: \"in_progress\", updatedAt: generatedAt };\n await ctx.stateStore.writeChange(state);\n\n ctx.output.result({\n ok: true,\n command: \"verify\",\n summary: \"已生成手动验证指令。\",\n nextSteps: [`阅读 openspec/changes/${changeId}/.fet/verify-instructions.md`, `完成后运行 fet verify --done --change ${changeId}`]\n });\n}\n\nasync function markDone(ctx: FetCommandContext, changeId: string): Promise<void> {\n await assertChangeExists(ctx, changeId);\n const declaredAt = new Date().toISOString();\n const instructionsPath = join(ctx.projectRoot, \"openspec\", \"changes\", changeId, \".fet\", \"verify-instructions.md\");\n const instructions = await readInstructions(instructionsPath, changeId);\n const instructionsGeneratedAt = readFrontMatterValue(instructions, \"generatedAt\") ?? declaredAt;\n const state = await ctx.stateStore.getOrCreateChange(changeId, \"verify\");\n state.currentPhase = \"verify\";\n state.phases.verify = { status: \"done\", updatedAt: declaredAt };\n state.manualVerify = {\n mode: \"manual\",\n status: \"declared_done\",\n declaredAt,\n instructionsPath: `openspec/changes/${changeId}/.fet/verify-instructions.md`,\n instructionsGeneratedAt,\n evidence: null\n };\n await ctx.stateStore.writeChange(state);\n\n ctx.output.result({\n ok: true,\n command: \"verify\",\n summary: \"已记录手动验证完成声明。\",\n nextSteps: [`fet sync --change ${changeId}`, `fet archive --change ${changeId}`]\n });\n}\n\nasync function assertChangeExists(ctx: FetCommandContext, changeId: string): Promise<void> {\n const inspection = await ctx.openSpec.inspectChange(ctx.projectRoot, changeId);\n if (!inspection.exists) {\n throw new FetError({\n code: ErrorCode.InvalidArguments,\n message: \"指定的 change 不存在\",\n details: { changeId },\n suggestedCommand: \"fet verify --change <change-id>\"\n });\n }\n}\n\nasync function readInstructions(path: string, changeId: string): Promise<string> {\n try {\n await stat(path);\n const content = await readFile(path, \"utf8\");\n const fileChangeId = readFrontMatterValue(content, \"changeId\");\n if (fileChangeId !== changeId) {\n throw new FetError({\n code: ErrorCode.StateCorrupted,\n message: \"验证指令文件与当前 change 不匹配\",\n details: { expected: changeId, actual: fileChangeId },\n suggestedCommand: `fet verify --change ${changeId}`\n });\n }\n return content;\n } catch (error) {\n if (error instanceof FetError) {\n throw error;\n }\n throw new FetError({\n code: ErrorCode.StateCorrupted,\n message: \"验证指令文件不存在或无法读取\",\n details: { path },\n suggestedCommand: `fet verify --change ${changeId}`\n });\n }\n}\n\nfunction readFrontMatterValue(content: string, key: string): string | null {\n const match = content.match(new RegExp(`^${key}:\\\\s*(.+)$`, \"m\"));\n return match?.[1]?.trim() ?? null;\n}\n\nfunction fingerprint(value: unknown): string {\n return `sha256:${createHash(\"sha256\").update(JSON.stringify(value)).digest(\"hex\")}`;\n}\n\nasync function resolveChangeId(ctx: FetCommandContext): Promise<string> {\n if (ctx.changeId) {\n return ctx.changeId;\n }\n\n const global = await ctx.stateStore.getOrCreateGlobal();\n if (global.activeChangeId) {\n return global.activeChangeId;\n }\n\n const inspection = await ctx.openSpec.inspectProject(ctx.projectRoot);\n if (inspection.changes.length === 1 && inspection.changes[0]) {\n return inspection.changes[0];\n }\n\n throw new FetError({\n code: ErrorCode.InvalidArguments,\n message: \"无法确定要验证的 change\",\n details: { openChangeIds: inspection.changes },\n suggestedCommand: \"fet verify --change <change-id>\"\n });\n}\n","import { resolve } from \"node:path\";\nimport { CursorAdapter } from \"../adapters/index.js\";\nimport { DefaultOpenSpecAdapter } from \"../openspec/index.js\";\nimport { ProjectScanner } from \"../scanner/index.js\";\nimport { detectProjectIdentity, StateStore } from \"../state/index.js\";\nimport { FET_VERSION } from \"../version.js\";\nimport { OutputWriter } from \"./output.js\";\n\nexport interface GlobalOptions {\n cwd?: string;\n json?: boolean;\n verbose?: boolean;\n yes?: boolean;\n change?: string;\n}\n\nexport async function createCommandContext(command: string, options: GlobalOptions) {\n const projectRoot = resolve(options.cwd ?? process.cwd());\n const project = await detectProjectIdentity(projectRoot);\n const output = new OutputWriter(Boolean(options.json));\n\n return {\n command,\n cwd: projectRoot,\n projectRoot,\n isTty: Boolean(process.stdout.isTTY),\n json: Boolean(options.json),\n verbose: Boolean(options.verbose),\n yes: Boolean(options.yes),\n changeId: options.change,\n fetVersion: FET_VERSION,\n output,\n stateStore: new StateStore(projectRoot, FET_VERSION, project),\n openSpec: new DefaultOpenSpecAdapter(),\n scanner: new ProjectScanner(),\n toolAdapters: [new CursorAdapter()]\n };\n}\n\nexport type FetCommandContext = Awaited<ReturnType<typeof createCommandContext>>;\n","import { mkdir, readFile, stat } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport { ErrorCode } from \"../../errors/codes.js\";\nimport { FetError } from \"../../errors/fet-error.js\";\nimport { atomicWrite } from \"../../fs/atomic-write.js\";\nimport { createBackup } from \"../../fs/backup.js\";\nimport type { DoctorCheck, ToolAdapter, ToolInstallPlan, ToolInstallResult } from \"../types.js\";\nimport { cursorRuleFile, cursorSkillFiles } from \"./templates.js\";\n\nexport class CursorAdapter implements ToolAdapter {\n readonly tool = \"cursor\";\n readonly adapterVersion = 1;\n\n async detect(projectRoot: string) {\n return {\n detected: await exists(join(projectRoot, \".cursor\")),\n reason: \"Cursor adapter is available for any project\"\n };\n }\n\n async planInstall(_projectRoot: string): Promise<ToolInstallPlan> {\n return {\n tool: this.tool,\n files: [...cursorSkillFiles(), cursorRuleFile()].map((file) => ({\n ...file,\n managed: true\n }))\n };\n }\n\n async install(projectRoot: string, plan: ToolInstallPlan, force = false): Promise<ToolInstallResult> {\n const written: string[] = [];\n const skipped: string[] = [];\n\n for (const file of plan.files) {\n const target = join(projectRoot, file.path);\n const existing = await readExisting(target);\n if (existing && !existing.includes(\"FET:MANAGED\") && !force) {\n throw new FetError({\n code: ErrorCode.ToolAdapterConflict,\n message: \"Cursor 配置文件已存在且不归 FET 管理\",\n details: { path: file.path },\n suggestedCommand: \"fet init --yes\"\n });\n }\n if (existing && !existing.includes(\"FET:MANAGED\") && force) {\n await createBackup(target);\n }\n await mkdir(dirname(target), { recursive: true });\n await atomicWrite(target, file.content);\n written.push(file.path);\n }\n\n return { tool: this.tool, written, skipped };\n }\n\n async doctor(projectRoot: string): Promise<DoctorCheck[]> {\n const plan = await this.planInstall(projectRoot);\n const checks: DoctorCheck[] = [];\n for (const file of plan.files) {\n const target = join(projectRoot, file.path);\n const content = await readExisting(target);\n const managed = Boolean(content?.includes(\"FET:MANAGED\"));\n const versionMatches = Boolean(content?.includes(`adapterVersion: ${this.adapterVersion}`));\n checks.push({\n id: `cursor:${file.path}`,\n status: !content ? \"warn\" : managed && versionMatches ? \"pass\" : \"warn\",\n message: !content\n ? `${file.path} 缺失`\n : !managed\n ? `${file.path} 存在但不归 FET 管理`\n : !versionMatches\n ? `${file.path} adapterVersion 已过期`\n : `${file.path} 存在且版本匹配`,\n suggestedCommand: !content || !managed || !versionMatches ? \"fet init\" : undefined\n });\n }\n return checks;\n }\n}\n\nasync function readExisting(path: string): Promise<string | null> {\n try {\n return await readFile(path, \"utf8\");\n } catch {\n return null;\n }\n}\n\nasync function exists(path: string): Promise<boolean> {\n try {\n await stat(path);\n return true;\n } catch {\n return false;\n }\n}\n","import { FET_VERSION } from \"../../version.js\";\n\nconst commands = [\n \"explore\",\n \"propose\",\n \"new\",\n \"continue\",\n \"ff\",\n \"apply\",\n \"verify\",\n \"sync\",\n \"archive\",\n \"bulk-archive\",\n \"onboard\"\n];\n\nexport function cursorSkillFiles(): Array<{ path: string; content: string }> {\n return commands.map((command) => ({\n path: `.cursor/skills/fet-${command}/SKILL.md`,\n content: renderSkill(command)\n }));\n}\n\nexport function cursorRuleFile(): { path: string; content: string } {\n return {\n path: \".cursor/rules/fet-context.mdc\",\n content: `<!-- FET:MANAGED\nschemaVersion: 1\nfetVersion: ${FET_VERSION}\ngenerator: cursor-adapter\nadapterVersion: 1\nFET:END -->\n\n---\ndescription: Load FET project context for implementation tasks\nalwaysApply: false\n---\n\n当用户请求修改项目、实现 OpenSpec change、运行 FET 工作流或解释项目结构时,优先阅读:\n\n- AGENTS.md\n- openspec/config.yaml\n- 当前 change 目录下的 OpenSpec 规划产物\n\n如果用户输入类似 \\`/fet apply\\` 的请求,Cursor 当前版本未必会把本文件注册为原生 slash command。此时请把它当作工作流意图,并提示用户在终端执行对应的 \\`fet <cmd>\\` 命令。\n`\n };\n}\n\nfunction renderSkill(command: string): string {\n return `<!-- FET:MANAGED\nschemaVersion: 1\nfetVersion: ${FET_VERSION}\ngenerator: cursor-adapter\nadapterVersion: 1\ncommand: fet ${command}\nFET:END -->\n\n---\nname: fet-${command}\ndescription: Run FET-managed OpenSpec ${command} workflow from the terminal\ndisable-model-invocation: true\n---\n\n注意:此文件采用 Cursor Skill 目录结构。它提供 \\`/fet-${command}\\` 风格的工作流说明,不承诺注册 \\`/fet ${command}\\` 这种带空格的原生 slash command。\n\n请在终端中执行:\n\n\\`\\`\\`sh\nfet ${command}\n\\`\\`\\`\n\n执行前请确认已阅读 AGENTS.md 与 openspec/config.yaml。\n`;\n}\n","import { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport type { OpenSpecIdentity } from \"../state/types.js\";\nimport { inspectOpenSpecChange, inspectOpenSpecProject } from \"./inspector.js\";\nimport { resolveOpenSpecExecutable } from \"./resolver.js\";\nimport { runOpenSpec } from \"./runner.js\";\nimport type {\n OpenSpecAdapter,\n OpenSpecCapabilities,\n OpenSpecChangeInspection,\n OpenSpecProjectInspection,\n OpenSpecRunOptions,\n OpenSpecRunResult\n} from \"./types.js\";\n\nconst execFileAsync = promisify(execFile);\n\nexport class DefaultOpenSpecAdapter implements OpenSpecAdapter {\n private identity?: OpenSpecIdentity;\n\n async resolveExecutable(): Promise<OpenSpecIdentity> {\n this.identity ??= await resolveOpenSpecExecutable();\n return this.identity;\n }\n\n async getCapabilities(): Promise<OpenSpecCapabilities> {\n const identity = await this.resolveExecutable();\n const executable = identity.executablePath === \"npx openspec\" ? \"npx\" : identity.executablePath;\n const args = identity.executablePath === \"npx openspec\" ? [\"openspec\", \"--help\"] : [\"--help\"];\n\n try {\n const { stdout } = await execFileAsync(executable, args, { shell: process.platform === \"win32\" });\n return {\n version: identity.version,\n commands: parseCommands(stdout),\n supported: true\n };\n } catch {\n return {\n version: identity.version,\n commands: [],\n supported: false\n };\n }\n }\n\n async run(command: string, args: string[], options: OpenSpecRunOptions): Promise<OpenSpecRunResult> {\n const identity = await this.resolveExecutable();\n return runOpenSpec(identity.executablePath, command, args, options);\n }\n\n inspectProject(projectRoot: string): Promise<OpenSpecProjectInspection> {\n return inspectOpenSpecProject(projectRoot);\n }\n\n inspectChange(projectRoot: string, changeId: string): Promise<OpenSpecChangeInspection> {\n return inspectOpenSpecChange(projectRoot, changeId);\n }\n}\n\nfunction parseCommands(help: string): string[] {\n const known = [\n \"init\",\n \"explore\",\n \"propose\",\n \"new\",\n \"continue\",\n \"ff\",\n \"apply\",\n \"verify\",\n \"sync\",\n \"archive\",\n \"bulk-archive\",\n \"onboard\"\n ];\n return known.filter((command) => help.includes(command));\n}\n","import { readdir, stat } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport type { OpenSpecChangeInspection, OpenSpecProjectInspection } from \"./types.js\";\n\nexport async function inspectOpenSpecProject(projectRoot: string): Promise<OpenSpecProjectInspection> {\n const openspecPath = join(projectRoot, \"openspec\");\n const changesPath = join(openspecPath, \"changes\");\n const archivePath = join(openspecPath, \"archive\");\n\n return {\n exists: await exists(openspecPath),\n changes: await listDirectories(changesPath),\n archived: await listDirectories(archivePath)\n };\n}\n\nexport async function inspectOpenSpecChange(\n projectRoot: string,\n changeId: string\n): Promise<OpenSpecChangeInspection> {\n const changePath = join(projectRoot, \"openspec\", \"changes\", changeId);\n const tasksPath = join(changePath, \"tasks.md\");\n const specsPath = join(changePath, \"specs\");\n\n return {\n changeId,\n exists: await exists(changePath),\n hasProposal: await exists(join(changePath, \"proposal.md\")),\n hasTasks: await exists(tasksPath),\n hasSpecs: await exists(specsPath),\n tasksPath,\n changePath\n };\n}\n\nasync function listDirectories(path: string): Promise<string[]> {\n try {\n const entries = await readdir(path, { withFileTypes: true });\n return entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name);\n } catch {\n return [];\n }\n}\n\nasync function exists(path: string): Promise<boolean> {\n try {\n await stat(path);\n return true;\n } catch {\n return false;\n }\n}\n","import { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport { ErrorCode } from \"../errors/codes.js\";\nimport { FetError } from \"../errors/fet-error.js\";\nimport type { OpenSpecIdentity } from \"../state/types.js\";\n\nconst execFileAsync = promisify(execFile);\n\nexport async function resolveOpenSpecExecutable(): Promise<OpenSpecIdentity> {\n const executablePath = await findExecutable();\n const version = await readVersion(executablePath);\n return {\n executablePath,\n version,\n adapterVersion: 1\n };\n}\n\nasync function findExecutable(): Promise<string> {\n const command = process.platform === \"win32\" ? \"where.exe\" : \"which\";\n try {\n const { stdout } = await exec(command, [\"openspec\"]);\n const first = stdout\n .split(/\\r?\\n/)\n .map((line) => line.trim())\n .find(Boolean);\n if (first) {\n return first;\n }\n } catch {\n // Try npx below.\n }\n\n try {\n await exec(\"npx\", [\"openspec\", \"--version\"]);\n return \"npx openspec\";\n } catch {\n throw new FetError({\n code: ErrorCode.OpenSpecNotFound,\n message: \"OpenSpec CLI 未安装\",\n suggestedCommand: \"npm install -g @fission-ai/openspec\"\n });\n }\n}\n\nasync function readVersion(executablePath: string): Promise<string> {\n const command = executablePath === \"npx openspec\" ? \"npx\" : executablePath;\n const args = executablePath === \"npx openspec\" ? [\"openspec\", \"--version\"] : [\"--version\"];\n try {\n const { stdout, stderr } = await exec(command, args);\n return stdout.trim() || stderr.trim() || \"unknown\";\n } catch (error) {\n throw new FetError({\n code: ErrorCode.OpenSpecUnsupportedVersion,\n message: \"无法读取 OpenSpec 版本\",\n details: { executablePath },\n cause: error\n });\n }\n}\n\nfunction exec(command: string, args: string[]) {\n return execFileAsync(command, args, { shell: process.platform === \"win32\" });\n}\n","import { spawn } from \"node:child_process\";\nimport { ErrorCode } from \"../errors/codes.js\";\nimport { FetError } from \"../errors/fet-error.js\";\nimport type { OpenSpecRunOptions, OpenSpecRunResult } from \"./types.js\";\n\nexport async function runOpenSpec(\n executablePath: string,\n command: string,\n args: string[],\n options: OpenSpecRunOptions\n): Promise<OpenSpecRunResult> {\n const spawnCommand = executablePath === \"npx openspec\" ? \"npx\" : executablePath;\n const spawnArgs = executablePath === \"npx openspec\" ? [\"openspec\", command, ...args] : [command, ...args];\n\n return new Promise((resolve, reject) => {\n const stdout: Buffer[] = [];\n const stderr: Buffer[] = [];\n const child = spawn(spawnCommand, spawnArgs, {\n cwd: options.cwd,\n stdio: options.stdio ?? \"inherit\",\n shell: process.platform === \"win32\"\n });\n\n if (child.stdout) {\n child.stdout.on(\"data\", (chunk: Buffer) => stdout.push(chunk));\n }\n if (child.stderr) {\n child.stderr.on(\"data\", (chunk: Buffer) => stderr.push(chunk));\n }\n\n child.on(\"error\", (error) => {\n reject(\n new FetError({\n code: ErrorCode.OpenSpecCommandFailed,\n message: \"OpenSpec 命令启动失败\",\n details: { command, args },\n cause: error\n })\n );\n });\n\n child.on(\"close\", (exitCode, signal) => {\n resolve({\n command,\n args,\n exitCode: exitCode ?? 1,\n signal,\n stdout: stdout.length ? Buffer.concat(stdout).toString(\"utf8\") : undefined,\n stderr: stderr.length ? Buffer.concat(stderr).toString(\"utf8\") : undefined\n });\n });\n });\n}\n","import { readFile, stat } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { parse } from \"yaml\";\nimport type { ScannedCommand, ScannedWorkspace } from \"./types.js\";\n\ninterface PackageJson {\n name?: string;\n packageManager?: string;\n scripts?: Record<string, string>;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n workspaces?: string[] | { packages?: string[] };\n}\n\nexport async function readPackageJson(projectRoot: string): Promise<PackageJson | null> {\n try {\n return JSON.parse(await readFile(join(projectRoot, \"package.json\"), \"utf8\"));\n } catch {\n return null;\n }\n}\n\nexport interface PackageManagerDetection {\n manager: string;\n confidence: \"high\" | \"medium\" | \"low\";\n warnings: string[];\n}\n\nexport async function detectPackageManager(projectRoot: string, pkg: PackageJson | null): Promise<PackageManagerDetection> {\n const warnings: string[] = [];\n if (pkg?.packageManager) {\n const declared = pkg.packageManager.split(\"@\")[0] ?? \"unknown\";\n const locks = await detectLockManagers(projectRoot);\n const conflicting = locks.filter((item) => item !== declared);\n if (conflicting.length) {\n warnings.push(`packageManager 声明为 ${declared},但同时发现锁文件:${conflicting.join(\", \")}`);\n }\n return { manager: declared, confidence: \"high\", warnings };\n }\n\n const locks = await detectLockManagers(projectRoot);\n if (locks.length > 1) {\n warnings.push(`发现多个包管理器锁文件:${locks.join(\", \")},默认使用 ${locks[0]}`);\n return { manager: locks[0] ?? \"npm\", confidence: \"medium\", warnings };\n }\n if (locks[0]) {\n return { manager: locks[0], confidence: \"high\", warnings };\n }\n return { manager: \"npm\", confidence: \"low\", warnings };\n}\n\nexport function extractCommands(pkg: PackageJson | null, packageManager: string): Record<string, ScannedCommand> {\n const scripts = pkg?.scripts ?? {};\n const result: Record<string, ScannedCommand> = {};\n const scriptNames = [\"dev\", \"build\", \"lint\", \"typecheck\", \"check\", \"test\", \"test:unit\"];\n\n for (const name of scriptNames) {\n if (scripts[name]) {\n const dimension = name === \"check\" ? \"typecheck\" : name === \"test:unit\" ? \"test\" : name;\n if (result[dimension]) {\n continue;\n }\n result[dimension] = {\n command: scriptCommand(packageManager, name),\n source: `package.json:scripts.${name}`,\n required: name === \"build\"\n };\n }\n }\n\n return result;\n}\n\nexport function detectFramework(pkg: PackageJson | null): { name: string; confidence: \"high\" | \"medium\" | \"low\"; sources: string[] } {\n const deps = { ...(pkg?.dependencies ?? {}), ...(pkg?.devDependencies ?? {}) };\n const candidates: Array<[string, string[]]> = [\n [\"next\", [\"next\"]],\n [\"nuxt\", [\"nuxt\"]],\n [\"vite\", [\"vite\"]],\n [\"sveltekit\", [\"@sveltejs/kit\"]],\n [\"angular\", [\"@angular/core\", \"@angular/cli\"]],\n [\"react\", [\"react\"]],\n [\"vue\", [\"vue\"]],\n [\"svelte\", [\"svelte\"]]\n ];\n for (const [candidate, packages] of candidates) {\n if (packages.some((name) => deps[name])) {\n return { name: candidate, confidence: \"high\", sources: [\"package.json\"] };\n }\n }\n return { name: \"unknown\", confidence: \"low\", sources: [] };\n}\n\nexport async function detectLanguage(projectRoot: string, pkg: PackageJson | null): Promise<string> {\n const deps = { ...(pkg?.dependencies ?? {}), ...(pkg?.devDependencies ?? {}) };\n if (deps.typescript || (await exists(join(projectRoot, \"tsconfig.json\")))) {\n return \"typescript\";\n }\n return \"javascript\";\n}\n\nexport async function detectWorkspaces(projectRoot: string, pkg: PackageJson | null): Promise<ScannedWorkspace[]> {\n const packageWorkspaces = normalizeWorkspaces(pkg?.workspaces).map((path) => ({\n name: path,\n path,\n source: \"package.json:workspaces\"\n }));\n if (packageWorkspaces.length) {\n return packageWorkspaces;\n }\n\n try {\n const workspace = parse(await readFile(join(projectRoot, \"pnpm-workspace.yaml\"), \"utf8\")) as { packages?: string[] } | null;\n return (workspace?.packages ?? []).map((path) => ({\n name: path,\n path,\n source: \"pnpm-workspace.yaml:packages\"\n }));\n } catch {\n return [];\n }\n}\n\nasync function detectLockManagers(projectRoot: string): Promise<string[]> {\n const lockFiles: Array<[string, string]> = [\n [\"pnpm-lock.yaml\", \"pnpm\"],\n [\"yarn.lock\", \"yarn\"],\n [\"bun.lockb\", \"bun\"],\n [\"bun.lock\", \"bun\"],\n [\"package-lock.json\", \"npm\"]\n ];\n const found: string[] = [];\n for (const [file, manager] of lockFiles) {\n if (await exists(join(projectRoot, file))) {\n found.push(manager);\n }\n }\n return found;\n}\n\nfunction normalizeWorkspaces(workspaces: PackageJson[\"workspaces\"]): string[] {\n if (Array.isArray(workspaces)) {\n return workspaces;\n }\n return workspaces?.packages ?? [];\n}\n\nfunction scriptCommand(packageManager: string, name: string): string {\n return packageManager === \"npm\" ? `npm run ${name}` : `${packageManager} ${name}`;\n}\n\nasync function exists(path: string): Promise<boolean> {\n try {\n await stat(path);\n return true;\n } catch {\n return false;\n }\n}\n","import { readdir, stat } from \"node:fs/promises\";\nimport { join, relative, sep } from \"node:path\";\nimport type { ScannedRoute } from \"./types.js\";\n\nexport async function scanRoutes(projectRoot: string): Promise<ScannedRoute[]> {\n const candidates = [\"src/routes\", \"src/pages\", \"app\", \"pages\"];\n const routes: ScannedRoute[] = [];\n\n for (const candidate of candidates) {\n const root = join(projectRoot, candidate);\n if (!(await exists(root))) {\n continue;\n }\n for (const file of await listFiles(root)) {\n if (!/\\.(tsx?|jsx?|vue|svelte)$/.test(file)) {\n continue;\n }\n routes.push({\n path: inferRoutePath(relative(root, file)),\n source: relative(projectRoot, file).split(sep).join(\"/\"),\n inferred: true,\n confidence: \"medium\"\n });\n }\n }\n\n return routes.slice(0, 100);\n}\n\nfunction inferRoutePath(relativePath: string): string {\n const normalized = relativePath.split(sep).join(\"/\");\n const withoutExt = normalized.replace(/\\.(tsx?|jsx?|vue|svelte)$/, \"\");\n const withoutIndex = withoutExt.replace(/\\/index$/, \"\").replace(/^index$/, \"\");\n return `/${withoutIndex}`.replace(/\\/+/g, \"/\");\n}\n\nasync function listFiles(root: string): Promise<string[]> {\n const entries = await readdir(root, { withFileTypes: true });\n const files: string[] = [];\n for (const entry of entries) {\n const path = join(root, entry.name);\n if (entry.isDirectory()) {\n files.push(...(await listFiles(path)));\n } else {\n files.push(path);\n }\n }\n return files;\n}\n\nasync function exists(path: string): Promise<boolean> {\n try {\n await stat(path);\n return true;\n } catch {\n return false;\n }\n}\n","import { detectFramework, detectLanguage, detectPackageManager, detectWorkspaces, extractCommands, readPackageJson } from \"./package.js\";\nimport { scanRoutes } from \"./routes.js\";\nimport type { ProjectScanResult, ScanOptions } from \"./types.js\";\n\nexport class ProjectScanner {\n async scan(projectRoot: string, _options: ScanOptions = {}): Promise<ProjectScanResult> {\n const pkg = await readPackageJson(projectRoot);\n const packageManager = await detectPackageManager(projectRoot, pkg);\n const framework = detectFramework(pkg);\n const workspaces = await detectWorkspaces(projectRoot, pkg);\n const language = await detectLanguage(projectRoot, pkg);\n const warnings = [...packageManager.warnings];\n if (framework.name === \"unknown\") {\n warnings.push(\"未能从 package.json 识别主要框架\");\n }\n\n return {\n generatedAt: new Date().toISOString(),\n scannerVersion: 1,\n project: {\n name: pkg?.name ?? \"unknown\",\n packageManager: packageManager.manager,\n packageManagerConfidence: packageManager.confidence,\n framework,\n language,\n monorepo: workspaces.length > 0,\n workspaces\n },\n commands: extractCommands(pkg, packageManager.manager),\n routes: await scanRoutes(projectRoot),\n conventions: [],\n skippedFiles: [],\n warnings\n };\n }\n}\n\nexport type {\n ProjectScanResult,\n ScanOptions,\n ScannedCommand,\n ScannedConvention,\n ScannedProjectMetadata,\n ScannedRoute,\n ScannedWorkspace,\n SkippedFile\n} from \"./types.js\";\n","import { FetError } from \"../errors/fet-error.js\";\n\nexport interface CommandResult {\n ok: true;\n command: string;\n summary: string;\n warnings?: string[];\n nextSteps?: string[];\n data?: unknown;\n}\n\nexport class OutputWriter {\n constructor(private readonly json: boolean) {}\n\n info(message: string, details?: unknown): void {\n if (!this.json) {\n process.stdout.write(`${message}${formatDetails(details)}\\n`);\n }\n }\n\n warn(message: string, details?: unknown): void {\n if (!this.json) {\n process.stderr.write(`警告:${message}${formatDetails(details)}\\n`);\n }\n }\n\n error(error: FetError): void {\n if (this.json) {\n process.stderr.write(`${JSON.stringify({ ok: false, error: error.toJSON() }, null, 2)}\\n`);\n return;\n }\n\n process.stderr.write(`FET 无法继续:${error.message}\\n`);\n if (error.details !== undefined) {\n process.stderr.write(`\\n详情:\\n${formatBlock(error.details)}\\n`);\n }\n if (error.suggestedCommand) {\n process.stderr.write(`\\n建议:\\n ${error.suggestedCommand}\\n`);\n }\n }\n\n result(result: CommandResult): void {\n if (this.json) {\n process.stdout.write(`${JSON.stringify(result, null, 2)}\\n`);\n return;\n }\n\n process.stdout.write(`${result.summary}\\n`);\n for (const warning of result.warnings ?? []) {\n process.stdout.write(`警告:${warning}\\n`);\n }\n if (result.nextSteps?.length) {\n process.stdout.write(\"\\n下一步:\\n\");\n for (const step of result.nextSteps) {\n process.stdout.write(` ${step}\\n`);\n }\n }\n }\n}\n\nfunction formatDetails(details: unknown): string {\n if (details === undefined) {\n return \"\";\n }\n return ` ${JSON.stringify(details)}`;\n}\n\nfunction formatBlock(details: unknown): string {\n if (typeof details === \"string\") {\n return ` ${details}`;\n }\n return JSON.stringify(details, null, 2)\n .split(\"\\n\")\n .map((line) => ` ${line}`)\n .join(\"\\n\");\n}\n"],"mappings":";;;;;;;AAAA,SAAS,eAAe;;;ACAxB,SAAS,YAAAA,WAAU,QAAAC,aAAY;AAC/B,SAAS,QAAAC,aAAY;;;ACDrB,SAAS,eAAe;AACxB,SAAS,MAAM,QAAQ,aAAa;AAOpC,eAAsB,YACpB,YACA,SAC4B;AAC5B,QAAM,MAAM,QAAQ,UAAU,GAAG,EAAE,WAAW,KAAK,CAAC;AACpD,QAAM,WAAW,GAAG,UAAU,QAAQ,QAAQ,GAAG,IAAI,KAAK,IAAI,CAAC;AAC/D,QAAM,SAAS,MAAM,KAAK,UAAU,IAAI;AAExC,MAAI;AACF,UAAM,OAAO,UAAU,OAAO;AAC9B,UAAM,OAAO,KAAK;AAAA,EACpB,UAAE;AACA,UAAM,OAAO,MAAM;AAAA,EACrB;AAEA,QAAM,OAAO,UAAU,UAAU;AACjC,SAAO,EAAE,MAAM,YAAY,SAAS;AACtC;;;ACzBA,SAAS,UAAU,YAAY;AAC/B,SAAS,UAAU,WAAAC,UAAS,YAAY;AAExC,eAAsB,aAAa,UAA0C;AAC3E,MAAI;AACF,UAAM,KAAK,QAAQ;AAAA,EACrB,QAAQ;AACN,WAAO;AAAA,EACT;AAEA,QAAM,aAAY,oBAAI,KAAK,GACxB,YAAY,EACZ,QAAQ,SAAS,EAAE,EACnB,QAAQ,SAAS,EAAE,EACnB,QAAQ,KAAK,GAAG;AACnB,QAAM,aAAa,KAAKA,SAAQ,QAAQ,GAAG,GAAG,SAAS,QAAQ,CAAC,eAAe,SAAS,EAAE;AAC1F,QAAM,SAAS,UAAU,UAAU;AACnC,SAAO;AACT;;;AClBA,SAAS,gBAAgB;AACzB,SAAS,WAAAC,UAAS,QAAAC,aAAY;AAC9B,SAAS,SAAAC,QAAO,QAAAC,OAAM,UAAU,UAAU;AAmB1C,eAAsB,gBACpB,aACA,UACA,IACY;AACZ,QAAM,WAAWC,MAAK,aAAa,YAAY,WAAW;AAC1D,QAAM,OAAiB;AAAA,IACrB,KAAK,QAAQ;AAAA,IACb,UAAU,SAAS;AAAA,IACnB,KAAK,SAAS;AAAA,IACd,SAAS,SAAS;AAAA,IAClB,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IAClC,YAAY,SAAS;AAAA,EACvB;AAEA,MAAI;AACJ,MAAI;AACF,UAAMC,OAAMC,SAAQ,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;AAClD,aAAS,MAAMC,MAAK,UAAU,IAAI;AAClC,UAAM,OAAO,UAAU,KAAK,UAAU,MAAM,MAAM,CAAC,CAAC;AAAA,EACtD,QAAQ;AACN,UAAM,IAAI,SAAS;AAAA,MACjB;AAAA,MACA,SAAS;AAAA,MACT,SAAS,MAAM,iBAAiB,QAAQ;AAAA,MACxC,kBAAkB;AAAA,IACpB,CAAC;AAAA,EACH,UAAE;AACA,UAAM,QAAQ,MAAM;AAAA,EACtB;AAEA,MAAI;AACF,WAAO,MAAM,GAAG;AAAA,EAClB,UAAE;AACA,UAAM,GAAG,UAAU,EAAE,OAAO,KAAK,CAAC;AAAA,EACpC;AACF;AAEA,eAAe,iBAAiB,UAAoC;AAClE,MAAI;AACF,WAAO,KAAK,MAAM,MAAM,SAAS,UAAU,MAAM,CAAC;AAAA,EACpD,QAAQ;AACN,WAAO,EAAE,MAAM,SAAS;AAAA,EAC1B;AACF;AAEA,eAAsB,UAAU,aAAuC;AACrE,QAAM,WAAWH,MAAK,aAAa,YAAY,WAAW;AAC1D,MAAI;AACF,UAAM,GAAG,QAAQ;AACjB,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;AC3EA,SAAS,QAAAI,aAAY;AACrB,SAAS,YAAAC,iBAAgB;AAmBlB,SAAS,kBAAkB,YAAiC;AACjE,SAAO;AAAA,IACL,eAAe;AAAA,IACf,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IAClC,aAAa;AAAA,IACb;AAAA,IACA,OAAO,CAAC;AAAA,EACV;AACF;AAEA,eAAsB,iBAAiB,aAAqB,SAAqC;AAC/F,QAAM;AAAA,IACJC,MAAK,aAAa,YAAY,wBAAwB;AAAA,IACtD,GAAG,KAAK,UAAU,SAAS,MAAM,CAAC,CAAC;AAAA;AAAA,EACrC;AACF;;;ACnCO,IAAM,cAAc;;;ACApB,IAAM,aAAa;AACnB,IAAM,WAAW;AACjB,IAAM,aAAa;AACnB,IAAM,WAAW;AAEjB,SAAS,qBAAqB,SAA0B;AAC7D,SAAO,MAAM,SAAS,UAAU,MAAM,KAAK,MAAM,SAAS,QAAQ,MAAM,KAAK,QAAQ,QAAQ,UAAU,IAAI,QAAQ,QAAQ,QAAQ;AACrI;AAEO,SAAS,4BAA4B,SAA0B;AACpE,QAAM,aAAa,MAAM,SAAS,UAAU;AAC5C,QAAM,WAAW,MAAM,SAAS,QAAQ;AACxC,SAAO,eAAe,YAAY,aAAa,KAAK,WAAW,KAAM,eAAe,KAAK,QAAQ,QAAQ,UAAU,IAAI,QAAQ,QAAQ,QAAQ;AACjJ;AAEO,SAAS,qBAAqB,UAAyB,WAA2B;AACvF,MAAI,CAAC,UAAU;AACb,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ,SAAS,QAAQ,UAAU;AACzC,QAAM,MAAM,SAAS,QAAQ,QAAQ;AACrC,MAAI,UAAU,MAAM,QAAQ,MAAM,MAAM,OAAO;AAC7C,WAAO;AAAA,EACT;AAEA,QAAM,SAAS,SAAS,MAAM,GAAG,KAAK;AACtC,QAAM,QAAQ,SAAS,MAAM,MAAM,SAAS,MAAM;AAClD,QAAM,gBAAgB,YAAY,SAAS;AAC3C,SAAO,GAAG,MAAM,GAAG,UAAU;AAAA,EAAK,aAAa;AAAA,EAAK,QAAQ,GAAG,KAAK;AACtE;AAEA,SAAS,YAAY,SAAyB;AAC5C,QAAM,QAAQ,QAAQ,QAAQ,UAAU;AACxC,QAAM,MAAM,QAAQ,QAAQ,QAAQ;AACpC,MAAI,UAAU,MAAM,QAAQ,MAAM,MAAM,OAAO;AAC7C,WAAO,QAAQ,KAAK;AAAA,EACtB;AACA,SAAO,QAAQ,MAAM,QAAQ,WAAW,QAAQ,GAAG,EAAE,KAAK;AAC5D;AAEA,SAAS,MAAM,SAAiB,QAAwB;AACtD,SAAO,QAAQ,MAAM,MAAM,EAAE,SAAS;AACxC;;;ACvCO,SAAS,eAAe,MAAiC;AAC9D,QAAMC,YAAW,OAAO,QAAQ,KAAK,QAAQ,EAC1C,IAAI,CAAC,CAAC,MAAM,OAAO,MAAM,KAAK,IAAI,QAAQ,QAAQ,OAAO,QAAQ,QAAQ,MAAM,IAAI,EACnF,KAAK,IAAI;AACZ,QAAM,SAAS,KAAK,OACjB,IAAI,CAAC,UAAU,KAAK,MAAM,IAAI,MAAM,MAAM,MAAM,MAAM,MAAM,UAAU,GAAG,MAAM,WAAW,cAAc,EAAE,IAAI,EAC9G,KAAK,IAAI;AACZ,QAAM,aAAa,KAAK,QAAQ,WAAW,IAAI,CAAC,cAAc,KAAK,UAAU,IAAI,MAAM,UAAU,IAAI,MAAM,UAAU,MAAM,IAAI,EAAE,KAAK,IAAI;AAE1I,SAAO;AAAA;AAAA,EAEP,UAAU;AAAA;AAAA;AAAA,UAGF,KAAK,QAAQ,IAAI;AAAA,qBACN,KAAK,QAAQ,cAAc,KAAK,KAAK,QAAQ,wBAAwB;AAAA,eAC3E,KAAK,QAAQ,UAAU,IAAI,KAAK,KAAK,QAAQ,UAAU,UAAU;AAAA,cAClE,KAAK,QAAQ,QAAQ;AAAA,cACrB,KAAK,QAAQ,WAAW,QAAQ,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMhD,cAAc,yBAAyB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMvCA,aAAY,+DAA+D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAU3E,UAAU,iDAAiD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kBAQ3C,KAAK,WAAW;AAAA,iBACjB,WAAW;AAAA,qBACP,KAAK,cAAc;AAAA,cAC1B,KAAK,SAAS,SAAS,KAAK,SAAS,KAAK,IAAI,IAAI,MAAM;AAAA,EACpE,QAAQ;AAAA;AAAA,EAER,UAAU;AAAA;AAAA;AAAA;AAAA,EAIV,QAAQ;AAAA;AAEV;;;AChEA,SAAS,iBAAiB;AAInB,SAAS,gBAAgB,MAAiC;AAC/D,SAAO,UAAU;AAAA,IACf,KAAK;AAAA,MACH,eAAe;AAAA,MACf,aAAa,KAAK;AAAA,MAClB,YAAY;AAAA,MACZ,gBAAgB,KAAK;AAAA,MACrB,SAAS;AAAA,QACP,gBAAgB,KAAK,QAAQ;AAAA,QAC7B,0BAA0B,KAAK,QAAQ;AAAA,QACvC,WAAW,KAAK,QAAQ;AAAA,QACxB,UAAU,KAAK,QAAQ;AAAA,QACvB,UAAU,KAAK,QAAQ;AAAA,QACvB,YAAY,KAAK,QAAQ;AAAA,MAC3B;AAAA,MACA,UAAU,KAAK;AAAA,MACf,YAAY;AAAA,QACV,UAAU,KAAK,QAAQ;AAAA,QACvB,SAAS;AAAA,UACP,MAAM;AAAA,UACN,WAAW;AAAA,UACX,MAAM;AAAA,QACR;AAAA,QACA,YAAY,KAAK,QAAQ;AAAA,MAC3B;AAAA,IACF;AAAA,EACF,CAAC;AACH;;;AC7BO,SAAS,yBAAyB,UAAkB,eAAc,oBAAI,KAAK,GAAE,YAAY,GAAW;AACzG,SAAO;AAAA;AAAA,cAEK,WAAW;AAAA,eACV,WAAW;AAAA,YACd,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,6BAeS,QAAQ;AAAA;AAAA;AAGrC;;;ACzBA,IAAM,QAAQ;AACd,IAAM,MAAM;AAEZ,IAAM,QAAQ;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEO,SAAS,eAAe,UAAiC;AAC9D,QAAM,QAAQ,GAAG,KAAK;AAAA,EAAK,MAAM,KAAK,IAAI,CAAC;AAAA,EAAK,GAAG;AACnD,MAAI,CAAC,YAAY,CAAC,SAAS,KAAK,GAAG;AACjC,WAAO,GAAG,KAAK;AAAA;AAAA,EACjB;AAEA,QAAM,QAAQ,SAAS,QAAQ,KAAK;AACpC,QAAM,MAAM,SAAS,QAAQ,GAAG;AAChC,MAAI,UAAU,MAAM,QAAQ,MAAM,MAAM,OAAO;AAC7C,WAAO,GAAG,SAAS,MAAM,GAAG,KAAK,CAAC,GAAG,KAAK,GAAG,SAAS,MAAM,MAAM,IAAI,MAAM,CAAC;AAAA,EAC/E;AAEA,SAAO,GAAG,SAAS,QAAQ,QAAQ,EAAE,CAAC;AAAA;AAAA,EAAO,KAAK;AAAA;AACpD;;;ACxBA,SAAS,YAAAC,iBAAgB;AACzB,SAAS,QAAAC,aAAY;;;ACDrB,SAAS,YAAAC,iBAAgB;AACzB,SAAS,qBAAqB;AAE9B,eAAsB,eAAe,YAAoB,iBAA0C;AACjG,QAAM,SAAS,cAAc,eAAe;AAC5C,QAAM,UAAU,OAAO,IAAI,OAAO,IAAI;AAEtC,MAAI,WAAW;AACf,MAAI;AACF,eAAW,MAAMA,UAAS,YAAY,MAAM;AAAA,EAC9C,QAAQ;AACN,WAAO;AAAA,EACT;AAEA,QAAM,MAAM,cAAc,YAAY,IAAI;AAC1C,MAAI,IAAI,OAAO,OAAO;AACtB,SAAO,IAAI,SAAS;AACtB;;;ADRA,eAAsB,qBAAqB,KAAuC;AAChF,QAAM;AAAA,IACJ,IAAI;AAAA,IACJ,EAAE,SAAS,kBAAkB,KAAK,IAAI,KAAK,YAAY,IAAI,WAAW;AAAA,IACtE,YAAY,mBAAmB,GAAG;AAAA,EACpC;AAEA,MAAI,OAAO,OAAO;AAAA,IAChB,IAAI;AAAA,IACJ,SAAS;AAAA,IACT,SAAS;AAAA,EACX,CAAC;AACH;AAEA,eAAsB,mBAAmB,KAAyD;AAChG,QAAM,OAAO,MAAM,IAAI,QAAQ,KAAK,IAAI,aAAa,CAAC,CAAC;AACvD,QAAM,aAAaC,MAAK,IAAI,aAAa,WAAW;AACpD,QAAM,aAAaA,MAAK,IAAI,aAAa,YAAY,aAAa;AAElE,QAAM,iBAAiB,MAAM,aAAa,UAAU;AACpD,QAAM,WAAW,CAAC,GAAG,KAAK,QAAQ;AAClC,MAAI,kBAAkB,4BAA4B,cAAc,GAAG;AACjE,UAAM,IAAI,SAAS;AAAA,MACjB;AAAA,MACA,SAAS;AAAA,MACT,SAAS,EAAE,MAAM,YAAY;AAAA,MAC7B,kBAAkB;AAAA,IACpB,CAAC;AAAA,EACH;AACA,MAAI,kBAAkB,CAAC,qBAAqB,cAAc,GAAG;AAC3D,QAAI,CAAC,IAAI,KAAK;AACZ,YAAM,IAAI,SAAS;AAAA,QACjB;AAAA,QACA,SAAS;AAAA,QACT,SAAS,EAAE,MAAM,YAAY;AAAA,QAC7B,kBAAkB;AAAA,MACpB,CAAC;AAAA,IACH;AACA,UAAM,aAAa,MAAM,aAAa,UAAU;AAChD,QAAI,YAAY;AACd,eAAS,KAAK,yDAAsB,UAAU,EAAE;AAAA,IAClD;AAAA,EACF;AACA,QAAM,YAAY,YAAY,qBAAqB,gBAAgB,eAAe,IAAI,CAAC,CAAC;AACxF,QAAM,YAAY,YAAY,MAAM,eAAe,YAAY,gBAAgB,IAAI,CAAC,CAAC;AAErF,QAAM,QAAQ,MAAM,IAAI,WAAW,kBAAkB;AACrD,QAAM,UAAU;AAAA,IACd,mBAAmB,KAAK;AAAA,IACxB,iBAAiB,KAAK;AAAA,IACtB,gBAAgB,KAAK;AAAA,EACvB;AACA,QAAM,IAAI,WAAW,YAAY,KAAK;AAEtC,SAAO,EAAE,SAAS;AACpB;AAEA,eAAe,aAAa,MAAsC;AAChE,MAAI;AACF,WAAO,MAAMC,UAAS,MAAM,MAAM;AAAA,EACpC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;AXjEA,eAAsB,YAAY,KAAuC;AACvE,QAAM,qBAAqB,MAAM,OAAOC,MAAK,IAAI,aAAa,YAAY,aAAa,CAAC;AACxF,QAAM;AAAA,IACJ,IAAI;AAAA,IACJ,EAAE,SAAS,QAAQ,KAAK,IAAI,KAAK,YAAY,IAAI,WAAW;AAAA,IAC5D,YAAY;AACV,YAAM,UAAU,kBAAkB,IAAI,UAAU;AAChD,YAAM,iBAAiB,IAAI,aAAa,OAAO;AAE/C,YAAM,WAAW,MAAM,IAAI,SAAS,kBAAkB;AACtD,UAAI,CAAC,oBAAoB;AACvB,cAAM,SAAS,MAAM,IAAI,SAAS,IAAI,QAAQ,CAAC,WAAW,MAAM,GAAG,EAAE,KAAK,IAAI,aAAa,OAAO,UAAU,CAAC;AAC7G,YAAI,OAAO,aAAa,GAAG;AACzB,kBAAQ,WAAW,OAAO;AAC1B;AAAA,QACF;AAAA,MACF;AAEA,YAAM,gBAAgB,MAAM,mBAAmB,GAAG;AAClD,YAAM,gBAAgB,GAAG;AAEzB,YAAM,QAAQ,MAAM,IAAI,WAAW,kBAAkB;AACrD,YAAM,WAAW;AAEjB,iBAAW,WAAW,IAAI,cAAc;AACtC,cAAM,OAAO,MAAM,QAAQ,YAAY,IAAI,WAAW;AACtD,cAAM,SAAS,MAAM,QAAQ,QAAQ,IAAI,aAAa,MAAM,IAAI,GAAG;AACnE,cAAM,aAAa,QAAQ,IAAI,IAAI;AAAA,UACjC,gBAAgB,QAAQ;AAAA,UACxB,WAAW;AAAA,UACX,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,QACpC;AACA,gBAAQ,MAAM,KAAK,GAAG,OAAO,QAAQ,IAAI,CAAC,UAAU,EAAE,WAAW,SAAkB,MAAM,QAAQ,OAAgB,EAAE,CAAC;AAAA,MACtH;AAEA,cAAQ,eAAc,oBAAI,KAAK,GAAE,YAAY;AAC7C,YAAM,iBAAiB,IAAI,aAAa,OAAO;AAC/C,YAAM,IAAI,WAAW,YAAY,KAAK;AACtC,iBAAW,WAAW,cAAc,UAAU;AAC5C,YAAI,OAAO,KAAK,OAAO;AAAA,MACzB;AAAA,IACF;AAAA,EACF;AAEA,MAAI,OAAO,OAAO;AAAA,IAChB,IAAI;AAAA,IACJ,SAAS;AAAA,IACT,SAAS;AAAA,IACT,WAAW,CAAC,6DAAyC,8DAAsB;AAAA,EAC7E,CAAC;AACH;AAEA,eAAe,gBAAgB,KAAuC;AACpE,QAAM,gBAAgBA,MAAK,IAAI,aAAa,YAAY;AACxD,QAAM,WAAW,MAAMC,cAAa,aAAa;AACjD,QAAM,YAAY,eAAe,eAAe,QAAQ,CAAC;AAC3D;AAEA,eAAeA,cAAa,MAAsC;AAChE,MAAI;AACF,WAAO,MAAMC,UAAS,MAAM,MAAM;AAAA,EACpC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAe,OAAO,MAAgC;AACpD,MAAI;AACF,UAAMC,MAAK,IAAI;AACf,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;AahFA,SAAS,QAAAC,aAAY;AACrB,SAAS,QAAAC,aAAY;AAKrB,eAAsB,cAAc,KAAwB,UAAiC,CAAC,GAAkB;AAC9G,QAAM,SAAwB,CAAC;AAE/B,SAAO,KAAK,MAAM,cAAc,GAAG,CAAC;AACpC,SAAO,KAAK,MAAM,WAAW,GAAG,CAAC;AACjC,SAAO,KAAK,MAAM,UAAU,UAAUC,MAAK,IAAI,aAAa,WAAW,GAAG,0BAAgB,oBAAoB,CAAC;AAC/G,SAAO,KAAK,MAAM,UAAU,UAAUA,MAAK,IAAI,aAAa,YAAY,aAAa,GAAG,qCAA2B,UAAU,CAAC;AAE9H,aAAW,WAAW,IAAI,cAAc;AACtC,WAAO,KAAK,GAAI,MAAM,QAAQ,OAAO,IAAI,WAAW,CAAE;AAAA,EACxD;AAEA,QAAM,WAAWA,MAAK,IAAI,aAAa,YAAY,WAAW;AAC9D,MAAI,MAAMC,QAAO,QAAQ,GAAG;AAC1B,QAAI,QAAQ,SAAS;AACnB,YAAM,UAAU,IAAI,WAAW;AAC/B,aAAO,KAAK,EAAE,IAAI,QAAQ,QAAQ,QAAQ,SAAS,wCAAyB,CAAC;AAAA,IAC/E,OAAO;AACL,aAAO,KAAK,EAAE,IAAI,QAAQ,QAAQ,QAAQ,SAAS,mCAAyB,kBAAkB,wBAAwB,CAAC;AAAA,IACzH;AAAA,EACF;AAEA,QAAM,WAAW,OAAO,OAAO,CAAC,UAAU,MAAM,WAAW,MAAM,EAAE,IAAI,CAAC,UAAU,MAAM,OAAO;AAC/F,MAAI,OAAO,OAAO;AAAA,IAChB,IAAI;AAAA,IACJ,SAAS;AAAA,IACT,SAAS,SAAS,SAAS,8CAAW,SAAS,MAAM,4DAAe;AAAA,IACpE;AAAA,IACA,MAAM;AAAA,EACR,CAAC;AACH;AAEA,eAAe,cAAc,KAA8C;AACzE,MAAI;AACF,UAAM,WAAW,MAAM,IAAI,SAAS,kBAAkB;AACtD,WAAO,EAAE,IAAI,YAAY,QAAQ,QAAQ,SAAS,aAAa,SAAS,cAAc,KAAK,SAAS,OAAO,IAAI;AAAA,EACjH,SAAS,OAAO;AACd,WAAO,EAAE,IAAI,YAAY,QAAQ,QAAQ,SAAS,iBAAiB,QAAQ,MAAM,UAAU,oCAAgB;AAAA,EAC7G;AACF;AAEA,eAAe,WAAW,KAA8C;AACtE,MAAI;AACF,UAAM,QAAQ,MAAM,IAAI,WAAW,WAAW;AAC9C,WAAO,QACH,EAAE,IAAI,SAAS,QAAQ,QAAQ,SAAS,iDAAc,IACtD,EAAE,IAAI,SAAS,QAAQ,QAAQ,SAAS,8DAAiB,kBAAkB,WAAW;AAAA,EAC5F,SAAS,OAAO;AACd,WAAO,EAAE,IAAI,SAAS,QAAQ,QAAQ,SAAS,iBAAiB,QAAQ,MAAM,UAAU,2CAAa;AAAA,EACvG;AACF;AAEA,eAAe,UAAU,IAAY,MAAc,SAAiB,kBAAgD;AAClH,SAAQ,MAAMA,QAAO,IAAI,IACrB,EAAE,IAAI,QAAQ,QAAQ,SAAS,GAAG,EAAE,gBAAM,IAC1C,EAAE,IAAI,QAAQ,QAAQ,SAAS,SAAS,iBAAiB;AAC/D;AAEA,eAAeA,QAAO,MAAgC;AACpD,MAAI;AACF,UAAMC,MAAK,IAAI;AACf,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;ACvEA,SAAS,gBAAgB;AACzB,SAAS,iBAAiB;AAG1B,IAAM,gBAAgB,UAAU,QAAQ;AAExC,eAAsB,sBAAsB,aAA+C;AACzF,QAAM,CAAC,SAAS,QAAQ,UAAU,IAAI,MAAM,QAAQ,IAAI;AAAA,IACtD,IAAI,aAAa,CAAC,aAAa,iBAAiB,CAAC;AAAA,IACjD,IAAI,aAAa,CAAC,UAAU,gBAAgB,CAAC;AAAA,IAC7C,IAAI,aAAa,CAAC,aAAa,MAAM,CAAC;AAAA,EACxC,CAAC;AAED,SAAO;AAAA,IACL;AAAA,IACA,cAAc;AAAA,IACd;AAAA,IACA;AAAA,EACF;AACF;AAEA,eAAe,IAAI,KAAa,MAAwC;AACtE,MAAI;AACF,UAAM,EAAE,OAAO,IAAI,MAAM,cAAc,OAAO,MAAM,EAAE,IAAI,CAAC;AAC3D,WAAO,OAAO,KAAK,KAAK;AAAA,EAC1B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;AC5BA,SAAS,SAAAC,QAAO,YAAAC,iBAAgB;AAChC,SAAS,QAAAC,aAAY;;;ACGrB,IAAM,SAAwB,CAAC,WAAW,WAAW,aAAa,UAAU,QAAQ,SAAS;AAEtF,SAAS,kBAAkB,YAAoB,SAAuC;AAC3F,QAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AACnC,SAAO;AAAA,IACL,eAAe;AAAA,IACf;AAAA,IACA,WAAW;AAAA,IACX,WAAW;AAAA,IACX;AAAA,IACA,UAAU;AAAA,IACV,gBAAgB;AAAA,IAChB,eAAe,CAAC;AAAA,IAChB,SAAS;AAAA,MACP,mBAAmB;AAAA,MACnB,iBAAiB;AAAA,MACjB,gBAAgB;AAAA,IAClB;AAAA,IACA,cAAc,CAAC;AAAA,IACf,qBAAqB;AAAA,IACrB,YAAY;AAAA,EACd;AACF;AAEO,SAAS,kBAAkB,YAAoB,UAAkB,OAAiC;AACvG,QAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AACnC,SAAO;AAAA,IACL,eAAe;AAAA,IACf;AAAA,IACA;AAAA,IACA,WAAW;AAAA,IACX,WAAW;AAAA,IACX,cAAc;AAAA,IACd,QAAQ,OAAO;AAAA,MACb,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,QAAQ,SAAS,QAAQ,gBAAgB,cAAc,CAAC,CAAC;AAAA,IACzF;AAAA,IACA,OAAO;AAAA,MACL,QAAQ;AAAA,MACR,cAAc,CAAC;AAAA,MACf,cAAc;AAAA,IAChB;AAAA,IACA,cAAc;AAAA,IACd,qBAAqB;AAAA,IACrB,UAAU,CAAC;AAAA,EACb;AACF;AAEO,SAAS,kBAAkB,OAA8C;AAC9E,MAAI,CAAC,SAAS,KAAK,KAAK,MAAM,kBAAkB,GAAG;AACjD,UAAM,kBAAkB,0DAAkB;AAAA,EAC5C;AACA,MAAI,OAAO,MAAM,eAAe,YAAY,CAAC,SAAS,MAAM,OAAO,GAAG;AACpE,UAAM,eAAe,8DAAY;AAAA,EACnC;AACF;AAEO,SAAS,kBAAkB,OAA8C;AAC9E,MAAI,CAAC,SAAS,KAAK,KAAK,MAAM,kBAAkB,GAAG;AACjD,UAAM,kBAAkB,0DAAkB;AAAA,EAC5C;AACA,MAAI,OAAO,MAAM,eAAe,YAAY,OAAO,MAAM,aAAa,UAAU;AAC9E,UAAM,eAAe,8DAAY;AAAA,EACnC;AACF;AAEA,SAAS,kBAAkB,SAA2B;AACpD,SAAO,IAAI,SAAS;AAAA,IAClB;AAAA,IACA;AAAA,IACA,kBAAkB;AAAA,EACpB,CAAC;AACH;AAEA,SAAS,eAAe,SAA2B;AACjD,SAAO,IAAI,SAAS;AAAA,IAClB;AAAA,IACA;AAAA,IACA,kBAAkB;AAAA,EACpB,CAAC;AACH;AAEA,SAAS,SAAS,OAAkD;AAClE,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;;;ADjFO,IAAM,aAAN,MAAiB;AAAA,EACtB,YACmB,aACA,YACA,SACjB;AAHiB;AACA;AACA;AAAA,EAChB;AAAA,EAHgB;AAAA,EACA;AAAA,EACA;AAAA,EAGnB,MAAM,aAA0C;AAC9C,QAAI;AACF,YAAM,QAAQ,KAAK,MAAM,MAAMC,UAAS,KAAK,WAAW,GAAG,MAAM,CAAC;AAClE,wBAAkB,KAAK;AACvB,aAAO;AAAA,IACT,SAAS,OAAO;AACd,UAAI,WAAW,KAAK,GAAG;AACrB,eAAO;AAAA,MACT;AACA,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAM,oBAA0C;AAC9C,WAAQ,MAAM,KAAK,WAAW,KAAM,kBAAkB,KAAK,YAAY,KAAK,OAAO;AAAA,EACrF;AAAA,EAEA,MAAM,YAAY,OAAmC;AACnD,UAAM,aAAY,oBAAI,KAAK,GAAE,YAAY;AACzC,UAAMC,OAAMC,MAAK,KAAK,aAAa,UAAU,GAAG,EAAE,WAAW,KAAK,CAAC;AACnE,UAAM,YAAY,KAAK,WAAW,GAAG,GAAG,KAAK,UAAU,OAAO,MAAM,CAAC,CAAC;AAAA,CAAI;AAAA,EAC5E;AAAA,EAEA,MAAM,WAAW,UAA+C;AAC9D,QAAI;AACF,YAAM,QAAQ,KAAK,MAAM,MAAMF,UAAS,KAAK,WAAW,QAAQ,GAAG,MAAM,CAAC;AAC1E,wBAAkB,KAAK;AACvB,aAAO;AAAA,IACT,SAAS,OAAO;AACd,UAAI,WAAW,KAAK,GAAG;AACrB,eAAO;AAAA,MACT;AACA,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAM,kBAAkB,UAAkB,OAA0C;AAClF,WAAQ,MAAM,KAAK,WAAW,QAAQ,KAAM,kBAAkB,KAAK,YAAY,UAAU,KAAK;AAAA,EAChG;AAAA,EAEA,MAAM,YAAY,OAAmC;AACnD,UAAM,aAAY,oBAAI,KAAK,GAAE,YAAY;AACzC,UAAMC,OAAMC,MAAK,KAAK,aAAa,YAAY,WAAW,MAAM,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;AAC9F,UAAM,YAAY,KAAK,WAAW,MAAM,QAAQ,GAAG,GAAG,KAAK,UAAU,OAAO,MAAM,CAAC,CAAC;AAAA,CAAI;AAAA,EAC1F;AAAA,EAEQ,aAAqB;AAC3B,WAAOA,MAAK,KAAK,aAAa,YAAY,gBAAgB;AAAA,EAC5D;AAAA,EAEQ,WAAW,UAA0B;AAC3C,WAAOA,MAAK,KAAK,aAAa,YAAY,WAAW,UAAU,gBAAgB;AAAA,EACjF;AACF;AAEA,SAAS,WAAW,OAAyB;AAC3C,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,UAAU,SAAS,MAAM,SAAS;AAC1F;;;AEtEA,SAAS,YAAAC,iBAAgB;AAEzB,eAAsB,qBAAqB,WAAsC;AAC/E,MAAI;AACJ,MAAI;AACF,cAAU,MAAMA,UAAS,WAAW,MAAM;AAAA,EAC5C,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,YAAsB,CAAC;AAC7B,QAAM,UAAU;AAChB,MAAI;AACJ,SAAQ,QAAQ,QAAQ,KAAK,OAAO,GAAI;AACtC,QAAI,MAAM,CAAC,GAAG;AACZ,gBAAU,KAAK,MAAM,CAAC,CAAC;AAAA,IACzB;AAAA,EACF;AACA,SAAO;AACT;;;ACbA,IAAM,iBAA8C;AAAA,EAClD,SAAS;AAAA,EACT,SAAS;AAAA,EACT,KAAK;AAAA,EACL,UAAU;AAAA,EACV,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,SAAS;AAAA,EACT,gBAAgB;AAAA,EAChB,SAAS;AACX;AAEA,eAAsB,aAAa,KAAwB,SAAiB,MAA+B;AACzG,QAAM,eAAe,gBAAgB,IAAI;AACzC,QAAM;AAAA,IACJ,IAAI;AAAA,IACJ,EAAE,SAAS,KAAK,IAAI,KAAK,YAAY,IAAI,WAAW;AAAA,IACpD,YAAY;AACV,UAAI,CAAC,QAAQ,WAAW,cAAc,EAAE,SAAS,OAAO,GAAG;AACzD,cAAM,eAAe,GAAG;AAAA,MAC1B;AAEA,YAAM,SAAS,MAAM,mBAAmB,KAAK,SAAS,YAAY;AAClE,YAAM,SAAS,MAAM,IAAI,SAAS,IAAI,OAAO,SAAS,OAAO,MAAM,EAAE,KAAK,IAAI,aAAa,OAAO,IAAI,OAAO,SAAS,UAAU,CAAC;AACjI,UAAI,OAAO,aAAa,GAAG;AACzB,cAAM,IAAI,SAAS;AAAA,UACjB;AAAA,UACA,SAAS,YAAY,OAAO;AAAA,UAC5B,SAAS;AAAA,UACT,aAAa;AAAA,QACf,CAAC;AAAA,MACH;AAEA,YAAM,aAAa,MAAM,IAAI,SAAS,eAAe,IAAI,WAAW;AACpE,YAAM,QAAQ,MAAM,IAAI,WAAW,kBAAkB;AACrD,YAAM,gBAAgB,WAAW;AACjC,UAAI,IAAI,YAAY,WAAW,QAAQ,SAAS,IAAI,QAAQ,GAAG;AAC7D,cAAM,iBAAiB,IAAI;AAAA,MAC7B,WAAW,MAAM,kBAAkB,CAAC,WAAW,QAAQ,SAAS,MAAM,cAAc,GAAG;AACrF,cAAM,iBAAiB,WAAW,QAAQ,WAAW,IAAK,WAAW,QAAQ,CAAC,KAAK,OAAQ;AAAA,MAC7F,WAAW,CAAC,MAAM,kBAAkB,WAAW,QAAQ,WAAW,GAAG;AACnE,cAAM,iBAAiB,WAAW,QAAQ,CAAC,KAAK;AAAA,MAClD;AACA,YAAM,IAAI,WAAW,YAAY,KAAK;AAEtC,YAAM,WAAW,IAAI,YAAY,MAAM;AACvC,UAAI,YAAY,WAAW,QAAQ,SAAS,QAAQ,GAAG;AACrD,cAAM,mBAAmB,MAAM,IAAI,SAAS,cAAc,IAAI,aAAa,QAAQ;AACnF,cAAM,cAAc,MAAM,IAAI,WAAW,kBAAkB,UAAU,eAAe,OAAO,KAAK,SAAS;AACzG,oBAAY,eAAe,eAAe,OAAO,KAAK,YAAY;AAClE,oBAAY,OAAO,YAAY,YAAY,IAAI;AAAA,UAC7C,QAAQ;AAAA,UACR,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,QACpC;AACA,oBAAY,sBAAsB;AAAA,UAChC,SAAS,OAAO;AAAA,UAChB,MAAM,OAAO;AAAA,UACb,UAAU,OAAO;AAAA,UACjB,QAAO,oBAAI,KAAK,GAAE,YAAY;AAAA,QAChC;AACA,oBAAY,MAAM,eAAe,MAAM,qBAAqB,iBAAiB,SAAS;AACtF,oBAAY,MAAM,gBAAe,oBAAI,KAAK,GAAE,YAAY;AACxD,cAAM,IAAI,WAAW,YAAY,WAAW;AAAA,MAC9C;AAAA,IACF;AAAA,EACF;AAEA,MAAI,OAAO,OAAO;AAAA,IAChB,IAAI;AAAA,IACJ;AAAA,IACA,SAAS,OAAO,OAAO;AAAA,EACzB,CAAC;AACH;AAEA,eAAsB,mBAAmB,KAAwB,SAAiB,MAA+B;AAC/G,QAAM,SAAS,MAAM,IAAI,SAAS,IAAI,SAAS,gBAAgB,IAAI,GAAG,EAAE,KAAK,IAAI,aAAa,OAAO,IAAI,OAAO,SAAS,UAAU,CAAC;AACpI,MAAI,OAAO,aAAa,GAAG;AACzB,UAAM,IAAI,SAAS;AAAA,MACjB;AAAA,MACA,SAAS,YAAY,OAAO;AAAA,MAC5B,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AACF;AAEA,SAAS,gBAAgB,MAA0B;AACjD,QAAM,SAAmB,CAAC;AAC1B,WAAS,QAAQ,GAAG,QAAQ,KAAK,QAAQ,SAAS,GAAG;AACnD,UAAM,MAAM,KAAK,KAAK;AACtB,QAAI,QAAQ,WAAW,QAAQ,YAAY;AACzC,eAAS;AACT;AAAA,IACF;AACA,QAAI,KAAK,WAAW,QAAQ,KAAK,KAAK,WAAW,WAAW,GAAG;AAC7D;AAAA,IACF;AACA,QAAI,QAAQ,WAAW,QAAQ,YAAY,QAAQ,eAAe,QAAQ,cAAc;AACtF;AAAA,IACF;AACA,QAAI,KAAK;AACP,aAAO,KAAK,GAAG;AAAA,IACjB;AAAA,EACF;AACA,SAAO;AACT;AAEA,eAAe,mBACb,KACA,SACA,MAC8C;AAC9C,UAAQ,SAAS;AAAA,IACf,KAAK;AAAA,IACL,KAAK;AACH,aAAO,EAAE,SAAS,OAAO,MAAM,KAAK,CAAC,MAAM,WAAW,OAAO,CAAC,UAAU,GAAG,IAAI,EAAE;AAAA,IACnF,KAAK;AACH,aAAO,EAAE,SAAS,gBAAgB,MAAM,CAAC,GAAG,iBAAiB,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,YAAY,MAAM,gBAAgB,GAAG,CAAC,EAAE;AAAA,IAC5I,KAAK;AACH,aAAO,EAAE,SAAS,UAAU,MAAM,CAAC,YAAY,MAAM,gBAAgB,GAAG,CAAC,EAAE;AAAA,IAC7E,KAAK;AACH,aAAO,EAAE,SAAS,gBAAgB,MAAM,CAAC,SAAS,YAAY,MAAM,gBAAgB,GAAG,CAAC,EAAE;AAAA,IAC5F,KAAK;AACH,aAAO,EAAE,SAAS,YAAY,MAAM,CAAC,IAAI,YAAY,KAAK,CAAC,KAAM,MAAM,gBAAgB,GAAG,GAAI,UAAU,UAAU,UAAU,EAAE;AAAA,IAChI,KAAK;AACH,aAAO,EAAE,SAAS,WAAW,MAAM,CAAC,IAAI,YAAY,KAAK,CAAC,KAAM,MAAM,gBAAgB,GAAG,GAAI,GAAG,KAAK,MAAM,IAAI,WAAW,IAAI,CAAC,CAAC,EAAE;AAAA,IACpI,KAAK;AACH,YAAM,IAAI,SAAS;AAAA,QACjB;AAAA,QACA,SAAS;AAAA,QACT,kBAAkB;AAAA,MACpB,CAAC;AAAA,IACH,KAAK;AACH,aAAO,EAAE,SAAS,gBAAgB,MAAM,CAAC,YAAY,YAAY,MAAM,gBAAgB,GAAG,CAAC,EAAE;AAAA,IAC/F,KAAK;AACH,aAAO,EAAE,SAAS,gBAAgB,MAAM,CAAC,EAAE;AAAA,IAC7C;AACE,aAAO,EAAE,SAAS,KAAK;AAAA,EAC3B;AACF;AAEA,eAAe,gBAAgB,KAAyC;AACtE,MAAI,IAAI,UAAU;AAChB,WAAO,IAAI;AAAA,EACb;AACA,QAAM,QAAQ,MAAM,IAAI,WAAW,kBAAkB;AACrD,MAAI,MAAM,gBAAgB;AACxB,WAAO,MAAM;AAAA,EACf;AACA,QAAM,aAAa,MAAM,IAAI,SAAS,eAAe,IAAI,WAAW;AACpE,MAAI,WAAW,QAAQ,WAAW,KAAK,WAAW,QAAQ,CAAC,GAAG;AAC5D,WAAO,WAAW,QAAQ,CAAC;AAAA,EAC7B;AACA,QAAM,IAAI,SAAS;AAAA,IACjB;AAAA,IACA,SAAS;AAAA,IACT,SAAS,EAAE,eAAe,WAAW,QAAQ;AAAA,IAC7C,kBAAkB;AAAA,EACpB,CAAC;AACH;AAEA,SAAS,iBAAiB,QAA4B;AACpD,SAAO,OAAO,OAAO,OAAO;AAC9B;AAEA,eAAe,eAAe,KAAuC;AACnE,QAAM,SAAS,MAAM,IAAI,WAAW,kBAAkB;AACtD,QAAM,WAAW,IAAI,YAAY,OAAO;AACxC,MAAI,CAAC,UAAU;AACb,UAAM,IAAI,SAAS;AAAA,MACjB;AAAA,MACA,SAAS;AAAA,MACT,kBAAkB;AAAA,IACpB,CAAC;AAAA,EACH;AACA,QAAM,SAAS,MAAM,IAAI,WAAW,WAAW,QAAQ;AACvD,QAAM,aAAa,MAAM,IAAI,SAAS,eAAe,IAAI,WAAW;AACpE,MAAI,CAAC,WAAW,QAAQ,SAAS,QAAQ,GAAG;AAC1C,UAAM,IAAI,SAAS;AAAA,MACjB;AAAA,MACA,SAAS;AAAA,MACT,SAAS,EAAE,UAAU,eAAe,WAAW,QAAQ;AAAA,MACvD,kBAAkB;AAAA,IACpB,CAAC;AAAA,EACH;AACA,MAAI,QAAQ,cAAc,WAAW,iBAAiB;AACpD,UAAM,IAAI,SAAS;AAAA,MACjB;AAAA,MACA,SAAS;AAAA,MACT,SAAS,EAAE,SAAS;AAAA,MACpB,kBAAkB,uBAAuB,QAAQ;AAAA,IACnD,CAAC;AAAA,EACH;AACF;;;ACxMA,SAAS,kBAAkB;AAC3B,SAAS,SAAAC,QAAO,YAAAC,WAAU,QAAAC,aAAY;AACtC,SAAS,QAAAC,aAAY;AAOrB,eAAsB,cAAc,KAAwB,SAA4D;AACtH,MAAI,QAAQ,MAAM;AAChB,UAAM,OAAO,MAAM,IAAI,QAAQ,KAAK,IAAI,aAAa,CAAC,CAAC;AACvD,UAAM,OAAO;AAAA,MACX,eAAe;AAAA,MACf,gBAAgB,KAAK,QAAQ;AAAA,MAC7B,YAAY;AAAA,QACV;AAAA,UACE,MAAM;AAAA,UACN,KAAK;AAAA,UACL,UAAU,OAAO,QAAQ,KAAK,QAAQ,EACnC,OAAO,CAAC,CAAC,IAAI,MAAM,CAAC,QAAQ,aAAa,MAAM,EAAE,SAAS,IAAI,CAAC,EAC/D,IAAI,CAAC,CAAC,WAAW,OAAO,OAAO;AAAA,YAC9B;AAAA,YACA,SAAS,QAAQ;AAAA,YACjB,QAAQ,QAAQ;AAAA,YAChB,UAAU,QAAQ;AAAA,YAClB,iBAAiB,QAAQ,WAAW,SAAS;AAAA,UAC/C,EAAE;AAAA,QACN;AAAA,MACF;AAAA,MACA,SAAS,CAAC,QAAQ,aAAa,MAAM,EAAE,OAAO,CAAC,SAAS,CAAC,KAAK,SAAS,IAAI,CAAC;AAAA,IAC9E;AACA,QAAI,IAAI,KAAK;AACX,YAAM,SAAS,MAAM,IAAI,WAAW,kBAAkB;AACtD,aAAO,sBAAsB;AAAA,QAC3B,eAAe;AAAA,QACf,aAAY,oBAAI,KAAK,GAAE,YAAY;AAAA,QACnC,oBAAoB,YAAY,IAAI;AAAA,QACpC,gBAAgB,KAAK;AAAA,QACrB,MAAM,KAAK,WAAW;AAAA,UAAQ,CAAC,cAC7B,UAAU,SAAS,IAAI,CAAC,aAAa;AAAA,YACnC,KAAK,UAAU;AAAA,YACf,WAAW,QAAQ;AAAA,YACnB,SAAS,QAAQ;AAAA,YACjB,QAAQ,QAAQ;AAAA,YAChB,UAAU,QAAQ;AAAA,UACpB,EAAE;AAAA,QACJ;AAAA,MACF;AACA,YAAM,IAAI,WAAW,YAAY,MAAM;AAAA,IACzC;AAEA,QAAI,OAAO,OAAO;AAAA,MAChB,IAAI;AAAA,MACJ,SAAS;AAAA,MACT,SAAS,IAAI,MAAM,8HAAyC;AAAA,MAC5D,UAAU,KAAK,QAAQ,IAAI,CAAC,SAAS,sBAAO,IAAI,+GAAqB;AAAA,MACrE,MAAM;AAAA,MACN,WAAW,IAAI,MAAM,CAAC,wGAA6B,IAAI,CAAC,wCAAU,4EAAoC,wGAA6B;AAAA,IACrI,CAAC;AACD;AAAA,EACF;AAEA,QAAM;AAAA,IACJ,IAAI;AAAA,IACJ,EAAE,SAAS,UAAU,KAAK,IAAI,KAAK,YAAY,IAAI,WAAW;AAAA,IAC9D,YAAY;AACV,YAAM,WAAW,MAAM,gBAAgB,GAAG;AAC1C,UAAI,QAAQ,MAAM;AAChB,cAAM,SAAS,KAAK,QAAQ;AAAA,MAC9B,OAAO;AACL,cAAM,kBAAkB,KAAK,QAAQ;AAAA,MACvC;AAAA,IACF;AAAA,EACF;AACF;AAEA,eAAe,kBAAkB,KAAwB,UAAiC;AACxF,QAAM,mBAAmB,KAAK,QAAQ;AACtC,QAAM,eAAc,oBAAI,KAAK,GAAE,YAAY;AAC3C,QAAM,MAAMC,MAAK,IAAI,aAAa,YAAY,WAAW,UAAU,MAAM;AACzE,QAAM,mBAAmBA,MAAK,KAAK,wBAAwB;AAC3D,QAAMC,OAAM,KAAK,EAAE,WAAW,KAAK,CAAC;AACpC,QAAM,YAAY,kBAAkB,yBAAyB,UAAU,WAAW,CAAC;AAEnF,QAAM,QAAQ,MAAM,IAAI,WAAW,kBAAkB,UAAU,QAAQ;AACvE,QAAM,eAAe;AACrB,QAAM,OAAO,SAAS,EAAE,QAAQ,eAAe,WAAW,YAAY;AACtE,QAAM,IAAI,WAAW,YAAY,KAAK;AAEtC,MAAI,OAAO,OAAO;AAAA,IAChB,IAAI;AAAA,IACJ,SAAS;AAAA,IACT,SAAS;AAAA,IACT,WAAW,CAAC,iCAAuB,QAAQ,gCAAgC,6DAAoC,QAAQ,EAAE;AAAA,EAC3H,CAAC;AACH;AAEA,eAAe,SAAS,KAAwB,UAAiC;AAC/E,QAAM,mBAAmB,KAAK,QAAQ;AACtC,QAAM,cAAa,oBAAI,KAAK,GAAE,YAAY;AAC1C,QAAM,mBAAmBD,MAAK,IAAI,aAAa,YAAY,WAAW,UAAU,QAAQ,wBAAwB;AAChH,QAAM,eAAe,MAAM,iBAAiB,kBAAkB,QAAQ;AACtE,QAAM,0BAA0B,qBAAqB,cAAc,aAAa,KAAK;AACrF,QAAM,QAAQ,MAAM,IAAI,WAAW,kBAAkB,UAAU,QAAQ;AACvE,QAAM,eAAe;AACrB,QAAM,OAAO,SAAS,EAAE,QAAQ,QAAQ,WAAW,WAAW;AAC9D,QAAM,eAAe;AAAA,IACnB,MAAM;AAAA,IACN,QAAQ;AAAA,IACR;AAAA,IACA,kBAAkB,oBAAoB,QAAQ;AAAA,IAC9C;AAAA,IACA,UAAU;AAAA,EACZ;AACA,QAAM,IAAI,WAAW,YAAY,KAAK;AAEtC,MAAI,OAAO,OAAO;AAAA,IAChB,IAAI;AAAA,IACJ,SAAS;AAAA,IACT,SAAS;AAAA,IACT,WAAW,CAAC,qBAAqB,QAAQ,IAAI,wBAAwB,QAAQ,EAAE;AAAA,EACjF,CAAC;AACH;AAEA,eAAe,mBAAmB,KAAwB,UAAiC;AACzF,QAAM,aAAa,MAAM,IAAI,SAAS,cAAc,IAAI,aAAa,QAAQ;AAC7E,MAAI,CAAC,WAAW,QAAQ;AACtB,UAAM,IAAI,SAAS;AAAA,MACjB;AAAA,MACA,SAAS;AAAA,MACT,SAAS,EAAE,SAAS;AAAA,MACpB,kBAAkB;AAAA,IACpB,CAAC;AAAA,EACH;AACF;AAEA,eAAe,iBAAiB,MAAc,UAAmC;AAC/E,MAAI;AACF,UAAME,MAAK,IAAI;AACf,UAAM,UAAU,MAAMC,UAAS,MAAM,MAAM;AAC3C,UAAM,eAAe,qBAAqB,SAAS,UAAU;AAC7D,QAAI,iBAAiB,UAAU;AAC7B,YAAM,IAAI,SAAS;AAAA,QACjB;AAAA,QACA,SAAS;AAAA,QACT,SAAS,EAAE,UAAU,UAAU,QAAQ,aAAa;AAAA,QACpD,kBAAkB,uBAAuB,QAAQ;AAAA,MACnD,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT,SAAS,OAAO;AACd,QAAI,iBAAiB,UAAU;AAC7B,YAAM;AAAA,IACR;AACA,UAAM,IAAI,SAAS;AAAA,MACjB;AAAA,MACA,SAAS;AAAA,MACT,SAAS,EAAE,KAAK;AAAA,MAChB,kBAAkB,uBAAuB,QAAQ;AAAA,IACnD,CAAC;AAAA,EACH;AACF;AAEA,SAAS,qBAAqB,SAAiB,KAA4B;AACzE,QAAM,QAAQ,QAAQ,MAAM,IAAI,OAAO,IAAI,GAAG,cAAc,GAAG,CAAC;AAChE,SAAO,QAAQ,CAAC,GAAG,KAAK,KAAK;AAC/B;AAEA,SAAS,YAAY,OAAwB;AAC3C,SAAO,UAAU,WAAW,QAAQ,EAAE,OAAO,KAAK,UAAU,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;AACnF;AAEA,eAAe,gBAAgB,KAAyC;AACtE,MAAI,IAAI,UAAU;AAChB,WAAO,IAAI;AAAA,EACb;AAEA,QAAM,SAAS,MAAM,IAAI,WAAW,kBAAkB;AACtD,MAAI,OAAO,gBAAgB;AACzB,WAAO,OAAO;AAAA,EAChB;AAEA,QAAM,aAAa,MAAM,IAAI,SAAS,eAAe,IAAI,WAAW;AACpE,MAAI,WAAW,QAAQ,WAAW,KAAK,WAAW,QAAQ,CAAC,GAAG;AAC5D,WAAO,WAAW,QAAQ,CAAC;AAAA,EAC7B;AAEA,QAAM,IAAI,SAAS;AAAA,IACjB;AAAA,IACA,SAAS;AAAA,IACT,SAAS,EAAE,eAAe,WAAW,QAAQ;AAAA,IAC7C,kBAAkB;AAAA,EACpB,CAAC;AACH;;;AClMA,SAAS,eAAe;;;ACAxB,SAAS,SAAAC,QAAO,YAAAC,WAAU,QAAAC,aAAY;AACtC,SAAS,WAAAC,UAAS,QAAAC,aAAY;;;ACC9B,IAAM,WAAW;AAAA,EACf;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEO,SAAS,mBAA6D;AAC3E,SAAO,SAAS,IAAI,CAAC,aAAa;AAAA,IAChC,MAAM,sBAAsB,OAAO;AAAA,IACnC,SAAS,YAAY,OAAO;AAAA,EAC9B,EAAE;AACJ;AAEO,SAAS,iBAAoD;AAClE,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS;AAAA;AAAA,cAEC,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkBvB;AACF;AAEA,SAAS,YAAY,SAAyB;AAC5C,SAAO;AAAA;AAAA,cAEK,WAAW;AAAA;AAAA;AAAA,eAGV,OAAO;AAAA;AAAA;AAAA;AAAA,YAIV,OAAO;AAAA,wCACqB,OAAO;AAAA;AAAA;AAAA;AAAA,wHAIP,OAAO,kGAA4B,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA,MAK5E,OAAO;AAAA;AAAA;AAAA;AAAA;AAKb;;;ADjEO,IAAM,gBAAN,MAA2C;AAAA,EACvC,OAAO;AAAA,EACP,iBAAiB;AAAA,EAE1B,MAAM,OAAO,aAAqB;AAChC,WAAO;AAAA,MACL,UAAU,MAAMC,QAAOC,MAAK,aAAa,SAAS,CAAC;AAAA,MACnD,QAAQ;AAAA,IACV;AAAA,EACF;AAAA,EAEA,MAAM,YAAY,cAAgD;AAChE,WAAO;AAAA,MACL,MAAM,KAAK;AAAA,MACX,OAAO,CAAC,GAAG,iBAAiB,GAAG,eAAe,CAAC,EAAE,IAAI,CAAC,UAAU;AAAA,QAC9D,GAAG;AAAA,QACH,SAAS;AAAA,MACX,EAAE;AAAA,IACJ;AAAA,EACF;AAAA,EAEA,MAAM,QAAQ,aAAqB,MAAuB,QAAQ,OAAmC;AACnG,UAAM,UAAoB,CAAC;AAC3B,UAAM,UAAoB,CAAC;AAE3B,eAAW,QAAQ,KAAK,OAAO;AAC7B,YAAM,SAASA,MAAK,aAAa,KAAK,IAAI;AAC1C,YAAM,WAAW,MAAM,aAAa,MAAM;AAC1C,UAAI,YAAY,CAAC,SAAS,SAAS,aAAa,KAAK,CAAC,OAAO;AAC3D,cAAM,IAAI,SAAS;AAAA,UACjB;AAAA,UACA,SAAS;AAAA,UACT,SAAS,EAAE,MAAM,KAAK,KAAK;AAAA,UAC3B,kBAAkB;AAAA,QACpB,CAAC;AAAA,MACH;AACA,UAAI,YAAY,CAAC,SAAS,SAAS,aAAa,KAAK,OAAO;AAC1D,cAAM,aAAa,MAAM;AAAA,MAC3B;AACA,YAAMC,OAAMC,SAAQ,MAAM,GAAG,EAAE,WAAW,KAAK,CAAC;AAChD,YAAM,YAAY,QAAQ,KAAK,OAAO;AACtC,cAAQ,KAAK,KAAK,IAAI;AAAA,IACxB;AAEA,WAAO,EAAE,MAAM,KAAK,MAAM,SAAS,QAAQ;AAAA,EAC7C;AAAA,EAEA,MAAM,OAAO,aAA6C;AACxD,UAAM,OAAO,MAAM,KAAK,YAAY,WAAW;AAC/C,UAAM,SAAwB,CAAC;AAC/B,eAAW,QAAQ,KAAK,OAAO;AAC7B,YAAM,SAASF,MAAK,aAAa,KAAK,IAAI;AAC1C,YAAM,UAAU,MAAM,aAAa,MAAM;AACzC,YAAM,UAAU,QAAQ,SAAS,SAAS,aAAa,CAAC;AACxD,YAAM,iBAAiB,QAAQ,SAAS,SAAS,mBAAmB,KAAK,cAAc,EAAE,CAAC;AAC1F,aAAO,KAAK;AAAA,QACV,IAAI,UAAU,KAAK,IAAI;AAAA,QACvB,QAAQ,CAAC,UAAU,SAAS,WAAW,iBAAiB,SAAS;AAAA,QACjE,SAAS,CAAC,UACN,GAAG,KAAK,IAAI,kBACZ,CAAC,UACC,GAAG,KAAK,IAAI,qDACZ,CAAC,iBACC,GAAG,KAAK,IAAI,uCACZ,GAAG,KAAK,IAAI;AAAA,QACpB,kBAAkB,CAAC,WAAW,CAAC,WAAW,CAAC,iBAAiB,aAAa;AAAA,MAC3E,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAEA,eAAe,aAAa,MAAsC;AAChE,MAAI;AACF,WAAO,MAAMG,UAAS,MAAM,MAAM;AAAA,EACpC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAeJ,QAAO,MAAgC;AACpD,MAAI;AACF,UAAMK,MAAK,IAAI;AACf,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;AEhGA,SAAS,YAAAC,iBAAgB;AACzB,SAAS,aAAAC,kBAAiB;;;ACD1B,SAAS,SAAS,QAAAC,aAAY;AAC9B,SAAS,QAAAC,cAAY;AAGrB,eAAsB,uBAAuB,aAAyD;AACpG,QAAM,eAAeA,OAAK,aAAa,UAAU;AACjD,QAAM,cAAcA,OAAK,cAAc,SAAS;AAChD,QAAM,cAAcA,OAAK,cAAc,SAAS;AAEhD,SAAO;AAAA,IACL,QAAQ,MAAMC,QAAO,YAAY;AAAA,IACjC,SAAS,MAAM,gBAAgB,WAAW;AAAA,IAC1C,UAAU,MAAM,gBAAgB,WAAW;AAAA,EAC7C;AACF;AAEA,eAAsB,sBACpB,aACA,UACmC;AACnC,QAAM,aAAaD,OAAK,aAAa,YAAY,WAAW,QAAQ;AACpE,QAAM,YAAYA,OAAK,YAAY,UAAU;AAC7C,QAAM,YAAYA,OAAK,YAAY,OAAO;AAE1C,SAAO;AAAA,IACL;AAAA,IACA,QAAQ,MAAMC,QAAO,UAAU;AAAA,IAC/B,aAAa,MAAMA,QAAOD,OAAK,YAAY,aAAa,CAAC;AAAA,IACzD,UAAU,MAAMC,QAAO,SAAS;AAAA,IAChC,UAAU,MAAMA,QAAO,SAAS;AAAA,IAChC;AAAA,IACA;AAAA,EACF;AACF;AAEA,eAAe,gBAAgB,MAAiC;AAC9D,MAAI;AACF,UAAM,UAAU,MAAM,QAAQ,MAAM,EAAE,eAAe,KAAK,CAAC;AAC3D,WAAO,QAAQ,OAAO,CAAC,UAAU,MAAM,YAAY,CAAC,EAAE,IAAI,CAAC,UAAU,MAAM,IAAI;AAAA,EACjF,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAEA,eAAeA,QAAO,MAAgC;AACpD,MAAI;AACF,UAAMF,MAAK,IAAI;AACf,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;ACnDA,SAAS,YAAAG,iBAAgB;AACzB,SAAS,aAAAC,kBAAiB;AAK1B,IAAMC,iBAAgBC,WAAUC,SAAQ;AAExC,eAAsB,4BAAuD;AAC3E,QAAM,iBAAiB,MAAM,eAAe;AAC5C,QAAM,UAAU,MAAM,YAAY,cAAc;AAChD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,gBAAgB;AAAA,EAClB;AACF;AAEA,eAAe,iBAAkC;AAC/C,QAAM,UAAU,QAAQ,aAAa,UAAU,cAAc;AAC7D,MAAI;AACF,UAAM,EAAE,OAAO,IAAI,MAAM,KAAK,SAAS,CAAC,UAAU,CAAC;AACnD,UAAM,QAAQ,OACX,MAAM,OAAO,EACb,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC,EACzB,KAAK,OAAO;AACf,QAAI,OAAO;AACT,aAAO;AAAA,IACT;AAAA,EACF,QAAQ;AAAA,EAER;AAEA,MAAI;AACF,UAAM,KAAK,OAAO,CAAC,YAAY,WAAW,CAAC;AAC3C,WAAO;AAAA,EACT,QAAQ;AACN,UAAM,IAAI,SAAS;AAAA,MACjB;AAAA,MACA,SAAS;AAAA,MACT,kBAAkB;AAAA,IACpB,CAAC;AAAA,EACH;AACF;AAEA,eAAe,YAAY,gBAAyC;AAClE,QAAM,UAAU,mBAAmB,iBAAiB,QAAQ;AAC5D,QAAM,OAAO,mBAAmB,iBAAiB,CAAC,YAAY,WAAW,IAAI,CAAC,WAAW;AACzF,MAAI;AACF,UAAM,EAAE,QAAQ,OAAO,IAAI,MAAM,KAAK,SAAS,IAAI;AACnD,WAAO,OAAO,KAAK,KAAK,OAAO,KAAK,KAAK;AAAA,EAC3C,SAAS,OAAO;AACd,UAAM,IAAI,SAAS;AAAA,MACjB;AAAA,MACA,SAAS;AAAA,MACT,SAAS,EAAE,eAAe;AAAA,MAC1B,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AACF;AAEA,SAAS,KAAK,SAAiB,MAAgB;AAC7C,SAAOF,eAAc,SAAS,MAAM,EAAE,OAAO,QAAQ,aAAa,QAAQ,CAAC;AAC7E;;;AC/DA,SAAS,aAAa;AAKtB,eAAsB,YACpB,gBACA,SACA,MACA,SAC4B;AAC5B,QAAM,eAAe,mBAAmB,iBAAiB,QAAQ;AACjE,QAAM,YAAY,mBAAmB,iBAAiB,CAAC,YAAY,SAAS,GAAG,IAAI,IAAI,CAAC,SAAS,GAAG,IAAI;AAExG,SAAO,IAAI,QAAQ,CAACG,UAAS,WAAW;AACtC,UAAM,SAAmB,CAAC;AAC1B,UAAM,SAAmB,CAAC;AAC1B,UAAM,QAAQ,MAAM,cAAc,WAAW;AAAA,MAC3C,KAAK,QAAQ;AAAA,MACb,OAAO,QAAQ,SAAS;AAAA,MACxB,OAAO,QAAQ,aAAa;AAAA,IAC9B,CAAC;AAED,QAAI,MAAM,QAAQ;AAChB,YAAM,OAAO,GAAG,QAAQ,CAAC,UAAkB,OAAO,KAAK,KAAK,CAAC;AAAA,IAC/D;AACA,QAAI,MAAM,QAAQ;AAChB,YAAM,OAAO,GAAG,QAAQ,CAAC,UAAkB,OAAO,KAAK,KAAK,CAAC;AAAA,IAC/D;AAEA,UAAM,GAAG,SAAS,CAAC,UAAU;AAC3B;AAAA,QACE,IAAI,SAAS;AAAA,UACX;AAAA,UACA,SAAS;AAAA,UACT,SAAS,EAAE,SAAS,KAAK;AAAA,UACzB,OAAO;AAAA,QACT,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AAED,UAAM,GAAG,SAAS,CAAC,UAAU,WAAW;AACtC,MAAAA,SAAQ;AAAA,QACN;AAAA,QACA;AAAA,QACA,UAAU,YAAY;AAAA,QACtB;AAAA,QACA,QAAQ,OAAO,SAAS,OAAO,OAAO,MAAM,EAAE,SAAS,MAAM,IAAI;AAAA,QACjE,QAAQ,OAAO,SAAS,OAAO,OAAO,MAAM,EAAE,SAAS,MAAM,IAAI;AAAA,MACnE,CAAC;AAAA,IACH,CAAC;AAAA,EACH,CAAC;AACH;;;AHrCA,IAAMC,iBAAgBC,WAAUC,SAAQ;AAEjC,IAAM,yBAAN,MAAwD;AAAA,EACrD;AAAA,EAER,MAAM,oBAA+C;AACnD,SAAK,aAAa,MAAM,0BAA0B;AAClD,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAM,kBAAiD;AACrD,UAAM,WAAW,MAAM,KAAK,kBAAkB;AAC9C,UAAM,aAAa,SAAS,mBAAmB,iBAAiB,QAAQ,SAAS;AACjF,UAAM,OAAO,SAAS,mBAAmB,iBAAiB,CAAC,YAAY,QAAQ,IAAI,CAAC,QAAQ;AAE5F,QAAI;AACF,YAAM,EAAE,OAAO,IAAI,MAAMF,eAAc,YAAY,MAAM,EAAE,OAAO,QAAQ,aAAa,QAAQ,CAAC;AAChG,aAAO;AAAA,QACL,SAAS,SAAS;AAAA,QAClB,UAAU,cAAc,MAAM;AAAA,QAC9B,WAAW;AAAA,MACb;AAAA,IACF,QAAQ;AACN,aAAO;AAAA,QACL,SAAS,SAAS;AAAA,QAClB,UAAU,CAAC;AAAA,QACX,WAAW;AAAA,MACb;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,IAAI,SAAiB,MAAgB,SAAyD;AAClG,UAAM,WAAW,MAAM,KAAK,kBAAkB;AAC9C,WAAO,YAAY,SAAS,gBAAgB,SAAS,MAAM,OAAO;AAAA,EACpE;AAAA,EAEA,eAAe,aAAyD;AACtE,WAAO,uBAAuB,WAAW;AAAA,EAC3C;AAAA,EAEA,cAAc,aAAqB,UAAqD;AACtF,WAAO,sBAAsB,aAAa,QAAQ;AAAA,EACpD;AACF;AAEA,SAAS,cAAc,MAAwB;AAC7C,QAAM,QAAQ;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,SAAO,MAAM,OAAO,CAAC,YAAY,KAAK,SAAS,OAAO,CAAC;AACzD;;;AI5EA,SAAS,YAAAG,YAAU,QAAAC,aAAY;AAC/B,SAAS,QAAAC,cAAY;AACrB,SAAS,aAAa;AAYtB,eAAsB,gBAAgB,aAAkD;AACtF,MAAI;AACF,WAAO,KAAK,MAAM,MAAMF,WAASE,OAAK,aAAa,cAAc,GAAG,MAAM,CAAC;AAAA,EAC7E,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAQA,eAAsB,qBAAqB,aAAqB,KAA2D;AACzH,QAAM,WAAqB,CAAC;AAC5B,MAAI,KAAK,gBAAgB;AACvB,UAAM,WAAW,IAAI,eAAe,MAAM,GAAG,EAAE,CAAC,KAAK;AACrD,UAAMC,SAAQ,MAAM,mBAAmB,WAAW;AAClD,UAAM,cAAcA,OAAM,OAAO,CAAC,SAAS,SAAS,QAAQ;AAC5D,QAAI,YAAY,QAAQ;AACtB,eAAS,KAAK,qCAAsB,QAAQ,+DAAa,YAAY,KAAK,IAAI,CAAC,EAAE;AAAA,IACnF;AACA,WAAO,EAAE,SAAS,UAAU,YAAY,QAAQ,SAAS;AAAA,EAC3D;AAEA,QAAM,QAAQ,MAAM,mBAAmB,WAAW;AAClD,MAAI,MAAM,SAAS,GAAG;AACpB,aAAS,KAAK,2EAAe,MAAM,KAAK,IAAI,CAAC,kCAAS,MAAM,CAAC,CAAC,EAAE;AAChE,WAAO,EAAE,SAAS,MAAM,CAAC,KAAK,OAAO,YAAY,UAAU,SAAS;AAAA,EACtE;AACA,MAAI,MAAM,CAAC,GAAG;AACZ,WAAO,EAAE,SAAS,MAAM,CAAC,GAAG,YAAY,QAAQ,SAAS;AAAA,EAC3D;AACA,SAAO,EAAE,SAAS,OAAO,YAAY,OAAO,SAAS;AACvD;AAEO,SAAS,gBAAgB,KAAyB,gBAAwD;AAC/G,QAAM,UAAU,KAAK,WAAW,CAAC;AACjC,QAAM,SAAyC,CAAC;AAChD,QAAM,cAAc,CAAC,OAAO,SAAS,QAAQ,aAAa,SAAS,QAAQ,WAAW;AAEtF,aAAW,QAAQ,aAAa;AAC9B,QAAI,QAAQ,IAAI,GAAG;AACjB,YAAM,YAAY,SAAS,UAAU,cAAc,SAAS,cAAc,SAAS;AACnF,UAAI,OAAO,SAAS,GAAG;AACrB;AAAA,MACF;AACA,aAAO,SAAS,IAAI;AAAA,QAClB,SAAS,cAAc,gBAAgB,IAAI;AAAA,QAC3C,QAAQ,wBAAwB,IAAI;AAAA,QACpC,UAAU,SAAS;AAAA,MACrB;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAEO,SAAS,gBAAgB,KAAqG;AACnI,QAAM,OAAO,EAAE,GAAI,KAAK,gBAAgB,CAAC,GAAI,GAAI,KAAK,mBAAmB,CAAC,EAAG;AAC7E,QAAM,aAAwC;AAAA,IAC5C,CAAC,QAAQ,CAAC,MAAM,CAAC;AAAA,IACjB,CAAC,QAAQ,CAAC,MAAM,CAAC;AAAA,IACjB,CAAC,QAAQ,CAAC,MAAM,CAAC;AAAA,IACjB,CAAC,aAAa,CAAC,eAAe,CAAC;AAAA,IAC/B,CAAC,WAAW,CAAC,iBAAiB,cAAc,CAAC;AAAA,IAC7C,CAAC,SAAS,CAAC,OAAO,CAAC;AAAA,IACnB,CAAC,OAAO,CAAC,KAAK,CAAC;AAAA,IACf,CAAC,UAAU,CAAC,QAAQ,CAAC;AAAA,EACvB;AACA,aAAW,CAAC,WAAW,QAAQ,KAAK,YAAY;AAC9C,QAAI,SAAS,KAAK,CAAC,SAAS,KAAK,IAAI,CAAC,GAAG;AACvC,aAAO,EAAE,MAAM,WAAW,YAAY,QAAQ,SAAS,CAAC,cAAc,EAAE;AAAA,IAC1E;AAAA,EACF;AACA,SAAO,EAAE,MAAM,WAAW,YAAY,OAAO,SAAS,CAAC,EAAE;AAC3D;AAEA,eAAsB,eAAe,aAAqB,KAA0C;AAClG,QAAM,OAAO,EAAE,GAAI,KAAK,gBAAgB,CAAC,GAAI,GAAI,KAAK,mBAAmB,CAAC,EAAG;AAC7E,MAAI,KAAK,cAAe,MAAMC,QAAOF,OAAK,aAAa,eAAe,CAAC,GAAI;AACzE,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEA,eAAsB,iBAAiB,aAAqB,KAAsD;AAChH,QAAM,oBAAoB,oBAAoB,KAAK,UAAU,EAAE,IAAI,CAAC,UAAU;AAAA,IAC5E,MAAM;AAAA,IACN;AAAA,IACA,QAAQ;AAAA,EACV,EAAE;AACF,MAAI,kBAAkB,QAAQ;AAC5B,WAAO;AAAA,EACT;AAEA,MAAI;AACF,UAAM,YAAY,MAAM,MAAMF,WAASE,OAAK,aAAa,qBAAqB,GAAG,MAAM,CAAC;AACxF,YAAQ,WAAW,YAAY,CAAC,GAAG,IAAI,CAAC,UAAU;AAAA,MAChD,MAAM;AAAA,MACN;AAAA,MACA,QAAQ;AAAA,IACV,EAAE;AAAA,EACJ,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAEA,eAAe,mBAAmB,aAAwC;AACxE,QAAM,YAAqC;AAAA,IACzC,CAAC,kBAAkB,MAAM;AAAA,IACzB,CAAC,aAAa,MAAM;AAAA,IACpB,CAAC,aAAa,KAAK;AAAA,IACnB,CAAC,YAAY,KAAK;AAAA,IAClB,CAAC,qBAAqB,KAAK;AAAA,EAC7B;AACA,QAAM,QAAkB,CAAC;AACzB,aAAW,CAAC,MAAM,OAAO,KAAK,WAAW;AACvC,QAAI,MAAME,QAAOF,OAAK,aAAa,IAAI,CAAC,GAAG;AACzC,YAAM,KAAK,OAAO;AAAA,IACpB;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,oBAAoB,YAAiD;AAC5E,MAAI,MAAM,QAAQ,UAAU,GAAG;AAC7B,WAAO;AAAA,EACT;AACA,SAAO,YAAY,YAAY,CAAC;AAClC;AAEA,SAAS,cAAc,gBAAwB,MAAsB;AACnE,SAAO,mBAAmB,QAAQ,WAAW,IAAI,KAAK,GAAG,cAAc,IAAI,IAAI;AACjF;AAEA,eAAeE,QAAO,MAAgC;AACpD,MAAI;AACF,UAAMH,MAAK,IAAI;AACf,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;AC9JA,SAAS,WAAAI,UAAS,QAAAC,aAAY;AAC9B,SAAS,QAAAC,QAAM,UAAU,WAAW;AAGpC,eAAsB,WAAW,aAA8C;AAC7E,QAAM,aAAa,CAAC,cAAc,aAAa,OAAO,OAAO;AAC7D,QAAM,SAAyB,CAAC;AAEhC,aAAW,aAAa,YAAY;AAClC,UAAM,OAAOA,OAAK,aAAa,SAAS;AACxC,QAAI,CAAE,MAAMC,QAAO,IAAI,GAAI;AACzB;AAAA,IACF;AACA,eAAW,QAAQ,MAAM,UAAU,IAAI,GAAG;AACxC,UAAI,CAAC,4BAA4B,KAAK,IAAI,GAAG;AAC3C;AAAA,MACF;AACA,aAAO,KAAK;AAAA,QACV,MAAM,eAAe,SAAS,MAAM,IAAI,CAAC;AAAA,QACzC,QAAQ,SAAS,aAAa,IAAI,EAAE,MAAM,GAAG,EAAE,KAAK,GAAG;AAAA,QACvD,UAAU;AAAA,QACV,YAAY;AAAA,MACd,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO,OAAO,MAAM,GAAG,GAAG;AAC5B;AAEA,SAAS,eAAe,cAA8B;AACpD,QAAM,aAAa,aAAa,MAAM,GAAG,EAAE,KAAK,GAAG;AACnD,QAAM,aAAa,WAAW,QAAQ,6BAA6B,EAAE;AACrE,QAAM,eAAe,WAAW,QAAQ,YAAY,EAAE,EAAE,QAAQ,WAAW,EAAE;AAC7E,SAAO,IAAI,YAAY,GAAG,QAAQ,QAAQ,GAAG;AAC/C;AAEA,eAAe,UAAU,MAAiC;AACxD,QAAM,UAAU,MAAMH,SAAQ,MAAM,EAAE,eAAe,KAAK,CAAC;AAC3D,QAAM,QAAkB,CAAC;AACzB,aAAW,SAAS,SAAS;AAC3B,UAAM,OAAOE,OAAK,MAAM,MAAM,IAAI;AAClC,QAAI,MAAM,YAAY,GAAG;AACvB,YAAM,KAAK,GAAI,MAAM,UAAU,IAAI,CAAE;AAAA,IACvC,OAAO;AACL,YAAM,KAAK,IAAI;AAAA,IACjB;AAAA,EACF;AACA,SAAO;AACT;AAEA,eAAeC,QAAO,MAAgC;AACpD,MAAI;AACF,UAAMF,MAAK,IAAI;AACf,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;ACrDO,IAAM,iBAAN,MAAqB;AAAA,EAC1B,MAAM,KAAK,aAAqB,WAAwB,CAAC,GAA+B;AACtF,UAAM,MAAM,MAAM,gBAAgB,WAAW;AAC7C,UAAM,iBAAiB,MAAM,qBAAqB,aAAa,GAAG;AAClE,UAAM,YAAY,gBAAgB,GAAG;AACrC,UAAM,aAAa,MAAM,iBAAiB,aAAa,GAAG;AAC1D,UAAM,WAAW,MAAM,eAAe,aAAa,GAAG;AACtD,UAAM,WAAW,CAAC,GAAG,eAAe,QAAQ;AAC5C,QAAI,UAAU,SAAS,WAAW;AAChC,eAAS,KAAK,sEAAyB;AAAA,IACzC;AAEA,WAAO;AAAA,MACL,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,MACpC,gBAAgB;AAAA,MAChB,SAAS;AAAA,QACP,MAAM,KAAK,QAAQ;AAAA,QACnB,gBAAgB,eAAe;AAAA,QAC/B,0BAA0B,eAAe;AAAA,QACzC;AAAA,QACA;AAAA,QACA,UAAU,WAAW,SAAS;AAAA,QAC9B;AAAA,MACF;AAAA,MACA,UAAU,gBAAgB,KAAK,eAAe,OAAO;AAAA,MACrD,QAAQ,MAAM,WAAW,WAAW;AAAA,MACpC,aAAa,CAAC;AAAA,MACd,cAAc,CAAC;AAAA,MACf;AAAA,IACF;AAAA,EACF;AACF;;;ACxBO,IAAM,eAAN,MAAmB;AAAA,EACxB,YAA6B,MAAe;AAAf;AAAA,EAAgB;AAAA,EAAhB;AAAA,EAE7B,KAAK,SAAiB,SAAyB;AAC7C,QAAI,CAAC,KAAK,MAAM;AACd,cAAQ,OAAO,MAAM,GAAG,OAAO,GAAG,cAAc,OAAO,CAAC;AAAA,CAAI;AAAA,IAC9D;AAAA,EACF;AAAA,EAEA,KAAK,SAAiB,SAAyB;AAC7C,QAAI,CAAC,KAAK,MAAM;AACd,cAAQ,OAAO,MAAM,qBAAM,OAAO,GAAG,cAAc,OAAO,CAAC;AAAA,CAAI;AAAA,IACjE;AAAA,EACF;AAAA,EAEA,MAAM,OAAuB;AAC3B,QAAI,KAAK,MAAM;AACb,cAAQ,OAAO,MAAM,GAAG,KAAK,UAAU,EAAE,IAAI,OAAO,OAAO,MAAM,OAAO,EAAE,GAAG,MAAM,CAAC,CAAC;AAAA,CAAI;AACzF;AAAA,IACF;AAEA,YAAQ,OAAO,MAAM,qCAAY,MAAM,OAAO;AAAA,CAAI;AAClD,QAAI,MAAM,YAAY,QAAW;AAC/B,cAAQ,OAAO,MAAM;AAAA;AAAA,EAAU,YAAY,MAAM,OAAO,CAAC;AAAA,CAAI;AAAA,IAC/D;AACA,QAAI,MAAM,kBAAkB;AAC1B,cAAQ,OAAO,MAAM;AAAA;AAAA,IAAY,MAAM,gBAAgB;AAAA,CAAI;AAAA,IAC7D;AAAA,EACF;AAAA,EAEA,OAAO,QAA6B;AAClC,QAAI,KAAK,MAAM;AACb,cAAQ,OAAO,MAAM,GAAG,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAAA,CAAI;AAC3D;AAAA,IACF;AAEA,YAAQ,OAAO,MAAM,GAAG,OAAO,OAAO;AAAA,CAAI;AAC1C,eAAW,WAAW,OAAO,YAAY,CAAC,GAAG;AAC3C,cAAQ,OAAO,MAAM,qBAAM,OAAO;AAAA,CAAI;AAAA,IACxC;AACA,QAAI,OAAO,WAAW,QAAQ;AAC5B,cAAQ,OAAO,MAAM,8BAAU;AAC/B,iBAAW,QAAQ,OAAO,WAAW;AACnC,gBAAQ,OAAO,MAAM,KAAK,IAAI;AAAA,CAAI;AAAA,MACpC;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,cAAc,SAA0B;AAC/C,MAAI,YAAY,QAAW;AACzB,WAAO;AAAA,EACT;AACA,SAAO,IAAI,KAAK,UAAU,OAAO,CAAC;AACpC;AAEA,SAAS,YAAY,SAA0B;AAC7C,MAAI,OAAO,YAAY,UAAU;AAC/B,WAAO,KAAK,OAAO;AAAA,EACrB;AACA,SAAO,KAAK,UAAU,SAAS,MAAM,CAAC,EACnC,MAAM,IAAI,EACV,IAAI,CAAC,SAAS,KAAK,IAAI,EAAE,EACzB,KAAK,IAAI;AACd;;;AV3DA,eAAsB,qBAAqB,SAAiB,SAAwB;AAClF,QAAM,cAAc,QAAQ,QAAQ,OAAO,QAAQ,IAAI,CAAC;AACxD,QAAM,UAAU,MAAM,sBAAsB,WAAW;AACvD,QAAM,SAAS,IAAI,aAAa,QAAQ,QAAQ,IAAI,CAAC;AAErD,SAAO;AAAA,IACL;AAAA,IACA,KAAK;AAAA,IACL;AAAA,IACA,OAAO,QAAQ,QAAQ,OAAO,KAAK;AAAA,IACnC,MAAM,QAAQ,QAAQ,IAAI;AAAA,IAC1B,SAAS,QAAQ,QAAQ,OAAO;AAAA,IAChC,KAAK,QAAQ,QAAQ,GAAG;AAAA,IACxB,UAAU,QAAQ;AAAA,IAClB,YAAY;AAAA,IACZ;AAAA,IACA,YAAY,IAAI,WAAW,aAAa,aAAa,OAAO;AAAA,IAC5D,UAAU,IAAI,uBAAuB;AAAA,IACrC,SAAS,IAAI,eAAe;AAAA,IAC5B,cAAc,CAAC,IAAI,cAAc,CAAC;AAAA,EACpC;AACF;;;ArB1BA,IAAM,UAAU,IAAI,QAAQ;AAE5B,QACG,KAAK,KAAK,EACV,YAAY,6DAA6D,EACzE,wBAAwB,EACxB,QAAQ,WAAW,EACnB,OAAO,gBAAgB,4CAAS,EAChC,OAAO,iBAAiB,8BAAoB,EAC5C,OAAO,SAAS,0EAAc,EAC9B,OAAO,UAAU,2CAAa,EAC9B,OAAO,aAAa,sCAAQ,EAC5B,OAAO,cAAc,sCAAQ;AAEhC,iBAAiB,QAAQ,QAAQ,MAAM,CAAC,EAAE,YAAY,mCAAoB,EAAE,OAAO,KAAK,QAAQ,WAAW,CAAC;AAC5G,iBAAiB,QAAQ,QAAQ,gBAAgB,CAAC,EAAE,YAAY,4CAAS,EAAE,OAAO,KAAK,kBAAkB,oBAAoB,CAAC;AAC9H,iBAAiB,QACd,QAAQ,QAAQ,EAChB,YAAY,oEAAa,EACzB,OAAO,cAAc,qCAAY,CAAC,EAClC;AAAA,EACC,KAAK,UAAU,CAAC,KAAK,YAAmC,cAAc,KAAK,EAAE,SAAS,QAAQ,QAAQ,OAAO,EAAE,CAAC,CAAC;AACnH;AAEF,iBAAiB,QACd,QAAQ,QAAQ,EAChB,YAAY,sCAAQ,EACpB,OAAO,UAAU,wDAAW,EAC5B,OAAO,UAAU,oEAAa,CAAC,EAC/B,OAAO,KAAK,UAAU,aAAa,CAAC;AAEvC,WAAW,WAAW,CAAC,WAAW,WAAW,OAAO,YAAY,MAAM,SAAS,QAAQ,WAAW,gBAAgB,SAAS,GAAG;AAC5H,mBAAiB,QACd,QAAQ,GAAG,OAAO,YAAY,EAC9B,YAAY,qCAAiB,OAAO,EAAE,EACtC,mBAAmB,IAAI,EACvB,mBAAmB,CAAC,EACpB,OAAO,KAAK,SAAS,CAAC,KAAK,OAAiB,CAAC,MAAM,aAAa,KAAK,SAAS,IAAI,CAAC,CAAC;AACzF;AAEA,iBAAiB,QACd,QAAQ,iCAAiC,EACzC,YAAY,kEAAqB,EACjC,mBAAmB,IAAI,EACvB,mBAAmB,CAAC,EACpB,OAAO,KAAK,eAAe,CAAC,KAAK,SAAiB,OAAiB,CAAC,MAAM,mBAAmB,KAAK,SAAS,IAAI,CAAC,CAAC;AAEpH,QAAQ,WAAW,QAAQ,IAAI,EAAE,MAAM,CAAC,UAAU;AAChD,QAAM,OAAO,QAAQ,KAAK,SAAS,QAAQ;AAC3C,QAAM,SAAS,IAAI,aAAa,IAAI;AACpC,QAAM,WAAW,WAAW,KAAK;AACjC,SAAO,MAAM,QAAQ;AACrB,UAAQ,WAAW,SAAS;AAC9B,CAAC;AAED,SAAS,KACP,SACA,SACA;AACA,SAAO,UAAU,SAAY;AAC3B,UAAM,eAAe,KAAK,KAAK,SAAS,CAAC;AACzC,UAAM,OAAO,cAAc,YAAY,IAClC,EAAE,GAAI,aAAa,QAAQ,KAAK,GAAqB,GAAI,aAAa,KAAK,EAAoB,IAC/F,QAAQ,KAAK;AAClB,UAAM,MAAM,MAAM,qBAAqB,SAAS,EAAE,GAAG,MAAM,GAAG,qBAAqB,IAAI,EAAE,CAAC;AAC1F,QAAI;AACF,YAAM,QAAQ,KAAK,GAAG,IAAI;AAAA,IAC5B,SAAS,OAAO;AACd,YAAM,WAAW,WAAW,KAAK;AACjC,UAAI,OAAO,MAAM,QAAQ;AACzB,cAAQ,WAAW,SAAS;AAAA,IAC9B;AAAA,EACF;AACF;AAEA,SAAS,cAAc,OAAkC;AACvD,SAAO,iBAAiB;AAC1B;AAEA,SAAS,iBAAiB,SAA2B;AACnD,SAAO,QACJ,OAAO,gBAAgB,4CAAS,EAChC,OAAO,iBAAiB,8BAAoB,EAC5C,OAAO,SAAS,0EAAc,EAC9B,OAAO,UAAU,2CAAa,EAC9B,OAAO,aAAa,sCAAQ,EAC5B,OAAO,cAAc,sCAAQ;AAClC;AAEA,SAAS,qBAAqB,MAAgC;AAC5D,QAAM,SAAS,KAAK,QAAQ,CAAC,QAAS,MAAM,QAAQ,GAAG,IAAI,MAAM,CAAC,CAAE;AACpE,QAAM,UAAyB,CAAC;AAChC,WAAS,QAAQ,GAAG,QAAQ,OAAO,QAAQ,SAAS,GAAG;AACrD,UAAM,QAAQ,OAAO,KAAK;AAC1B,QAAI,OAAO,UAAU,UAAU;AAC7B;AAAA,IACF;AACA,QAAI,UAAU,WAAW,OAAO,OAAO,QAAQ,CAAC,MAAM,UAAU;AAC9D,cAAQ,MAAM,OAAO,QAAQ,CAAC;AAC9B,eAAS;AAAA,IACX,WAAW,MAAM,WAAW,QAAQ,GAAG;AACrC,cAAQ,MAAM,MAAM,MAAM,SAAS,MAAM;AAAA,IAC3C,WAAW,UAAU,cAAc,OAAO,OAAO,QAAQ,CAAC,MAAM,UAAU;AACxE,cAAQ,SAAS,OAAO,QAAQ,CAAC;AACjC,eAAS;AAAA,IACX,WAAW,MAAM,WAAW,WAAW,GAAG;AACxC,cAAQ,SAAS,MAAM,MAAM,YAAY,MAAM;AAAA,IACjD,WAAW,UAAU,SAAS;AAC5B,cAAQ,MAAM;AAAA,IAChB,WAAW,UAAU,UAAU;AAC7B,cAAQ,OAAO;AAAA,IACjB,WAAW,UAAU,aAAa;AAChC,cAAQ,UAAU;AAAA,IACpB;AAAA,EACF;AACA,SAAO;AACT;","names":["readFile","stat","join","dirname","dirname","join","mkdir","open","join","mkdir","dirname","open","join","readFile","join","commands","readFile","join","readFile","join","readFile","join","readOptional","readFile","stat","stat","join","join","exists","stat","mkdir","readFile","join","readFile","mkdir","join","readFile","mkdir","readFile","stat","join","join","mkdir","stat","readFile","mkdir","readFile","stat","dirname","join","exists","join","mkdir","dirname","readFile","stat","execFile","promisify","stat","join","exists","execFile","promisify","execFileAsync","promisify","execFile","resolve","execFileAsync","promisify","execFile","readFile","stat","join","locks","exists","readdir","stat","join","exists"]}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/package.json
CHANGED
|
@@ -1,49 +1,43 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@nick848/fet",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "Frontend workflow orchestration around OpenSpec
|
|
5
|
-
"type": "module",
|
|
6
|
-
"engines": {
|
|
7
|
-
"node": ">=18"
|
|
8
|
-
},
|
|
9
|
-
"bin": {
|
|
10
|
-
"fet": "./dist/cli.js"
|
|
11
|
-
},
|
|
12
|
-
"
|
|
13
|
-
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
"
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
"
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
"
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
"
|
|
37
|
-
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
"devDependencies": {
|
|
45
|
-
"@types/node": "^22.13.5",
|
|
46
|
-
"typescript": "^5.7.3",
|
|
47
|
-
"vitest": "^3.0.5"
|
|
48
|
-
}
|
|
49
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@nick848/fet",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Frontend workflow orchestration tool built around OpenSpec.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=18"
|
|
8
|
+
},
|
|
9
|
+
"bin": {
|
|
10
|
+
"fet": "./dist/cli/index.js"
|
|
11
|
+
},
|
|
12
|
+
"main": "./dist/index.js",
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsup",
|
|
15
|
+
"dev": "tsx src/cli/index.ts",
|
|
16
|
+
"prepack": "npm run typecheck && npm run test && npm run build",
|
|
17
|
+
"test": "vitest run",
|
|
18
|
+
"test:real-openspec": "vitest run tests/integration/real-openspec.test.ts",
|
|
19
|
+
"typecheck": "tsc --noEmit",
|
|
20
|
+
"release:check": "npm run typecheck && npm run test && npm run build && npm pack --dry-run"
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist"
|
|
24
|
+
],
|
|
25
|
+
"keywords": [
|
|
26
|
+
"openspec",
|
|
27
|
+
"workflow",
|
|
28
|
+
"cli"
|
|
29
|
+
],
|
|
30
|
+
"author": "nick848",
|
|
31
|
+
"license": "MIT",
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"commander": "^12.1.0",
|
|
34
|
+
"yaml": "^2.8.4"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@types/node": "^25.6.0",
|
|
38
|
+
"tsup": "^8.5.1",
|
|
39
|
+
"tsx": "^4.21.0",
|
|
40
|
+
"typescript": "^6.0.3",
|
|
41
|
+
"vitest": "^4.1.5"
|
|
42
|
+
}
|
|
43
|
+
}
|
package/dist/apply.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function runApply(cwd: string): Promise<void>;
|
package/dist/apply.js
DELETED
|
@@ -1,172 +0,0 @@
|
|
|
1
|
-
import chokidar from "chokidar";
|
|
2
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
3
|
-
import { join } from "node:path";
|
|
4
|
-
import { ensureAutoRunApproval } from "./approval.js";
|
|
5
|
-
import { writeFileAtomicSameDirTmp } from "./atomic-write.js";
|
|
6
|
-
import { computeCommandFingerprint } from "./fingerprint.js";
|
|
7
|
-
import { FET_VERSION, getOpenSpecLaunch } from "./openspec.js";
|
|
8
|
-
import { applyInstructionsPath, changeStatePath, tasksPath } from "./paths.js";
|
|
9
|
-
import { defaultChangeState, readChangeState, readGlobalState, reconcileStates, writeChangeState, writeGlobalState, } from "./state.js";
|
|
10
|
-
import { firstIncompleteTask } from "./tasks.js";
|
|
11
|
-
import { resolveWatchRoots } from "./watch-paths.js";
|
|
12
|
-
const APPLY_PHASES = new Set(["planned", "proposed", "implement"]);
|
|
13
|
-
function buildApplyInstructions(params) {
|
|
14
|
-
const front = [
|
|
15
|
-
"---",
|
|
16
|
-
`generatedAt: ${new Date().toISOString()}`,
|
|
17
|
-
`fetVersion: ${FET_VERSION}`,
|
|
18
|
-
`changeId: ${params.changeId}`,
|
|
19
|
-
`taskId: ${params.taskId}`,
|
|
20
|
-
"---",
|
|
21
|
-
"",
|
|
22
|
-
].join("\n");
|
|
23
|
-
const body = [
|
|
24
|
-
`# Apply: ${params.changeId}`,
|
|
25
|
-
"",
|
|
26
|
-
`## Current task (${params.taskId})`,
|
|
27
|
-
"",
|
|
28
|
-
params.taskTitle,
|
|
29
|
-
"",
|
|
30
|
-
"## Required context",
|
|
31
|
-
"",
|
|
32
|
-
"- Read `AGENTS.md` and `openspec/config.yaml` at repo root.",
|
|
33
|
-
`- Read change artifacts under \`openspec/changes/${params.changeId}/\` (proposal, specs, design, tasks).`,
|
|
34
|
-
"",
|
|
35
|
-
"## After coding",
|
|
36
|
-
"",
|
|
37
|
-
"Run in a **second terminal** (this session may be holding the watcher):",
|
|
38
|
-
"",
|
|
39
|
-
"```bash",
|
|
40
|
-
"fet validate",
|
|
41
|
-
"```",
|
|
42
|
-
"",
|
|
43
|
-
].join("\n");
|
|
44
|
-
return front + body;
|
|
45
|
-
}
|
|
46
|
-
function resolveActiveChangeId(cwd) {
|
|
47
|
-
const g = readGlobalState(cwd);
|
|
48
|
-
if (g.activeChangeId)
|
|
49
|
-
return g.activeChangeId;
|
|
50
|
-
if (g.openChanges.length === 1)
|
|
51
|
-
return g.openChanges[0] ?? null;
|
|
52
|
-
return null;
|
|
53
|
-
}
|
|
54
|
-
export async function runApply(cwd) {
|
|
55
|
-
const launch = getOpenSpecLaunch();
|
|
56
|
-
console.log(`[fet] OpenSpec: ${launch.displayPath}`);
|
|
57
|
-
let global = readGlobalState(cwd);
|
|
58
|
-
const rec = reconcileStates(cwd, global);
|
|
59
|
-
global = rec.global;
|
|
60
|
-
for (const w of rec.warnings)
|
|
61
|
-
console.error(`[fet] ${w}`);
|
|
62
|
-
writeGlobalState(cwd, global);
|
|
63
|
-
const changeId = resolveActiveChangeId(cwd);
|
|
64
|
-
if (!changeId) {
|
|
65
|
-
console.error("[fet] No active change. Set openspec/fet-state.json activeChangeId or ensure a single open change.");
|
|
66
|
-
process.exitCode = 1;
|
|
67
|
-
return;
|
|
68
|
-
}
|
|
69
|
-
let cs = readChangeState(cwd, changeId);
|
|
70
|
-
if (!cs)
|
|
71
|
-
cs = defaultChangeState(changeId);
|
|
72
|
-
const phase = (cs.currentPhase || "implement").toLowerCase();
|
|
73
|
-
if (!APPLY_PHASES.has(phase)) {
|
|
74
|
-
console.error(`[fet] apply requires currentPhase in planned | proposed | implement (got "${cs.currentPhase}").`);
|
|
75
|
-
process.exitCode = 1;
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
|
-
const tp = join(cwd, tasksPath(changeId));
|
|
79
|
-
if (!existsSync(tp)) {
|
|
80
|
-
console.error(`[fet] Missing tasks.md for change ${changeId}`);
|
|
81
|
-
process.exitCode = 1;
|
|
82
|
-
return;
|
|
83
|
-
}
|
|
84
|
-
const fpNow = computeCommandFingerprint(cwd);
|
|
85
|
-
if (global.autoRunApproval?.commandFingerprint !== fpNow) {
|
|
86
|
-
global = { ...global, autoRunApproval: undefined };
|
|
87
|
-
writeGlobalState(cwd, global);
|
|
88
|
-
}
|
|
89
|
-
try {
|
|
90
|
-
await ensureAutoRunApproval(cwd);
|
|
91
|
-
}
|
|
92
|
-
catch (e) {
|
|
93
|
-
console.error(e instanceof Error ? e.message : e);
|
|
94
|
-
process.exitCode = 1;
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
const md = readFileSync(tp, "utf8");
|
|
98
|
-
const next = firstIncompleteTask(md);
|
|
99
|
-
if (!next) {
|
|
100
|
-
console.log(`[fet] All tasks appear complete for ${changeId}. Run fet verify when ready.`);
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
const instructions = buildApplyInstructions({
|
|
104
|
-
changeId,
|
|
105
|
-
taskId: next.id,
|
|
106
|
-
taskTitle: next.title || "(no title)",
|
|
107
|
-
});
|
|
108
|
-
const outPath = join(cwd, applyInstructionsPath(changeId));
|
|
109
|
-
writeFileAtomicSameDirTmp(outPath, instructions);
|
|
110
|
-
cs = { ...cs, currentTaskId: next.id, currentPhase: phase };
|
|
111
|
-
writeChangeState(cwd, cs);
|
|
112
|
-
console.log(`[fet] Wrote ${applyInstructionsPath(changeId)} (atomic tmp → rename)`);
|
|
113
|
-
console.log(`[fet] Current task: ${next.id} (auto_next=${next.autoNext})`);
|
|
114
|
-
console.log("[fet] Watching for file activity. When all tasks are done (e.g. after validate), this process will exit. Ctrl+C to stop early.");
|
|
115
|
-
const stateFile = join(cwd, changeStatePath(changeId));
|
|
116
|
-
let debounce = null;
|
|
117
|
-
const roots = resolveWatchRoots(cwd);
|
|
118
|
-
const watched = [...roots, stateFile, join(cwd, tasksPath(changeId))];
|
|
119
|
-
const watcher = chokidar.watch(watched, {
|
|
120
|
-
ignored: /(node_modules|\.git|dist|build)/,
|
|
121
|
-
ignoreInitial: true,
|
|
122
|
-
});
|
|
123
|
-
const bump = (path) => {
|
|
124
|
-
if (debounce)
|
|
125
|
-
clearTimeout(debounce);
|
|
126
|
-
debounce = setTimeout(() => {
|
|
127
|
-
console.log(`[fet] (${path}) idle ~3s since last file change`);
|
|
128
|
-
}, 3000);
|
|
129
|
-
};
|
|
130
|
-
let allDone = false;
|
|
131
|
-
const checkAllTasksDone = () => {
|
|
132
|
-
try {
|
|
133
|
-
const t = readFileSync(join(cwd, tasksPath(changeId)), "utf8");
|
|
134
|
-
if (!firstIncompleteTask(t)) {
|
|
135
|
-
console.log("[fet] All tasks complete. Run `fet verify`. Apply watcher exiting.");
|
|
136
|
-
allDone = true;
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
catch {
|
|
140
|
-
/* ignore */
|
|
141
|
-
}
|
|
142
|
-
};
|
|
143
|
-
await new Promise((resolve) => {
|
|
144
|
-
let settled = false;
|
|
145
|
-
let poll = null;
|
|
146
|
-
const finish = () => {
|
|
147
|
-
if (settled)
|
|
148
|
-
return;
|
|
149
|
-
settled = true;
|
|
150
|
-
if (poll)
|
|
151
|
-
clearInterval(poll);
|
|
152
|
-
watcher.close().then(() => resolve(), () => resolve());
|
|
153
|
-
};
|
|
154
|
-
process.once("SIGINT", finish);
|
|
155
|
-
poll = setInterval(() => {
|
|
156
|
-
checkAllTasksDone();
|
|
157
|
-
if (allDone)
|
|
158
|
-
finish();
|
|
159
|
-
}, 2000);
|
|
160
|
-
watcher.on("all", (_ev, path) => {
|
|
161
|
-
if (path)
|
|
162
|
-
bump(String(path));
|
|
163
|
-
if (path && String(path).replace(/\\/g, "/").endsWith("tasks.md")) {
|
|
164
|
-
checkAllTasksDone();
|
|
165
|
-
if (allDone)
|
|
166
|
-
finish();
|
|
167
|
-
}
|
|
168
|
-
});
|
|
169
|
-
});
|
|
170
|
-
if (debounce)
|
|
171
|
-
clearTimeout(debounce);
|
|
172
|
-
}
|
package/dist/approval.d.ts
DELETED
package/dist/approval.js
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { readGlobalState, writeGlobalState } from "./state.js";
|
|
2
|
-
import { collectScriptFingerprintParts, computeCommandFingerprint } from "./fingerprint.js";
|
|
3
|
-
import { confirmAutoRun } from "./prompt.js";
|
|
4
|
-
/** DESIGN 6.2 / 14.7: shared auto-run approval for apply, validate, verify --auto */
|
|
5
|
-
export async function ensureAutoRunApproval(cwd) {
|
|
6
|
-
let global = readGlobalState(cwd);
|
|
7
|
-
const fp = computeCommandFingerprint(cwd);
|
|
8
|
-
if (global.autoRunApproval?.commandFingerprint === fp)
|
|
9
|
-
return;
|
|
10
|
-
const { parts } = collectScriptFingerprintParts(cwd);
|
|
11
|
-
console.log("[fet] The following may run non-sandboxed scripts (npm test / lint / tsc, etc.):");
|
|
12
|
-
for (const p of parts)
|
|
13
|
-
console.log(` - ${p}`);
|
|
14
|
-
const ok = await confirmAutoRun("[fet] Approve auto-run?");
|
|
15
|
-
if (!ok)
|
|
16
|
-
throw new Error("Approval declined");
|
|
17
|
-
global = {
|
|
18
|
-
...global,
|
|
19
|
-
autoRunApproval: {
|
|
20
|
-
confirmedAt: new Date().toISOString(),
|
|
21
|
-
commandFingerprint: fp,
|
|
22
|
-
packageManager: "npm",
|
|
23
|
-
},
|
|
24
|
-
};
|
|
25
|
-
writeGlobalState(cwd, global);
|
|
26
|
-
}
|
package/dist/atomic-write.d.ts
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
/** DESIGN 14.5: same-dir `*.tmp` then rename (e.g. apply-instructions.md.tmp). */
|
|
2
|
-
export declare function writeFileAtomicSameDirTmp(targetPath: string, content: string): void;
|
|
3
|
-
/** Write text atomically: temp file, fsync, rename (same directory). */
|
|
4
|
-
export declare function writeFileAtomicSync(targetPath: string, content: string): void;
|
|
5
|
-
export declare function backupIfExists(filePath: string): void;
|